remaining clone methods
[cdmlib.git] / cdmlib-model / src / main / java / eu / etaxonomy / cdm / model / agent / Team.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.beans.PropertyChangeEvent;
13 import java.beans.PropertyChangeListener;
14 import java.util.ArrayList;
15 import java.util.HashSet;
16 import java.util.List;
17
18 import javax.persistence.Entity;
19 import javax.persistence.FetchType;
20 import javax.persistence.ManyToMany;
21 import javax.persistence.Transient;
22 import javax.xml.bind.annotation.XmlAccessType;
23 import javax.xml.bind.annotation.XmlAccessorType;
24 import javax.xml.bind.annotation.XmlElement;
25 import javax.xml.bind.annotation.XmlElementWrapper;
26 import javax.xml.bind.annotation.XmlIDREF;
27 import javax.xml.bind.annotation.XmlRootElement;
28 import javax.xml.bind.annotation.XmlSchemaType;
29 import javax.xml.bind.annotation.XmlType;
30
31 import org.apache.log4j.Logger;
32 import org.hibernate.annotations.Cascade;
33 import org.hibernate.annotations.CascadeType;
34 import org.hibernate.annotations.IndexColumn;
35 import org.hibernate.envers.Audited;
36 import org.hibernate.search.annotations.Indexed;
37 import org.springframework.beans.factory.annotation.Configurable;
38
39 import eu.etaxonomy.cdm.model.common.User;
40 import eu.etaxonomy.cdm.strategy.cache.agent.TeamDefaultCacheStrategy;
41 import eu.etaxonomy.cdm.strategy.match.Match;
42 import eu.etaxonomy.cdm.strategy.match.MatchMode;
43
44 /**
45 * This class represents teams of {@link Person persons}. A team exists either for itself
46 * or is built with the list of (distinct) persons who belong to it.
47 * In the first case the inherited attribute {@link eu.etaxonomy.cdm.model.common.IdentifiableEntity#getTitleCache() titleCache} is to be used.
48 * In the second case at least all abbreviated names
49 * (the inherited attributes {@link TeamOrPersonBase#getNomenclaturalTitle() nomenclaturalTitle})
50 * or all full names (the strings returned by Person.generateTitle)
51 * of the persons must exist. A team is a {@link java.util.List list} of persons.
52 * <P>
53 * This class corresponds to: <ul>
54 * <li> Team according to the TDWG ontology
55 * <li> AgentNames (partially) according to the TCS
56 * <li> MicroAgent (partially) according to the ABCD schema
57 * </ul>
58 *
59 * @author m.doering
60 * @version 1.0
61 * @created 08-Nov-2007 13:06:58
62 */
63 @XmlAccessorType(XmlAccessType.FIELD)
64 @XmlType(name = "Team", propOrder = {
65 "protectedNomenclaturalTitleCache",
66 "teamMembers"
67 })
68 @XmlRootElement(name = "Team")
69 @Entity
70 @Indexed(index = "eu.etaxonomy.cdm.model.agent.AgentBase")
71 @Audited
72 @Configurable
73 public class Team extends TeamOrPersonBase<Team> {
74 private static final long serialVersionUID = 97640416905934622L;
75 public static final Logger logger = Logger.getLogger(Team.class);
76
77 @XmlElement(name = "ProtectedNomenclaturalTitleCache")
78 private boolean protectedNomenclaturalTitleCache = false;
79
80 //An abreviated name for the team (e. g. in case of nomenclatural authorteams). A non abreviated name for the team (e. g.
81 //in case of some bibliographical references)
82 @XmlElementWrapper(name = "TeamMembers", nillable = true)
83 @XmlElement(name = "TeamMember")
84 @XmlIDREF
85 @XmlSchemaType(name = "IDREF")
86 @IndexColumn(name="sortIndex", base = 0)
87 @ManyToMany(fetch = FetchType.LAZY)
88 @Cascade(CascadeType.SAVE_UPDATE)
89 @Match(MatchMode.MATCH)
90 private List<Person> teamMembers;
91
92
93 /**
94 * Creates a new team instance without any concrete {@link Person members}.
95 */
96 static public Team NewInstance(){
97 return new Team();
98 }
99
100 /**
101 * Creates a new team instance with a bibliographic and nomenclatural title
102 * but without any {@link Person members}. The caches are set to protected.
103 */
104 static public Team NewTitledInstance(String title, String nomTitle){
105 Team result = new Team();
106 result.setTitleCache(title, true);
107 result.setNomenclaturalTitle(nomTitle, true);
108 return result;
109 }
110
111 /**
112 * Class constructor (including the cache strategy defined in
113 * {@link eu.etaxonomy.cdm.strategy.cache.agent.TeamDefaultCacheStrategy TeamDefaultCacheStrategy}).
114 */
115 public Team() {
116 super();
117 this.cacheStrategy = TeamDefaultCacheStrategy.NewInstance();
118 addListenersToMembers();
119 }
120
121 /**
122 * Adds a property change listener to all team members.
123 */
124 private void addListenersToMembers() {
125 List<Person> members = getTeamMembers();
126 for (Person member : members){
127 addListenerForTeamMember(member);
128 }
129 }
130
131 /**
132 * @return
133 */
134 private void addListenerForTeamMember(Person member) {
135 PropertyChangeListener listener = new PropertyChangeListener() {
136 public void propertyChange(PropertyChangeEvent e) {
137 if (! isProtectedTitleCache()){
138 titleCache = titleCache;
139 }
140 if (! isProtectedNomenclaturalTitleCache()){
141 nomenclaturalTitle = nomenclaturalTitle;
142 }
143 }
144 };
145 member.addPropertyChangeListener(listener);
146 }
147
148 /**
149 * Returns the list of {@link Person members} belonging to <i>this</i> team.
150 * A person may be a member of several distinct teams.
151 */
152 public List<Person> getTeamMembers(){
153 if(teamMembers == null) {
154 this.teamMembers = new ArrayList<Person>();
155 }
156 return this.teamMembers;
157 }
158
159 protected void setTeamMembers(List<Person> teamMembers) {
160 this.teamMembers = teamMembers;
161 addListenersToMembers();
162 }
163
164 /**
165 * Adds a new {@link Person person} to <i>this</i> team at the end of the members' list.
166 *
167 * @param person the person who should be added to the other team members
168 * @see #getTeamMembers()
169 * @see Person
170 */
171 public void addTeamMember(Person person){
172 if (person != null){
173 getTeamMembers().add(person);
174 firePropertyChange("teamMember", null, person);
175 addListenerForTeamMember(person);
176 }
177 }
178
179 /**
180 * Adds a new {@link Person person} to <i>this</i> team
181 * at the given index place of the members' list. If the person is already
182 * a member of the list he will be moved to the given index place.
183 * The index must be an integer (>=0). If the index is larger than
184 * the present number of members the person will be added at the end of the list.
185 *
186 * @param person the person who should be added to the other team members
187 * @param index the position at which the person should be placed within the members' list (starting with 0)
188 * @see #getTeamMembers()
189 * @see Person
190 */
191 public void addTeamMember(Person person, int index){
192 if (person != null){
193 int oldIndex = getTeamMembers().indexOf(person);
194 if (oldIndex != -1 ){
195 getTeamMembers().remove(person);
196 }
197 if (index >= getTeamMembers().size()){
198 index = getTeamMembers().size();
199 }
200 getTeamMembers().add(index, person);
201 addListenerForTeamMember(person);
202 firePropertyChange("teamMember", null, person);
203 }
204 }
205
206 /**
207 * Removes one person from the list of members of <i>this</i> team.
208 *
209 * @param person the person who should be deleted from <i>this</i> team
210 * @see #getTeamMembers()
211 */
212 public void removeTeamMember(Person person){
213 boolean wasMember = getTeamMembers().remove(person);
214 if (wasMember){
215 firePropertyChange("teamMember", person, null);
216 }
217
218 }
219
220
221 /**
222 * Generates or returns the {@link TeamOrPersonBase#getnomenclaturalTitle() nomenclatural identification} string for <i>this</i> team.
223 * This method overrides {@link TeamOrPersonBase#getNomenclaturalTitle() getNomenclaturalTitle}.
224 * This string is built with the {@link TeamOrPersonBase#getNomenclaturalTitle() abbreviated names}
225 * of all persons belonging to its (ordered) members' list if the flag
226 * {@link #protectedNomenclaturalTitleCache protectedNomenclaturalTitleCache} is not set.
227 * Otherwise this method returns the present nomenclatural abbreviation.
228 * In case the string is generated the cache strategy used is defined in
229 * {@link eu.etaxonomy.cdm.strategy.cache.agent.TeamDefaultCacheStrategy TeamDefaultCacheStrategy}.
230 * The result might be kept as nomenclatural abbreviation
231 * by using the {@link #setNomenclaturalTitle(String) setNomenclaturalTitle} method.
232 *
233 * @return a string which identifies <i>this</i> team for nomenclature
234 */
235 @Override
236 @Transient
237 public String getNomenclaturalTitle() {
238 if (protectedNomenclaturalTitleCache == PROTECTED){
239 return this.nomenclaturalTitle;
240 }
241 if (nomenclaturalTitle == null){
242 this.nomenclaturalTitle = cacheStrategy.getNomenclaturalTitle(this);
243 }else{
244 //as long as team members to not inform the team about changes the cache must be created new each time
245 nomenclaturalTitle = cacheStrategy.getNomenclaturalTitle(this);
246 }
247 return nomenclaturalTitle;
248 }
249
250 /**
251 * Assigns a {@link TeamOrPersonBase#nomenclaturalTitle nomenclatural identification} string to <i>this</i> team
252 * and protects it from overwriting.
253 * This method overrides {@link TeamOrPersonBase#setNomenclaturalTitle(String) setNomenclaturalTitle}.
254 *
255 * @see #getNomenclaturalTitle()
256 * @see #setNomenclaturalTitle(String, boolean)
257 */
258 @Override
259 public void setNomenclaturalTitle(String nomenclaturalTitle) {
260 this.setNomenclaturalTitle(nomenclaturalTitle, PROTECTED);
261 }
262
263 /**
264 * Assigns a {@link TeamOrPersonBase#nomenclaturalTitle nomenclatural identification} string to <i>this</i> team
265 * and a protection flag status to this string.
266 *
267 * @see #getNomenclaturalTitle()
268 */
269 public void setNomenclaturalTitle(String nomenclaturalTitle, boolean protectedNomenclaturalTitleCache) {
270 firePropertyChange("nomenclaturalTitle", this.nomenclaturalTitle, nomenclaturalTitle);
271 this.nomenclaturalTitle = nomenclaturalTitle;
272 this.protectedNomenclaturalTitleCache = protectedNomenclaturalTitleCache;
273 }
274
275 /* (non-Javadoc)
276 * @see eu.etaxonomy.cdm.model.agent.TeamOrPersonBase#getTitleCache()
277 */
278 @Override
279 //@Transient //TODO a.kohlbecker remove??
280 public String getTitleCache() {
281 isGeneratingTitleCache = true;
282 String result = "";
283 if (isProtectedTitleCache()){
284 result = this.titleCache;
285 }else{
286 result = generateTitle();
287 result = replaceEmptyTitleByNomTitle(result);
288 result = getTruncatedCache(result);
289 }
290 isGeneratingTitleCache = false;
291 return result;
292 }
293
294 public boolean isProtectedNomenclaturalTitleCache() {
295 return protectedNomenclaturalTitleCache;
296 }
297
298 public void setProtectedNomenclaturalTitleCache(
299 boolean protectedNomenclaturalTitleCache) {
300 this.protectedNomenclaturalTitleCache = protectedNomenclaturalTitleCache;
301 }
302
303 //*********************** CLONE ********************************************************/
304
305 /**
306 * Clones <i>this</i> Team. This is a shortcut that enables to create
307 * a new instance that differs only slightly from <i>this</i> Team.
308 * The corresponding person is cloned.
309 *
310 * @see eu.etaxonomy.cdm.model.media.IdentifiableMediaEntity#clone()
311 * @see java.lang.Object#clone()
312 */
313 @Override
314 public Object clone() {
315 try{
316 Team result = (Team)super.clone();
317 result.teamMembers = new ArrayList<Person>();
318 for (Person teamMember: this.teamMembers){
319 result.addTeamMember(teamMember);
320 }
321 //no changes to protectedNomenclaturalTitleCache
322 return result;
323 } catch (CloneNotSupportedException e){
324 logger.warn("Object does not implement cloneable");
325 e.printStackTrace();
326 return null;
327 }
328
329
330 }
331
332
333 }