Project

General

Profile

Download (13 KB) Statistics
| Branch: | Tag: | Revision:
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.Column;
16
import javax.persistence.Entity;
17
import javax.persistence.FetchType;
18
import javax.persistence.OneToMany;
19
import javax.xml.bind.annotation.XmlAccessType;
20
import javax.xml.bind.annotation.XmlAccessorType;
21
import javax.xml.bind.annotation.XmlElement;
22
import javax.xml.bind.annotation.XmlElementWrapper;
23
import javax.xml.bind.annotation.XmlRootElement;
24
import javax.xml.bind.annotation.XmlType;
25

    
26
import org.apache.log4j.Logger;
27
import org.hibernate.annotations.Cascade;
28
import org.hibernate.annotations.CascadeType;
29
import org.hibernate.envers.Audited;
30
import org.hibernate.search.annotations.Field;
31
import org.hibernate.search.annotations.IndexedEmbedded;
32
import org.joda.time.Partial;
33
import org.springframework.beans.factory.annotation.Configurable;
34

    
35
import eu.etaxonomy.cdm.model.common.TimePeriod;
36
import eu.etaxonomy.cdm.strategy.cache.agent.PersonDefaultCacheStrategy;
37
import eu.etaxonomy.cdm.strategy.match.Match;
38
import eu.etaxonomy.cdm.strategy.match.MatchMode;
39
import eu.etaxonomy.cdm.validation.annotation.NullOrNotEmpty;
40
import javassist.compiler.ast.Keyword;
41

    
42
/**
43
 * This class represents human beings, living or dead.<BR>
44
 * It includes name parts, {@link Contact contact} details, {@link InstitutionalMembership institutional membership},
45
 * and other possible information such as life {@link TimePeriod time period},
46
 * taxonomic and/or geographical {@link Keyword specialization}.
47
 * For a short abbreviated name the inherited attribute {@link TeamOrPersonBase#getNomenclaturalTitle() nomenclaturalTitle}
48
 * is to be used.<BR>
49
 * For other alternative (string-)names {@link eu.etaxonomy.cdm.model.common.OriginalSourceBase OriginalSource} instances must be created
50
 * and the inherited attribute {@link eu.etaxonomy.cdm.model.common.ReferencedEntityBase#getOriginalNameString() originalNameString} must be used.
51
 * <P>
52
 * This class corresponds to: <ul>
53
 * <li> Person according to the TDWG ontology
54
 * <li> AgentName (partially) according to the TCS
55
 * <li> Person (PersonName partially) according to the ABCD schema
56
 * </ul>
57
 *
58
 * @author m.doering
59
 * @since 08-Nov-2007 13:06:42
60
 */
61
@XmlAccessorType(XmlAccessType.FIELD)
62
@XmlType(name = "Person", propOrder = {
63
	    "prefix",
64
	    "firstname",
65
	    "initials",
66
	    "lastname",
67
	    "suffix",
68
	    "lifespan",
69
	    "institutionalMemberships"
70
})
71
@XmlRootElement(name = "Person")
72
@Entity
73
//@Indexed disabled to reduce clutter in indexes, since this type is not used by any search
74
//@Indexed(index = "eu.etaxonomy.cdm.model.agent.AgentBase")
75
@Audited
76
@Configurable
77
public class Person extends TeamOrPersonBase<Person>{
78
	private static final long serialVersionUID = 4153566493065539763L;
79
	public static final Logger logger = Logger.getLogger(Person.class);
80

    
81
    @XmlElement(name = "Prefix")
82
    @Field
83
  //TODO Val #3379
84
//    @NullOrNotEmpty
85
    @Column(length=255)
86
	private String prefix;
87

    
88
    @XmlElement(name = "FirstName")
89
    @Field
90
  //TODO Val #3379
91
//    @NullOrNotEmpty
92
    @Column(length=255)
93
	private String firstname;
94

    
95
    @XmlElement(name = "FirstName")
96
    @Field
97
    @NullOrNotEmpty
98
    @Column(length=80)
99
    private String initials;
100

    
101
    @XmlElement(name = "LastName")
102
    @Field
103
  //TODO Val #3379
104
//    @NullOrNotEmpty
105
    @Column(length=255)
106
	private String lastname;
107

    
108
    @XmlElement(name = "Suffix")
109
    @Field
110
  //TODO Val #3379
111
//    @NullOrNotEmpty
112
    @Column(length=255)
113
	private String suffix;
114

    
115
    @XmlElement(name = "Lifespan")
116
    @IndexedEmbedded
117
    @Match(value=MatchMode.EQUAL_OR_ONE_NULL)
118
  //TODO Val #3379    check carefully what the condition is that lifespan is really null in legacy data
119
//    @NotNull
120
	private TimePeriod lifespan = TimePeriod.NewInstance();
121

    
122
    @XmlElementWrapper(name = "InstitutionalMemberships", nillable = true)
123
    @XmlElement(name = "InstitutionalMembership")
124
    @OneToMany(fetch=FetchType.LAZY, mappedBy = "person")
125
	@Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE})
126
	protected Set<InstitutionalMembership> institutionalMemberships;
127

    
128
// *********************** FACTORY **********************************/
129

    
130
	/**
131
	 * Creates a new empty instance for a person whose existence is all what is known.
132
	 * This can be a provisional solution until more information about <i>this</i> person
133
	 * can be gathered, for instance in case a member of a nomenclatural author team
134
	 * is not explicitly mentioned. It also includes the cache strategy defined in
135
	 * {@link eu.etaxonomy.cdm.strategy.cache.agent.PersonDefaultCacheStrategy PersonDefaultCacheStrategy}.
136
	 */
137
	public static Person NewInstance(){
138
		return new Person();
139
	}
140

    
141
	/**
142
	 * Creates a new instance for a person for whom an "identification" string
143
	 * is all what is known. This string is generally a short or a complete name.
144
	 * As this string is kept in the {@link eu.etaxonomy.cdm.model.common.IdentifiableEntity#getTitleCache() titleCache}
145
	 * attribute and should not be overwritten by the {@link #generateTitle() generateTitle} method
146
	 * the {@link eu.etaxonomy.cdm.model.common.IdentifiableEntity#isProtectedTitleCache() protectedTitleCache} flag will be turned on.
147
	 */
148
	public static Person NewTitledInstance(String titleCache){
149
		Person result = new Person();
150
		result.setTitleCache(titleCache, true);
151
		return result;
152
	}
153

    
154
// *********************** CONSTRUCTOR **********************************/
155

    
156
	/**
157
	 * Class constructor.
158
	 *
159
	 * @see #Person(String, String, String)
160
	 */
161
	protected Person() {
162
		super();
163
		this.cacheStrategy = PersonDefaultCacheStrategy.NewInstance();
164

    
165
	}
166

    
167
	/**
168
	 * Class constructor using a "forenames" string (including initials),
169
	 * a surname (family name) and an abbreviated name as used in nomenclature.
170
	 * For the abbreviated name the inherited attribute {@link TeamOrPersonBase#getNomenclaturalTitle() nomenclaturalTitle}
171
	 * is used.
172
	 *
173
	 * @param  firstname     		the given name
174
	 * @param  lastname      		the hereditary name
175
	 * @param  nomenclaturalTitel 	the abbreviated name
176
	 * @see                  		#Person()
177
	 * @see                  		#NewInstance()
178
	 */
179
	public Person(String firstname, String lastname, String nomenclaturalTitel) {
180
		this.setFirstname(firstname);
181
		this.setLastname(lastname);
182
		logger.debug("before - Set nomenclatural Title");
183
		this.setNomenclaturalTitle(nomenclaturalTitel);
184
		logger.debug("after - Set nomenclatural Title");
185
	}
186

    
187
// *********************** GETTER SETTER ADDER **********************************/
188

    
189
	/**
190
	 * Returns the set of {@link InstitutionalMembership institution memberships} corresponding to <i>this</i> person.
191
	 *
192
	 * @see     InstitutionalMembership
193
	 */
194
	public Set<InstitutionalMembership> getInstitutionalMemberships(){
195
		if(institutionalMemberships == null) {
196
			this.institutionalMemberships = new HashSet<InstitutionalMembership>();
197
		}
198
		return this.institutionalMemberships;
199
	}
200

    
201
	protected void addInstitutionalMembership(InstitutionalMembership ims){
202
		getInstitutionalMemberships().add(ims);
203
		if (ims.getPerson() != this){
204
			logger.warn("Institutional membership's person has to be changed for adding it to person: " + this);
205
			ims.getPerson().removeInstitutionalMembership(ims);
206
			ims.setPerson(this);
207

    
208
		}
209
	}
210

    
211
	/**
212
	 * Adds a new {@link InstitutionalMembership membership} of <i>this</i> person in an {@link Institution institution}
213
	 * to the set of his institution memberships.
214
	 * This method also creates a new institutional membership instance.
215
	 *
216
	 * @param  institution  the institution <i>this</i> person belongs to
217
	 * @param  period       the time period for which <i>this</i> person has been a member of the institution
218
	 * @param  department   the string label for the department <i>this</i> person belongs to,
219
	 * 					    within the institution
220
	 * @param  role         the string label for the persons's role within the department or institution
221
	 * @see 			    #getInstitutionalMemberships()
222
	 * @see 			    InstitutionalMembership#InstitutionalMembership(Institution, Person, TimePeriod, String, String)
223
	 */
224
	public InstitutionalMembership addInstitutionalMembership(Institution institution, TimePeriod period, String department, String role){
225
		return new InstitutionalMembership(institution, this, period, department, role);
226
	}
227

    
228
	/**
229
	 * Removes one element from the set of institutional memberships of <i>this</i> person.
230
	 * Institute and person attributes of the institutional membership object
231
	 * will be nullified.
232
	 *
233
	 * @param  ims  the institutional membership of <i>this</i> person which should be deleted
234
	 * @see     	#getInstitutionalMemberships()
235
	 */
236
	public void removeInstitutionalMembership(InstitutionalMembership ims){
237
		ims.setInstitute(null);
238
		ims.setPerson(null);
239
		getInstitutionalMemberships().remove(ims);
240
	}
241

    
242
	/**
243
	 * Returns the string representing the prefix (for instance "Prof.&nbsp;Dr.<!-- -->")
244
	 * to <i>this</i> person's name.
245
	 */
246
	public String getPrefix(){
247
		return this.prefix;
248
	}
249
	/**
250
	 * @see  #getPrefix()
251
	 */
252
	public void setPrefix(String prefix){
253
		this.prefix = isBlank(prefix) ? null : prefix;
254
	}
255

    
256

    
257
	/**
258
	 * Returns the string representing the given name or forename
259
	 * (for instance "John") of <i>this</i> person.
260
	 * This is the part of his name which is not shared with other
261
	 * family members. <BR>
262
	 * Pure initials should be stored in {@link #getInitials() initials}
263
	 * A combination of expanded names and initials maybe stored here.
264
	 * <BR> In user interfaces (UI) this field should better be called
265
	 * "Other/given names" according to {@link https://www.w3.org/International/questions/qa-personal-names.en#fielddesign }.
266
	 *
267
	 * @see #getInitials()
268
	 * @see #getLastname()
269
	 * @see https://www.w3.org/International/questions/qa-personal-names.en#fielddesign
270
	 */
271
	public String getFirstname(){
272
		return this.firstname;
273
	}
274
	/**
275
	 * @see  #getFirstname()
276
	 */
277
	public void setFirstname(String firstname){
278
		this.firstname = isBlank(firstname) ? null : firstname;
279
	}
280

    
281
    /**
282
     * Returns the initials of this person as used in bibliographic
283
     * references. Usually these are the first letters of each firstname
284
     * followed by "." per firstname. For East Asian names it may
285
     * be the first 2 letters. Also dashes are kept.
286
     * @return the initials
287
     */
288
    public String getInitials(){
289
        return this.initials;
290
    }
291
    /**
292
     * @see  #getInitals()
293
     */
294
    public void setInitials(String initials){
295
        this.initials = isBlank(initials) ? null : initials;
296
    }
297

    
298

    
299
	/**
300
	 * Returns the string representing the hereditary name (surname or family name)
301
	 * (for instance "Smith") of <i>this</i> person.
302
	 * This is the part of his name which is common to (all) other
303
	 * members of his family, as distinct from the given name or forename.
304
	 *
305
     * <BR> In user interfaces (UI) this field should better be called
306
     * "Family name" according to {@link https://www.w3.org/International/questions/qa-personal-names.en#fielddesign }.
307
     *
308
     * @see #getInitials()
309
     * @see #getLastname()
310
     * @see https://www.w3.org/International/questions/qa-personal-names.en#fielddesign
311
	 */
312
	public String getLastname(){
313
		return this.lastname;
314
	}
315
	/**
316
	 * @see  #getLastname()
317
	 */
318
	public void setLastname(String lastname){
319
		this.lastname = isBlank(lastname) ? null : lastname;
320
	}
321

    
322

    
323
	/**
324
	 * Returns the string representing the suffix (for instance "Junior")
325
	 * of <i>this</i> person's name.
326
	 */
327
	public String getSuffix(){
328
		return this.suffix;
329
	}
330
	/**
331
	 * @see  #getSuffix()
332
	 */
333
	public void setSuffix(String suffix){
334
		this.suffix = isBlank(suffix) ? null: suffix;
335
	}
336

    
337

    
338
	/**
339
	 * Returns the {@link eu.etaxonomy.cdm.model.common.TimePeriod period of time}
340
	 * in which <i>this</i> person was alive (life span).
341
	 * The general form is birth date - death date
342
	 * (XXXX - YYYY; XXXX - or - YYYY as appropriate),
343
	 * but a simple flourished date (fl. XXXX) is also possible
344
	 * if that is all what is known.
345
	 *
346
	 * @see  eu.etaxonomy.cdm.model.common.TimePeriod
347
	 */
348
	public TimePeriod getLifespan(){
349
		if(lifespan == null) {
350
			this.lifespan = TimePeriod.NewInstance(new Partial(), new Partial());
351
		}
352
		return this.lifespan;
353
	}
354
	/**
355
	 * @see  #getLifespan()
356
	 */
357
	public void setLifespan(TimePeriod lifespan){
358
		if (lifespan == null){
359
			this.lifespan = TimePeriod.NewInstance(new Partial(), new Partial());
360
		}
361
		this.lifespan = lifespan;
362
	}
363

    
364
//*********************** CLONE ********************************************************/
365

    
366
	/**
367
	 * Clones <i>this</i> Person. This is a shortcut that enables to create
368
	 * a new instance that differs only slightly from <i>this</i> Person.
369
	 *
370
	 * @see eu.etaxonomy.cdm.model.media.IdentifiableMediaEntity#clone()
371
	 * @see java.lang.Object#clone()
372
	 */
373
	@Override
374
	public Object clone() {
375
		try{
376
			Person result = (Person)super.clone();
377
			//no changes to firstname, lastname, lifespan, prefix, suffix
378
			return result;
379
		} catch (CloneNotSupportedException e){
380
			logger.warn("Object does not implement cloneable");
381
			e.printStackTrace();
382
			return null;
383
		}
384
	}
385

    
386
}
(7-7/11)