2 * Copyright (C) 2007 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
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.
10 package eu
.etaxonomy
.cdm
.model
.agent
;
12 import java
.beans
.PropertyChangeEvent
;
13 import java
.beans
.PropertyChangeListener
;
14 import java
.util
.ArrayList
;
15 import java
.util
.List
;
17 import javax
.persistence
.Entity
;
18 import javax
.persistence
.FetchType
;
19 import javax
.persistence
.ManyToMany
;
20 import javax
.persistence
.Transient
;
21 import javax
.xml
.bind
.annotation
.XmlAccessType
;
22 import javax
.xml
.bind
.annotation
.XmlAccessorType
;
23 import javax
.xml
.bind
.annotation
.XmlElement
;
24 import javax
.xml
.bind
.annotation
.XmlElementWrapper
;
25 import javax
.xml
.bind
.annotation
.XmlIDREF
;
26 import javax
.xml
.bind
.annotation
.XmlRootElement
;
27 import javax
.xml
.bind
.annotation
.XmlSchemaType
;
28 import javax
.xml
.bind
.annotation
.XmlType
;
30 import org
.apache
.log4j
.Logger
;
31 import org
.hibernate
.annotations
.Cascade
;
32 import org
.hibernate
.annotations
.CascadeType
;
33 import org
.hibernate
.annotations
.IndexColumn
;
34 import org
.hibernate
.envers
.Audited
;
35 import org
.hibernate
.search
.annotations
.Indexed
;
36 import org
.springframework
.beans
.factory
.annotation
.Configurable
;
38 import eu
.etaxonomy
.cdm
.strategy
.cache
.agent
.TeamDefaultCacheStrategy
;
39 import eu
.etaxonomy
.cdm
.strategy
.match
.Match
;
40 import eu
.etaxonomy
.cdm
.strategy
.match
.MatchMode
;
43 * This class represents teams of {@link Person persons}. A team exists either for itself
44 * or is built with the list of (distinct) persons who belong to it.
45 * In the first case the inherited attribute {@link eu.etaxonomy.cdm.model.common.IdentifiableEntity#getTitleCache() titleCache} is to be used.
46 * In the second case at least all abbreviated names
47 * (the inherited attributes {@link TeamOrPersonBase#getNomenclaturalTitle() nomenclaturalTitle})
48 * or all full names (the strings returned by Person.generateTitle)
49 * of the persons must exist. A team is a {@link java.util.List list} of persons.
51 * This class corresponds to: <ul>
52 * <li> Team according to the TDWG ontology
53 * <li> AgentNames (partially) according to the TCS
54 * <li> MicroAgent (partially) according to the ABCD schema
59 * @created 08-Nov-2007 13:06:58
61 @XmlAccessorType(XmlAccessType
.FIELD
)
62 @XmlType(name
= "Team", propOrder
= {
63 "protectedNomenclaturalTitleCache",
64 "protectedCollectorTitleCache",
68 @XmlRootElement(name
= "Team")
70 @Indexed(index
= "eu.etaxonomy.cdm.model.agent.AgentBase")
73 public class Team
extends TeamOrPersonBase
<Team
> {
74 private static final long serialVersionUID
= 97640416905934622L;
75 public static final Logger logger
= Logger
.getLogger(Team
.class);
77 @XmlElement(name
= "ProtectedNomenclaturalTitleCache")
78 private boolean protectedNomenclaturalTitleCache
= false;
80 //under construction #4311
81 @XmlElement(name
= "ProtectedCollectorTitleCache")
82 private boolean protectedCollectorTitleCache
= false;
84 //An abbreviated name for the team (e. g. in case of nomenclatural authorteams).
85 //A non abbreviated name for the team (e. g.
86 //in case of some bibliographical references)
87 @XmlElementWrapper(name
= "TeamMembers", nillable
= true)
88 @XmlElement(name
= "TeamMember")
90 @XmlSchemaType(name
= "IDREF")
91 @IndexColumn(name
="sortIndex", base
= 0)
92 @ManyToMany(fetch
= FetchType
.LAZY
)
93 @Cascade(CascadeType
.SAVE_UPDATE
)
94 @Match(MatchMode
.MATCH
)
95 private List
<Person
> teamMembers
;
97 @XmlElement(name
= "hasMoreMembers")
98 private boolean hasMoreMembers
;
103 * Creates a new team instance without any concrete {@link Person members}.
105 static public Team
NewInstance(){
110 * Creates a new team instance with a bibliographic and nomenclatural title
111 * but without any {@link Person members}. The caches are set to protected.
113 static public Team
NewTitledInstance(String title
, String nomTitle
){
114 Team result
= new Team();
115 result
.setTitleCache(title
, true);
116 result
.setNomenclaturalTitle(nomTitle
, true);
121 * Class constructor (including the cache strategy defined in
122 * {@link eu.etaxonomy.cdm.strategy.cache.agent.TeamDefaultCacheStrategy TeamDefaultCacheStrategy}).
126 this.cacheStrategy
= TeamDefaultCacheStrategy
.NewInstance();
127 addListenersToMembers();
131 * Adds a property change listener to all team members.
133 private void addListenersToMembers() {
134 List
<Person
> members
= getTeamMembers();
135 for (Person member
: members
){
136 addListenerForTeamMember(member
);
143 private void addListenerForTeamMember(Person member
) {
144 PropertyChangeListener listener
= new PropertyChangeListener() {
146 public void propertyChange(PropertyChangeEvent e
) {
148 // ---- code with no effect below -----
149 // if (! isProtectedTitleCache()){
150 // titleCache = titleCache;
152 // if (! isProtectedNomenclaturalTitleCache()){
153 // nomenclaturalTitle = nomenclaturalTitle;
157 member
.addPropertyChangeListener(listener
);
161 * Returns the list of {@link Person members} belonging to <i>this</i> team.
162 * A person may be a member of several distinct teams.
164 public List
<Person
> getTeamMembers(){
165 if(teamMembers
== null) {
166 this.teamMembers
= new ArrayList
<Person
>();
168 return this.teamMembers
;
171 protected void setTeamMembers(List
<Person
> teamMembers
) {
172 this.teamMembers
= teamMembers
;
173 addListenersToMembers();
177 * Adds a new {@link Person person} to <i>this</i> team at the end of the members' list.
179 * @param person the person who should be added to the other team members
180 * @see #getTeamMembers()
183 public void addTeamMember(Person person
){
185 getTeamMembers().add(person
);
186 firePropertyChange("teamMember", null, person
);
187 addListenerForTeamMember(person
);
192 * Adds a new {@link Person person} to <i>this</i> team
193 * at the given index place of the members' list. If the person is already
194 * a member of the list he will be moved to the given index place.
195 * The index must be an integer (>=0). If the index is larger than
196 * the present number of members the person will be added at the end of the list.
198 * @param person the person who should be added to the other team members
199 * @param index the position at which the person should be placed within the members' list (starting with 0)
200 * @see #getTeamMembers()
203 public void addTeamMember(Person person
, int index
){
205 int oldIndex
= getTeamMembers().indexOf(person
);
206 if (oldIndex
!= -1 ){
207 getTeamMembers().remove(person
);
209 if (index
>= getTeamMembers().size()){
210 index
= getTeamMembers().size();
212 getTeamMembers().add(index
, person
);
213 addListenerForTeamMember(person
);
214 firePropertyChange("teamMember", null, person
);
219 * Removes one person from the list of members of <i>this</i> team.
221 * @param person the person who should be deleted from <i>this</i> team
222 * @see #getTeamMembers()
224 public void removeTeamMember(Person person
){
225 boolean wasMember
= getTeamMembers().remove(person
);
227 firePropertyChange("teamMember", person
, null);
233 * Generates or returns the {@link TeamOrPersonBase#getnomenclaturalTitle() nomenclatural identification} string for <i>this</i> team.
234 * This method overrides {@link TeamOrPersonBase#getNomenclaturalTitle() getNomenclaturalTitle}.
235 * This string is built with the {@link TeamOrPersonBase#getNomenclaturalTitle() abbreviated names}
236 * of all persons belonging to its (ordered) members' list if the flag
237 * {@link #protectedNomenclaturalTitleCache protectedNomenclaturalTitleCache} is not set.
238 * Otherwise this method returns the present nomenclatural abbreviation.
239 * In case the string is generated the cache strategy used is defined in
240 * {@link eu.etaxonomy.cdm.strategy.cache.agent.TeamDefaultCacheStrategy TeamDefaultCacheStrategy}.
241 * The result might be kept as nomenclatural abbreviation
242 * by using the {@link #setNomenclaturalTitle(String) setNomenclaturalTitle} method.
244 * @return a string which identifies <i>this</i> team for nomenclature
248 public String
getNomenclaturalTitle() {
249 if (protectedNomenclaturalTitleCache
== PROTECTED
){
250 return this.nomenclaturalTitle
;
252 if (nomenclaturalTitle
== null){
253 this.nomenclaturalTitle
= cacheStrategy
.getNomenclaturalTitle(this);
255 //as long as team members to not inform the team about changes the cache must be created new each time
256 nomenclaturalTitle
= cacheStrategy
.getNomenclaturalTitle(this);
258 return nomenclaturalTitle
;
262 * Assigns a {@link TeamOrPersonBase#nomenclaturalTitle nomenclatural identification} string to <i>this</i> team
263 * and protects it from overwriting.
264 * This method overrides {@link TeamOrPersonBase#setNomenclaturalTitle(String) setNomenclaturalTitle}.
266 * @see #getNomenclaturalTitle()
267 * @see #setNomenclaturalTitle(String, boolean)
270 public void setNomenclaturalTitle(String nomenclaturalTitle
) {
271 this.setNomenclaturalTitle(nomenclaturalTitle
, PROTECTED
);
275 * Assigns a {@link TeamOrPersonBase#nomenclaturalTitle nomenclatural identification} string to <i>this</i> team
276 * and a protection flag status to this string.
278 * @see #getNomenclaturalTitle()
280 public void setNomenclaturalTitle(String nomenclaturalTitle
, boolean protectedNomenclaturalTitleCache
) {
281 firePropertyChange("nomenclaturalTitle", this.nomenclaturalTitle
, nomenclaturalTitle
);
282 this.nomenclaturalTitle
= nomenclaturalTitle
== "" ?
null: nomenclaturalTitle
;
283 this.protectedNomenclaturalTitleCache
= protectedNomenclaturalTitleCache
;
288 //@Transient //TODO a.kohlbecker remove??
289 public String
getTitleCache() {
290 isGeneratingTitleCache
= true;
292 if (isProtectedTitleCache()){
293 result
= this.titleCache
;
295 result
= generateTitle();
296 result
= replaceEmptyTitleByNomTitle(result
);
297 result
= getTruncatedCache(result
);
298 this.titleCache
= result
;
300 isGeneratingTitleCache
= false;
305 * Protected nomenclatural title cache flag should be set to true, if
306 * the title cache is to be preferred against the atomized data.
307 * This may be the case if no atomized data exists or if atomization
308 * was incomplete for whatever reason.
311 public boolean isProtectedNomenclaturalTitleCache() {
312 return protectedNomenclaturalTitleCache
;
315 public void setProtectedNomenclaturalTitleCache(
316 boolean protectedNomenclaturalTitleCache
) {
317 this.protectedNomenclaturalTitleCache
= protectedNomenclaturalTitleCache
;
322 * The hasMoreMembers flag is true if this team has more members than
323 * mentioned in the {@link #teamMembers} list. This is usually the case
324 * when "et al." is used in the team representation. Formatters should add
325 * "et al." or an according post fix to the team string representation
326 * if this flag is set.
329 public boolean isHasMoreMembers() {
330 return hasMoreMembers
;
333 public void setHasMoreMembers(boolean hasMoreMembers
) {
334 this.hasMoreMembers
= hasMoreMembers
;
337 //*********************** CLONE ********************************************************/
340 * Clones <i>this</i> Team. This is a shortcut that enables to create
341 * a new instance that differs only slightly from <i>this</i> Team.
342 * The corresponding person is cloned.
344 * @see eu.etaxonomy.cdm.model.media.IdentifiableMediaEntity#clone()
345 * @see java.lang.Object#clone()
348 public Object
clone() {
350 Team result
= (Team
)super.clone();
351 result
.teamMembers
= new ArrayList
<Person
>();
352 for (Person teamMember
: this.teamMembers
){
353 result
.addTeamMember(teamMember
);
355 //no changes to protectedNomenclaturalTitleCache
357 } catch (CloneNotSupportedException e
){
358 logger
.warn("Object does not implement cloneable");