addInstitutionalMembership returns the membership
[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 javax.persistence.Entity;
16 import javax.persistence.FetchType;
17 import javax.persistence.OneToMany;
18 import javax.validation.constraints.NotNull;
19 import javax.validation.constraints.Size;
20 import javax.xml.bind.annotation.XmlAccessType;
21 import javax.xml.bind.annotation.XmlAccessorType;
22 import javax.xml.bind.annotation.XmlElement;
23 import javax.xml.bind.annotation.XmlElementWrapper;
24 import javax.xml.bind.annotation.XmlRootElement;
25 import javax.xml.bind.annotation.XmlType;
26
27 import org.apache.log4j.Logger;
28 import org.hibernate.annotations.Cascade;
29 import org.hibernate.annotations.CascadeType;
30 import org.hibernate.envers.Audited;
31 import org.hibernate.search.annotations.Field;
32 import org.hibernate.search.annotations.Index;
33 import org.hibernate.search.annotations.Indexed;
34 import org.hibernate.search.annotations.IndexedEmbedded;
35 import org.joda.time.Partial;
36 import org.springframework.beans.factory.annotation.Configurable;
37
38 import eu.etaxonomy.cdm.model.common.TimePeriod;
39 import eu.etaxonomy.cdm.model.common.User;
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(index=Index.TOKENIZED)
85 @NullOrNotEmpty
86 @Size(max = 255)
87 private String prefix;
88
89 @XmlElement(name = "FirstName")
90 @Field(index=Index.TOKENIZED)
91 @NullOrNotEmpty
92 @Size(max = 255)
93 private String firstname;
94
95 @XmlElement(name = "LastName")
96 @Field(index=Index.TOKENIZED)
97 @NullOrNotEmpty
98 @Size(max = 255)
99 private String lastname;
100
101 @XmlElement(name = "Suffix")
102 @Field(index=Index.TOKENIZED)
103 @NullOrNotEmpty
104 @Size(max = 255)
105 private String suffix;
106
107 @XmlElement(name = "Lifespan")
108 @IndexedEmbedded
109 @Match(value=MatchMode.EQUAL_OR_ONE_NULL)
110 @NotNull
111 private TimePeriod lifespan = TimePeriod.NewInstance();
112
113 @XmlElementWrapper(name = "InstitutionalMemberships", nillable = true)
114 @XmlElement(name = "InstitutionalMembership")
115 @OneToMany(fetch=FetchType.LAZY, mappedBy = "person")
116 @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE})
117 protected Set<InstitutionalMembership> institutionalMemberships;
118
119 /**
120 * Creates a new empty instance for a person whose existence is all what is known.
121 * This can be a provisional solution until more information about <i>this</i> person
122 * can be gathered, for instance in case a member of a nomenclatural author team
123 * is not explicitly mentioned. It also includes the cache strategy defined in
124 * {@link eu.etaxonomy.cdm.strategy.cache.agent.PersonDefaultCacheStrategy PersonDefaultCacheStrategy}.
125 */
126 public static Person NewInstance(){
127 return new Person();
128 }
129
130 /**
131 * Creates a new instance for a person for whom an "identification" string
132 * is all what is known. This string is generally a short or a complete name.
133 * As this string is kept in the {@link eu.etaxonomy.cdm.model.common.IdentifiableEntity#getTitleCache() titleCache}
134 * attribute and should not be overwritten by the {@link #generateTitle() generateTitle} method
135 * the {@link eu.etaxonomy.cdm.model.common.IdentifiableEntity#isProtectedTitleCache() protectedTitleCache} flag will be turned on.
136 */
137 public static Person NewTitledInstance(String titleCache){
138 Person result = new Person();
139 result.setTitleCache(titleCache, true);
140 return result;
141 }
142
143
144 /**
145 * Class constructor.
146 *
147 * @see #Person(String, String, String)
148 */
149 protected Person() {
150 super();
151 this.cacheStrategy = PersonDefaultCacheStrategy.NewInstance();
152
153 }
154
155 /**
156 * Class constructor using a "forenames" string (including initials),
157 * a surname (family name) and an abbreviated name as used in nomenclature.
158 * For the abbreviated name the inherited attribute {@link TeamOrPersonBase#getNomenclaturalTitle() nomenclaturalTitle}
159 * is used.
160 *
161 * @param firstname the given name
162 * @param lastname the hereditary name
163 * @param nomenclaturalTitel the abbreviated name
164 * @see #Person()
165 * @see #NewInstance()
166 */
167 public Person(String firstname, String lastname, String nomenclaturalTitel) {
168 this.setFirstname(firstname);
169 this.setLastname(lastname);
170 logger.debug("before - Set nomenclatural Title");
171 this.setNomenclaturalTitle(nomenclaturalTitel);
172 logger.debug("after - Set nomenclatural Title");
173 }
174
175
176 /**
177 * Returns the set of {@link InstitutionalMembership institution memberships} corresponding to <i>this</i> person.
178 *
179 * @see InstitutionalMembership
180 */
181 public Set<InstitutionalMembership> getInstitutionalMemberships(){
182 if(institutionalMemberships == null) {
183 this.institutionalMemberships = new HashSet<InstitutionalMembership>();
184 }
185 return this.institutionalMemberships;
186 }
187
188 protected void addInstitutionalMembership(InstitutionalMembership ims){
189 getInstitutionalMemberships().add(ims);
190 if (ims.getPerson() != this){
191 logger.warn("Institutional membership's person has to be changed for adding it to person: " + this);
192 ims.getPerson().removeInstitutionalMembership(ims);
193 ims.setPerson(this);
194
195 }
196 }
197
198 /**
199 * Adds a new {@link InstitutionalMembership membership} of <i>this</i> person in an {@link Institution institution}
200 * to the set of his institution memberships.
201 * This method also creates a new institutional membership instance.
202 *
203 * @param institution the institution <i>this</i> person belongs to
204 * @param period the time period for which <i>this</i> person has been a member of the institution
205 * @param department the string label for the department <i>this</i> person belongs to,
206 * within the institution
207 * @param role the string label for the persons's role within the department or institution
208 * @see #getInstitutionalMemberships()
209 * @see InstitutionalMembership#InstitutionalMembership(Institution, Person, TimePeriod, String, String)
210 */
211 public InstitutionalMembership addInstitutionalMembership(Institution institution, TimePeriod period, String department, String role){
212 return new InstitutionalMembership(institution, this, period, department, role);
213 }
214
215 /**
216 * Removes one element from the set of institutional memberships of <i>this</i> person.
217 * Institute and person attributes of the institutional membership object
218 * will be nullified.
219 *
220 * @param ims the institutional membership of <i>this</i> person which should be deleted
221 * @see #getInstitutionalMemberships()
222 */
223 public void removeInstitutionalMembership(InstitutionalMembership ims){
224 ims.setInstitute(null);
225 ims.setPerson(null);
226 getInstitutionalMemberships().remove(ims);
227 }
228
229 /**
230 * Returns the string representing the prefix (for instance "Prof.&nbsp;Dr.<!-- -->")
231 * to <i>this</i> person's name.
232 */
233 public String getPrefix(){
234 return this.prefix;
235 }
236 /**
237 * @see #getPrefix()
238 */
239 public void setPrefix(String prefix){
240 this.prefix = prefix;
241 }
242
243
244 /**
245 * Returns the string representing the given name or forename
246 * (for instance "John") of <i>this</i> person.
247 * This is the part of his name which is not shared with other
248 * family members. Actually it may be just initials (for instance "G.&nbsp;Jr."),
249 * all forenames in full or a combination of expanded names and initials.
250 */
251 public String getFirstname(){
252 return this.firstname;
253 }
254 /**
255 * @see #getFirstname()
256 */
257 public void setFirstname(String firstname){
258 this.firstname = firstname;
259 }
260
261
262 /**
263 * Returns the string representing the hereditary name (surname or family name)
264 * (for instance "Smith") of <i>this</i> person.
265 * This is the part of his name which is common to (all) other
266 * members of his family, as distinct from the given name or forename.
267 */
268 public String getLastname(){
269 return this.lastname;
270 }
271 /**
272 * @see #getLastname()
273 */
274 public void setLastname(String lastname){
275 this.lastname = lastname;
276 }
277
278
279 /**
280 * Returns the string representing the suffix (for instance "Junior")
281 * of <i>this</i> person's name.
282 */
283 public String getSuffix(){
284 return this.suffix;
285 }
286 /**
287 * @see #getSuffix()
288 */
289 public void setSuffix(String suffix){
290 this.suffix = suffix;
291 }
292
293
294 /**
295 * Returns the {@link eu.etaxonomy.cdm.model.common.TimePeriod period of time}
296 * in which <i>this</i> person was alive (life span).
297 * The general form is birth date - death date
298 * (XXXX - YYYY; XXXX - or - YYYY as appropriate),
299 * but a simple flourished date (fl. XXXX) is also possible
300 * if that is all what is known.
301 *
302 * @see eu.etaxonomy.cdm.model.common.TimePeriod
303 */
304 public TimePeriod getLifespan(){
305 if(lifespan == null) {
306 this.lifespan = TimePeriod.NewInstance(new Partial(), new Partial());
307 }
308 return this.lifespan;
309 }
310 /**
311 * @see #getLifespan()
312 */
313 public void setLifespan(TimePeriod lifespan){
314 this.lifespan = lifespan;
315 }
316
317 // /**
318 // * Generates the "full" name string of <i>this</i> person according to the strategy
319 // * defined in {@link eu.etaxonomy.cdm.strategy.cache.agent.PersonDefaultCacheStrategy PersonDefaultCacheStrategy}.
320 // * The used attributes are:
321 // * {@link #getPrefix() prefix}, {@link #getFirstname() firstname}, {@link #getLastname() lastname} and {@link #getSuffix() suffix}.
322 // * This method overrides {@link eu.etaxonomy.cdm.model.common.IdentifiableEntity#generateTitle() generateTitle}.
323 // * The result might be kept as {@link eu.etaxonomy.cdm.model.common.IdentifiableEntity#setTitleCache(String) titleCache} if the
324 // * flag {@link eu.etaxonomy.cdm.model.common.IdentifiableEntity#protectedTitleCache protectedTitleCache} is not set.
325 // *
326 // * @return the string with the full name of <i>this</i> person
327 // */
328 // @Override
329 // public String generateTitle() {
330 // String title = null;
331 // if (cacheStrategy != null) {
332 // title = cacheStrategy.getTitleCache(this);
333 // }
334 // return title;
335 // }
336
337 //*********************** CLONE ********************************************************/
338
339 /**
340 * Clones <i>this</i> Person. This is a shortcut that enables to create
341 * a new instance that differs only slightly from <i>this</i> Person.
342 *
343 * @see eu.etaxonomy.cdm.model.media.IdentifiableMediaEntity#clone()
344 * @see java.lang.Object#clone()
345 */
346 @Override
347 public Object clone() {
348 try{
349 Person result = (Person)super.clone();
350 //no changes to firstname, lastname, lifespan, prefix, suffix
351 return result;
352 } catch (CloneNotSupportedException e){
353 logger.warn("Object does not implement cloneable");
354 e.printStackTrace();
355 return null;
356 }
357
358
359 }
360
361 }