Project

General

Profile

Download (11.5 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.OriginalSourceBase;
27
import eu.etaxonomy.cdm.model.reference.Reference;
28
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
29

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

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

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

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

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

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

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

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

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

    
114

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

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

    
129
	private int startPos;
130

    
131
	private int endPos;
132

    
133

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

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

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

    
155

    
156

    
157
// ***************** FACTORY METHOD ***********************************
158

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

    
165

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

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

    
187
//********************** CONSTRUCTOR ********************************************/
188

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

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

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

    
204

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

    
227
// ****************    GETTER / SETTER ******************************************/
228

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

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

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

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

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

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

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

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

    
356

    
357
}
(30-30/56)