merge trunk to cdm-3.3 branch
[cdmlib.git] / cdmlib-model / src / main / java / eu / etaxonomy / cdm / model / agent / Person.java
1 /**
2 * Copyright (C) 2007 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
5 *
6 * The contents of this file are subject to the Mozilla Public License Version 1.1
7 * See LICENSE.TXT at the top of this package for the full license terms.
8 */
9
10 package eu.etaxonomy.cdm.model.agent;
11
12 import java.util.HashSet;
13 import java.util.Set;
14
15 import javassist.compiler.ast.Keyword;
16
17 import javax.persistence.Entity;
18 import javax.persistence.FetchType;
19 import javax.persistence.OneToMany;
20 import javax.validation.constraints.NotNull;
21 import javax.validation.constraints.Size;
22 import javax.xml.bind.annotation.XmlAccessType;
23 import javax.xml.bind.annotation.XmlAccessorType;
24 import javax.xml.bind.annotation.XmlElement;
25 import javax.xml.bind.annotation.XmlElementWrapper;
26 import javax.xml.bind.annotation.XmlRootElement;
27 import javax.xml.bind.annotation.XmlType;
28
29 import org.apache.log4j.Logger;
30 import org.hibernate.annotations.Cascade;
31 import org.hibernate.annotations.CascadeType;
32 import org.hibernate.envers.Audited;
33 import org.hibernate.search.annotations.Field;
34 import org.hibernate.search.annotations.Indexed;
35 import org.hibernate.search.annotations.IndexedEmbedded;
36 import org.joda.time.Partial;
37 import org.springframework.beans.factory.annotation.Configurable;
38
39 import eu.etaxonomy.cdm.model.common.TimePeriod;
40 import eu.etaxonomy.cdm.strategy.cache.agent.PersonDefaultCacheStrategy;
41 import eu.etaxonomy.cdm.strategy.match.Match;
42 import eu.etaxonomy.cdm.strategy.match.MatchMode;
43 import eu.etaxonomy.cdm.validation.annotation.NullOrNotEmpty;
44
45 /**
46 * This class represents human beings, living or dead.<BR>
47 * It includes name parts, {@link Contact contact} details, {@link InstitutionalMembership institutional membership},
48 * and other possible information such as life {@link TimePeriod time period},
49 * taxonomic and/or geographical {@link Keyword specialization}.
50 * For a short abbreviated name the inherited attribute {@link TeamOrPersonBase#getNomenclaturalTitle() nomenclaturalTitle}
51 * is to be used.<BR>
52 * For other alternative (string-)names {@link eu.etaxonomy.cdm.model.common.OriginalSourceBase OriginalSource} instances must be created
53 * and the inherited attribute {@link eu.etaxonomy.cdm.model.common.ReferencedEntityBase#getOriginalNameString() originalNameString} must be used.
54 * <P>
55 * This class corresponds to: <ul>
56 * <li> Person according to the TDWG ontology
57 * <li> AgentName (partially) according to the TCS
58 * <li> Person (PersonName partially) according to the ABCD schema
59 * </ul>
60 *
61 * @author m.doering
62 * @version 1.0
63 * @created 08-Nov-2007 13:06:42
64 */
65 @XmlAccessorType(XmlAccessType.FIELD)
66 @XmlType(name = "Person", propOrder = {
67 "prefix",
68 "firstname",
69 "lastname",
70 "suffix",
71 "lifespan",
72 "institutionalMemberships"
73 })
74 @XmlRootElement(name = "Person")
75 @Entity
76 @Indexed(index = "eu.etaxonomy.cdm.model.agent.AgentBase")
77 @Audited
78 @Configurable
79 public class Person extends TeamOrPersonBase<Person>{
80 private static final long serialVersionUID = 4153566493065539763L;
81 public static final Logger logger = Logger.getLogger(Person.class);
82
83 @XmlElement(name = "Prefix")
84 @Field
85 //TODO Val #3379
86 // @NullOrNotEmpty
87 @Size(max = 255)
88 private String prefix;
89
90 @XmlElement(name = "FirstName")
91 @Field
92 //TODO Val #3379
93 // @NullOrNotEmpty
94 @Size(max = 255)
95 private String firstname;
96
97 @XmlElement(name = "LastName")
98 @Field
99 //TODO Val #3379
100 // @NullOrNotEmpty
101 @Size(max = 255)
102 private String lastname;
103
104 @XmlElement(name = "Suffix")
105 @Field
106 //TODO Val #3379
107 // @NullOrNotEmpty
108 @Size(max = 255)
109 private String suffix;
110
111 @XmlElement(name = "Lifespan")
112 @IndexedEmbedded
113 @Match(value=MatchMode.EQUAL_OR_ONE_NULL)
114 //TODO Val #3379 check carefully what the condition is that lifespan is really null in legacy data
115 // @NotNull
116 private TimePeriod lifespan = TimePeriod.NewInstance();
117
118 @XmlElementWrapper(name = "InstitutionalMemberships", nillable = true)
119 @XmlElement(name = "InstitutionalMembership")
120 @OneToMany(fetch=FetchType.LAZY, mappedBy = "person")
121 @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE})
122 protected Set<InstitutionalMembership> institutionalMemberships;
123
124 /**
125 * Creates a new empty instance for a person whose existence is all what is known.
126 * This can be a provisional solution until more information about <i>this</i> person
127 * can be gathered, for instance in case a member of a nomenclatural author team
128 * is not explicitly mentioned. It also includes the cache strategy defined in
129 * {@link eu.etaxonomy.cdm.strategy.cache.agent.PersonDefaultCacheStrategy PersonDefaultCacheStrategy}.
130 */
131 public static Person NewInstance(){
132 return new Person();
133 }
134
135 /**
136 * Creates a new instance for a person for whom an "identification" string
137 * is all what is known. This string is generally a short or a complete name.
138 * As this string is kept in the {@link eu.etaxonomy.cdm.model.common.IdentifiableEntity#getTitleCache() titleCache}
139 * attribute and should not be overwritten by the {@link #generateTitle() generateTitle} method
140 * the {@link eu.etaxonomy.cdm.model.common.IdentifiableEntity#isProtectedTitleCache() protectedTitleCache} flag will be turned on.
141 */
142 public static Person NewTitledInstance(String titleCache){
143 Person result = new Person();
144 result.setTitleCache(titleCache, true);
145 return result;
146 }
147
148
149 /**
150 * Class constructor.
151 *
152 * @see #Person(String, String, String)
153 */
154 protected Person() {
155 super();
156 this.cacheStrategy = PersonDefaultCacheStrategy.NewInstance();
157
158 }
159
160 /**
161 * Class constructor using a "forenames" string (including initials),
162 * a surname (family name) and an abbreviated name as used in nomenclature.
163 * For the abbreviated name the inherited attribute {@link TeamOrPersonBase#getNomenclaturalTitle() nomenclaturalTitle}
164 * is used.
165 *
166 * @param firstname the given name
167 * @param lastname the hereditary name
168 * @param nomenclaturalTitel the abbreviated name
169 * @see #Person()
170 * @see #NewInstance()
171 */
172 public Person(String firstname, String lastname, String nomenclaturalTitel) {
173 this.setFirstname(firstname);
174 this.setLastname(lastname);
175 logger.debug("before - Set nomenclatural Title");
176 this.setNomenclaturalTitle(nomenclaturalTitel);
177 logger.debug("after - Set nomenclatural Title");
178 }
179
180
181 /**
182 * Returns the set of {@link InstitutionalMembership institution memberships} corresponding to <i>this</i> person.
183 *
184 * @see InstitutionalMembership
185 */
186 public Set<InstitutionalMembership> getInstitutionalMemberships(){
187 if(institutionalMemberships == null) {
188 this.institutionalMemberships = new HashSet<InstitutionalMembership>();
189 }
190 return this.institutionalMemberships;
191 }
192
193 protected void addInstitutionalMembership(InstitutionalMembership ims){
194 getInstitutionalMemberships().add(ims);
195 if (ims.getPerson() != this){
196 logger.warn("Institutional membership's person has to be changed for adding it to person: " + this);
197 ims.getPerson().removeInstitutionalMembership(ims);
198 ims.setPerson(this);
199
200 }
201 }
202
203 /**
204 * Adds a new {@link InstitutionalMembership membership} of <i>this</i> person in an {@link Institution institution}
205 * to the set of his institution memberships.
206 * This method also creates a new institutional membership instance.
207 *
208 * @param institution the institution <i>this</i> person belongs to
209 * @param period the time period for which <i>this</i> person has been a member of the institution
210 * @param department the string label for the department <i>this</i> person belongs to,
211 * within the institution
212 * @param role the string label for the persons's role within the department or institution
213 * @see #getInstitutionalMemberships()
214 * @see InstitutionalMembership#InstitutionalMembership(Institution, Person, TimePeriod, String, String)
215 */
216 public InstitutionalMembership addInstitutionalMembership(Institution institution, TimePeriod period, String department, String role){
217 return new InstitutionalMembership(institution, this, period, department, role);
218 }
219
220 /**
221 * Removes one element from the set of institutional memberships of <i>this</i> person.
222 * Institute and person attributes of the institutional membership object
223 * will be nullified.
224 *
225 * @param ims the institutional membership of <i>this</i> person which should be deleted
226 * @see #getInstitutionalMemberships()
227 */
228 public void removeInstitutionalMembership(InstitutionalMembership ims){
229 ims.setInstitute(null);
230 ims.setPerson(null);
231 getInstitutionalMemberships().remove(ims);
232 }
233
234 /**
235 * Returns the string representing the prefix (for instance "Prof.&nbsp;Dr.<!-- -->")
236 * to <i>this</i> person's name.
237 */
238 public String getPrefix(){
239 return this.prefix;
240 }
241 /**
242 * @see #getPrefix()
243 */
244 public void setPrefix(String prefix){
245 this.prefix = prefix;
246 }
247
248
249 /**
250 * Returns the string representing the given name or forename
251 * (for instance "John") of <i>this</i> person.
252 * This is the part of his name which is not shared with other
253 * family members. Actually it may be just initials (for instance "G.&nbsp;Jr."),
254 * all forenames in full or a combination of expanded names and initials.
255 */
256 public String getFirstname(){
257 return this.firstname;
258 }
259 /**
260 * @see #getFirstname()
261 */
262 public void setFirstname(String firstname){
263 this.firstname = firstname;
264 }
265
266
267 /**
268 * Returns the string representing the hereditary name (surname or family name)
269 * (for instance "Smith") of <i>this</i> person.
270 * This is the part of his name which is common to (all) other
271 * members of his family, as distinct from the given name or forename.
272 */
273 public String getLastname(){
274 return this.lastname;
275 }
276 /**
277 * @see #getLastname()
278 */
279 public void setLastname(String lastname){
280 this.lastname = lastname;
281 }
282
283
284 /**
285 * Returns the string representing the suffix (for instance "Junior")
286 * of <i>this</i> person's name.
287 */
288 public String getSuffix(){
289 return this.suffix;
290 }
291 /**
292 * @see #getSuffix()
293 */
294 public void setSuffix(String suffix){
295 this.suffix = suffix;
296 }
297
298
299 /**
300 * Returns the {@link eu.etaxonomy.cdm.model.common.TimePeriod period of time}
301 * in which <i>this</i> person was alive (life span).
302 * The general form is birth date - death date
303 * (XXXX - YYYY; XXXX - or - YYYY as appropriate),
304 * but a simple flourished date (fl. XXXX) is also possible
305 * if that is all what is known.
306 *
307 * @see eu.etaxonomy.cdm.model.common.TimePeriod
308 */
309 public TimePeriod getLifespan(){
310 if(lifespan == null) {
311 this.lifespan = TimePeriod.NewInstance(new Partial(), new Partial());
312 }
313 return this.lifespan;
314 }
315 /**
316 * @see #getLifespan()
317 */
318 public void setLifespan(TimePeriod lifespan){
319 if (lifespan == null){
320 this.lifespan = TimePeriod.NewInstance(new Partial(), new Partial());
321 }
322 this.lifespan = lifespan;
323 }
324
325 // /**
326 // * Generates the "full" name string of <i>this</i> person according to the strategy
327 // * defined in {@link eu.etaxonomy.cdm.strategy.cache.agent.PersonDefaultCacheStrategy PersonDefaultCacheStrategy}.
328 // * The used attributes are:
329 // * {@link #getPrefix() prefix}, {@link #getFirstname() firstname}, {@link #getLastname() lastname} and {@link #getSuffix() suffix}.
330 // * This method overrides {@link eu.etaxonomy.cdm.model.common.IdentifiableEntity#generateTitle() generateTitle}.
331 // * The result might be kept as {@link eu.etaxonomy.cdm.model.common.IdentifiableEntity#setTitleCache(String) titleCache} if the
332 // * flag {@link eu.etaxonomy.cdm.model.common.IdentifiableEntity#protectedTitleCache protectedTitleCache} is not set.
333 // *
334 // * @return the string with the full name of <i>this</i> person
335 // */
336 // @Override
337 // public String generateTitle() {
338 // String title = null;
339 // if (cacheStrategy != null) {
340 // title = cacheStrategy.getTitleCache(this);
341 // }
342 // return title;
343 // }
344
345 //*********************** CLONE ********************************************************/
346
347 /**
348 * Clones <i>this</i> Person. This is a shortcut that enables to create
349 * a new instance that differs only slightly from <i>this</i> Person.
350 *
351 * @see eu.etaxonomy.cdm.model.media.IdentifiableMediaEntity#clone()
352 * @see java.lang.Object#clone()
353 */
354 @Override
355 public Object clone() {
356 try{
357 Person result = (Person)super.clone();
358 //no changes to firstname, lastname, lifespan, prefix, suffix
359 return result;
360 } catch (CloneNotSupportedException e){
361 logger.warn("Object does not implement cloneable");
362 e.printStackTrace();
363 return null;
364 }
365
366
367 }
368
369 }