/**
* Copyright (C) 2007 EDIT
-* European Distributed Institute of Taxonomy
+* European Distributed Institute of Taxonomy
* http://www.e-taxonomy.eu
-*
+*
* The contents of this file are subject to the Mozilla Public License Version 1.1
* See LICENSE.TXT at the top of this package for the full license terms.
*/
package eu.etaxonomy.cdm.model.agent;
-import eu.etaxonomy.cdm.model.common.TimePeriod;
-import eu.etaxonomy.cdm.model.common.Keyword;
-import eu.etaxonomy.cdm.strategy.cache.PersonDefaultCacheStrategy;
+import java.util.HashSet;
+import java.util.Set;
+
+import javassist.compiler.ast.Keyword;
+
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.OneToMany;
+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.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.CascadeType;
-import java.util.*;
-import javax.persistence.*;
+import org.hibernate.envers.Audited;
+import org.hibernate.search.annotations.Field;
+import org.hibernate.search.annotations.IndexedEmbedded;
+import org.joda.time.Partial;
+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;
/**
- * A representation of a human being, living or dead.
+ * This class represents human beings, living or dead.<BR>
* It includes name parts, {@link Contact contact} details, {@link InstitutionalMembership institutional membership},
- * and other possible information such as life {@link common.TimePeriod time period},
- * taxonomic and/or geographical {@link common.Keyword specialization}.
+ * and other possible information such as life {@link TimePeriod time period},
+ * taxonomic and/or geographical {@link Keyword specialization}.
* For a short abbreviated name the inherited attribute {@link TeamOrPersonBase#getNomenclaturalTitle() nomenclaturalTitle}
- * is to be used.
- * For other alternative (string-)names {@link common.OriginalSource OriginalSource} instances must be created
- * and the inherited attribute {@link common.ReferencedEntityBase#getOriginalNameString() originalNameString} must be used.
- * <p>
- * See also the <a href="http://rs.tdwg.org/ontology/voc/Person.rdf">TDWG Ontology</a>
- *
+ * is to be used.<BR>
+ * For other alternative (string-)names {@link eu.etaxonomy.cdm.model.common.OriginalSourceBase OriginalSource} instances must be created
+ * and the inherited attribute {@link eu.etaxonomy.cdm.model.common.ReferencedEntityBase#getOriginalNameString() originalNameString} must be used.
+ * <P>
+ * This class corresponds to: <ul>
+ * <li> Person according to the TDWG ontology
+ * <li> AgentName (partially) according to the TCS
+ * <li> Person (PersonName partially) according to the ABCD schema
+ * </ul>
+ *
* @author m.doering
* @version 1.0
* @created 08-Nov-2007 13:06:42
*/
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "Person", propOrder = {
+ "prefix",
+ "firstname",
+ "lastname",
+ "suffix",
+ "lifespan",
+ "institutionalMemberships"
+})
+@XmlRootElement(name = "Person")
@Entity
-public class Person extends TeamOrPersonBase {
- static Logger logger = Logger.getLogger(Person.class);
+//@Indexed disabled to reduce clutter in indexes, since this type is not used by any search
+//@Indexed(index = "eu.etaxonomy.cdm.model.agent.AgentBase")
+@Audited
+@Configurable
+public class Person extends TeamOrPersonBase<Person>{
+ private static final long serialVersionUID = 4153566493065539763L;
+ public static final Logger logger = Logger.getLogger(Person.class);
+ @XmlElement(name = "Prefix")
+ @Field
+ //TODO Val #3379
+// @NullOrNotEmpty
+ @Size(max = 255)
private String prefix;
+
+ @XmlElement(name = "FirstName")
+ @Field
+ //TODO Val #3379
+// @NullOrNotEmpty
+ @Size(max = 255)
private String firstname;
+
+ @XmlElement(name = "LastName")
+ @Field
+ //TODO Val #3379
+// @NullOrNotEmpty
+ @Size(max = 255)
private String lastname;
+
+ @XmlElement(name = "Suffix")
+ @Field
+ //TODO Val #3379
+// @NullOrNotEmpty
+ @Size(max = 255)
private String suffix;
- private TimePeriod lifespan;
+
+ @XmlElement(name = "Lifespan")
+ @IndexedEmbedded
+ @Match(value=MatchMode.EQUAL_OR_ONE_NULL)
+ //TODO Val #3379 check carefully what the condition is that lifespan is really null in legacy data
+// @NotNull
+ private TimePeriod lifespan = TimePeriod.NewInstance();
+
+ @XmlElementWrapper(name = "InstitutionalMemberships", nillable = true)
+ @XmlElement(name = "InstitutionalMembership")
+ @OneToMany(fetch=FetchType.LAZY, mappedBy = "person")
+ @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE})
protected Set<InstitutionalMembership> institutionalMemberships;
- private Contact contact;
- private Set<Keyword> keywords = new HashSet<Keyword>();
- /**
+ /**
* Creates a new empty instance for a person whose existence is all what is known.
- * This can be a provisional solution until more information about this person
+ * This can be a provisional solution until more information about <i>this</i> person
* can be gathered, for instance in case a member of a nomenclatural author team
* is not explicitly mentioned. It also includes the cache strategy defined in
- * {@link eu.etaxonomy.cdm.strategy.cache.PersonDefaultCacheStrategy PersonDefaultCacheStrategy}.
+ * {@link eu.etaxonomy.cdm.strategy.cache.agent.PersonDefaultCacheStrategy PersonDefaultCacheStrategy}.
*/
public static Person NewInstance(){
return new Person();
}
-
- /**
+
+ /**
* Creates a new instance for a person for whom an "identification" string
* is all what is known. This string is generally a short or a complete name.
- * As this string is kept in the {@link common.IdentifiableEntity#getTitleCache() titleCache}
+ * As this string is kept in the {@link eu.etaxonomy.cdm.model.common.IdentifiableEntity#getTitleCache() titleCache}
* attribute and should not be overwritten by the {@link #generateTitle() generateTitle} method
- * the {@link common.IdentifiableEntity#isProtectedTitleCache() protectedTitleCache} flag will be turned on.
+ * the {@link eu.etaxonomy.cdm.model.common.IdentifiableEntity#isProtectedTitleCache() protectedTitleCache} flag will be turned on.
*/
public static Person NewTitledInstance(String titleCache){
Person result = new Person();
- result.setTitleCache(titleCache);
+ result.setTitleCache(titleCache, true);
return result;
}
-
-
- /**
+
+
+ /**
* Class constructor.
- *
+ *
* @see #Person(String, String, String)
*/
- private Person() {
+ protected Person() {
super();
this.cacheStrategy = PersonDefaultCacheStrategy.NewInstance();
}
-
- /**
+
+ /**
* Class constructor using a "forenames" string (including initials),
* a surname (family name) and an abbreviated name as used in nomenclature.
* For the abbreviated name the inherited attribute {@link TeamOrPersonBase#getNomenclaturalTitle() nomenclaturalTitle}
public Person(String firstname, String lastname, String nomenclaturalTitel) {
this.setFirstname(firstname);
this.setLastname(lastname);
+ logger.debug("before - Set nomenclatural Title");
this.setNomenclaturalTitle(nomenclaturalTitel);
+ logger.debug("after - Set nomenclatural Title");
}
-
-
- /**
- * Returns the set of {@link InstitutionalMembership institution memberships} corresponding to this person.
+
+
+ /**
+ * Returns the set of {@link InstitutionalMembership institution memberships} corresponding to <i>this</i> person.
*
* @see InstitutionalMembership
*/
- @OneToMany
- @Cascade({CascadeType.SAVE_UPDATE, CascadeType.DELETE})
public Set<InstitutionalMembership> getInstitutionalMemberships(){
+ if(institutionalMemberships == null) {
+ this.institutionalMemberships = new HashSet<InstitutionalMembership>();
+ }
return this.institutionalMemberships;
}
- /**
- * @see #getInstitutionalMemberships()
- */
- protected void setInstitutionalMemberships(Set<InstitutionalMembership> institutionalMemberships){
- this.institutionalMemberships = institutionalMemberships;
+
+ protected void addInstitutionalMembership(InstitutionalMembership ims){
+ getInstitutionalMemberships().add(ims);
+ if (ims.getPerson() != this){
+ logger.warn("Institutional membership's person has to be changed for adding it to person: " + this);
+ ims.getPerson().removeInstitutionalMembership(ims);
+ ims.setPerson(this);
+
+ }
}
-
- /**
- * Adds a new {@link InstitutionalMembership membership} of this person in an {@link Institution institution}
+
+ /**
+ * Adds a new {@link InstitutionalMembership membership} of <i>this</i> person in an {@link Institution institution}
* to the set of his institution memberships.
* This method also creates a new institutional membership instance.
*
- * @param institution the institution this person belongs to
- * @param period the time period for which this person has been a member of the institution
- * @param department the string label for the department this person belongs to,
+ * @param institution the institution <i>this</i> person belongs to
+ * @param period the time period for which <i>this</i> person has been a member of the institution
+ * @param department the string label for the department <i>this</i> person belongs to,
* within the institution
* @param role the string label for the persons's role within the department or institution
* @see #getInstitutionalMemberships()
* @see InstitutionalMembership#InstitutionalMembership(Institution, Person, TimePeriod, String, String)
*/
- public void addInstitutionalMembership(Institution institution, TimePeriod period, String department, String role){
- //TODO to be implemented?
- logger.warn("not yet fully implemented?");
- InstitutionalMembership ims = new InstitutionalMembership(institution, this, period, department, role);
- institutionalMemberships.add(ims);
+ public InstitutionalMembership addInstitutionalMembership(Institution institution, TimePeriod period, String department, String role){
+ return new InstitutionalMembership(institution, this, period, department, role);
}
-
- /**
- * Removes one element from the set of institutional memberships of this person.
+
+ /**
+ * Removes one element from the set of institutional memberships of <i>this</i> person.
* Institute and person attributes of the institutional membership object
* will be nullified.
*
- * @param ims the institutional membership of this person which should be deleted
+ * @param ims the institutional membership of <i>this</i> person which should be deleted
* @see #getInstitutionalMemberships()
*/
public void removeInstitutionalMembership(InstitutionalMembership ims){
- //TODO to be implemented?
- logger.warn("not yet fully implemented?");
ims.setInstitute(null);
ims.setPerson(null);
- this.institutionalMemberships.remove(ims);
+ getInstitutionalMemberships().remove(ims);
}
-
- /**
- * Returns the set of {@link common.Keyword keywords} mostly representing a taxonomic or
- * a geographical specialization of this person.
- * Keywords are items of a controlled {@link common.TermVocabulary vocabulary}.
- *
- * @see common.Keyword
- */
- @OneToMany
- @Cascade({CascadeType.SAVE_UPDATE, CascadeType.DELETE_ORPHAN})
- public Set<Keyword> getKeywords(){
- return this.keywords;
- }
- /**
- * @see #getKeywords()
- */
- public void setKeywords(Set<Keyword> keywords){
- this.keywords = keywords;
- }
- /**
- * Adds a new keyword from the keyword vocabulary to the set of keywords
- * describing or circumscribing this person's activities.
- *
- * @param keyword any keyword
- * @see #getKeywords()
- * @see common.Keyword
- */
- public void addKeyword(Keyword keyword){
- this.keywords.add(keyword);
- }
- /**
- * Removes one element from the set of keywords for this person.
- *
- * @param keyword the keyword which should be deleted
- * @see #getKeywords()
- */
- public void removeKeyword(Keyword keyword){
- this.keywords.remove(keyword);
- }
-
-
-
- /**
- * Returns the {@link Contact contact} of this person.
- * The contact contains several ways to approach this person.
- *
- * @see Contact
- */
- @ManyToOne
- @Cascade({CascadeType.SAVE_UPDATE})
- public Contact getContact(){
- return this.contact;
- }
- /**
- * @see #getContact()
- */
- public void setContact(Contact contact){
- this.contact = contact;
- }
-
-
/**
* Returns the string representing the prefix (for instance "Prof. Dr.<!-- -->")
- * to this person's name.
+ * to <i>this</i> person's name.
*/
public String getPrefix(){
return this.prefix;
* @see #getPrefix()
*/
public void setPrefix(String prefix){
- this.prefix = prefix;
+ this.prefix = StringUtils.isBlank(prefix) ? null : prefix;
}
/**
* Returns the string representing the given name or forename
- * (for instance "John") of this person.
+ * (for instance "John") of <i>this</i> person.
* This is the part of his name which is not shared with other
- * family members. Actually it may be just initials (for instance "G. Jr."),
- * all forenames in full or a combination of expanded names and initials.
+ * family members. Actually it may be just initials (for instance "G. Jr."),
+ * all forenames in full or a combination of expanded names and initials.
*/
public String getFirstname(){
return this.firstname;
* @see #getFirstname()
*/
public void setFirstname(String firstname){
- this.firstname = firstname;
+ this.firstname = StringUtils.isBlank(firstname) ? null : firstname;
}
-
+
/**
* Returns the string representing the hereditary name (surname or family name)
- * (for instance "Smith") of this person.
+ * (for instance "Smith") of <i>this</i> person.
* This is the part of his name which is common to (all) other
- * members of his family, as distinct from the given name or forename.
+ * members of his family, as distinct from the given name or forename.
*/
public String getLastname(){
return this.lastname;
* @see #getLastname()
*/
public void setLastname(String lastname){
- this.lastname = lastname;
+ this.lastname = StringUtils.isBlank(lastname) ? null : lastname;
}
/**
* Returns the string representing the suffix (for instance "Junior")
- * of this person's name.
+ * of <i>this</i> person's name.
*/
public String getSuffix(){
return this.suffix;
* @see #getSuffix()
*/
public void setSuffix(String suffix){
- this.suffix = suffix;
+ this.suffix = StringUtils.isBlank(suffix) ? null: suffix;
}
- /**
- * Returns the {@link common.TimePeriod period of time}
- * in which this person was alive (life span).
+ /**
+ * Returns the {@link eu.etaxonomy.cdm.model.common.TimePeriod period of time}
+ * in which <i>this</i> person was alive (life span).
* The general form is birth date - death date
* (XXXX - YYYY; XXXX - or - YYYY as appropriate),
* but a simple flourished date (fl. XXXX) is also possible
* if that is all what is known.
*
- * @see common.TimePeriod
+ * @see eu.etaxonomy.cdm.model.common.TimePeriod
*/
public TimePeriod getLifespan(){
+ if(lifespan == null) {
+ this.lifespan = TimePeriod.NewInstance(new Partial(), new Partial());
+ }
return this.lifespan;
}
/**
* @see #getLifespan()
*/
public void setLifespan(TimePeriod lifespan){
+ if (lifespan == null){
+ this.lifespan = TimePeriod.NewInstance(new Partial(), new Partial());
+ }
this.lifespan = lifespan;
}
+// /**
+// * Generates the "full" name string of <i>this</i> person according to the strategy
+// * defined in {@link eu.etaxonomy.cdm.strategy.cache.agent.PersonDefaultCacheStrategy PersonDefaultCacheStrategy}.
+// * The used attributes are:
+// * {@link #getPrefix() prefix}, {@link #getFirstname() firstname}, {@link #getLastname() lastname} and {@link #getSuffix() suffix}.
+// * This method overrides {@link eu.etaxonomy.cdm.model.common.IdentifiableEntity#generateTitle() generateTitle}.
+// * The result might be kept as {@link eu.etaxonomy.cdm.model.common.IdentifiableEntity#setTitleCache(String) titleCache} if the
+// * flag {@link eu.etaxonomy.cdm.model.common.IdentifiableEntity#protectedTitleCache protectedTitleCache} is not set.
+// *
+// * @return the string with the full name of <i>this</i> person
+// */
+// @Override
+// public String generateTitle() {
+// String title = null;
+// if (cacheStrategy != null) {
+// title = cacheStrategy.getTitleCache(this);
+// }
+// return title;
+// }
+
+//*********************** CLONE ********************************************************/
+
/**
- * Generates the "full" name string of this person according to the strategy
- * defined in {@link eu.etaxonomy.cdm.strategy.cache.PersonDefaultCacheStrategy PersonDefaultCacheStrategy}.
- * The used attributes are:
- * {@link #prefix prefix}, {@link #firstname firstname}, {@link #lastname lastname} and {@link #suffix suffix}.
- * This method overrides {@link common.IdentifiableEntity#generateTitle() generateTitle}.
- * The result might be kept as {@link common.IdentifiableEntity#setTitleCache(String) titleCache} if the
- * flag {@link common.IdentifiableEntity#protectedTitleCache protectedTitleCache} is not set.
- *
- * @return the string with the full name of this person
+ * Clones <i>this</i> Person. This is a shortcut that enables to create
+ * a new instance that differs only slightly from <i>this</i> Person.
+ *
+ * @see eu.etaxonomy.cdm.model.media.IdentifiableMediaEntity#clone()
+ * @see java.lang.Object#clone()
*/
@Override
- public String generateTitle() {
- String title = null;
- if (cacheStrategy != null) {
- title = cacheStrategy.getTitleCache(this);
- }
- return title;
+ public Object clone() {
+ try{
+ Person result = (Person)super.clone();
+ //no changes to firstname, lastname, lifespan, prefix, suffix
+ return result;
+ } catch (CloneNotSupportedException e){
+ logger.warn("Object does not implement cloneable");
+ e.printStackTrace();
+ return null;
+ }
+
+
}
}
\ No newline at end of file