root/trunk/cdmlib/cdmlib-model/src/main/java/eu/etaxonomy/cdm/model/agent/Team.java

Revision 12131, 11.0 kB (checked in by a.mueller, 12 months ago)

bugfix for team titlecache

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