Project

General

Profile

Download (11.4 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
    "source",
51
    "media",
52
    "key",
53
    "languageString",
54
    "annotation",
55
    "startPos",
56
    "endPos"
57
})
58
@Entity
59
@Audited
60
public class IntextReference extends VersionableEntity {
61
	private static final long serialVersionUID = -7002541566256975424L;
62

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

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

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

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

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

    
94
    @XmlElement(name = "Source")
95
    @XmlIDREF
96
    @XmlSchemaType(name = "IDREF")
97
    @ManyToOne(fetch = FetchType.LAZY)
98
    @Cascade({CascadeType.SAVE_UPDATE,CascadeType.MERGE})
99
    private OriginalSourceBase<?> source;
100

    
101
    @XmlElement(name = "Media")
102
    @XmlIDREF
103
    @XmlSchemaType(name = "IDREF")
104
    @ManyToOne(fetch = FetchType.LAZY)
105
	private Media media;
106

    
107
    @XmlElement(name = "SingleAccessKey")
108
    @XmlIDREF
109
    @XmlSchemaType(name = "IDREF")
110
    @ManyToOne(fetch = FetchType.LAZY)
111
    private PolytomousKey key;
112

    
113

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

    
121
    //TODO or do we want to link to LanguageString Base??
122
    @XmlElement(name = "Annotation")
123
    @XmlIDREF
124
    @XmlSchemaType(name = "IDREF")
125
    @ManyToOne(fetch = FetchType.LAZY)
126
    private Annotation annotation;
127

    
128
	private int startPos;
129

    
130
	private int endPos;
131

    
132

    
133
    public enum CDM_INTEXT_CLASS{
134
        REFERENCE("reference"),
135
        SOURCE("source"),
136
        TAXONNAME("name"),
137
        AGENT("agent"),
138
        MEDIA("media"),
139
        OCCURRENCE("occurrence"),
140
        TAXON("taxon"),
141
        KEY("key")
142
        ;
143
        String tag;
144

    
145
         private CDM_INTEXT_CLASS(String tag) {
146
            this.tag = tag;
147
        }
148

    
149
        public String tag(){
150
            return this.tag;
151
        }
152
    }
153

    
154

    
155

    
156
// ***************** FACTORY METHOD ***********************************
157

    
158
    public static IntextReference NewInstance(IIntextReferenceTarget target,
159
            IIntextReferencable referencedEntity, int start, int end){
160
        IntextReference result = new IntextReference(target, referencedEntity, start, end);
161
        return result;
162
    }
163

    
164

    
165
	public static LanguageString NewReferencedLanguageString(IIntextReferenceTarget target, String pre, String middle, String post, Language language){
166
        LanguageString result = LanguageString.NewInstance(null, language);
167
        IntextReference intextReference = IntextReference.NewInstance(target, result, 0, 0);
168
	    result.addIntextReference(intextReference);
169
	    result.setText(pre + intextReference.toInlineString(middle) + post);
170
        return result;
171
    }
172

    
173
    public static LanguageString NewReferencedLanguageString(IIntextReferenceTarget target, String text, int start, int end, Language language){
174
        if (start < 0 || end < 0 || start > end || end > text.length()){
175
            throw new IndexOutOfBoundsException("Start and end must be within bounds");
176
        }
177
        LanguageString result = LanguageString.NewInstance(text, language);
178
        IntextReference intextReference = IntextReference.NewInstance(target, result, start, end);
179
        result.addIntextReference(intextReference);
180
        String intext = text.substring(0, start) +
181
                intextReference.toInlineString(text.substring(start, end)) + text.substring(end);
182
        result.setText(intext);
183
        return result;
184
    }
185

    
186
//********************** CONSTRUCTOR ********************************************/
187

    
188
	/**
189
	 * @deprecated for internal use only
190
	 */
191
	@Deprecated //for hibernate use only
192
	private IntextReference(){}
193

    
194
	   private IntextReference(IIntextReferenceTarget target, IIntextReferencable referencedEntity, int start, int end) {
195
           super();
196
           setTarget(target);
197
           setReferencedEntity(referencedEntity);
198

    
199
           this.startPos = start;
200
           this.endPos = end;
201
   }
202

    
203

    
204
    public CDM_INTEXT_CLASS myClass(){
205
        if (agent != null){
206
            return CDM_INTEXT_CLASS.AGENT;
207
        }else if (media != null){
208
            return CDM_INTEXT_CLASS.MEDIA;
209
        }else if (taxonName != null){
210
            return CDM_INTEXT_CLASS.TAXONNAME;
211
        }else if (taxon != null){
212
            return CDM_INTEXT_CLASS.TAXON;
213
        }else if (reference != null){
214
            return CDM_INTEXT_CLASS.REFERENCE;
215
        }else if (source != null){
216
            return CDM_INTEXT_CLASS.SOURCE;
217
        }else if (occurrence != null){
218
            return CDM_INTEXT_CLASS.OCCURRENCE;
219
        }else if (key != null){
220
            return CDM_INTEXT_CLASS.KEY;
221
        }else{
222
            throw new IllegalStateException("Intext reference has no target object defined");
223
        }
224
    }
225

    
226
// ****************    GETTER / SETTER ******************************************/
227

    
228
   /**
229
    * Returns the target object. Throws an {@link IllegalStateException} if no target
230
    * is defined.
231
    *
232
    * @return
233
    */
234
   public IIntextReferenceTarget getTarget() {
235
       if (agent != null){
236
           return agent;
237
       }else if (media != null){
238
           return media;
239
       }else if (taxonName != null){
240
           return taxonName;
241
       }else if (taxon != null){
242
           return taxon;
243
       }else if (reference != null){
244
           return reference;
245
       }else if (source != null){
246
           return source;
247
       }else if (occurrence != null){
248
           return occurrence;
249
       }else if (key != null){
250
           return key;
251
       }else{
252
           throw new IllegalStateException("Intext reference has no target object defined");
253
       }
254
   }
255

    
256
   /**
257
     * @param target
258
     */
259
    private void setTarget(IIntextReferenceTarget target) {
260
        target = CdmBase.deproxy(target);
261
        if (target instanceof TaxonName){
262
            this.taxonName = (TaxonName)target;
263
        }else if (target instanceof TaxonBase){
264
            this.taxon = (TaxonBase<?>)target;
265
        }else if (target instanceof SpecimenOrObservationBase){
266
            this.occurrence = (SpecimenOrObservationBase<?>)target;
267
        }else if (target instanceof AgentBase){
268
            this.agent = (AgentBase<?>)target;
269
        }else if (target instanceof Reference){
270
            this.reference = (Reference)target;
271
        }else if (target instanceof OriginalSourceBase){
272
            this.source = (OriginalSourceBase<?>)target;
273
        }else if (target instanceof Media){
274
            this.media = (Media)target;
275
        }else if (target instanceof PolytomousKey){
276
            this.key = (PolytomousKey)target;
277
        }else{
278
            throw new IllegalArgumentException("Target entity not yet handled: " + target.getClass().getName());
279
        }
280
    }
281

    
282
   public IIntextReferencable getReferencedEntity() {
283
       if (languageString != null){
284
           return languageString;
285
       }else if (annotation != null){
286
           return annotation;
287
       }else{
288
           return null;
289
       }
290
   }
291

    
292
   /**
293
    * @param referencedEntity
294
    */
295
   public void setReferencedEntity(IIntextReferencable referencedEntity) {
296
       if (referencedEntity == null){
297
           this.annotation = null;
298
           this.languageString = null;
299
       }else if (this.getReferencedEntity() == referencedEntity){
300
           //do nothing
301
       }else{
302
           referencedEntity = CdmBase.deproxy(referencedEntity);
303
           if (referencedEntity instanceof LanguageString){
304
               this.languageString = (LanguageString)referencedEntity;
305
               this.annotation = null;
306
           }else if (referencedEntity instanceof Annotation){
307
               this.annotation = (Annotation)referencedEntity;
308
               this.languageString = null;
309
           }else{
310
               throw new IllegalArgumentException("Referenced entity type not yet supported: " + referencedEntity.getClass().getName());
311
           }
312
           if (!referencedEntity.getIntextReferences().contains(this)){
313
               referencedEntity.addIntextReference(this);
314
           }
315
       }
316
   }
317

    
318
	public int getStartPos() {
319
		return startPos;
320
	}
321
	public void setStartPos(int startPos) {
322
		this.startPos = startPos;
323
	}
324

    
325
	public int getEndPos() {
326
		return endPos;
327
	}
328
	public void setEndPos(int endPos) {
329
		this.endPos = endPos;
330
	}
331

    
332
	private static final String CDM_PREFIX = "cdm:";
333
	public String toInlineString(String innerText){
334
	    String tag = CDM_PREFIX + myClass().tag();
335
	    IIntextReferenceTarget entity = getTarget();
336
	    String attributes = " cdmId='" + entity.getUuid() + "' intextId='" + this.getUuid() + "'" + otherAttributes(entity);
337
	    String result;
338
	    if (StringUtils.isNotEmpty(innerText)){
339
	        result = "<" + tag + attributes + ">" + innerText + "</" + tag + ">";
340
	    }else{
341
            result = "<" + tag + attributes + "/>";
342
	    }
343
	    return result;
344
	}
345

    
346
    /**
347
     * Entity class dependent attributes
348
     * @param entity
349
     * @return
350
     */
351
    private String otherAttributes(IIntextReferenceTarget entity) {
352
        return "";
353
    }
354

    
355

    
356
}
(41-41/79)