Project

General

Profile

Download (10.9 KB) Statistics
| Branch: | Tag: | Revision:
1
/**
2
 *
3
 */
4
package eu.etaxonomy.cdm.model.common;
5

    
6
import javax.persistence.Entity;
7
import javax.persistence.FetchType;
8
import javax.persistence.ManyToOne;
9
import javax.xml.bind.annotation.XmlAccessType;
10
import javax.xml.bind.annotation.XmlAccessorType;
11
import javax.xml.bind.annotation.XmlElement;
12
import javax.xml.bind.annotation.XmlIDREF;
13
import javax.xml.bind.annotation.XmlSchemaType;
14
import javax.xml.bind.annotation.XmlType;
15

    
16
import org.apache.commons.lang.StringUtils;
17
import org.hibernate.annotations.Cascade;
18
import org.hibernate.annotations.CascadeType;
19
import org.hibernate.envers.Audited;
20

    
21
import eu.etaxonomy.cdm.model.agent.AgentBase;
22
import eu.etaxonomy.cdm.model.description.PolytomousKey;
23
import eu.etaxonomy.cdm.model.media.Media;
24
import eu.etaxonomy.cdm.model.name.TaxonName;
25
import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase;
26
import eu.etaxonomy.cdm.model.reference.Reference;
27
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
28

    
29
/**
30
 * This class represents a link to another CDM Base class from within a text.
31
 * If a text, e.g. a LanguageString links parts of its text to an other CDM Base
32
 * one may create a tag around the according text including id and uuid as attributes
33
 * and adding an IntextReference to the LanguageString. The IntextReference then points
34
 * to the according CdmBase.
35
 * This way we may keep referential integrity and we may also support correct
36
 * deduplication or deletion of the referenced objects.
37
 *
38
 * @see #4706
39
 *
40
 * @author a.mueller
41
 *
42
 */
43
@XmlAccessorType(XmlAccessType.FIELD)
44
@XmlType(name = "IntextReference", propOrder = {
45
    "taxonName",
46
    "taxon",
47
    "occurrence",
48
    "agent",
49
    "reference",
50
    "media",
51
    "key",
52
    "languageString",
53
    "annotation",
54
    "startPos",
55
    "endPos"
56
})
57
@Entity
58
@Audited
59
public class IntextReference extends VersionableEntity {
60
	private static final long serialVersionUID = -7002541566256975424L;
61

    
62
    @XmlElement(name = "TaxonName")
63
    @XmlIDREF
64
    @XmlSchemaType(name = "IDREF")
65
    @ManyToOne(fetch = FetchType.LAZY)
66
	private TaxonName taxonName;
67

    
68
    @XmlElement(name = "Taxon")
69
    @XmlIDREF
70
    @XmlSchemaType(name = "IDREF")
71
    @ManyToOne(fetch = FetchType.LAZY)
72
	private TaxonBase<?> taxon;
73

    
74
    @XmlElement(name = "Occurrence")
75
    @XmlIDREF
76
    @XmlSchemaType(name = "IDREF")
77
    @ManyToOne(fetch = FetchType.LAZY)
78
	private SpecimenOrObservationBase<?> occurrence;
79

    
80
    @XmlElement(name = "Agent")
81
    @XmlIDREF
82
    @XmlSchemaType(name = "IDREF")
83
    @ManyToOne(fetch = FetchType.LAZY)
84
	private AgentBase<?> agent;
85

    
86
    @XmlElement(name = "Reference")
87
    @XmlIDREF
88
    @XmlSchemaType(name = "IDREF")
89
    @ManyToOne(fetch = FetchType.LAZY)
90
    @Cascade({CascadeType.SAVE_UPDATE,CascadeType.MERGE})
91
    private Reference reference;
92

    
93
    @XmlElement(name = "Media")
94
    @XmlIDREF
95
    @XmlSchemaType(name = "IDREF")
96
    @ManyToOne(fetch = FetchType.LAZY)
97
	private Media media;
98

    
99
    @XmlElement(name = "SingleAccessKey")
100
    @XmlIDREF
101
    @XmlSchemaType(name = "IDREF")
102
    @ManyToOne(fetch = FetchType.LAZY)
103
    private PolytomousKey key;
104

    
105

    
106
    //TODO or do we want to link to LanguageString Base??
107
    @XmlElement(name = "LanguageString")
108
    @XmlIDREF
109
    @XmlSchemaType(name = "IDREF")
110
    @ManyToOne(fetch = FetchType.LAZY)
111
    private LanguageString languageString;
112

    
113
    //TODO or do we want to link to LanguageString Base??
114
    @XmlElement(name = "Annotation")
115
    @XmlIDREF
116
    @XmlSchemaType(name = "IDREF")
117
    @ManyToOne(fetch = FetchType.LAZY)
118
    private Annotation annotation;
119

    
120
	private int startPos;
121

    
122
	private int endPos;
123

    
124

    
125
    public enum CDM_INTEXT_CLASS{
126
        REFERENCE("reference"),
127
        TAXONNAME("name"),
128
        AGENT("agent"),
129
        MEDIA("media"),
130
        OCCURRENCE("occurrence"),
131
        TAXON("taxon"),
132
        KEY("key")
133
        ;
134
        String tag;
135

    
136
         private CDM_INTEXT_CLASS(String tag) {
137
            this.tag = tag;
138
        }
139

    
140
        public String tag(){
141
            return this.tag;
142
        }
143
    }
144

    
145

    
146

    
147
// ***************** FACTORY METHOD ***********************************
148

    
149
    public static IntextReference NewInstance(IIntextReferenceTarget target,
150
            IIntextReferencable referencedEntity, int start, int end){
151
        IntextReference result = new IntextReference(target, referencedEntity, start, end);
152
        return result;
153
    }
154

    
155

    
156
	public static LanguageString NewReferencedLanguageString(IIntextReferenceTarget target, String pre, String middle, String post, Language language){
157
        LanguageString result = LanguageString.NewInstance(null, language);
158
        IntextReference intextReference = IntextReference.NewInstance(target, result, 0, 0);
159
	    result.addIntextReference(intextReference);
160
	    result.setText(pre + intextReference.toInlineString(middle) + post);
161
        return result;
162
    }
163

    
164
    public static LanguageString NewReferencedLanguageString(IIntextReferenceTarget target, String text, int start, int end, Language language){
165
        if (start < 0 || end < 0 || start > end || end > text.length()){
166
            throw new IndexOutOfBoundsException("Start and end must be within bounds");
167
        }
168
        LanguageString result = LanguageString.NewInstance(text, language);
169
        IntextReference intextReference = IntextReference.NewInstance(target, result, start, end);
170
        result.addIntextReference(intextReference);
171
        String intext = text.substring(0, start) +
172
                intextReference.toInlineString(text.substring(start, end)) + text.substring(end);
173
        result.setText(intext);
174
        return result;
175
    }
176

    
177
//********************** CONSTRUCTOR ********************************************/
178

    
179
	/**
180
	 * @deprecated for internal use only
181
	 */
182
	@Deprecated //for hibernate use only
183
	private IntextReference(){}
184

    
185
	   private IntextReference(IIntextReferenceTarget target, IIntextReferencable referencedEntity, int start, int end) {
186
           super();
187
           setTarget(target);
188
           setReferencedEntity(referencedEntity);
189

    
190
           this.startPos = start;
191
           this.endPos = end;
192
   }
193

    
194

    
195
    public CDM_INTEXT_CLASS myClass(){
196
        if (agent != null){
197
            return CDM_INTEXT_CLASS.AGENT;
198
        }else if (media != null){
199
            return CDM_INTEXT_CLASS.MEDIA;
200
        }else if (taxonName != null){
201
            return CDM_INTEXT_CLASS.TAXONNAME;
202
        }else if (taxon != null){
203
            return CDM_INTEXT_CLASS.TAXON;
204
        }else if (reference != null){
205
            return CDM_INTEXT_CLASS.REFERENCE;
206
        }else if (occurrence != null){
207
            return CDM_INTEXT_CLASS.OCCURRENCE;
208
        }else if (key != null){
209
            return CDM_INTEXT_CLASS.KEY;
210
        }else{
211
            throw new IllegalStateException("Intext reference has no target object defined");
212
        }
213
    }
214

    
215
// ****************    GETTER / SETTER ******************************************/
216

    
217
   /**
218
    * Returns the target object. Throws an {@link IllegalStateException} if no target
219
    * is defined.
220
    *
221
    * @return
222
    */
223
   public IIntextReferenceTarget getTarget() {
224
       if (agent != null){
225
           return agent;
226
       }else if (media != null){
227
           return media;
228
       }else if (taxonName != null){
229
           return taxonName;
230
       }else if (taxon != null){
231
           return taxon;
232
       }else if (reference != null){
233
           return reference;
234
       }else if (occurrence != null){
235
           return occurrence;
236
       }else if (key != null){
237
           return key;
238
       }else{
239
           throw new IllegalStateException("Intext reference has no target object defined");
240
       }
241
   }
242

    
243
   /**
244
     * @param target
245
     */
246
    private void setTarget(IIntextReferenceTarget target) {
247
        target = CdmBase.deproxy(target);
248
        if (target instanceof TaxonName){
249
            this.taxonName = (TaxonName)target;
250
        }else if (target instanceof TaxonBase){
251
            this.taxon = (TaxonBase<?>)target;
252
        }else if (target instanceof SpecimenOrObservationBase){
253
            this.occurrence = (SpecimenOrObservationBase<?>)target;
254
        }else if (target instanceof AgentBase){
255
            this.agent = (AgentBase<?>)target;
256
        }else if (target instanceof Reference){
257
            this.reference = (Reference)target;
258
        }else if (target instanceof Media){
259
            this.media = (Media)target;
260
        }else if (target instanceof PolytomousKey){
261
            this.key = (PolytomousKey)target;
262
        }else{
263
            throw new IllegalArgumentException("Target entity not yet handled: " + target.getClass().getName());
264
        }
265
    }
266

    
267
   public IIntextReferencable getReferencedEntity() {
268
       if (languageString != null){
269
           return languageString;
270
       }else if (annotation != null){
271
           return annotation;
272
       }else{
273
           return null;
274
       }
275
   }
276

    
277
   /**
278
    * @param referencedEntity
279
    */
280
   public void setReferencedEntity(IIntextReferencable referencedEntity) {
281
       if (referencedEntity == null){
282
           this.annotation = null;
283
           this.languageString = null;
284
       }else if (this.getReferencedEntity() == referencedEntity){
285
           //do nothing
286
       }else{
287
           referencedEntity = CdmBase.deproxy(referencedEntity);
288
           if (referencedEntity instanceof LanguageString){
289
               this.languageString = (LanguageString)referencedEntity;
290
               this.annotation = null;
291
           }else if (referencedEntity instanceof Annotation){
292
               this.annotation = (Annotation)referencedEntity;
293
               this.languageString = null;
294
           }else{
295
               throw new IllegalArgumentException("Referenced entity type not yet supported: " + referencedEntity.getClass().getName());
296
           }
297
           if (!referencedEntity.getIntextReferences().contains(this)){
298
               referencedEntity.addIntextReference(this);
299
           }
300
       }
301
   }
302

    
303
	public int getStartPos() {
304
		return startPos;
305
	}
306
	public void setStartPos(int startPos) {
307
		this.startPos = startPos;
308
	}
309

    
310
	public int getEndPos() {
311
		return endPos;
312
	}
313
	public void setEndPos(int endPos) {
314
		this.endPos = endPos;
315
	}
316

    
317
	private static final String CDM_PREFIX = "cdm:";
318
	public String toInlineString(String innerText){
319
	    String tag = CDM_PREFIX + myClass().tag();
320
	    IIntextReferenceTarget entity = getTarget();
321
	    String attributes = " cdmId='" + entity.getUuid() + "' intextId='" + this.getUuid() + "'" + otherAttributes(entity);
322
	    String result;
323
	    if (StringUtils.isNotEmpty(innerText)){
324
	        result = "<" + tag + attributes + ">" + innerText + "</" + tag + ">";
325
	    }else{
326
            result = "<" + tag + attributes + "/>";
327
	    }
328
	    return result;
329
	}
330

    
331
    /**
332
     * Entity class dependent attributes
333
     * @param entity
334
     * @return
335
     */
336
    private String otherAttributes(IIntextReferenceTarget entity) {
337
        return "";
338
    }
339

    
340

    
341
}
(41-41/79)