Commit 304e535e authored by Matija Obreza's avatar Matija Obreza
Browse files

Ordered vocabulary terms

parent ba3ef426
......@@ -31,6 +31,7 @@ import javax.persistence.Lob;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.OrderColumn;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
......@@ -180,6 +181,7 @@ public class Descriptor extends UuidModel implements Publishable, Copyable<Descr
inverseJoinColumns = @JoinColumn(name = "termId", unique = true),
// unique constraints
uniqueConstraints = { @UniqueConstraint(columnNames = { "descriptorId", "termId" }) })
@OrderColumn(name = "idx")
private List<VocabularyTerm> terms;
/** The owner. */
......
......@@ -26,13 +26,13 @@ import javax.persistence.JoinTable;
import javax.persistence.Lob;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.OrderColumn;
import javax.persistence.UniqueConstraint;
import org.genesys.blocks.model.Publishable;
import org.genesys.blocks.model.UuidModel;
import org.genesys.blocks.security.model.AclAwareModel;
import org.genesys.common.model.Partner;
import org.hibernate.annotations.Cascade;
import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
......@@ -93,6 +93,7 @@ public class ControlledVocabulary extends UuidModel implements Publishable, AclA
inverseJoinColumns = @JoinColumn(name = "termId", unique = true),
// unique constraints
uniqueConstraints = { @UniqueConstraint(columnNames = { "vocabularyId", "termId" }) })
@OrderColumn(name = "idx")
private List<VocabularyTerm> terms;
/** The owner. */
......
......@@ -73,7 +73,7 @@ public interface VocabularyService {
* @return persisted vocabulary
*/
@PreAuthorize("hasRole('ADMINISTRATOR')")
ControlledVocabulary updateOrCreateVocabulary(UUID uuid, ControlledVocabulary updated);
ControlledVocabulary autoUpdateOrCreateVocabulary(UUID uuid, ControlledVocabulary updated);
/**
* Delete vocabulary.
......
......@@ -106,7 +106,9 @@ public class VocabularyServiceImpl implements VocabularyService {
protected ControlledVocabulary lazyLoad(final ControlledVocabulary vocabulary) {
if (vocabulary != null) {
vocabulary.getTerms().size();
vocabulary.getOwner().getId();
if (vocabulary.getOwner() != null) {
vocabulary.getOwner().getId();
}
}
return vocabulary;
}
......@@ -142,7 +144,6 @@ public class VocabularyServiceImpl implements VocabularyService {
vocabulary.setTermUrlPrefix(input.getTermUrlPrefix());
vocabulary.setUrl(input.getUrl());
vocabulary.setVersionTag(input.getVersionTag());
vocabulary.setOwner(input.getOwner());
if (input.getTerms() != null) {
List<VocabularyTerm> terms = vocabulary.getTerms();
......@@ -153,24 +154,75 @@ public class VocabularyServiceImpl implements VocabularyService {
terms.addAll(input.getTerms());
}
}
return lazyLoad(vocabRepository.save(vocabulary));
}
@Override
@Transactional
public ControlledVocabulary updateOrCreateVocabulary(final UUID uuid, final ControlledVocabulary updated) {
public ControlledVocabulary autoUpdateOrCreateVocabulary(final UUID uuid, final ControlledVocabulary input) {
final ControlledVocabulary oldVocabulary = getVocabulary(uuid);
if (oldVocabulary != null) {
updated.setUuid(oldVocabulary.getUuid());
updated.setVersion(oldVocabulary.getVersion());
LOG.info("Updating {} vocabulary with {} terms", oldVocabulary.getTitle(), updated.getTerms().size());
return updateVocabulary(updated);
LOG.info("Updating {} vocabulary with {} terms", oldVocabulary.getTitle(), input.getTerms().size());
if (input.getTerms() != null) {
List<VocabularyTerm> terms = oldVocabulary.getTerms();
updateTerms(terms, input);
if (terms == null) {
oldVocabulary.setTerms(input.getTerms());
} else {
terms.clear();
terms.addAll(input.getTerms());
}
}
return lazyLoad(vocabRepository.save(oldVocabulary));
} else {
updated.setUuid(uuid);
updated.setOwner(partnerService.getPrimaryPartner());
LOG.info("Creating {} vocabulary with {} terms", updated.getTitle(), updated.getTerms().size());
return createVocabulary(updated);
updateTerms(input);
input.setUuid(uuid);
input.setOwner(partnerService.getPrimaryPartner());
LOG.info("Creating {} vocabulary with {} terms", input.getTitle(), input.getTerms().size());
return createVocabulary(input);
}
}
/**
* Maps existing term IDs to input.terms by term code (which is the primary key
* within a vocabulary)
*
* @param terms
* @param input
*/
private void updateTerms(List<VocabularyTerm> existing, ControlledVocabulary input) {
if (existing == null || existing.isEmpty()) {
// Nothing to match against, persist all if them
updateTerms(input);
} else if (input != null && input.getTerms() != null) {
LOG.info("Matching against {} existing terms: {}", existing.size(), existing);
// match existing codes
input.getTerms().forEach(inputTerm -> {
// only when there's a code
if (inputTerm.getCode() != null) {
inputTerm.setId(existing.stream()
// the ones with codes only
.filter(existingTerm -> existingTerm != null && existingTerm.getCode() != null)
// find matching term by code
.filter(existingTerm -> existingTerm.getCode().equals(inputTerm.getCode()))
// get it's ID
.map(existingTerm -> existingTerm.getId())
// get the ID of the existing term by code or null
.findFirst().orElse(null));
if (inputTerm.getId() == null) {
LOG.info("New vocabulary term {}", inputTerm);
}
}
});
}
}
......@@ -192,13 +244,12 @@ public class VocabularyServiceImpl implements VocabularyService {
vocabRepository.delete(vocabulary);
return vocabulary;
}
@Override
public VocabularyTerm getVocabularyTerm(UUID vocabularyUuid, String code) throws NotFoundElement {
return vocabRepository.getVocabularyTerm(vocabularyUuid, code);
}
@Override
public List<VocabularyTerm> autocompleteTerms(UUID vocabularyUuid, String text) {
return vocabRepository.autocompleteVocabularyTerm(vocabularyUuid, text, new PageRequest(0, 20, new Sort("vt.code")));
......
......@@ -21,6 +21,7 @@ import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
......@@ -100,7 +101,7 @@ public class DavrosCountrySource {
inreader.close();
LOG.info("Returning {} countries from Davros", countries.size());
return countries;
return countries.stream().sorted((a, b) -> a.getCode3().compareTo(b.getCode3())).collect(Collectors.toList());
} catch (final ClientProtocolException e) {
LOG.error(e.getMessage(), e);
......
......@@ -21,6 +21,7 @@ import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
......@@ -89,7 +90,7 @@ public class GeonamesISOLanguageSource {
inreader.close();
LOG.info("Returning {} languages data from geonames.org", languages.size());
return languages;
return languages.stream().sorted((a, b) -> a.code.compareTo(b.code)).collect(Collectors.toList());
} catch (final ClientProtocolException e) {
LOG.error(e.getMessage(), e);
......
......@@ -23,6 +23,7 @@ import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
......@@ -41,23 +42,26 @@ import org.springframework.stereotype.Component;
@Component
public class ISO3166VocabularyUpdater {
/**
* ISO 3166-1 alpha-2 representation of names of countries and their subdivisions, contains two-letter country codes
* https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2
*/
public static UUID ISO3166_2ALPHA = UUID.fromString("3e39a73e-d1ed-40b0-9944-ac5795128686");
/**
* ISO 3166-1 alpha-2 representation of names of countries and their
* subdivisions, contains two-letter country codes
* https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2
*/
public static UUID ISO3166_2ALPHA = UUID.fromString("3e39a73e-d1ed-40b0-9944-ac5795128686");
/**
* ISO 3166-1 alpha-2 representation of names of countries and their subdivisions, contains three-letter country codes
* https://en.wikipedia.org/wiki/ISO_3166-1_alpha-3
*/
public static UUID ISO3166_3ALPHA = UUID.fromString("39a3d6a2-20e6-4fab-8bfe-acb1f9fe774c");
/**
* ISO 3166-1 alpha-2 representation of names of countries and their
* subdivisions, contains three-letter country codes
* https://en.wikipedia.org/wiki/ISO_3166-1_alpha-3
*/
public static UUID ISO3166_3ALPHA = UUID.fromString("39a3d6a2-20e6-4fab-8bfe-acb1f9fe774c");
/**
* ISO 3166-1 numeric representation of names of countries and their subdivisions, contains three-letter country codes
* https://en.wikipedia.org/wiki/ISO_3166-1_numeric
*/
public static UUID ISO3166_NUMERIC = UUID.fromString("bd45f660-853f-4034-a434-ed50679579cc");
/**
* ISO 3166-1 numeric representation of names of countries and their
* subdivisions, contains three-letter country codes
* https://en.wikipedia.org/wiki/ISO_3166-1_numeric
*/
public static UUID ISO3166_NUMERIC = UUID.fromString("bd45f660-853f-4034-a434-ed50679579cc");
/** The Constant LOG. */
public static final Log LOG = LogFactory.getLog(ISO3166VocabularyUpdater.class);
......@@ -131,7 +135,7 @@ public class ISO3166VocabularyUpdater {
}
});
vocabulary.setTerms(new ArrayList<>(assignedCodes.values()));
vocabulary.setTerms(new ArrayList<>(assignedCodes.values().stream().sorted((a, b) -> a.getCode().compareTo(b.getCode())).collect(Collectors.toList())));
return vocabulary;
}
......
......@@ -23,6 +23,7 @@ import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
......@@ -96,7 +97,7 @@ public class ISO639VocabularyUpdater {
}
});
vocabulary.setTerms(new ArrayList<>(assignedCodes.values()));
vocabulary.setTerms(new ArrayList<>(assignedCodes.values().stream().sorted((a, b) -> a.getCode().compareTo(b.getCode())).collect(Collectors.toList())));
return vocabulary;
}
}
......@@ -16,12 +16,9 @@
package org.genesys.catalog.server.controller.api.v0;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import org.genesys.catalog.exceptions.NotFoundElement;
import org.genesys.catalog.model.vocab.ControlledVocabulary;
import org.genesys.catalog.model.vocab.VocabularyTerm;
import org.genesys.catalog.service.VocabularyService;
import org.genesys.catalog.service.worker.ISO3166VocabularyUpdater;
......@@ -34,6 +31,7 @@ import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
/**
......@@ -63,12 +61,12 @@ public class GeoController {
@PreAuthorize("hasRole('ADMINISTRATOR')")
@PostMapping(value = "/update")
public List<ControlledVocabulary> updateCountriesCodes() throws IOException {
List<ControlledVocabulary> resultList = new ArrayList<>();
resultList.add(vocabularyService.updateOrCreateVocabulary(ISO3166_2ALPHA, iso3166VocabularyUpdater.getISO3166Alpha2Vocabulary()));
resultList.add(vocabularyService.updateOrCreateVocabulary(ISO3166_3ALPHA, iso3166VocabularyUpdater.getISO3166Alpha3Vocabulary()));
resultList.add(vocabularyService.updateOrCreateVocabulary(ISO3166_NUMERIC, iso3166VocabularyUpdater.getISO3166NumericVocabulary()));
return resultList;
public @ResponseBody String updateCountriesCodes() throws IOException {
LOG.info("Updating ISO country codes");
vocabularyService.autoUpdateOrCreateVocabulary(ISO3166_2ALPHA, iso3166VocabularyUpdater.getISO3166Alpha2Vocabulary());
vocabularyService.autoUpdateOrCreateVocabulary(ISO3166_3ALPHA, iso3166VocabularyUpdater.getISO3166Alpha3Vocabulary());
vocabularyService.autoUpdateOrCreateVocabulary(ISO3166_NUMERIC, iso3166VocabularyUpdater.getISO3166NumericVocabulary());
return "OK";
}
@GetMapping(value = "/iso3166/{code}", produces = MediaType.APPLICATION_JSON_VALUE)
......
......@@ -20,7 +20,6 @@ import java.util.Collections;
import java.util.List;
import java.util.UUID;
import org.genesys.catalog.model.vocab.ControlledVocabulary;
import org.genesys.catalog.model.vocab.VocabularyTerm;
import org.genesys.catalog.service.VocabularyService;
import org.genesys.catalog.service.worker.ISO639VocabularyUpdater;
......@@ -34,6 +33,7 @@ import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
/**
......@@ -59,8 +59,10 @@ public class LanguagesController {
@PreAuthorize("hasRole('ADMINISTRATOR')")
@PostMapping(value = "/update")
public ControlledVocabulary updateLanguages() throws IOException {
return vocabularyService.updateOrCreateVocabulary(ISO639_3, iso639VocabularyUpdater.getISO639Vocabulary());
public @ResponseBody String updateLanguages() throws IOException {
LOG.info("Updating ISO language codes");
vocabularyService.autoUpdateOrCreateVocabulary(ISO639_3, iso639VocabularyUpdater.getISO639Vocabulary());
return "OK";
}
@GetMapping(value = "/{code}", produces = MediaType.APPLICATION_JSON_VALUE)
......
......@@ -3334,3 +3334,48 @@ databaseChangeLog:
columnNames: uuid
constraintName: UK_l9msbmdgixl9wywrs5y2kxutp
tableName: crop
# Ordered terms
- changeSet:
id: 1516900616713-1
author: mobreza (generated)
changes:
- addColumn:
columns:
- column:
defaultValueNumeric: 0
constraints:
nullable: false
name: idx
type: INT(10)
tableName: controlled_vocabulary_term
- addPrimaryKey:
columnNames: vocabulary_id, term_id
constraintName: PRIMARY
tableName: controlled_vocabulary_term
- dropDefaultValue:
columnDataType: INT(10)
columnName: idx
tableName: controlled_vocabulary_term
- changeSet:
id: 1516900616713-2
author: mobreza (generated)
changes:
- addColumn:
columns:
- column:
defaultValueNumeric: 0
constraints:
nullable: false
name: idx
type: INT(10)
tableName: descriptor_term
- addPrimaryKey:
columnNames: descriptor_id, term_id
constraintName: PRIMARY
tableName: descriptor_term
- dropDefaultValue:
columnDataType: INT(10)
columnName: idx
tableName: descriptor_term
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment