cdmlib-model/src/main/java/eu/etaxonomy/cdm/strategy/parser/NonViralNameParserImpl.java -text
cdmlib-model/src/main/java/eu/etaxonomy/cdm/strategy/parser/NonViralNameParserImplRegExBase.java -text
cdmlib-model/src/main/java/eu/etaxonomy/cdm/strategy/parser/ParserProblem.java -text
+cdmlib-model/src/main/java/eu/etaxonomy/cdm/validation/Level2.java -text
+cdmlib-model/src/main/java/eu/etaxonomy/cdm/validation/Level3.java -text
+cdmlib-model/src/main/java/eu/etaxonomy/cdm/validation/annotation/CorrectEpithetsForRank.java -text
+cdmlib-model/src/main/java/eu/etaxonomy/cdm/validation/annotation/NoDuplicateNames.java -text
+cdmlib-model/src/main/java/eu/etaxonomy/cdm/validation/annotation/NullOrNotEmpty.java -text
+cdmlib-model/src/main/java/eu/etaxonomy/cdm/validation/constraint/CorrectEpithetsForRankValidator.java -text
+cdmlib-model/src/main/java/eu/etaxonomy/cdm/validation/constraint/NullOrNotEmptyValidator.java -text
+cdmlib-model/src/main/java/eu/etaxonomy/cdm/validation/constraint/StubValidator.java -text
+cdmlib-model/src/main/resources/ValidationMessages.properties -text
cdmlib-model/src/main/resources/log4j.properties -text
cdmlib-model/src/main/resources/terms/AbsenceTerm.csv -text
cdmlib-model/src/main/resources/terms/AnnotationType.csv -text
cdmlib-model/src/site/site.xml -text
cdmlib-model/src/test/java/eu/etaxonomy/cdm/aspectj/PropertyChangeTest.java -text
cdmlib-model/src/test/java/eu/etaxonomy/cdm/model/DatabaseInitialiser.java -text
+cdmlib-model/src/test/java/eu/etaxonomy/cdm/model/agent/AgentValidationTest.java -text
cdmlib-model/src/test/java/eu/etaxonomy/cdm/model/agent/InstitutionTypeTest.java -text
cdmlib-model/src/test/java/eu/etaxonomy/cdm/model/agent/InstitutionalMembershipTest.java -text
cdmlib-model/src/test/java/eu/etaxonomy/cdm/model/common/AnnotationTest.java -text
-<?xml version="1.0" encoding="UTF-8"?><project>
+<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<artifactId>cdmlib-parent</artifactId>
<groupId>eu.etaxonomy</groupId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
- <artifactId>spring-jdbc</artifactId>
+ <artifactId>org.springframework.jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
- <artifactId>spring-test</artifactId>
+ <artifactId>org.springframework.test</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
- <artifactId>spring-aspects</artifactId>
+ <artifactId>org.springframework.aspects</artifactId>
</dependency>
<dependency>
<groupId>net.sf.opencsv</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.1</version>
</dependency>
+ <dependency>
+ <groupId>jdom</groupId>
+ <artifactId>jdom</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>javax.validation</groupId>
+ <artifactId>validation-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.hibernate</groupId>
+ <artifactId>hibernate-validator</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-log4j12</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>jdom</groupId>
+ <artifactId>jdom</artifactId>
+ </dependency>
</dependencies>
</project>
\ No newline at end of file
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.Transient;
+import javax.validation.constraints.NotNull;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
@Embedded
@Merge(MergeMode.MERGE)
@Match(MatchMode.IGNORE)
+ @NotNull
private Contact contact;
/**
* @see Contact
*/
public Contact getContact(){
+ if(contact == null) {
+ this.contact = new Contact();
+ }
return this.contact;
}
/**
import javax.persistence.FetchType;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy;
import eu.etaxonomy.cdm.strategy.cache.common.IdentifiableEntityDefaultCacheStrategy;
+import eu.etaxonomy.cdm.validation.annotation.NullOrNotEmpty;
/**
* This class represents public or private institutions.
@XmlElement(name = "Code")
@Field(index=Index.TOKENIZED)
+ @NullOrNotEmpty
+ @Size(max = 255)
private String code;
@XmlElement(name = "Name")
@Field(index=Index.TOKENIZED)
+ @NullOrNotEmpty
+ @Size(max = 255)
private String name;
@XmlElementWrapper(name = "Types")
@XmlIDREF
@XmlSchemaType(name = "IDREF")
@ManyToMany(fetch = FetchType.LAZY)
+ @NotNull
private Set<InstitutionType> types = new HashSet<InstitutionType>();
@XmlElement(name = "IsPartOf")
* @see InstitutionType
*/
public Set<InstitutionType> getTypes(){
+ if(types == null) {
+ this.types = new HashSet<InstitutionType>();
+ }
return this.types;
}
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.OneToMany;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
+import javax.xml.bind.annotation.XmlIDREF;
import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlSchemaType;
import javax.xml.bind.annotation.XmlType;
import org.apache.log4j.Logger;
import org.hibernate.search.annotations.Index;
import org.hibernate.search.annotations.Indexed;
import org.hibernate.search.annotations.IndexedEmbedded;
+import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Configurable;
import eu.etaxonomy.cdm.model.common.TimePeriod;
import eu.etaxonomy.cdm.strategy.cache.agent.PersonDefaultCacheStrategy;
import eu.etaxonomy.cdm.strategy.match.Match;
import eu.etaxonomy.cdm.strategy.match.MatchMode;
+import eu.etaxonomy.cdm.validation.annotation.NullOrNotEmpty;
/**
* This class represents human beings, living or dead.<BR>
@XmlElement(name = "Prefix")
@Field(index=Index.TOKENIZED)
+ @NullOrNotEmpty
+ @Size(max = 255)
private String prefix;
@XmlElement(name = "FirstName")
@Field(index=Index.TOKENIZED)
+ @NullOrNotEmpty
+ @Size(max = 255)
private String firstname;
@XmlElement(name = "LastName")
@Field(index=Index.TOKENIZED)
+ @NullOrNotEmpty
+ @Size(max = 255)
private String lastname;
@XmlElement(name = "Suffix")
@Field(index=Index.TOKENIZED)
+ @NullOrNotEmpty
+ @Size(max = 255)
private String suffix;
@XmlElement(name = "Lifespan")
@IndexedEmbedded
@Match(value=MatchMode.EQUAL_OR_ONE_NULL)
+ @NotNull
private TimePeriod lifespan = TimePeriod.NewInstance();
@XmlElementWrapper(name = "InstitutionalMemberships")
@XmlElement(name = "InstitutionalMembership")
@OneToMany(fetch=FetchType.LAZY, mappedBy = "person")
@Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE})
+ @NotNull
protected Set<InstitutionalMembership> institutionalMemberships = new HashSet<InstitutionalMembership>();
/**
* @see InstitutionalMembership
*/
public Set<InstitutionalMembership> getInstitutionalMemberships(){
+ if(institutionalMemberships == null) {
+ this.institutionalMemberships = new HashSet<InstitutionalMembership>();
+ }
return this.institutionalMemberships;
}
* @see eu.etaxonomy.cdm.model.common.TimePeriod
*/
public TimePeriod getLifespan(){
+ if(lifespan == null) {
+ this.lifespan = TimePeriod.NewInstance(new DateTime(),new DateTime());
+ }
return this.lifespan;
}
/**
import javax.persistence.FetchType;
import javax.persistence.ManyToMany;
import javax.persistence.Transient;
+import javax.validation.constraints.NotNull;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
@ManyToMany(fetch = FetchType.LAZY)
@Cascade(CascadeType.SAVE_UPDATE)
@Match(MatchMode.MATCH)
+ @NotNull
private List<Person> teamMembers = new ArrayList<Person>();
* A person may be a member of several distinct teams.
*/
public List<Person> getTeamMembers(){
+ if(teamMembers == null) {
+ this.teamMembers = new ArrayList<Person>();
+ }
return this.teamMembers;
}
\r
import javax.persistence.Entity;\r
import javax.persistence.Transient;\r
+import javax.validation.constraints.Size;\r
import javax.xml.bind.annotation.XmlAccessType;\r
import javax.xml.bind.annotation.XmlAccessorType;\r
import javax.xml.bind.annotation.XmlElement;\r
import org.hibernate.search.annotations.Field;\r
import org.hibernate.search.annotations.Index;\r
import org.hibernate.search.annotations.Indexed;\r
-\r
+import eu.etaxonomy.cdm.common.CdmUtils;\r
import eu.etaxonomy.cdm.common.CdmUtils;\r
import eu.etaxonomy.cdm.strategy.cache.agent.INomenclaturalAuthorCacheStrategy;\r
-import eu.etaxonomy.cdm.strategy.match.IMatchable;\r
+import eu.etaxonomy.cdm.validation.annotation.NullOrNotEmpty;\r
\r
\r
/**\r
\r
@XmlElement(name="NomenclaturalTitle")\r
@Field(index=Index.TOKENIZED)\r
+ @NullOrNotEmpty\r
+ @Size(max = 255)\r
protected String nomenclaturalTitle;\r
\r
@Transient\r
import javax.persistence.FetchType;
import javax.persistence.MappedSuperclass;
import javax.persistence.OneToMany;
+import javax.validation.constraints.NotNull;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
@XmlElementWrapper(name = "Markers")
@XmlElement(name = "Marker")
@OneToMany(fetch=FetchType.LAZY)
- @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE})
+ @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE, CascadeType.DELETE_ORPHAN})
@Merge(MergeMode.ADD_CLONE)
+ @NotNull
protected Set<Marker> markers = new HashSet<Marker>();
@XmlElementWrapper(name = "Annotations")
@XmlElement(name = "Annotation")
@OneToMany(fetch=FetchType.LAZY)
- @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE})
+ @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE, CascadeType.DELETE_ORPHAN})
@Merge(MergeMode.ADD_CLONE)
+ @NotNull
protected Set<Annotation> annotations = new HashSet<Annotation>();
protected AnnotatableEntity() {
public Set<Marker> getMarkers(){
+ if(markers == null) {
+ this.markers = new HashSet<Marker>();
+ }
return this.markers;
}
public void addMarker(Marker marker){
//*************** ANNOTATIONS **********************************************
public Set<Annotation> getAnnotations(){
+ if(annotations == null) {
+ this.annotations = new HashSet<Annotation>();
+ }
return this.annotations;
}
public void addAnnotation(Annotation annotation){
import javax.persistence.ManyToOne;
import javax.persistence.MappedSuperclass;
import javax.persistence.Transient;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Min;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
@GeneratedValue(generator = "system-increment")
@DocumentId
@Match(MatchMode.IGNORE)
+ @NotNull
+ @Min(0)
private int id;
@XmlAttribute(required = true)
@XmlJavaTypeAdapter(UUIDAdapter.class)
@XmlID
@Type(type="uuidUserType")
- @NaturalId
+ @NaturalId // This has the effect of placing a "unique" constraint on the database column
@Column(length=36)
@Match(MatchMode.IGNORE)
+ @NotNull
protected UUID uuid;
@XmlElement (name = "Created", type= String.class)
\r
import java.util.UUID;\r
\r
+import javax.validation.GroupSequence;\r
+import javax.validation.groups.Default;\r
+\r
import org.joda.time.DateTime;\r
\r
-import eu.etaxonomy.cdm.model.agent.Person;\r
+import eu.etaxonomy.cdm.validation.Level2;\r
+import eu.etaxonomy.cdm.validation.Level3;\r
\r
+@GroupSequence({Default.class, Level2.class, Level3.class})\r
public interface ICdmBase {\r
\r
/**\r
import javax.persistence.MappedSuperclass;
import javax.persistence.OneToMany;
import javax.persistence.Transient;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import org.hibernate.search.annotations.Field;
import org.hibernate.search.annotations.FieldBridge;
import org.hibernate.search.annotations.Fields;
+import org.hibernate.validator.constraints.NotEmpty;
import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
import eu.etaxonomy.cdm.hibernate.StripHtmlBridge;
import eu.etaxonomy.cdm.strategy.match.Match.ReplaceMode;
import eu.etaxonomy.cdm.strategy.merge.Merge;
import eu.etaxonomy.cdm.strategy.merge.MergeMode;
+import eu.etaxonomy.cdm.validation.Level2;
/**
* Superclass for the primary CDM classes that can be referenced from outside via LSIDs and contain a simple generated title string as a label for human reading.
})
@FieldBridge(impl=StripHtmlBridge.class)
@Match(value=MatchMode.CACHE, cacheReplaceMode=ReplaceMode.ALL)
+ @NotEmpty(groups = Level2.class) // implictly NotNull
+ @Size(max = 255)
protected String titleCache;
//if true titleCache will not be automatically generated/updated
@Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE})
//TODO
@Merge(MergeMode.ADD_CLONE)
+ @NotNull
private Set<Rights> rights = new HashSet<Rights>();
@XmlElementWrapper(name = "Credits")
@Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE})
//TODO
@Merge(MergeMode.ADD_CLONE)
+ @NotNull
private List<Credit> credits = new ArrayList<Credit>();
@XmlElementWrapper(name = "Extensions")
@XmlElement(name = "Extension")
@OneToMany(fetch = FetchType.LAZY)
- @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE})
+ @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE, CascadeType.DELETE_ORPHAN})
@Merge(MergeMode.ADD_CLONE)
+ @NotNull
private Set<Extension> extensions = new HashSet<Extension>();
@XmlElementWrapper(name = "Sources")
@XmlElement(name = "OriginalSource")
@OneToMany(fetch = FetchType.LAZY)
- @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE})
+ @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE, CascadeType.DELETE_ORPHAN})
@Merge(MergeMode.ADD_CLONE)
+ @NotNull
private Set<IdentifiableSource> sources = new HashSet<IdentifiableSource>();
@XmlTransient
};
addPropertyChangeListener(listener);
}
-
/**
* By default, we expect most cdm objects to be abstract things
*/
public byte[] getData() {
return null;
- }
+ }
//******************************** CACHE *****************************************************/
public void setLsid(LSID lsid){
this.lsid = lsid;
}
-
-
/* (non-Javadoc)
* @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#getRights()
*/
public Set<Rights> getRights() {
+ if(rights == null) {
+ this.rights = new HashSet<Rights>();
+ }
return this.rights;
}
public List<Credit> getCredits() {
+ if(credits == null) {
+ this.credits = new ArrayList<Credit>();
+ }
return this.credits;
}
* @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#getExtensions()
*/
public Set<Extension> getExtensions(){
+ if(extensions == null) {
+ this.extensions = new HashSet<Extension>();
+ }
return this.extensions;
}
* @see eu.etaxonomy.cdm.model.common.ISourceable#getSources()
*/
public Set<IdentifiableSource> getSources() {
+ if(sources == null) {
+ this.sources = new HashSet<IdentifiableSource>();
+ }
return this.sources;
}
public void removeSource(IdentifiableSource source) {
this.sources.remove(source);
}
-
//******************************** TO STRING *****************************************************/
@XmlElement(name ="Updated", type = String.class)
@XmlJavaTypeAdapter(DateTimeAdapter.class)
//@XmlElement(name ="Updated")
+ //@XmlElement(name ="Updated")
@Type(type="dateTimeUserType")
@Basic(fetch = FetchType.LAZY)
@Match(MatchMode.IGNORE)
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
+import javax.validation.constraints.NotNull;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlType;
import org.apache.log4j.Logger;
+import org.hibernate.annotations.Cascade;
+import org.hibernate.annotations.CascadeType;
import org.hibernate.envers.Audited;
import org.hibernate.search.annotations.Indexed;
@XmlIDREF
@XmlSchemaType(name = "IDREF")
@ManyToMany(fetch = FetchType.LAZY)
+ @NotNull
private Set<Taxon> coveredTaxa = new HashSet<Taxon>();
@XmlElementWrapper( name = "GeographicalScope")
@XmlSchemaType(name = "IDREF")
@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(name="MediaKey_NamedArea")
+ @NotNull
private Set<NamedArea> geographicalScope = new HashSet<NamedArea>();
@XmlElementWrapper(name = "TaxonomicScope")
joinColumns=@JoinColumn(name="mediaKey_fk"),
inverseJoinColumns=@JoinColumn(name="taxon_fk")
)
+ @NotNull
private Set<Taxon> taxonomicScope = new HashSet<Taxon>();
@XmlElementWrapper( name = "ScopeRestrictions")
@XmlSchemaType(name = "IDREF")
@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(name="MediaKey_Scope")
+ @NotNull
private Set<Scope> scopeRestrictions = new HashSet<Scope>();
@XmlElementWrapper( name = "KeyRepresentations")
@XmlIDREF
@XmlSchemaType(name = "IDREF")
@ManyToMany(fetch = FetchType.LAZY)
+ @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE,CascadeType.DELETE, CascadeType.DELETE_ORPHAN})
+ @NotNull
private Set<Representation> keyRepresentations = new HashSet<Representation>();
/**
* <i>this</i> identification key.
*/
public Set<Taxon> getCoveredTaxa() {
+ if(coveredTaxa == null) {
+ this.coveredTaxa = new HashSet<Taxon>();
+ }
return coveredTaxa;
}
/**
* data where <i>this</i> identification key is valid.
*/
public Set<NamedArea> getGeographicalScope() {
+ if(geographicalScope == null) {
+ this.geographicalScope = new HashSet<NamedArea>();
+ }
return geographicalScope;
}
* scope of <i>this</i> identification key
*/
public Set<Taxon> getTaxonomicScope() {
+ if(taxonomicScope == null) {
+ this.taxonomicScope = new HashSet<Taxon>();
+ }
return taxonomicScope;
}
* <i>this</i> identification key
*/
public Set<Representation> getKeyRepresentations() {
+ if(keyRepresentations == null) {
+ this.keyRepresentations = new HashSet<Representation>();
+ }
return keyRepresentations;
}
* <i>this</i> identification key
*/
public Set<Scope> getScopeRestrictions() {
+ if(scopeRestrictions == null) {
+ this.scopeRestrictions = new HashSet<Scope>();
+ }
return scopeRestrictions;
}
import javax.persistence.JoinColumn;\r
import javax.persistence.JoinTable;\r
import javax.persistence.ManyToMany;\r
+import javax.validation.constraints.NotNull;\r
import javax.xml.bind.annotation.XmlAccessType;\r
import javax.xml.bind.annotation.XmlAccessorType;\r
import javax.xml.bind.annotation.XmlElement;\r
import javax.xml.bind.annotation.XmlType;\r
\r
import org.apache.log4j.Logger;\r
+import org.hibernate.annotations.Cascade;\r
+import org.hibernate.annotations.CascadeType;\r
import org.hibernate.envers.Audited;\r
import org.hibernate.search.annotations.Indexed;\r
\r
@XmlIDREF\r
@XmlSchemaType(name = "IDREF")\r
@ManyToMany(fetch = FetchType.LAZY)\r
+ @NotNull\r
private Set<Taxon> coveredTaxa = new HashSet<Taxon>();\r
\r
@XmlElementWrapper(name = "TaxonomicScope")\r
joinColumns=@JoinColumn(name="multiAccessKey_fk"),\r
inverseJoinColumns=@JoinColumn(name="taxon_fk")\r
)\r
+ @NotNull\r
private Set<Taxon> taxonomicScope = new HashSet<Taxon>();\r
\r
@XmlElementWrapper( name = "GeographicalScope")\r
@XmlSchemaType(name = "IDREF")\r
@ManyToMany(fetch = FetchType.LAZY)\r
@JoinTable(name="MultiAccessKey_NamedArea")\r
+ @NotNull\r
private Set<NamedArea> geographicalScope = new HashSet<NamedArea>();\r
\r
@XmlElementWrapper( name = "ScopeRestrictions")\r
@XmlSchemaType(name = "IDREF")\r
@ManyToMany(fetch = FetchType.LAZY)\r
@JoinTable(name="MultiAccessKey_Scope")\r
+ @NotNull\r
private Set<Scope> scopeRestrictions = new HashSet<Scope>();\r
\r
/** \r
* <i>this</i> identification key.\r
*/\r
public Set<Taxon> getCoveredTaxa() {\r
+ if(coveredTaxa == null) {\r
+ this.coveredTaxa = new HashSet<Taxon>();\r
+ }\r
return coveredTaxa;\r
}\r
/**\r
* data where <i>this</i> identification key is valid.\r
*/\r
public Set<NamedArea> getGeographicalScope() {\r
+ if(geographicalScope == null) {\r
+ this.geographicalScope = new HashSet<NamedArea>();\r
+ } \r
return geographicalScope;\r
}\r
\r
* scope of <i>this</i> identification key \r
*/\r
public Set<Taxon> getTaxonomicScope() {\r
+ if(taxonomicScope == null) {\r
+ this.taxonomicScope = new HashSet<Taxon>();\r
+ }\r
return taxonomicScope;\r
}\r
\r
* <i>this</i> identification key \r
*/\r
public Set<Scope> getScopeRestrictions() {\r
+ if(scopeRestrictions == null) {\r
+ this.scopeRestrictions = new HashSet<Scope>();\r
+ }\r
return scopeRestrictions;\r
}\r
\r
import javax.persistence.JoinColumn;\r
import javax.persistence.JoinTable;\r
import javax.persistence.ManyToMany;\r
+import javax.validation.constraints.NotNull;\r
import javax.xml.bind.annotation.XmlAccessType;\r
import javax.xml.bind.annotation.XmlAccessorType;\r
import javax.xml.bind.annotation.XmlElement;\r
@XmlIDREF\r
@XmlSchemaType(name = "IDREF")\r
@ManyToMany(fetch = FetchType.LAZY)\r
+ @NotNull\r
private Set<Taxon> coveredTaxa = new HashSet<Taxon>();\r
\r
@XmlElementWrapper(name = "TaxonomicScope")\r
joinColumns=@JoinColumn(name="polytomousKey_fk"),\r
inverseJoinColumns=@JoinColumn(name="taxon_fk")\r
)\r
+ @NotNull\r
private Set<Taxon> taxonomicScope = new HashSet<Taxon>();\r
\r
@XmlElementWrapper( name = "GeographicalScope")\r
@XmlSchemaType(name = "IDREF")\r
@ManyToMany(fetch = FetchType.LAZY)\r
@JoinTable(name="PolytomousKey_NamedArea")\r
+ @NotNull\r
private Set<NamedArea> geographicalScope = new HashSet<NamedArea>();\r
\r
@XmlElementWrapper( name = "ScopeRestrictions")\r
@XmlSchemaType(name = "IDREF")\r
@ManyToMany(fetch = FetchType.LAZY)\r
@JoinTable(name="PolytomousKey_Scope")\r
+ @NotNull\r
private Set<Scope> scopeRestrictions = new HashSet<Scope>();\r
\r
/** \r
* <i>this</i> identification key.\r
*/\r
public Set<Taxon> getCoveredTaxa() {\r
+ if(coveredTaxa == null) {\r
+ this.coveredTaxa = new HashSet<Taxon>();\r
+ }\r
return coveredTaxa;\r
}\r
/**\r
* data where <i>this</i> identification key is valid.\r
*/\r
public Set<NamedArea> getGeographicalScope() {\r
+ if(geographicalScope == null) {\r
+ this.geographicalScope = new HashSet<NamedArea>();\r
+ }\r
return geographicalScope;\r
}\r
\r
* scope of <i>this</i> identification key \r
*/\r
public Set<Taxon> getTaxonomicScope() {\r
+ if(taxonomicScope == null) {\r
+ this.taxonomicScope = new HashSet<Taxon>();\r
+ }\r
return taxonomicScope;\r
}\r
\r
* <i>this</i> identification key \r
*/\r
public Set<Scope> getScopeRestrictions() {\r
+ if(scopeRestrictions == null) {\r
+ this.scopeRestrictions = new HashSet<Scope>();\r
+ }\r
return scopeRestrictions;\r
}\r
\r
import javax.persistence.JoinTable;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
+import javax.validation.constraints.NotNull;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import org.hibernate.envers.Audited;
import org.hibernate.search.annotations.Indexed;
import org.hibernate.search.annotations.IndexedEmbedded;
+import org.hibernate.validator.constraints.NotEmpty;
import org.joda.time.DateTime;
import eu.etaxonomy.cdm.jaxb.DateTimeAdapter;
import eu.etaxonomy.cdm.model.common.IdentifiableEntity;
import eu.etaxonomy.cdm.model.common.Language;
import eu.etaxonomy.cdm.model.common.LanguageString;
+import eu.etaxonomy.cdm.validation.Level2;
/**
* A {@link Media media} is any kind of media that represents a media object.
@XmlJavaTypeAdapter(MultilanguageTextAdapter.class)
@OneToMany(fetch = FetchType.LAZY)
@IndexedEmbedded
- @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE,CascadeType.DELETE})
+ @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE,CascadeType.DELETE, CascadeType.DELETE_ORPHAN})
+ @NotNull
+ @NotEmpty(groups = Level2.class)
private Map<Language,LanguageString> title = new HashMap<Language,LanguageString>();
//creation date of the media (not of the record)
@OneToMany(fetch = FetchType.LAZY)
@IndexedEmbedded
@JoinTable(name = "Media_Description")
- @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE,CascadeType.DELETE})
+ @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE,CascadeType.DELETE,CascadeType.DELETE_ORPHAN})
+ @NotNull
private Map<Language,LanguageString> description = new HashMap<Language,LanguageString>();
//A single medium such as a picture can have multiple representations in files.
@XmlElementWrapper(name = "MediaRepresentations")
@XmlElement(name = "MediaRepresentation")
@OneToMany(mappedBy="media",fetch = FetchType.LAZY)
- @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE})
+ @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE, CascadeType.DELETE_ORPHAN})
+ @NotNull
+ @NotEmpty(groups = Level2.class)
private Set<MediaRepresentation> representations = new HashSet<MediaRepresentation>();
@XmlElement(name = "Artist")
}
public Set<MediaRepresentation> getRepresentations(){
+ if(representations == null) {
+ this.representations = new HashSet<MediaRepresentation>();
+ }
return this.representations;
}
}
public Map<Language,LanguageString> getTitle(){
+ if(title == null) {
+ this.title = new HashMap<Language,LanguageString>();
+ }
return this.title;
}
}
public Map<Language,LanguageString> getDescription(){
+ if(this.description == null) {
+ this.description = new HashMap<Language,LanguageString>();
+ }
return this.description;
}
@OneToMany (cascade = {javax.persistence.CascadeType.ALL}, fetch= FetchType.LAZY)
@IndexColumn(name="sortIndex", base = 0)
@JoinColumn (name = "representation_id", nullable=false)
- @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE_ORPHAN})
+ @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE, CascadeType.DELETE_ORPHAN})
private List<MediaRepresentationPart> mediaRepresentationParts = new ArrayList<MediaRepresentationPart>();
/**
import java.util.*;
import javax.persistence.*;
+import javax.validation.constraints.NotNull;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
@XmlElement(name = "UsedSequence")
@XmlIDREF
@XmlSchemaType(name = "IDREF")
- @OneToMany(fetch = FetchType.LAZY)
+ @OneToMany(fetch = FetchType.LAZY)// FIXME surely should be ManyToMany - you can use a sequence to construct several different phylogenetic trees
+ @NotNull
private Set<Sequence> usedSequences = new HashSet<Sequence>();
public Set<Sequence> getUsedSequences() {
- logger.debug("getUsedSequences");
+ if(usedSequences == null) {
+ this.usedSequences = new HashSet<Sequence>();
+ }
return usedSequences;
}
*/
protected NameTypeDesignation() {
}
+
+ public static NameTypeDesignation NewInstance() {
+ return new NameTypeDesignation();
+ }
/**
* Class constructor: creates a new name type designation instance
/**
* @see #getTypeName()
*/
- private void setTypeName(TaxonNameBase typeName){
+ public void setTypeName(TaxonNameBase typeName){
this.typeName = typeName;
}
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Transient;
+import javax.validation.constraints.Pattern;
+import javax.validation.constraints.Size;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import org.hibernate.search.annotations.Fields;
import org.hibernate.search.annotations.Index;
import org.hibernate.search.annotations.Indexed;
+import org.hibernate.validator.constraints.NotEmpty;
import org.springframework.beans.factory.annotation.Configurable;
import eu.etaxonomy.cdm.common.CdmUtils;
import eu.etaxonomy.cdm.strategy.match.Match.ReplaceMode;
import eu.etaxonomy.cdm.strategy.merge.Merge;
import eu.etaxonomy.cdm.strategy.merge.MergeMode;
+import eu.etaxonomy.cdm.validation.Level2;
+import eu.etaxonomy.cdm.validation.Level3;
+import eu.etaxonomy.cdm.validation.annotation.CorrectEpithetsForRank;
+import eu.etaxonomy.cdm.validation.annotation.NullOrNotEmpty;
+import eu.etaxonomy.cdm.validation.annotation.NoDuplicateNames;
/**
* The taxon name class for all non viral taxa. Parenthetical authorship is derived
"hybridFormula",
"monomHybrid",
"binomHybrid",
- "trinomHybrid"
+ "trinomHybrid",
})
@XmlRootElement(name = "NonViralName")
@Entity
@Indexed(index = "eu.etaxonomy.cdm.model.name.TaxonNameBase")
@Audited
@Configurable
+@CorrectEpithetsForRank(groups = Level2.class)
+@NoDuplicateNames(groups = Level3.class)
public class NonViralName<T extends NonViralName> extends TaxonNameBase<T, INonViralNameCacheStrategy> {
private static final long serialVersionUID = 4441110073881088033L;
private static final Logger logger = Logger.getLogger(NonViralName.class);
})
@Match(value=MatchMode.CACHE, cacheReplaceMode=ReplaceMode.DEFINED,
cacheReplacedProperties={"genusOrUninomial", "infraGenericEpithet", "specificEpithet", "infraSpecificEpithet"} )
+ @NotEmpty(groups = Level2.class) // implictly NotNull
+ @Size(max = 255)
private String nameCache;
@XmlElement(name = "ProtectedNameCache")
@Field(index=Index.TOKENIZED)
@Match(MatchMode.EQUAL_REQUIRED)
@CacheUpdate("nameCache")
- private String genusOrUninomial;
+ @NullOrNotEmpty
+ @Size(max = 255)
+ @Pattern(regexp = "[A-Z][a-z\\uc3a4\\uc3ab\\uc3af\\uc3b6\\uc3bc\\-]+", groups=Level2.class)
+ @NotEmpty(groups = Level3.class)
+ private String genusOrUninomial;
@XmlElement(name = "InfraGenericEpithet")
@Field(index=Index.TOKENIZED)
@CacheUpdate("nameCache")
- private String infraGenericEpithet;
+ @NullOrNotEmpty
+ @Size(max = 255)
+ @Pattern(regexp = "[a-z\\uc3a4\\uc3ab\\uc3af\\uc3b6\\uc3bc\\-]+", groups=Level2.class)
+ private String infraGenericEpithet;
@XmlElement(name = "SpecificEpithet")
@Field(index=Index.TOKENIZED)
@CacheUpdate("nameCache")
- private String specificEpithet;
+ @NullOrNotEmpty
+ @Size(max = 255)
+ @Pattern(regexp = "[a-z\\uc3a4\\uc3ab\\uc3af\\uc3b6\\uc3bc\\-]+", groups=Level2.class)
+ private String specificEpithet;
@XmlElement(name = "InfraSpecificEpithet")
@Field(index=Index.TOKENIZED)
@CacheUpdate("nameCache")
- private String infraSpecificEpithet;
+ @NullOrNotEmpty
+ @Size(max = 255)
+ @Pattern(regexp = "[a-z\\uc3a4\\uc3ab\\uc3af\\uc3b6\\uc3bc\\-]+", groups=Level3.class)
+ private String infraSpecificEpithet;
@XmlElement(name = "CombinationAuthorTeam", type = TeamOrPersonBase.class)
@XmlIDREF
@Target(TeamOrPersonBase.class)
@Cascade(CascadeType.SAVE_UPDATE)
@CacheUpdate("authorshipCache")
- private INomenclaturalAuthor combinationAuthorTeam;
+ private INomenclaturalAuthor combinationAuthorTeam;
@XmlElement(name = "ExCombinationAuthorTeam", type = TeamOrPersonBase.class)
@XmlIDREF
@Target(TeamOrPersonBase.class)
@Cascade(CascadeType.SAVE_UPDATE)
@CacheUpdate("authorshipCache")
- private INomenclaturalAuthor exCombinationAuthorTeam;
+ private INomenclaturalAuthor exCombinationAuthorTeam;
@XmlElement(name = "BasionymAuthorTeam", type = TeamOrPersonBase.class)
@XmlIDREF
@Target(TeamOrPersonBase.class)
@Cascade(CascadeType.SAVE_UPDATE)
@CacheUpdate("authorshipCache")
- private INomenclaturalAuthor basionymAuthorTeam;
+ private INomenclaturalAuthor basionymAuthorTeam;
@XmlElement(name = "ExBasionymAuthorTeam", type = TeamOrPersonBase.class)
@XmlIDREF
@Target(TeamOrPersonBase.class)
@Cascade(CascadeType.SAVE_UPDATE)
@CacheUpdate("authorshipCache")
- private INomenclaturalAuthor exBasionymAuthorTeam;
+ private INomenclaturalAuthor exBasionymAuthorTeam;
@XmlElement(name = "AuthorshipCache")
@Field(index=Index.TOKENIZED)
@Match(value=MatchMode.CACHE, cacheReplaceMode=ReplaceMode.DEFINED,
cacheReplacedProperties={"combinationAuthorTeam", "basionymAuthorTeam", "exCombinationAuthorTeam", "exBasionymAuthorTeam"} )
+ @NotEmpty(groups = Level2.class) // implictly NotNull
+ @Size(max = 255)
private String authorshipCache;
@XmlElement(name = "ProtectedAuthorshipCache")
- @CacheUpdate(value="authorshipCache")
- protected boolean protectedAuthorshipCache;
+ @CacheUpdate("authorshipCache")
+ protected boolean protectedAuthorshipCache;
@XmlElementWrapper(name = "HybridRelationsFromThisName")
@XmlElement(name = "HybridRelationsFromThisName")
return "xxx.";
}
}
-
+ @Transient
public String getInfraGenericMarker() throws UnknownCdmTypeException{
if (! this.isInfraGeneric()){
throw new IllegalStateException("An infrageneric marker is only available for a infrageneric rank but was asked for rank: " + this.toString());
protected SpecimenTypeDesignation(){
}
+ public static SpecimenTypeDesignation NewInstance() {
+ return new SpecimenTypeDesignation();
+ }
+
/**
* Class constructor: creates a new specimen type designation instance
* (including its {@link eu.etaxonomy.cdm.model.reference.ReferenceBase reference source} and
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Transient;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import org.hibernate.annotations.Table;
import org.hibernate.envers.Audited;
import org.hibernate.search.annotations.Field;
+import org.hibernate.validator.constraints.NotEmpty;
import org.springframework.util.ReflectionUtils;
import eu.etaxonomy.cdm.model.common.IParsable;
import eu.etaxonomy.cdm.strategy.merge.Merge;
import eu.etaxonomy.cdm.strategy.merge.MergeMode;
import eu.etaxonomy.cdm.strategy.parser.ParserProblem;
+import eu.etaxonomy.cdm.validation.Level2;
+import eu.etaxonomy.cdm.validation.annotation.NullOrNotEmpty;
/**
* The upmost (abstract) class for scientific taxon names regardless of any
@Column(length=330, name="fullTitleCache")
@Match(value=MatchMode.CACHE, cacheReplaceMode=ReplaceMode.ALL)
@CacheUpdate(noUpdate ="titleCache")
- protected String fullTitleCache;
+ @NotEmpty(groups = Level2.class)
+ @Size(max = 330)
+ protected String fullTitleCache;
//if true titleCache will not be automatically generated/updated
@XmlElement(name = "ProtectedFullTitleCache")
@CacheUpdate(value ="fullTitleCache", noUpdate ="titleCache")
- private boolean protectedFullTitleCache;
+ private boolean protectedFullTitleCache;
@XmlElementWrapper(name = "Descriptions")
@XmlElement(name = "Description")
@XmlElement(name = "AppendedPhrase")
@Field(index= org.hibernate.search.annotations.Index.TOKENIZED)
- @CacheUpdate(value ="nameCache")
- private String appendedPhrase;
+ @CacheUpdate(value ="nameCache")
+ @NullOrNotEmpty
+ @Size(max = 255)
+ private String appendedPhrase;
@XmlElement(name = "NomenclaturalMicroReference")
@Field(index= org.hibernate.search.annotations.Index.TOKENIZED)
- @CacheUpdate(noUpdate ="titleCache")
- private String nomenclaturalMicroReference;
+ @CacheUpdate(noUpdate ="titleCache")
+ @NullOrNotEmpty
+ @Size(max = 255)
+ private String nomenclaturalMicroReference;
@XmlAttribute
@CacheUpdate(noUpdate ={"titleCache","fullTitleCache"})
- private int parsingProblem = 0;
+ private int parsingProblem = 0;
@XmlAttribute
@CacheUpdate(noUpdate ={"titleCache","fullTitleCache"})
@XmlIDREF
@XmlSchemaType(name = "IDREF")
@ManyToMany(fetch = FetchType.LAZY)
- //TODO @Cascade({CascadeType.SAVE_UPDATE, CascadeType.DELETE_ORPHAN})
- @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE})
+ //TODO @Cascade({CascadeType.DELETE_ORPHAN})
+ @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE, CascadeType.DELETE_ORPHAN})
+ @NotNull
private Set<TypeDesignationBase> typeDesignations = new HashSet<TypeDesignationBase>();
@XmlElement(name = "HomotypicalGroup")
@Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE})
@Match(MatchMode.IGNORE)
@CacheUpdate(noUpdate ="titleCache")
- private HomotypicalGroup homotypicalGroup;
+ @NotNull
+ private HomotypicalGroup homotypicalGroup;
@XmlElementWrapper(name = "RelationsFromThisName")
@XmlElement(name = "RelationFromThisName")
@OneToMany(mappedBy="relatedFrom", fetch= FetchType.LAZY)
@Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE_ORPHAN})
@Merge(MergeMode.RELATION)
+ @NotNull
private Set<NameRelationship> relationsFromThisName = new HashSet<NameRelationship>();
@XmlElementWrapper(name = "RelationsToThisName")
@OneToMany(mappedBy="relatedTo", fetch= FetchType.LAZY)
@Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE , CascadeType.DELETE_ORPHAN })
@Merge(MergeMode.RELATION)
+ @NotNull
private Set<NameRelationship> relationsToThisName = new HashSet<NameRelationship>();
@XmlElementWrapper(name = "NomenclaturalStatuses")
@XmlElement(name = "NomenclaturalStatus")
@OneToMany(fetch= FetchType.LAZY)
- @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE})
+ @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE,CascadeType.DELETE,CascadeType.DELETE_ORPHAN})
+ @NotNull
private Set<NomenclaturalStatus> status = new HashSet<NomenclaturalStatus>();
@XmlElementWrapper(name = "TaxonBases")
@XmlIDREF
@XmlSchemaType(name = "IDREF")
@OneToMany(mappedBy="name", fetch= FetchType.LAZY)
+ @NotNull
private Set<TaxonBase> taxonBases = new HashSet<TaxonBase>();
@XmlElement(name = "Rank")
@XmlSchemaType(name = "IDREF")
@ManyToOne(fetch = FetchType.EAGER)
@CacheUpdate(value ="nameCache")
- private Rank rank;
+ @NotNull
+ private Rank rank;
@XmlElement(name = "NomenclaturalReference")
@XmlIDREF
@ManyToOne(fetch = FetchType.LAZY)
@Cascade({CascadeType.SAVE_UPDATE})
@CacheUpdate(noUpdate ="titleCache")
- private ReferenceBase nomenclaturalReference;
+ private ReferenceBase nomenclaturalReference;
// ************* CONSTRUCTORS *************/
/**
* @see #addRelationshipFromName(TaxonNameBase, NameRelationshipType, String)
*/
public Set<NameRelationship> getRelationsFromThisName() {
+ if(relationsFromThisName == null) {
+ this.relationsFromThisName = new HashSet<NameRelationship>();
+ }
return relationsFromThisName;
}
* @see #addRelationshipToName(TaxonNameBase, NameRelationshipType, String)
*/
public Set<NameRelationship> getRelationsToThisName() {
+ if(relationsToThisName == null) {
+ this.relationsToThisName = new HashSet<NameRelationship>();
+ }
return relationsToThisName;
}
* @see NomenclaturalStatusType
*/
public Set<NomenclaturalStatus> getStatus() {
+ if(status == null) {
+ this.status = new HashSet<NomenclaturalStatus>();
+ }
return status;
}
* @see SpecimenTypeDesignation
*/
public Set<TypeDesignationBase> getTypeDesignations() {
+ if(typeDesignations == null) {
+ this.typeDesignations = new HashSet<TypeDesignationBase>();
+ }
return typeDesignations;
}
* @see #getHomotypicalGroup()
*/
protected void setHomotypicalGroup(HomotypicalGroup homotypicalGroup) {
- if (homotypicalGroup == null){
- homotypicalGroup = HomotypicalGroup.NewInstance();
- }
this.homotypicalGroup = homotypicalGroup;
}
* @see #getSynonyms()
*/
public Set<TaxonBase> getTaxonBases() {
+ if(taxonBases == null) {
+ this.taxonBases = new HashSet<TaxonBase>();
+ }
return this.taxonBases;
}
@XmlElement(name = "Description")
@XmlJavaTypeAdapter(MultilanguageTextAdapter.class)
@OneToMany(fetch = FetchType.LAZY)
+ @Cascade({CascadeType.SAVE_UPDATE, CascadeType.DELETE, CascadeType.DELETE_ORPHAN})
@IndexedEmbedded
protected Map<Language,LanguageString> description = new HashMap<Language,LanguageString>();
--- /dev/null
+package eu.etaxonomy.cdm.validation;\r
+\r
+public interface Level2 {\r
+\r
+}\r
--- /dev/null
+package eu.etaxonomy.cdm.validation;\r
+\r
+public interface Level3 {\r
+\r
+}\r
--- /dev/null
+package eu.etaxonomy.cdm.validation.annotation;\r
+\r
+import static java.lang.annotation.ElementType.TYPE;\r
+import static java.lang.annotation.RetentionPolicy.RUNTIME;\r
+\r
+import java.lang.annotation.Documented;\r
+import java.lang.annotation.Retention;\r
+import java.lang.annotation.Target;\r
+\r
+import javax.validation.Constraint;\r
+import javax.validation.Payload;\r
+\r
+import eu.etaxonomy.cdm.validation.constraint.CorrectEpithetsForRankValidator;\r
+\r
+@Target( { TYPE })\r
+@Retention(RUNTIME)\r
+@Constraint(validatedBy = CorrectEpithetsForRankValidator.class)\r
+@Documented\r
+public @interface CorrectEpithetsForRank {\r
+String message() default "{eu.etaxonomy.cdm.validation.annotation.CorrectEpithetsForRank.message}";\r
+Class<? extends Payload>[] payload() default {};\r
+Class<?>[] groups() default {};\r
+}\r
--- /dev/null
+package eu.etaxonomy.cdm.validation.annotation;\r
+\r
+import static java.lang.annotation.ElementType.TYPE;\r
+import static java.lang.annotation.RetentionPolicy.RUNTIME;\r
+\r
+import java.lang.annotation.Documented;\r
+import java.lang.annotation.Retention;\r
+import java.lang.annotation.Target;\r
+\r
+import javax.validation.Constraint;\r
+import javax.validation.Payload;\r
+\r
+import eu.etaxonomy.cdm.validation.constraint.StubValidator;\r
+\r
+@Target( { TYPE })\r
+@Retention(RUNTIME)\r
+@Constraint(validatedBy = StubValidator.class)\r
+@Documented\r
+public @interface NoDuplicateNames {\r
+String message() default "{eu.etaxonomy.cdm.validation.annotation.NoDuplicateNames.message}";\r
+Class<? extends Payload>[] payload() default {};\r
+Class<?>[] groups() default {};\r
+}\r
--- /dev/null
+package eu.etaxonomy.cdm.validation.annotation;\r
+import static java.lang.annotation.ElementType.*;\r
+import static java.lang.annotation.RetentionPolicy.*;\r
+import java.lang.annotation.Documented;\r
+import java.lang.annotation.Retention;\r
+\r
+import java.lang.annotation.Target;\r
+import javax.validation.Constraint;\r
+import javax.validation.Payload;\r
+\r
+import eu.etaxonomy.cdm.validation.constraint.NullOrNotEmptyValidator;\r
+\r
+@Target( { METHOD, FIELD, ANNOTATION_TYPE })\r
+@Retention(RUNTIME)\r
+@Constraint(validatedBy = NullOrNotEmptyValidator.class)\r
+@Documented\r
+public @interface NullOrNotEmpty {\r
+String message() default "{eu.etaxonomy.cdm.validation.annotation.NullOrNotEmpty.message}";\r
+Class<? extends Payload>[] payload() default {};\r
+Class<?>[] groups() default {};\r
+}\r
--- /dev/null
+package eu.etaxonomy.cdm.validation.constraint;\r
+\r
+import javax.validation.ConstraintValidator;\r
+import javax.validation.ConstraintValidatorContext;\r
+\r
+import eu.etaxonomy.cdm.model.name.NonViralName;\r
+import eu.etaxonomy.cdm.validation.annotation.CorrectEpithetsForRank;\r
+\r
+public class CorrectEpithetsForRankValidator implements\r
+ ConstraintValidator<CorrectEpithetsForRank, NonViralName> {\r
+\r
+ public void initialize(CorrectEpithetsForRank correctEpithetsForRank) { }\r
+\r
+ public boolean isValid(NonViralName name, ConstraintValidatorContext constraintContext) {\r
+ boolean valid = true;\r
+ if(name.getRank().isSupraGeneric() || name.getRank().isGenus()) { \r
+ if(name.getInfraGenericEpithet() != null) {\r
+ valid = false;\r
+ constraintContext.buildErrorWithMessageTemplate("{eu.etaxonomy.cdm.validation.annotation.CorrectEpithetsForRank.epithetNotNull}").addSubNode("infraGenericEpithet").addError();\r
+ }\r
+ \r
+ if(name.getSpecificEpithet() != null) {\r
+ valid = false;\r
+ constraintContext.buildErrorWithMessageTemplate("{eu.etaxonomy.cdm.validation.annotation.CorrectEpithetsForRank.epithetNotNull}").addSubNode("specificEpithet").addError();\r
+ } \r
+ if(name.getInfraSpecificEpithet() != null) {\r
+ valid = false;\r
+ constraintContext.buildErrorWithMessageTemplate("{eu.etaxonomy.cdm.validation.annotation.CorrectEpithetsForRank.epithetNotNull}").addSubNode("infraSpecificEpithet").addError();\r
+ }\r
+ } else if(name.getRank().isInfraGeneric()) {\r
+ if(name.getInfraGenericEpithet() == null) {\r
+ valid = false;\r
+ constraintContext.buildErrorWithMessageTemplate("{eu.etaxonomy.cdm.validation.annotation.CorrectEpithetsForRank.epithetNull}").addSubNode("infraGenericEpithet").addError();\r
+ }\r
+ \r
+ if(name.getSpecificEpithet() != null) {\r
+ valid = false;\r
+ constraintContext.buildErrorWithMessageTemplate("{eu.etaxonomy.cdm.validation.annotation.CorrectEpithetsForRank.epithetNotNull}").addSubNode("specificEpithet").addError();\r
+ } \r
+ if(name.getInfraSpecificEpithet() != null) {\r
+ valid = false;\r
+ constraintContext.buildErrorWithMessageTemplate("{eu.etaxonomy.cdm.validation.annotation.CorrectEpithetsForRank.epithetNotNull}").addSubNode("infraSpecificEpithet").addError();\r
+ }\r
+ } else if(name.getRank().isSpecies()) {\r
+ if(name.getSpecificEpithet() == null) {\r
+ valid = false;\r
+ constraintContext.buildErrorWithMessageTemplate("{eu.etaxonomy.cdm.validation.annotation.CorrectEpithetsForRank.epithetNull}").addSubNode("specificEpithet").addError();\r
+ }\r
+ \r
+ if(name.getInfraSpecificEpithet() != null) {\r
+ valid = false;\r
+ constraintContext.buildErrorWithMessageTemplate("{eu.etaxonomy.cdm.validation.annotation.CorrectEpithetsForRank.epithetNotNull}").addSubNode("infraSpecificEpithet").addError();\r
+ }\r
+ } else if(name.getRank().isInfraSpecific()) {\r
+ if(name.getSpecificEpithet() == null) {\r
+ valid = false;\r
+ constraintContext.buildErrorWithMessageTemplate("{eu.etaxonomy.cdm.validation.annotation.CorrectEpithetsForRank.epithetNull}").addSubNode("specificEpithet").addError();\r
+ }\r
+ if(name.getInfraSpecificEpithet() == null) {\r
+ valid = false;\r
+ constraintContext.buildErrorWithMessageTemplate("{eu.etaxonomy.cdm.validation.annotation.CorrectEpithetsForRank.epithetNull}").addSubNode("infraSpecificEpithet").addError();\r
+ }\r
+ }\r
+ \r
+ return valid; \r
+ }\r
+}\r
--- /dev/null
+package eu.etaxonomy.cdm.validation.constraint;\r
+\r
+import javax.validation.ConstraintValidator;\r
+import javax.validation.ConstraintValidatorContext;\r
+\r
+import eu.etaxonomy.cdm.validation.annotation.NullOrNotEmpty;\r
+\r
+public class NullOrNotEmptyValidator implements\r
+ ConstraintValidator<NullOrNotEmpty, String> {\r
+\r
+ public void initialize(NullOrNotEmpty nullOrNotEmpty) { }\r
+\r
+ public boolean isValid(String string, ConstraintValidatorContext constraintContext) {\r
+ if(string == null) {\r
+ return true;\r
+ } else if(string.trim().length() > 0) {\r
+ return true;\r
+ } else {\r
+ return false;\r
+ }\r
+ }\r
+}\r
--- /dev/null
+package eu.etaxonomy.cdm.validation.constraint;\r
+\r
+import java.lang.annotation.Annotation;\r
+\r
+import javax.validation.ConstraintValidator;\r
+import javax.validation.ConstraintValidatorContext;\r
+\r
+/**\r
+ * Stub validatior for use when a constraint uses cdmlib-services component\r
+ * (and therfore the implementation requires components that are not visible \r
+ * in the cdmlib-model package)\r
+ * \r
+ * To resolve this circular dependency, use this stub as the validator in the\r
+ * annotation, then substitute an implementation using an XML config file.\r
+ * \r
+ * @author ben.clark\r
+ */\r
+public class StubValidator implements\r
+ ConstraintValidator<Annotation,Object> {\r
+ \r
+ public void initialize(Annotation annotation) { }\r
+\r
+ public boolean isValid(Object obj, ConstraintValidatorContext constraintContext) {\r
+ return true;\r
+ }\r
+}\r
--- /dev/null
+eu.etaxonomy.cdm.validation.annotation.NullOrNotEmpty.message=must be either null, or contain at least one non-whitespace character\r
+eu.etaxonomy.cdm.validation.annotation.NoDuplicateNames.message=must not have the same uninomial, genus part, infra-generic epithet, specific epithet, infra-specific epithet, and rank as other names in the database.\r
+eu.etaxonomy.cdm.validation.annotation.CorrectEpithetsForRank.epithetNotNull=must be empty for a name of this rank. Remove this epithet or change the rank of this name\r
+eu.etaxonomy.cdm.validation.annotation.CorrectEpithetsForRank.epithetNull=must not be empty for a name of this rank. Add an epithet or change the rank of this name\r
+eu.etaxonomy.cdm.validation.annotation.CorrectEpithetsForRank.message=must have the epithets required for a name of this rank
\ No newline at end of file
--- /dev/null
+/**\r
+ * \r
+ */\r
+package eu.etaxonomy.cdm.model.agent;\r
+\r
+import java.util.Set;\r
+\r
+import javax.validation.ConstraintViolation;\r
+import javax.validation.Validation;\r
+import javax.validation.Validator;\r
+import javax.validation.ValidatorFactory;\r
+\r
+import org.junit.BeforeClass;\r
+import org.junit.Test;\r
+\r
+/**\r
+ * @author b.clark\r
+ *\r
+ */\r
+public class AgentValidationTest {\r
+\r
+ private static Validator validator;\r
+\r
+ @BeforeClass\r
+ public static void onSetUp() throws Exception {\r
+ ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); \r
+ validator = factory.getValidator();\r
+ }\r
+\r
+ @Test\r
+ public void testNullTitleCache() {\r
+ Person person = Person.NewInstance();\r
+ Set<ConstraintViolation<Person>> constraintViolations = validator.validate(person);\r
+ \r
+ for(ConstraintViolation<Person> constraintViolation : constraintViolations) {\r
+ System.out.println(constraintViolation.getMessage());\r
+ }\r
+ }\r
+}\r