Commit 861e5d88 authored by Matija Obreza's avatar Matija Obreza
Browse files

Merge branch '128-vocabularyterm-with-id' into 'master'

Resolve "VocabularyTerm with id"

Closes #128

See merge request !119
parents 666aaaeb 304e535e
......@@ -20,17 +20,18 @@ import java.util.List;
import javax.persistence.Cacheable;
import javax.persistence.CascadeType;
import javax.persistence.CollectionTable;
import javax.persistence.Column;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
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;
......@@ -135,13 +136,13 @@ public class Descriptor extends UuidModel implements Publishable, Copyable<Descr
@Column(nullable = false)
private DataType dataType;
/** The key. */
@Column(name = "keyDescriptor")
/** The key. */
@Column(name = "keyDescriptor", nullable = false)
private boolean key;
/** The publisher. */
@Column(length = 200)
private String publisher;
/** The publisher. */
@Column(length = 200)
private String publisher;
/** Not published by default. */
private boolean published = false;
......@@ -174,10 +175,13 @@ public class Descriptor extends UuidModel implements Publishable, Copyable<Descr
/**
* Vocabulary terms specific to this descriptor (99% of the cases).
*/
@ElementCollection(fetch = FetchType.LAZY)
@CollectionTable(name = "DescriptorTerm", joinColumns = @JoinColumn(name = "descriptorId"),
@OneToMany(fetch = FetchType.LAZY, cascade = { CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH }, orphanRemoval = true)
@JoinTable(name = "DescriptorTerm", joinColumns = @JoinColumn(name = "descriptorId"),
// other side
inverseJoinColumns = @JoinColumn(name = "termId", unique = true),
// unique constraints
uniqueConstraints = { @UniqueConstraint(columnNames = { "descriptorId", "code" }) })
uniqueConstraints = { @UniqueConstraint(columnNames = { "descriptorId", "termId" }) })
@OrderColumn(name = "idx")
private List<VocabularyTerm> terms;
/** The owner. */
......@@ -213,9 +217,9 @@ public class Descriptor extends UuidModel implements Publishable, Copyable<Descr
* @param descriptor the descriptor
*/
public Descriptor(final Descriptor descriptor) {
this(descriptor.getVersionTag(), descriptor.getTitle(), descriptor.description, descriptor.getDataType(), descriptor.isPublished(), descriptor.isKey(), descriptor.getIntegerOnly(), descriptor
.getMinValue(), descriptor.getMaxValue(), descriptor.getColumnName(), descriptor.getUom(), descriptor.getVocabulary(), descriptor.getOwner(), descriptor
.getDescriptorLists());
this(descriptor.getVersionTag(), descriptor.getTitle(), descriptor.description, descriptor.getDataType(), descriptor.isPublished(), descriptor.isKey(), descriptor
.getIntegerOnly(), descriptor.getMinValue(), descriptor.getMaxValue(), descriptor.getColumnName(), descriptor.getUom(), descriptor.getVocabulary(), descriptor
.getOwner(), descriptor.getDescriptorLists());
}
/**
......@@ -236,9 +240,9 @@ public class Descriptor extends UuidModel implements Publishable, Copyable<Descr
* @param owner the owner
* @param descriptorLists the descriptor lists
*/
public Descriptor(final String versionTag, final String title, final String description, final DataType dataType, final boolean published, final boolean key, final Boolean integerOnly,
final Double minValue, final Double maxValue, final String columnName, final String uom, final ControlledVocabulary vocabulary, final Partner owner,
final List<DescriptorList> descriptorLists) {
public Descriptor(final String versionTag, final String title, final String description, final DataType dataType, final boolean published, final boolean key,
final Boolean integerOnly, final Double minValue, final Double maxValue, final String columnName, final String uom, final ControlledVocabulary vocabulary,
final Partner owner, final List<DescriptorList> descriptorLists) {
this.versionTag = versionTag;
this.title = title;
this.description = description;
......@@ -501,43 +505,43 @@ public class Descriptor extends UuidModel implements Publishable, Copyable<Descr
this.vocabulary = vocabulary;
}
/**
* Checks if is key.
*
* @return the key
*/
public boolean isKey() {
return key;
}
/**
* Sets the key.
*
* @param key the key to set
*/
public void setKey(final boolean key) {
this.key = key;
}
/**
/**
* Checks if is key.
*
* @return the key
*/
public boolean isKey() {
return key;
}
/**
* Sets the key.
*
* @param key the key to set
*/
public void setKey(final boolean key) {
this.key = key;
}
/**
* Sets the publisher.
*
* @param publisher the new publisher
*/
public void setPublisher(String publisher) {
public void setPublisher(String publisher) {
this.publisher = publisher;
}
/**
/**
* Gets the publisher.
*
* @return the publisher
*/
public String getPublisher() {
public String getPublisher() {
return publisher;
}
/**
/**
* Checks if is published.
*
* @return the published
......@@ -628,9 +632,14 @@ public class Descriptor extends UuidModel implements Publishable, Copyable<Descr
Copyable.super.apply(source);
if (source.getTerms() != null) {
this.terms = new ArrayList<>(source.getTerms());
if (this.terms == null) {
this.terms = new ArrayList<>(source.getTerms());
} else {
this.terms.clear();
this.terms.addAll(source.getTerms());
}
}
if ((this.dataType == DataType.CODED || this.dataType == DataType.SCALE) && ((this.terms == null || this.terms.size() == 0) && this.vocabulary == null)) {
throw new DataIntegrityViolationException("Coded descriptor " + this.title + " requires a vocabulary");
}
......@@ -675,9 +684,9 @@ public class Descriptor extends UuidModel implements Publishable, Copyable<Descr
}
// When using a specified vocabulary
if (this.vocabulary != null) {
if (this.vocabulary != null && this.terms != null) {
// We don't use our terms
this.terms = null;
this.terms.clear();
}
return this;
......
......@@ -17,14 +17,16 @@ package org.genesys.catalog.model.vocab;
import java.util.List;
import javax.persistence.CollectionTable;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
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;
......@@ -85,10 +87,13 @@ public class ControlledVocabulary extends UuidModel implements Publishable, AclA
private String termUrlPrefix;
/** The terms. */
@ElementCollection(fetch = FetchType.EAGER)
@CollectionTable(name = "ControlledVocabularyTerm", joinColumns = @JoinColumn(name = "vocabularyId"),
@OneToMany(fetch = FetchType.LAZY, cascade = { CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH }, orphanRemoval = true)
@JoinTable(name = "ControlledVocabularyTerm", joinColumns = @JoinColumn(name = "vocabularyId"),
// other side
inverseJoinColumns = @JoinColumn(name = "termId", unique = true),
// unique constraints
uniqueConstraints = { @UniqueConstraint(columnNames = { "vocabularyId", "code" }) })
uniqueConstraints = { @UniqueConstraint(columnNames = { "vocabularyId", "termId" }) })
@OrderColumn(name = "idx")
private List<VocabularyTerm> terms;
/** The owner. */
......@@ -131,7 +136,7 @@ public class ControlledVocabulary extends UuidModel implements Publishable, AclA
public void setPublished(final boolean published) {
this.published = published;
}
/**
* Gets the publisher.
*
......@@ -140,7 +145,7 @@ public class ControlledVocabulary extends UuidModel implements Publishable, AclA
public String getPublisher() {
return publisher;
}
/**
* Sets the publisher.
*
......@@ -259,5 +264,4 @@ public class ControlledVocabulary extends UuidModel implements Publishable, AclA
this.terms = terms;
}
}
......@@ -15,12 +15,14 @@
*/
package org.genesys.catalog.model.vocab;
import java.io.Serializable;
import java.text.MessageFormat;
import javax.persistence.Column;
import javax.persistence.Embeddable;
import javax.persistence.Entity;
import javax.persistence.Lob;
import javax.persistence.Table;
import org.genesys.blocks.model.BasicModel;
/**
* A single vocabulary term, belonging to a {@link ControlledVocabulary}.
......@@ -35,14 +37,15 @@ import javax.persistence.Lob;
*
* @author Matija Obreza
*/
@Embeddable
public class VocabularyTerm implements Serializable {
@Entity
@Table(name = "Term")
public class VocabularyTerm extends BasicModel {
/** The Constant serialVersionUID. */
private static final long serialVersionUID = 6568957772654494563L;
/** Term code. */
@Column(nullable = false)
@Column(nullable = false, length = 50)
private String code;
/**
......
......@@ -15,10 +15,14 @@
*/
package org.genesys.catalog.persistence.vocab;
import java.util.List;
import java.util.UUID;
import org.genesys.catalog.model.vocab.ControlledVocabulary;
import org.genesys.catalog.model.vocab.VocabularyTerm;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.querydsl.QueryDslPredicateExecutor;
import org.springframework.stereotype.Repository;
......@@ -44,4 +48,25 @@ public interface ControlledVocabularyRepository extends JpaRepository<Controlled
* @return the by uuid and version
*/
ControlledVocabulary getByUuidAndVersion(UUID uuid, int version);
/**
* Gets the vocabulary term.
*
* @param vocabularyUuid the vocabulary uuid
* @param code the code
* @return the vocabulary term
*/
@Query("select vt from ControlledVocabulary cv inner join cv.terms as vt where cv.uuid = ?1 and vt.code = ?2")
VocabularyTerm getVocabularyTerm(UUID vocabularyUuid, String code);
/**
* Autocomplete vocabulary term.
*
* @param vocabularyUuid the vocabulary uuid
* @param text the text
* @param page the page
* @return the list
*/
@Query("select vt from ControlledVocabulary cv inner join cv.terms as vt where cv.uuid = ?1 and (vt.code like concat(?2, '%') or vt.title like concat(?2, '%') or vt.description like concat(?2, '%'))")
List<VocabularyTerm> autocompleteVocabularyTerm(UUID vocabularyUuid, String text, Pageable page);
}
/*
* Copyright 2017 Global Crop Diversity Trust
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.genesys.catalog.persistence.vocab;
import org.genesys.catalog.model.vocab.VocabularyTerm;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.querydsl.QueryDslPredicateExecutor;
import org.springframework.stereotype.Repository;
/**
* The Interface VocabularyTerm.
*/
@Repository
public interface VocabularyTermRepository extends JpaRepository<VocabularyTerm, Long>, QueryDslPredicateExecutor<VocabularyTerm> {
}
......@@ -15,9 +15,12 @@
*/
package org.genesys.catalog.service;
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.filters.ControlledVocabularyFilter;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
......@@ -62,15 +65,15 @@ public interface VocabularyService {
@PreAuthorize("hasRole('ADMINISTRATOR') or hasPermission(#input, 'write')")
ControlledVocabulary updateVocabulary(ControlledVocabulary input);
/**
* Update persisted vocabulary or register a new controlled vocabulary
*
* @param updated updated vocabulary definition
* @param uuid the uuid
* @return persisted vocabulary
*/
@PreAuthorize("hasRole('ADMINISTRATOR')")
ControlledVocabulary updateOrCreateVocabulary(UUID uuid, ControlledVocabulary updated);
/**
* Update persisted vocabulary or register a new controlled vocabulary.
*
* @param uuid the uuid
* @param updated updated vocabulary definition
* @return persisted vocabulary
*/
@PreAuthorize("hasRole('ADMINISTRATOR')")
ControlledVocabulary autoUpdateOrCreateVocabulary(UUID uuid, ControlledVocabulary updated);
/**
* Delete vocabulary.
......@@ -90,4 +93,22 @@ public interface VocabularyService {
*/
Page<ControlledVocabulary> listVocabularies(ControlledVocabularyFilter filters, Pageable page);
/**
* Gets the vocabulary term.
*
* @param vocabularyUuid the vocabulary uuid
* @param code the code
* @return the vocabulary term
*/
VocabularyTerm getVocabularyTerm(UUID vocabularyUuid, String code) throws NotFoundElement;
/**
* Autocomplete vocabulary term
*
* @param vocabularyUuid
* @param text
* @return
*/
List<VocabularyTerm> autocompleteTerms(UUID vocabularyUuid, String text);
}
......@@ -24,7 +24,9 @@ import org.genesys.catalog.exceptions.InvalidApiUsageException;
import org.genesys.catalog.exceptions.NotFoundElement;
import org.genesys.catalog.model.traits.Descriptor;
import org.genesys.catalog.model.traits.Descriptor.DataType;
import org.genesys.catalog.model.vocab.VocabularyTerm;
import org.genesys.catalog.persistence.traits.DescriptorRepository;
import org.genesys.catalog.persistence.vocab.VocabularyTermRepository;
import org.genesys.catalog.service.DescriptorService;
import org.genesys.catalog.service.filters.DescriptorFilter;
import org.genesys.catalog.util.Utils;
......@@ -57,6 +59,9 @@ public class DescriptorServiceImpl implements DescriptorService {
@Autowired
private DescriptorRepository descriptorRepository;
@Autowired
private VocabularyTermRepository termRepository;
/** The utils. */
@Autowired
private Utils utils;
......@@ -69,6 +74,8 @@ public class DescriptorServiceImpl implements DescriptorService {
public Descriptor createDescriptor(final Descriptor input) {
LOG.info("Creating descriptor: {} - {}", input.getTitle(), input.getDataType());
updateTerms(input);
final Descriptor descriptor = new Descriptor();
descriptor.apply(input);
descriptor.setUuid(input.getUuid());
......@@ -77,6 +84,22 @@ public class DescriptorServiceImpl implements DescriptorService {
return lazyLoad(descriptorRepository.save(descriptor));
}
/**
* Persist or update terms in descriptor itself. It updates descriptor's own
* terms List
*
* @param descriptor
*/
protected void updateTerms(final Descriptor descriptor) {
List<VocabularyTerm> terms = descriptor.getTerms();
if (terms != null && !terms.isEmpty()) {
List<VocabularyTerm> r = termRepository.save(terms);
terms.clear();
System.err.println("Adding " + r);
terms.addAll(r);
}
}
/**
* {@inheritDoc}
*/
......@@ -95,10 +118,10 @@ public class DescriptorServiceImpl implements DescriptorService {
throw new InvalidApiUsageException("Descriptor owner can't be changed");
}
updateTerms(input);
descriptor.apply(input);
// Keep owner
descriptor.setOwner(owner);
return lazyLoad(descriptorRepository.save(descriptor));
}
......@@ -214,7 +237,8 @@ public class DescriptorServiceImpl implements DescriptorService {
}
} else {
// clear terms list
descriptor.setTerms(null);
if (descriptor.getTerms() != null)
descriptor.getTerms().clear();
}
return descriptor;
......@@ -241,6 +265,7 @@ public class DescriptorServiceImpl implements DescriptorService {
target.setUuid(source.getUuid());
}
updates.add(target);
updateTerms(source);
target.apply(source);
}
......
......@@ -16,11 +16,15 @@
package org.genesys.catalog.service.impl;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import org.genesys.catalog.exceptions.InvalidApiUsageException;
import org.genesys.catalog.exceptions.NotFoundElement;
import org.genesys.catalog.model.vocab.ControlledVocabulary;
import org.genesys.catalog.model.vocab.VocabularyTerm;
import org.genesys.catalog.persistence.vocab.ControlledVocabularyRepository;
import org.genesys.catalog.persistence.vocab.VocabularyTermRepository;
import org.genesys.catalog.service.PartnerService;
import org.genesys.catalog.service.VocabularyService;
import org.genesys.catalog.service.filters.ControlledVocabularyFilter;
......@@ -31,7 +35,9 @@ import org.springframework.dao.ConcurrencyFailureException;
import org.springframework.dao.DataAccessResourceFailureException;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
......@@ -48,7 +54,10 @@ public class VocabularyServiceImpl implements VocabularyService {
private ControlledVocabularyRepository vocabRepository;
@Autowired
private PartnerService partnerService;
private VocabularyTermRepository termRepository;
@Autowired
private PartnerService partnerService;
@Override
@Transactional
......@@ -64,6 +73,7 @@ public class VocabularyServiceImpl implements VocabularyService {
controlledVocabulary.setOwner(input.getOwner());
if ((input.getTerms() != null) && !input.getTerms().isEmpty()) {
updateTerms(input);
controlledVocabulary.setTerms(input.getTerms());
} else {
controlledVocabulary.setTerms(new ArrayList<>());
......@@ -71,6 +81,22 @@ public class VocabularyServiceImpl implements VocabularyService {
return lazyLoad(vocabRepository.save(controlledVocabulary));
}
/**
* Persist or update terms in descriptor itself. It updates descriptor's own
* terms List
*
* @param descriptor
*/
protected void updateTerms(final ControlledVocabulary vocabulary) {
List<VocabularyTerm> terms = vocabulary.getTerms();
if (terms != null && !terms.isEmpty()) {
List<VocabularyTerm> r = termRepository.save(terms);
terms.clear();
System.err.println("Adding " + r);
terms.addAll(r);
}
}
@Override
public ControlledVocabulary getVocabulary(final UUID uuid) {
final ControlledVocabulary vocabulary = vocabRepository.getByUuid(uuid);
......@@ -80,6 +106,9 @@ public class VocabularyServiceImpl implements VocabularyService {
protected ControlledVocabulary lazyLoad(final ControlledVocabulary vocabulary) {
if (vocabulary != null) {
vocabulary.getTerms().size();
if (vocabulary.getOwner() != null) {
vocabulary.getOwner().getId();
}
}
return vocabulary;
}
......@@ -106,6 +135,8 @@ public class VocabularyServiceImpl implements VocabularyService {
throw new DataAccessResourceFailureException("Published vocabulary can't be updated");
}
updateTerms(input);
vocabulary.setDescription(input.getDescription());
vocabulary.setPublished(input.isPublished());
vocabulary.setPublisher(input.getPublisher());
......@@ -113,28 +144,87 @@ public class VocabularyServiceImpl implements VocabularyService {
vocabulary.setTermUrlPrefix(input.getTermUrlPrefix());
vocabulary.setUrl(input.getUrl());
vocabulary.setVersionTag(input.getVersionTag());