Project

General

Profile

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

    
31
/**
32
 * This class represents a link to another CDM Base class from within a text.
33
 * If a text, e.g. a LanguageString links parts of its text to an other CDM Base
34
 * one may create a tag around the according text including id and uuid as attributes
35
 * and adding an IntextReference to the LanguageString. The IntextReference then points
36
 * to the according CdmBase.
37
 * This way we may keep referential integrity and we may also support correct
38
 * deduplication or deletion of the referenced objects.
39
 *
40
 * @see #4706
41
 *
42
 * @author a.mueller
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 CdmLinkBase {
62

    
63
    private static final long serialVersionUID = -7002541566256975424L;
64

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

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

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

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

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

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

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

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

    
115

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

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

    
130
	private int startPos;
131

    
132
	private int endPos;
133

    
134

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

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

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

    
156

    
157

    
158
// ***************** FACTORY METHOD ***********************************
159

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

    
166

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

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

    
188
//********************** CONSTRUCTOR ********************************************/
189

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

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

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

    
205

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

    
228
// ****************    GETTER / SETTER ******************************************/
229

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

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

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

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

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

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

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

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

    
357

    
358
}
(32-32/57)