Project

General

Profile

Download (9.45 KB) Statistics
| Branch: | Tag: | Revision:
1
/**
2
* Copyright (C) 2009 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.common;
11

    
12
import java.util.HashSet;
13
import java.util.Iterator;
14
import java.util.List;
15
import java.util.Map;
16
import java.util.Set;
17
import java.util.UUID;
18

    
19
import javax.persistence.Column;
20
import javax.persistence.Entity;
21
import javax.persistence.FetchType;
22
import javax.persistence.JoinColumn;
23
import javax.persistence.JoinTable;
24
import javax.persistence.OneToMany;
25
import javax.persistence.Transient;
26
import javax.xml.bind.annotation.XmlAccessType;
27
import javax.xml.bind.annotation.XmlAccessorType;
28
import javax.xml.bind.annotation.XmlElement;
29
import javax.xml.bind.annotation.XmlElementWrapper;
30
import javax.xml.bind.annotation.XmlSeeAlso;
31
import javax.xml.bind.annotation.XmlType;
32

    
33
import org.apache.log4j.Logger;
34
import org.hibernate.annotations.Cascade;
35
import org.hibernate.annotations.CascadeType;
36
import org.hibernate.envers.Audited;
37
import org.hibernate.search.annotations.Analyze;
38
import org.hibernate.search.annotations.Field;
39
import org.hibernate.search.annotations.IndexedEmbedded;
40

    
41
import au.com.bytecode.opencsv.CSVWriter;
42
import eu.etaxonomy.cdm.common.CdmUtils;
43
import eu.etaxonomy.cdm.model.description.TextData;
44
import eu.etaxonomy.cdm.model.name.HybridRelationshipType;
45
import eu.etaxonomy.cdm.model.name.NameRelationshipType;
46
import eu.etaxonomy.cdm.model.taxon.SynonymType;
47
import eu.etaxonomy.cdm.model.taxon.TaxonRelationshipType;
48
import eu.etaxonomy.cdm.model.term.DefinedTermBase;
49
import eu.etaxonomy.cdm.model.term.OrderedTermBase;
50
import eu.etaxonomy.cdm.model.term.Representation;
51
import eu.etaxonomy.cdm.model.term.TermBase;
52
import eu.etaxonomy.cdm.model.term.TermType;
53

    
54
@XmlAccessorType(XmlAccessType.FIELD)
55
@XmlType(name = "RelationshipTermBase", propOrder = {
56
    "symmetric",
57
    "transitive",
58
    "inverseRepresentations",
59
    "inverseSymbol"
60
})
61
@XmlSeeAlso({
62
	HybridRelationshipType.class,
63
	NameRelationshipType.class,
64
	SynonymType.class,
65
	TaxonRelationshipType.class
66
})
67
@Entity
68
@Audited
69
public abstract class RelationshipTermBase<T extends RelationshipTermBase<T>>
70
          extends OrderedTermBase<T> {
71
	private static final long serialVersionUID = 5497187985269083971L;
72
	@SuppressWarnings("unused")
73
	private static final Logger logger = Logger.getLogger(RelationshipTermBase.class);
74

    
75
	@XmlElement(name = "Symmetrical")
76
	@Field(analyze = Analyze.NO)
77
	@Column(name="symmetrical") //to be compatible with PostGreSQL
78
	private boolean symmetric;
79

    
80
	@XmlElement(name = "Transitive")
81
	@Field(analyze = Analyze.NO)
82
	private boolean transitive;
83

    
84
	@XmlElementWrapper(name = "InverseRepresentations")
85
	@XmlElement(name = "Representation")
86
	@OneToMany(fetch = FetchType.EAGER, orphanRemoval=true)  //eager loading same as TermBase.representations
87
	@JoinTable(name="DefinedTermBase_InverseRepresentation",  //see also Feature.inverseRepresentations
88
        joinColumns=@JoinColumn(name="DefinedTermBase_id")
89
//	    inverseJoinColumns
90
    )
91
	@Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE})
92
	@IndexedEmbedded(depth = 2)
93
	private Set<Representation> inverseRepresentations = new HashSet<>();
94

    
95
    @XmlElement(name = "inverseSymbol")
96
    @Column(length=30)
97
    //the symbol to be used in String representations for the reverse representation of this term #5734
98
    //this term can be changed by the database instance even if the term is not managed by this instance
99
    //as it is only for representation and has no semantic or identifying character
100
    //empty string is explicitly allowed and should be distinguished from NULL!
101
    private String inverseSymbol;
102

    
103
//******************** CONSTRUCTOR ************************/
104

    
105
    //for JAXB only, TODO needed?
106
    @Deprecated
107
    private RelationshipTermBase(){super();}
108

    
109

    
110
	protected RelationshipTermBase(TermType type) {
111
		super(type);
112
	}
113
	public RelationshipTermBase(TermType type, String term, String label, String labelAbbrev, boolean symmetric, boolean transitive) {
114
		super(type, term, label, labelAbbrev);
115
		setSymmetric(symmetric);
116
		setTransitive(transitive);
117
	}
118

    
119
//************************** METHODS ********************************
120

    
121
	public boolean isSymmetric() {
122
		return symmetric;
123
	}
124
	public void setSymmetric(boolean symmetric) {
125
		this.symmetric = symmetric;
126
	}
127

    
128
	public boolean isTransitive() {
129
		return transitive;
130
	}
131
	public void setTransitive(boolean transitive) {
132
		this.transitive = transitive;
133
	}
134

    
135
	public Set<Representation> getInverseRepresentations() {
136
		return inverseRepresentations;
137
	}
138

    
139
	public void addInverseRepresentation(Representation inverseRepresentation) {
140
		this.inverseRepresentations.add(inverseRepresentation);
141
	}
142
	public void removeInverseRepresentation(Representation inverseRepresentation) {
143
		this.inverseRepresentations.remove(inverseRepresentation);
144
	}
145
	public void addRepresentation(Representation representation, Representation inverseRepresentation) {
146
		this.addRepresentation(representation);
147
		this.addInverseRepresentation(inverseRepresentation);
148
	}
149

    
150
	public Representation getInverseRepresentation(Language lang) {
151
		if (lang == null){
152
		    return null;
153
		}
154
	    Representation result = null;
155
		if (this.isSymmetric()){
156
			for (Representation repr : this.getRepresentations()){
157
				if (repr != null && lang.equals(repr.getLanguage())){
158
					result = repr;
159
				}
160
			}
161
		}else{
162
			for (Representation repr : this.getInverseRepresentations()){
163
				if (repr != null && lang.equals(repr.getLanguage())){
164
					result = repr;
165
				}
166
			}
167
		}
168
		return result;
169
	}
170

    
171
	/**
172
	 * Returns the InverseRepresentation in the preferred language. Preferred languages
173
	 * are specified by the parameter languages, which receives a list of
174
	 * Language instances in the order of preference. If no representation in
175
	 * any preferred languages is found the method falls back to return the
176
	 * Representation in Language.DEFAULT() and if necessary further falls back
177
	 * to return the first element found if any.
178
	 *
179
	 * TODO think about this fall-back strategy &
180
	 * see also {@link TextData#getPreferredLanguageString(List)}
181
	 * see also {@link TermBase#getPreferredRepresentation(List)}
182
	 *
183
	 * @param languages
184
	 * @return
185
	 */
186
    public Representation getPreferredInverseRepresentation(List<Language> languages) {
187
		Representation repr = null;
188
		if(languages != null){
189
			for(Language language : languages) {
190
				repr = getInverseRepresentation(language);
191
				if(repr != null){
192
					return repr;
193
				}
194
			}
195
		}
196
		if(repr == null){
197
			repr = getInverseRepresentation(Language.DEFAULT());
198
		}
199
		if(repr == null){
200
			Iterator<Representation> it = getInverseRepresentations().iterator();
201
			if(it.hasNext()){
202
				repr = getInverseRepresentations().iterator().next();
203
			}
204
		}
205
		return repr;
206
	}
207

    
208
	/*
209
	 * Inverse representation convenience methods similar to TermBase.xxx
210
	 * @see eu.etaxonomy.cdm.model.term.TermBase#getLabel()
211
	 */
212
	@Transient
213
	public String getInverseLabel() {
214
		if(getInverseLabel(Language.DEFAULT())!=null){
215
			return this.getInverseRepresentation(Language.DEFAULT()).getLabel();
216
		}else{
217
			for (Representation r : inverseRepresentations){
218
				return r.getLabel();
219
			}
220
		}
221
		return super.getUuid().toString();
222
	}
223

    
224
	public String getInverseLabel(Language lang) {
225
		Representation r = this.getInverseRepresentation(lang);
226
		if(r==null){
227
			return null;
228
		}else{
229
			return r.getLabel();
230
		}
231
	}
232

    
233
	@Transient
234
	public String getInverseDescription() {
235
		return this.getInverseRepresentation(Language.DEFAULT()).getDescription();
236
	}
237

    
238
	public String getInverseDescription(Language lang) {
239
		return this.getInverseRepresentation(lang).getDescription();
240
	}
241

    
242
    public String getInverseSymbol() {
243
        return inverseSymbol;
244
    }
245
    public void setInverseSymbol(String inverseSymbol) {
246
        this.inverseSymbol = inverseSymbol;
247
    }
248

    
249
//**************** CSV *************************/
250

    
251
	@Override
252
	public T readCsvLine(Class<T> termClass, List<String> csvLine, TermType termType, Map<UUID,DefinedTermBase> terms, boolean abbrevAsId) {
253
		T newInstance = super.readCsvLine(termClass, csvLine, termType, terms, abbrevAsId);
254

    
255
		String inverseText = CdmUtils.Ne(csvLine.get(6).trim());
256
		String inverseLabel = csvLine.get(5).trim();
257
		String inverseLabelAbbrev = CdmUtils.Ne(csvLine.get(7).trim());
258
		newInstance.addInverseRepresentation(new Representation(inverseText, inverseLabel, inverseLabelAbbrev, Language.CSV_LANGUAGE()) );
259
		newInstance.setSymmetric(Boolean.parseBoolean(csvLine.get(8)));
260
		newInstance.setTransitive(Boolean.parseBoolean(csvLine.get(9)));
261
		return newInstance;
262
	}
263

    
264
	@Override
265
	public void writeCsvLine(CSVWriter writer,T term) {
266
		String [] line = new String[8];
267
		line[0] = term.getUuid().toString();
268
		line[1] = term.getUri().toString();
269
		line[2] = term.getLabel();
270
		line[3] = term.getDescription();
271
		line[4] = term.getDescription();
272
		line[5] = term.getInverseLabel();
273
		line[6] = term.getInverseDescription();
274
		line[7] = String.valueOf(term.isSymmetric());
275
		line[8] = String.valueOf(term.isTransitive());
276
		writer.writeNext(line);
277
	}
278
	//*********************************** CLONE *********************************************************/
279

    
280
	@Override
281
	public RelationshipTermBase<T> clone() {
282
		RelationshipTermBase<T> result = (RelationshipTermBase<T>)super.clone();
283

    
284
		result.inverseRepresentations = new HashSet<>();
285
		for (Representation rep: this.inverseRepresentations){
286
			result.addInverseRepresentation((Representation)rep.clone());
287
		}
288

    
289
		//no changes to: symmetric, transitiv
290
		return result;
291
	}
292

    
293

    
294
}
(48-48/56)