Project

General

Profile

Download (13.7 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
	    "familyName",
65
	    "givenName",
66
	    "initials",
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 = "GivenName")
89
    @Field
90
  //TODO Val #3379
91
//    @NullOrNotEmpty
92
    @Column(length=255)
93
	private String givenName;
94

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

    
101
    @XmlElement(name = "FamilyName")
102
    @Field
103
  //TODO Val #3379
104
//    @NullOrNotEmpty
105
    @Column(length=255)
106
	private String familyName;
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
	public static Person NewInstance(String nomRefTitle, String familyName, String initials, String givenName){
155
        Person result = new Person();
156
        result.setNomenclaturalTitle(nomRefTitle);
157
        result.setFamilyName(familyName);
158
        result.setInitials(initials);
159
        result.setGivenName(givenName);
160
        return result;
161
    }
162

    
163

    
164
// *********************** CONSTRUCTOR **********************************/
165

    
166
	/**
167
	 * Class constructor.
168
	 *
169
	 * @see #Person(String, String, String)
170
	 */
171
	protected Person() {
172
		super();
173
		this.cacheStrategy = PersonDefaultCacheStrategy.NewInstance();
174

    
175
	}
176

    
177
	/**
178
	 * Class constructor using a "forenames" string (including initials),
179
	 * a surname (family name) and an abbreviated name as used in nomenclature.
180
	 * For the abbreviated name the inherited attribute {@link TeamOrPersonBase#getNomenclaturalTitle() nomenclaturalTitle}
181
	 * is used.
182
	 *
183
	 * @param  givenname     		the given name
184
	 * @param  familyname      		the hereditary name
185
	 * @param  nomenclaturalTitel 	the abbreviated name
186
	 * @see                  		#Person()
187
	 * @see                  		#NewInstance()
188
	 */
189
	public Person(String givenname, String familyname, String nomenclaturalTitel) {
190
		this.setGivenName(givenname);
191
		this.setFamilyName(familyname);
192
		logger.debug("before - Set nomenclatural Title");
193
		this.setNomenclaturalTitle(nomenclaturalTitel);
194
		logger.debug("after - Set nomenclatural Title");
195
	}
196

    
197
// *********************** GETTER SETTER ADDER **********************************/
198

    
199
	/**
200
	 * Returns the set of {@link InstitutionalMembership institution memberships} corresponding to <i>this</i> person.
201
	 *
202
	 * @see     InstitutionalMembership
203
	 */
204
	public Set<InstitutionalMembership> getInstitutionalMemberships(){
205
		if(institutionalMemberships == null) {
206
			this.institutionalMemberships = new HashSet<>();
207
		}
208
		return this.institutionalMemberships;
209
	}
210

    
211
	protected void addInstitutionalMembership(InstitutionalMembership ims){
212
		getInstitutionalMemberships().add(ims);
213
		if (ims.getPerson() != this){
214
			logger.warn("Institutional membership's person has to be changed for adding it to person: " + this);
215
			ims.getPerson().removeInstitutionalMembership(ims);
216
			ims.setPerson(this);
217
		}
218
	}
219

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

    
237
	/**
238
	 * Removes one element from the set of institutional memberships of <i>this</i> person.
239
	 * Institute and person attributes of the institutional membership object
240
	 * will be nullified.
241
	 *
242
	 * @param  ims  the institutional membership of <i>this</i> person which should be deleted
243
	 * @see     	#getInstitutionalMemberships()
244
	 */
245
	public void removeInstitutionalMembership(InstitutionalMembership ims){
246
		ims.setInstitute(null);
247
		ims.setPerson(null);
248
		getInstitutionalMemberships().remove(ims);
249
	}
250

    
251
	/**
252
	 * Returns the string representing the prefix (for instance "Prof.&nbsp;Dr.<!-- -->")
253
	 * to <i>this</i> person's name.
254
	 */
255
	public String getPrefix(){
256
		return this.prefix;
257
	}
258
	/**
259
	 * @see  #getPrefix()
260
	 */
261
	public void setPrefix(String prefix){
262
		this.prefix = isBlank(prefix) ? null : prefix;
263
	}
264

    
265

    
266
	/**
267
	 * Returns the string representing the given name or forename
268
	 * (for instance "John") of <i>this</i> person.
269
	 * This is the part of his name which is not shared with other
270
	 * family members. <BR>
271
	 * Pure initials should be stored in {@link #getInitials() initials}
272
	 * A combination of expanded names and initials maybe stored here.
273
	 * <BR> In user interfaces (UI) this field should better be called
274
	 * "Other/given names" according to {@link https://www.w3.org/International/questions/qa-personal-names.en#fielddesign }.
275
	 *
276
	 * @see #getInitials()
277
	 * @see #getFamilyName()
278
	 * @see https://www.w3.org/International/questions/qa-personal-names.en#fielddesign
279
	 */
280
	public String getGivenName(){
281
		return this.givenName;
282
	}
283
	/**
284
	 * @see  #getGivenName()
285
	 */
286
	public void setGivenName(String givenName){
287
		this.givenName = isBlank(givenName) ? null : givenName;
288
	}
289

    
290
    /**
291
     * Returns the initials of this person as used in bibliographic
292
     * references. Usually these are the first letters of each givenname
293
     * followed by "." per givenname. For East Asian names it may
294
     * be the first 2 letters. Also dashes are kept.
295
     * @return the initials
296
     */
297
    public String getInitials(){
298
        return this.initials;
299
    }
300
    /**
301
     * @see  #getInitals()
302
     */
303
    public void setInitials(String initials){
304
        this.initials = isBlank(initials) ? null : initials;
305
    }
306

    
307

    
308
	/**
309
	 * Returns the string representing the hereditary name (surname or family name)
310
	 * (for instance "Smith") of <i>this</i> person.
311
	 * This is the part of his name which is common to (all) other
312
	 * members of his family, as distinct from the given name or forename.
313
	 *
314
     * <BR> In user interfaces (UI) this field should better be called
315
     * "Family name" according to {@link https://www.w3.org/International/questions/qa-personal-names.en#fielddesign }.
316
     *
317
     * @see #getInitials()
318
     * @see #getGivenName()
319
     * @see https://www.w3.org/International/questions/qa-personal-names.en#fielddesign
320
	 */
321
	public String getFamilyName(){
322
		return this.familyName;
323
	}
324
	/**
325
	 * @see  #getfamilyName()
326
	 */
327
	public void setFamilyName(String familyName){
328
		this.familyName = isBlank(familyName) ? null : familyName;
329
	}
330

    
331

    
332
	/**
333
	 * Returns the string representing the suffix (for instance "Junior")
334
	 * of <i>this</i> person's name.
335
	 */
336
	public String getSuffix(){
337
		return this.suffix;
338
	}
339
	/**
340
	 * @see  #getSuffix()
341
	 */
342
	public void setSuffix(String suffix){
343
		this.suffix = isBlank(suffix) ? null: suffix;
344
	}
345

    
346

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

    
373
    @Override
374
    public boolean updateCaches(){
375
        boolean result = false;
376
        result |= super.updateCaches();
377
        if (this.nomenclaturalTitle == null){
378
            this.nomenclaturalTitle = this.getTitleCache();
379
            if ( this.nomenclaturalTitle != null ){
380
                 result = true;
381
            }
382
         }
383

    
384
         return result;
385
     }
386

    
387
//*********************** CLONE ********************************************************/
388

    
389
	/**
390
	 * Clones <i>this</i> Person. This is a shortcut that enables to create
391
	 * a new instance that differs only slightly from <i>this</i> Person.
392
	 *
393
	 * @see eu.etaxonomy.cdm.model.media.IdentifiableMediaEntity#clone()
394
	 * @see java.lang.Object#clone()
395
	 */
396
	@Override
397
	public Object clone() {
398
		try{
399
			Person result = (Person)super.clone();
400
			//no changes to givenname, familyname, lifespan, prefix, suffix
401
			return result;
402
		} catch (CloneNotSupportedException e){
403
			logger.warn("Object does not implement cloneable");
404
			e.printStackTrace();
405
			return null;
406
		}
407
	}
408

    
409
}
(7-7/11)