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.JoinTable;
|
23
|
import javax.persistence.OneToMany;
|
24
|
import javax.persistence.Transient;
|
25
|
import javax.xml.bind.annotation.XmlAccessType;
|
26
|
import javax.xml.bind.annotation.XmlAccessorType;
|
27
|
import javax.xml.bind.annotation.XmlElement;
|
28
|
import javax.xml.bind.annotation.XmlElementWrapper;
|
29
|
import javax.xml.bind.annotation.XmlSeeAlso;
|
30
|
import javax.xml.bind.annotation.XmlType;
|
31
|
|
32
|
import org.apache.log4j.Logger;
|
33
|
import org.hibernate.annotations.Cascade;
|
34
|
import org.hibernate.annotations.CascadeType;
|
35
|
import org.hibernate.envers.Audited;
|
36
|
import org.hibernate.search.annotations.Analyze;
|
37
|
import org.hibernate.search.annotations.Field;
|
38
|
import org.hibernate.search.annotations.IndexedEmbedded;
|
39
|
|
40
|
import au.com.bytecode.opencsv.CSVWriter;
|
41
|
import eu.etaxonomy.cdm.model.description.TextData;
|
42
|
import eu.etaxonomy.cdm.model.name.HybridRelationshipType;
|
43
|
import eu.etaxonomy.cdm.model.name.NameRelationshipType;
|
44
|
import eu.etaxonomy.cdm.model.taxon.SynonymRelationshipType;
|
45
|
import eu.etaxonomy.cdm.model.taxon.TaxonRelationshipType;
|
46
|
|
47
|
@XmlAccessorType(XmlAccessType.FIELD)
|
48
|
@XmlType(name = "RelationshipTermBase", propOrder = {
|
49
|
"symmetric",
|
50
|
"transitive",
|
51
|
"inverseRepresentations",
|
52
|
"reverseSymbol"
|
53
|
})
|
54
|
@XmlSeeAlso({
|
55
|
HybridRelationshipType.class,
|
56
|
NameRelationshipType.class,
|
57
|
SynonymRelationshipType.class,
|
58
|
TaxonRelationshipType.class
|
59
|
})
|
60
|
@Entity
|
61
|
@Audited
|
62
|
public abstract class RelationshipTermBase<T extends RelationshipTermBase> extends OrderedTermBase<T> {
|
63
|
private static final long serialVersionUID = 5497187985269083971L;
|
64
|
@SuppressWarnings("unused")
|
65
|
private static final Logger logger = Logger.getLogger(RelationshipTermBase.class);
|
66
|
|
67
|
@XmlElement(name = "Symmetrical")
|
68
|
@Field(analyze = Analyze.NO)
|
69
|
@Column(name="symmetrical") //to be compatible with PostGreSQL
|
70
|
private boolean symmetric;
|
71
|
|
72
|
@XmlElement(name = "Transitive")
|
73
|
@Field(analyze = Analyze.NO)
|
74
|
private boolean transitive;
|
75
|
|
76
|
@XmlElementWrapper(name = "InverseRepresentations")
|
77
|
@XmlElement(name = "Representation")
|
78
|
@OneToMany(fetch = FetchType.LAZY)
|
79
|
@JoinTable(name="RelationshipTermBase_inverseRepresentation")
|
80
|
@Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE})
|
81
|
@IndexedEmbedded(depth = 2)
|
82
|
private Set<Representation> inverseRepresentations = new HashSet<Representation>();
|
83
|
|
84
|
@XmlElement(name = "reverseSymbol")
|
85
|
@Column(length=10)
|
86
|
//the symbol to be used in String representations for the reverse representation of this term #5734
|
87
|
//this term can be changed by the database instance even if the term is not managed by this instance as it is only for representation and has no semantic or identifying character
|
88
|
//empty string is explicitly allowed and should be distinguished from NULL!
|
89
|
private String reverseSymbol;
|
90
|
|
91
|
//******************** CONSTRUCTOR ************************/
|
92
|
|
93
|
//for JAXB only, TODO needed?
|
94
|
@Deprecated
|
95
|
private RelationshipTermBase(){super();}
|
96
|
|
97
|
|
98
|
protected RelationshipTermBase(TermType type) {
|
99
|
super(type);
|
100
|
}
|
101
|
public RelationshipTermBase(TermType type, String term, String label, String labelAbbrev, boolean symmetric, boolean transitive) {
|
102
|
super(type, term, label, labelAbbrev);
|
103
|
setSymmetric(symmetric);
|
104
|
setTransitive(transitive);
|
105
|
}
|
106
|
|
107
|
//************************** METHODS ********************************
|
108
|
|
109
|
public boolean isSymmetric() {
|
110
|
return symmetric;
|
111
|
}
|
112
|
public void setSymmetric(boolean symmetric) {
|
113
|
this.symmetric = symmetric;
|
114
|
}
|
115
|
|
116
|
public boolean isTransitive() {
|
117
|
return transitive;
|
118
|
}
|
119
|
public void setTransitive(boolean transitive) {
|
120
|
this.transitive = transitive;
|
121
|
}
|
122
|
|
123
|
public Set<Representation> getInverseRepresentations() {
|
124
|
return inverseRepresentations;
|
125
|
}
|
126
|
|
127
|
public void addInverseRepresentation(Representation inverseRepresentation) {
|
128
|
this.inverseRepresentations.add(inverseRepresentation);
|
129
|
}
|
130
|
public void removeInverseRepresentation(Representation inverseRepresentation) {
|
131
|
this.inverseRepresentations.remove(inverseRepresentation);
|
132
|
}
|
133
|
public void addRepresentation(Representation representation, Representation inverseRepresentation) {
|
134
|
this.addRepresentation(representation);
|
135
|
this.addInverseRepresentation(inverseRepresentation);
|
136
|
}
|
137
|
|
138
|
public Representation getInverseRepresentation(Language lang) {
|
139
|
Representation result = null;
|
140
|
if (this.isSymmetric()){
|
141
|
for (Representation repr : this.getRepresentations()){
|
142
|
if (lang.equals(repr.getLanguage())){
|
143
|
result = repr;
|
144
|
}
|
145
|
}
|
146
|
}else{
|
147
|
for (Representation repr : this.getInverseRepresentations()){
|
148
|
if (lang.equals(repr.getLanguage())){
|
149
|
result = repr;
|
150
|
}
|
151
|
}
|
152
|
}
|
153
|
return result;
|
154
|
}
|
155
|
|
156
|
/**
|
157
|
* Returns the InverseRepresentation in the preferred language. Preferred languages
|
158
|
* are specified by the parameter languages, which receives a list of
|
159
|
* Language instances in the order of preference. If no representation in
|
160
|
* any preferred languages is found the method falls back to return the
|
161
|
* Representation in Language.DEFAULT() and if necessary further falls back
|
162
|
* to return the first element found if any.
|
163
|
*
|
164
|
* TODO think about this fall-back strategy &
|
165
|
* see also {@link TextData#getPreferredLanguageString(List)}
|
166
|
* see also {@link TermBase#getPreferredRepresentation(List)}
|
167
|
*
|
168
|
* @param languages
|
169
|
* @return
|
170
|
*/
|
171
|
public Representation getPreferredInverseRepresentation(List<Language> languages) {
|
172
|
Representation repr = null;
|
173
|
if(languages != null){
|
174
|
for(Language language : languages) {
|
175
|
repr = getInverseRepresentation(language);
|
176
|
if(repr != null){
|
177
|
return repr;
|
178
|
}
|
179
|
}
|
180
|
}
|
181
|
if(repr == null){
|
182
|
repr = getInverseRepresentation(Language.DEFAULT());
|
183
|
}
|
184
|
if(repr == null){
|
185
|
Iterator<Representation> it = getInverseRepresentations().iterator();
|
186
|
if(it.hasNext()){
|
187
|
repr = getInverseRepresentations().iterator().next();
|
188
|
}
|
189
|
}
|
190
|
return repr;
|
191
|
}
|
192
|
|
193
|
/*
|
194
|
* Inverse representation convenience methods similar to TermBase.xxx
|
195
|
* @see eu.etaxonomy.cdm.model.common.TermBase#getLabel()
|
196
|
*/
|
197
|
@Transient
|
198
|
public String getInverseLabel() {
|
199
|
if(getInverseLabel(Language.DEFAULT())!=null){
|
200
|
return this.getInverseRepresentation(Language.DEFAULT()).getLabel();
|
201
|
}else{
|
202
|
for (Representation r : inverseRepresentations){
|
203
|
return r.getLabel();
|
204
|
}
|
205
|
}
|
206
|
return super.getUuid().toString();
|
207
|
}
|
208
|
|
209
|
public String getInverseLabel(Language lang) {
|
210
|
Representation r = this.getInverseRepresentation(lang);
|
211
|
if(r==null){
|
212
|
return null;
|
213
|
}else{
|
214
|
return r.getLabel();
|
215
|
}
|
216
|
}
|
217
|
|
218
|
@Transient
|
219
|
public String getInverseDescription() {
|
220
|
return this.getInverseRepresentation(Language.DEFAULT()).getDescription();
|
221
|
}
|
222
|
|
223
|
public String getInverseDescription(Language lang) {
|
224
|
return this.getInverseRepresentation(lang).getDescription();
|
225
|
}
|
226
|
|
227
|
@Override
|
228
|
public T readCsvLine(Class<T> termClass, List<String> csvLine, Map<UUID,DefinedTermBase> terms, boolean abbrevAsId) {
|
229
|
T newInstance = super.readCsvLine(termClass, csvLine, terms, abbrevAsId);
|
230
|
|
231
|
String inverseText = csvLine.get(6).trim();
|
232
|
String inverseLabel = csvLine.get(5).trim();
|
233
|
String inverseLabelAbbrev = csvLine.get(7).trim();
|
234
|
newInstance.addInverseRepresentation(new Representation(inverseText, inverseLabel, inverseLabelAbbrev, Language.CSV_LANGUAGE()) );
|
235
|
newInstance.setSymmetric(Boolean.parseBoolean(csvLine.get(8)));
|
236
|
newInstance.setTransitive(Boolean.parseBoolean(csvLine.get(9)));
|
237
|
return newInstance;
|
238
|
}
|
239
|
|
240
|
@Override
|
241
|
public void writeCsvLine(CSVWriter writer,T term) {
|
242
|
String [] line = new String[8];
|
243
|
line[0] = term.getUuid().toString();
|
244
|
line[1] = term.getUri().toString();
|
245
|
line[2] = term.getLabel();
|
246
|
line[3] = term.getDescription();
|
247
|
line[4] = term.getDescription();
|
248
|
line[5] = term.getInverseLabel();
|
249
|
line[6] = term.getInverseDescription();
|
250
|
line[7] = String.valueOf(term.isSymmetric());
|
251
|
line[8] = String.valueOf(term.isTransitive());
|
252
|
writer.writeNext(line);
|
253
|
}
|
254
|
//*********************************** CLONE *********************************************************/
|
255
|
|
256
|
/* (non-Javadoc)
|
257
|
* @see eu.etaxonomy.cdm.model.common.DefinedTermBase#clone()
|
258
|
* @see java.lang.Object#clone()
|
259
|
*/
|
260
|
@Override
|
261
|
public Object clone() {
|
262
|
RelationshipTermBase<?> result = (RelationshipTermBase<?>)super.clone();
|
263
|
|
264
|
result.inverseRepresentations = new HashSet<Representation>();
|
265
|
for (Representation rep: this.inverseRepresentations){
|
266
|
result.addInverseRepresentation((Representation)rep.clone());
|
267
|
}
|
268
|
|
269
|
//no changes to: symmetric, transitiv
|
270
|
return result;
|
271
|
}
|
272
|
|
273
|
|
274
|
}
|