TermBase and descendants indexed using hibernate search
[cdmlib.git] / cdmlib-model / src / main / java / eu / etaxonomy / cdm / model / common / RelationshipTermBase.java
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.Entity;
20 import javax.persistence.FetchType;
21 import javax.persistence.JoinTable;
22 import javax.persistence.OneToMany;
23 import javax.persistence.Transient;
24 import javax.xml.bind.annotation.XmlAccessType;
25 import javax.xml.bind.annotation.XmlAccessorType;
26 import javax.xml.bind.annotation.XmlElement;
27 import javax.xml.bind.annotation.XmlElementWrapper;
28 import javax.xml.bind.annotation.XmlIDREF;
29 import javax.xml.bind.annotation.XmlRootElement;
30 import javax.xml.bind.annotation.XmlSchemaType;
31 import javax.xml.bind.annotation.XmlSeeAlso;
32 import javax.xml.bind.annotation.XmlType;
33
34 import org.apache.log4j.Logger;
35 import org.hibernate.annotations.Cascade;
36 import org.hibernate.annotations.CascadeType;
37 import org.hibernate.envers.Audited;
38 import org.hibernate.search.annotations.Field;
39 import org.hibernate.search.annotations.Index;
40 import org.hibernate.search.annotations.Indexed;
41 import org.hibernate.search.annotations.IndexedEmbedded;
42
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.SynonymRelationshipType;
47 import eu.etaxonomy.cdm.model.taxon.TaxonRelationshipType;
48
49 import au.com.bytecode.opencsv.CSVWriter;
50
51 @XmlAccessorType(XmlAccessType.FIELD)
52 @XmlType(name = "RelationshipTermBase", propOrder = {
53 "symmetric",
54 "transitive",
55 "inverseRepresentations"
56 })
57 @XmlSeeAlso({
58 HybridRelationshipType.class,
59 NameRelationshipType.class,
60 SynonymRelationshipType.class,
61 TaxonRelationshipType.class
62 })
63 @Entity
64 @Indexed(index = "eu.etaxonomy.cdm.model.common.DefinedTermBase")
65 @Audited
66 public abstract class RelationshipTermBase<T extends RelationshipTermBase> extends OrderedTermBase<T> {
67 private static final long serialVersionUID = 5497187985269083971L;
68 @SuppressWarnings("unused")
69 private static final Logger logger = Logger.getLogger(RelationshipTermBase.class);
70
71 @XmlElement(name = "Symmetric")
72 @Field(index=Index.UN_TOKENIZED)
73 private boolean symmetric;
74
75 @XmlElement(name = "Transitive")
76 @Field(index=Index.UN_TOKENIZED)
77 private boolean transitive;
78
79 @XmlElementWrapper(name = "InverseRepresentations")
80 @XmlElement(name = "Representation")
81 @OneToMany(fetch = FetchType.LAZY)
82 @JoinTable(name="RelationshipTermBase_inverseRepresentation")
83 @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE})
84 @IndexedEmbedded(depth = 2)
85 private Set<Representation> inverseRepresentations = new HashSet<Representation>();
86
87 public RelationshipTermBase() {
88 }
89 public RelationshipTermBase(String term, String label, String labelAbbrev, boolean symmetric, boolean transitive) {
90 super(term, label, labelAbbrev);
91 setSymmetric(symmetric);
92 setTransitive(transitive);
93 }
94
95
96 public boolean isSymmetric() {
97 return symmetric;
98 }
99 public void setSymmetric(boolean symmetric) {
100 this.symmetric = symmetric;
101 }
102
103 public boolean isTransitive() {
104 return transitive;
105 }
106 public void setTransitive(boolean transitive) {
107 this.transitive = transitive;
108 }
109
110 public Set<Representation> getInverseRepresentations() {
111 return inverseRepresentations;
112 }
113
114 public void addInverseRepresentation(Representation inverseRepresentation) {
115 this.inverseRepresentations.add(inverseRepresentation);
116 }
117 public void removeInverseRepresentation(Representation inverseRepresentation) {
118 this.inverseRepresentations.remove(inverseRepresentation);
119 }
120 public void addRepresentation(Representation representation, Representation inverseRepresentation) {
121 this.addRepresentation(representation);
122 this.addInverseRepresentation(inverseRepresentation);
123 }
124
125 public Representation getInverseRepresentation(Language lang) {
126 Representation result = null;
127 if (this.isSymmetric()){
128 for (Representation repr : this.getRepresentations()){
129 if (repr.getLanguage() == lang){
130 result = repr;
131 }
132 }
133 }else{
134 for (Representation repr : this.getInverseRepresentations()){
135 if (repr.getLanguage() == lang){
136 result = repr;
137 }
138 }
139 }
140 return result;
141 }
142
143 /**
144 * Returns the InverseRepresentation in the preferred language. Preferred languages
145 * are specified by the parameter languages, which receives a list of
146 * Language instances in the order of preference. If no representation in
147 * any preferred languages is found the method falls back to return the
148 * Representation in Language.DEFAULT() and if necessary further falls back
149 * to return the first element found if any.
150 *
151 * TODO think about this fall-back strategy &
152 * see also {@link TextData#getPreferredLanguageString(List)}
153 * see also {@link TermBase#getPreferredRepresentation(List)}
154 *
155 * @param languages
156 * @return
157 */
158 public Representation getPreferredInverseRepresentation(List<Language> languages) {
159 Representation repr = null;
160 if(languages != null){
161 for(Language language : languages) {
162 repr = getInverseRepresentation(language);
163 if(repr != null){
164 return repr;
165 }
166 }
167 }
168 if(repr == null){
169 repr = getInverseRepresentation(Language.DEFAULT());
170 }
171 if(repr == null){
172 Iterator<Representation> it = getInverseRepresentations().iterator();
173 if(it.hasNext()){
174 repr = getInverseRepresentations().iterator().next();
175 }
176 }
177 return repr;
178 }
179
180 /*
181 * Inverse representation convenience methods similar to TermBase.xxx
182 * @see eu.etaxonomy.cdm.model.common.TermBase#getLabel()
183 */
184 @Transient
185 public String getInverseLabel() {
186 if(getInverseLabel(Language.DEFAULT())!=null){
187 return this.getInverseRepresentation(Language.DEFAULT()).getLabel();
188 }else{
189 for (Representation r : inverseRepresentations){
190 return r.getLabel();
191 }
192 }
193 return super.getUuid().toString();
194 }
195
196 public String getInverseLabel(Language lang) {
197 Representation r = this.getInverseRepresentation(lang);
198 if(r==null){
199 return null;
200 }else{
201 return r.getLabel();
202 }
203 }
204
205 @Transient
206 public String getInverseDescription() {
207 return this.getInverseRepresentation(Language.DEFAULT()).getDescription();
208 }
209
210 public String getInverseDescription(Language lang) {
211 return this.getInverseRepresentation(lang).getDescription();
212 }
213
214 @Override
215 public T readCsvLine(Class<T> termClass, List<String> csvLine, Map<UUID,DefinedTermBase> terms) {
216 T newInstance = super.readCsvLine(termClass, csvLine, terms);
217
218 String inverseText = csvLine.get(5).trim();
219 String inverseLabel = csvLine.get(4).trim();
220 String inverseLabelAbbrev = null;
221 newInstance.addInverseRepresentation(new Representation(inverseText, inverseLabel, inverseLabelAbbrev, Language.ENGLISH()) );
222 newInstance.setSymmetric(Boolean.parseBoolean(csvLine.get(6)));
223 newInstance.setTransitive(Boolean.parseBoolean(csvLine.get(7)));
224 return newInstance;
225 }
226
227 @Override
228 public void writeCsvLine(CSVWriter writer,T term) {
229 String [] line = new String[8];
230 line[0] = term.getUuid().toString();
231 line[1] = term.getUri();
232 line[2] = term.getLabel();
233 line[3] = term.getDescription();
234 line[4] = term.getInverseLabel();
235 line[5] = term.getInverseDescription();
236 line[6] = String.valueOf(term.isSymmetric());
237 line[7] = String.valueOf(term.isTransitive());
238 writer.writeNext(line);
239 }
240
241 }