Project

General

Profile

Download (14.3 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.annotations.Type;
30
import org.hibernate.envers.Audited;
31
import org.hibernate.search.annotations.Field;
32
import org.hibernate.search.annotations.FieldBridge;
33
import org.hibernate.search.annotations.IndexedEmbedded;
34
import org.springframework.beans.factory.annotation.Configurable;
35

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

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

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

    
91
    @XmlElement(name = "GivenName")
92
    @Field
93
  //TODO Val #3379
94
//    @NullOrNotEmpty
95
    @Column(length=255)
96
	private String givenName;
97

    
98
    @XmlElement(name = "Initials")
99
    @Field
100
    @NullOrNotEmpty
101
    @Column(length=80)
102
    private String initials;
103

    
104
    @XmlElement(name = "FamilyName")
105
    @Field
106
  //TODO Val #3379
107
//    @NullOrNotEmpty
108
    @Column(length=255)
109
	private String familyName;
110

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

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

    
125
    @XmlElement(name = "Orcid")
126
    @Field
127
    @FieldBridge(impl = OrcidBridge.class)
128
    @Type(type="orcidUserType")
129
    @Column(length=16)
130
    private ORCID orcid;
131

    
132
    @XmlElementWrapper(name = "InstitutionalMemberships", nillable = true)
133
    @XmlElement(name = "InstitutionalMembership")
134
    @OneToMany(fetch=FetchType.LAZY, mappedBy = "person")
135
	@Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE})
136
	protected Set<InstitutionalMembership> institutionalMemberships;
137

    
138
// *********************** FACTORY **********************************/
139

    
140
	/**
141
	 * Creates a new empty instance for a person whose existence is all what is known.
142
	 * This can be a provisional solution until more information about <i>this</i> person
143
	 * can be gathered, for instance in case a member of a nomenclatural author team
144
	 * is not explicitly mentioned. It also includes the cache strategy defined in
145
	 * {@link eu.etaxonomy.cdm.strategy.cache.agent.PersonDefaultCacheStrategy PersonDefaultCacheStrategy}.
146
	 */
147
	public static Person NewInstance(){
148
		return new Person();
149
	}
150

    
151
	/**
152
	 * Creates a new instance for a person for whom an "identification" string
153
	 * is all what is known. This string is generally a short or a complete name.
154
	 * As this string is kept in the {@link eu.etaxonomy.cdm.model.common.IdentifiableEntity#getTitleCache() titleCache}
155
	 * attribute and should not be overwritten by the {@link #generateTitle() generateTitle} method
156
	 * the {@link eu.etaxonomy.cdm.model.common.IdentifiableEntity#isProtectedTitleCache() protectedTitleCache} flag will be turned on.
157
	 */
158
	public static Person NewTitledInstance(String titleCache){
159
		Person result = new Person();
160
		result.setTitleCache(titleCache, true);
161
		return result;
162
	}
163

    
164
	public static Person NewInstance(String nomRefTitle, String familyName, String initials, String givenName){
165
        Person result = new Person();
166
        result.setNomenclaturalTitle(nomRefTitle);
167
        result.setFamilyName(familyName);
168
        result.setInitials(initials);
169
        result.setGivenName(givenName);
170
        return result;
171
    }
172

    
173

    
174
// *********************** CONSTRUCTOR **********************************/
175

    
176
	/**
177
	 * Class constructor.
178
	 *
179
	 * @see #Person(String, String, String)
180
	 */
181
	protected Person() {
182
		super();
183
		this.cacheStrategy = PersonDefaultCacheStrategy.NewInstance();
184

    
185
	}
186

    
187
	/**
188
	 * Class constructor using a "forenames" string (including initials),
189
	 * a surname (family name) and an abbreviated name as used in nomenclature.
190
	 * For the abbreviated name the inherited attribute {@link TeamOrPersonBase#getNomenclaturalTitle() nomenclaturalTitle}
191
	 * is used.
192
	 *
193
	 * @param  givenname     		the given name
194
	 * @param  familyname      		the hereditary name
195
	 * @param  nomenclaturalTitel 	the abbreviated name
196
	 * @see                  		#Person()
197
	 * @see                  		#NewInstance()
198
	 */
199
	public Person(String givenname, String familyname, String nomenclaturalTitel) {
200
		this.setGivenName(givenname);
201
		this.setFamilyName(familyname);
202
		logger.debug("before - Set nomenclatural Title");
203
		this.setNomenclaturalTitle(nomenclaturalTitel);
204
		logger.debug("after - Set nomenclatural Title");
205
	}
206

    
207
// *********************** GETTER SETTER ADDER **********************************/
208

    
209
	/**
210
	 * Returns the set of {@link InstitutionalMembership institution memberships} corresponding to <i>this</i> person.
211
	 *
212
	 * @see     InstitutionalMembership
213
	 */
214
	public Set<InstitutionalMembership> getInstitutionalMemberships(){
215
		if(institutionalMemberships == null) {
216
			this.institutionalMemberships = new HashSet<>();
217
		}
218
		return this.institutionalMemberships;
219
	}
220

    
221
	protected void addInstitutionalMembership(InstitutionalMembership ims){
222
		getInstitutionalMemberships().add(ims);
223
		if (ims.getPerson() != this){
224
			logger.warn("Institutional membership's person has to be changed for adding it to person: " + this);
225
			ims.getPerson().removeInstitutionalMembership(ims);
226
			ims.setPerson(this);
227
		}
228
	}
229

    
230
	/**
231
	 * Adds a new {@link InstitutionalMembership membership} of <i>this</i> person in an {@link Institution institution}
232
	 * to the set of his institution memberships.
233
	 * This method also creates a new institutional membership instance.
234
	 *
235
	 * @param  institution  the institution <i>this</i> person belongs to
236
	 * @param  period       the time period for which <i>this</i> person has been a member of the institution
237
	 * @param  department   the string label for the department <i>this</i> person belongs to,
238
	 * 					    within the institution
239
	 * @param  role         the string label for the persons's role within the department or institution
240
	 * @see 			    #getInstitutionalMemberships()
241
	 * @see 			    InstitutionalMembership#InstitutionalMembership(Institution, Person, TimePeriod, String, String)
242
	 */
243
	public InstitutionalMembership addInstitutionalMembership(Institution institution, TimePeriod period, String department, String role){
244
		return new InstitutionalMembership(institution, this, period, department, role);
245
	}
246

    
247
	/**
248
	 * Removes one element from the set of institutional memberships of <i>this</i> person.
249
	 * Institute and person attributes of the institutional membership object
250
	 * will be nullified.
251
	 *
252
	 * @param  ims  the institutional membership of <i>this</i> person which should be deleted
253
	 * @see     	#getInstitutionalMemberships()
254
	 */
255
	public void removeInstitutionalMembership(InstitutionalMembership ims){
256
		ims.setInstitute(null);
257
		ims.setPerson(null);
258
		getInstitutionalMemberships().remove(ims);
259
	}
260

    
261
	/**
262
	 * Returns the string representing the prefix (for instance "Prof.&nbsp;Dr.<!-- -->")
263
	 * to <i>this</i> person's name.
264
	 */
265
	public String getPrefix(){
266
		return this.prefix;
267
	}
268
	/**
269
	 * @see  #getPrefix()
270
	 */
271
	public void setPrefix(String prefix){
272
		this.prefix = isBlank(prefix) ? null : prefix;
273
	}
274

    
275

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

    
300
    /**
301
     * Returns the initials of this person as used in bibliographic
302
     * references. Usually these are the first letters of each givenname
303
     * followed by "." per givenname. For East Asian names it may
304
     * be the first 2 letters. Also dashes are kept.
305
     * @return the initials
306
     */
307
    public String getInitials(){
308
        return this.initials;
309
    }
310
    /**
311
     * @see  #getInitals()
312
     */
313
    public void setInitials(String initials){
314
        this.initials = isBlank(initials) ? null : initials;
315
    }
316

    
317

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

    
341

    
342
	/**
343
	 * Returns the string representing the suffix (for instance "Junior")
344
	 * of <i>this</i> person's name.
345
	 */
346
	public String getSuffix(){
347
		return this.suffix;
348
	}
349
	/**
350
	 * @see  #getSuffix()
351
	 */
352
	public void setSuffix(String suffix){
353
		this.suffix = isBlank(suffix) ? null: suffix;
354
	}
355

    
356

    
357
	/**
358
	 * Returns the {@link eu.etaxonomy.cdm.model.common.TimePeriod period of time}
359
	 * in which <i>this</i> person was alive (life span).
360
	 * The general form is birth date - death date
361
	 * (XXXX - YYYY; XXXX - or - YYYY as appropriate),
362
	 * but a simple flourished date (fl. XXXX) is also possible
363
	 * if that is all what is known.
364
	 *
365
	 * @see  eu.etaxonomy.cdm.model.common.TimePeriod
366
	 */
367
	public TimePeriod getLifespan(){
368
		if(lifespan == null) {
369
			this.lifespan = TimePeriod.NewInstance();
370
		}
371
		return this.lifespan;
372
	}
373
	/**
374
	 * @see  #getLifespan()
375
	 */
376
	public void setLifespan(TimePeriod lifespan){
377
		this.lifespan = lifespan != null? lifespan : TimePeriod.NewInstance();
378
	}
379

    
380

    
381
    /**
382
     * The {@link ORCID ORCiD} of this person.<BR>
383
     * See https://orcid.org/ for information on ORCiD.
384
     * @return the ORCiD
385
     */
386
    public ORCID getOrcid() {
387
        return orcid;
388
    }
389
    /**
390
     * @see #getOrcid()
391
     */
392
    public void setOrcid(ORCID orcid) {
393
        this.orcid = orcid;
394
    }
395

    
396
    @Override
397
    public boolean updateCaches(){
398
        boolean result = false;
399
        result |= super.updateCaches();
400
        if (this.nomenclaturalTitle == null){
401
            this.nomenclaturalTitle = this.getTitleCache();
402
            if ( this.nomenclaturalTitle != null ){
403
                 result = true;
404
            }
405
         }
406

    
407
         return result;
408
     }
409

    
410
//*********************** CLONE ********************************************************/
411

    
412
	/**
413
	 * Clones <i>this</i> Person. This is a shortcut that enables to create
414
	 * a new instance that differs only slightly from <i>this</i> Person.
415
	 *
416
	 * @see eu.etaxonomy.cdm.model.media.IdentifiableMediaEntity#clone()
417
	 * @see java.lang.Object#clone()
418
	 */
419
	@Override
420
	public Object clone() {
421
		try{
422
			Person result = (Person)super.clone();
423
			//no changes to givenname, familyname, lifespan, prefix, suffix
424
			return result;
425
		} catch (CloneNotSupportedException e){
426
			logger.warn("Object does not implement cloneable");
427
			e.printStackTrace();
428
			return null;
429
		}
430
	}
431

    
432
}
(8-8/12)