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.lang3.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
    "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 CdmLinkBase {
61

    
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 = "Occurrence")
71
    @XmlIDREF
72
    @XmlSchemaType(name = "IDREF")
73
    @ManyToOne(fetch = FetchType.LAZY)
74
	private SpecimenOrObservationBase<?> occurrence;
75

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

    
82
    @XmlElement(name = "Reference")
83
    @XmlIDREF
84
    @XmlSchemaType(name = "IDREF")
85
    @ManyToOne(fetch = FetchType.LAZY)
86
    @Cascade({CascadeType.SAVE_UPDATE,CascadeType.MERGE})
87
    private Reference reference;
88

    
89
    @XmlElement(name = "Source")
90
    @XmlIDREF
91
    @XmlSchemaType(name = "IDREF")
92
    @ManyToOne(fetch = FetchType.LAZY)
93
    @Cascade({CascadeType.SAVE_UPDATE,CascadeType.MERGE})
94
    private OriginalSourceBase<?> source;
95

    
96
    @XmlElement(name = "Media")
97
    @XmlIDREF
98
    @XmlSchemaType(name = "IDREF")
99
    @ManyToOne(fetch = FetchType.LAZY)
100
	private Media media;
101

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

    
108

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

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

    
123
	private int startPos;
124

    
125
	private int endPos;
126

    
127

    
128
    public enum CDM_INTEXT_CLASS{
129
        REFERENCE("reference"),
130
        SOURCE("source"),
131
        TAXONNAME("name"),
132
        AGENT("agent"),
133
        MEDIA("media"),
134
        OCCURRENCE("occurrence"),
135
        TAXON("taxon"),
136
        KEY("key")
137
        ;
138
        String tag;
139

    
140
         private CDM_INTEXT_CLASS(String tag) {
141
            this.tag = tag;
142
        }
143

    
144
        public String tag(){
145
            return this.tag;
146
        }
147
    }
148

    
149

    
150

    
151
// ***************** FACTORY METHOD ***********************************
152

    
153
    public static IntextReference NewInstance(IIntextReferenceTarget target,
154
            IIntextReferencable referencedEntity, int start, int end){
155
        IntextReference result = new IntextReference(target, referencedEntity, start, end);
156
        return result;
157
    }
158

    
159

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

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

    
181
//********************** CONSTRUCTOR ********************************************/
182

    
183
	/**
184
	 * @deprecated for internal use only
185
	 */
186
	@Deprecated //for hibernate use only
187
	private IntextReference(){}
188

    
189
	   private IntextReference(IIntextReferenceTarget target, IIntextReferencable referencedEntity, int start, int end) {
190
           super();
191
           setTarget(target);
192
           setReferencedEntity(referencedEntity);
193

    
194
           this.startPos = start;
195
           this.endPos = end;
196
   }
197

    
198

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

    
221
// ****************    GETTER / SETTER ******************************************/
222

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

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

    
277
   public IIntextReferencable getReferencedEntity() {
278
       if (languageString != null){
279
           return languageString;
280
       }else if (annotation != null){
281
           return annotation;
282
       }else{
283
           return null;
284
       }
285
   }
286

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

    
313
	public int getStartPos() {
314
		return startPos;
315
	}
316
	public void setStartPos(int startPos) {
317
		this.startPos = startPos;
318
	}
319

    
320
	public int getEndPos() {
321
		return endPos;
322
	}
323
	public void setEndPos(int endPos) {
324
		this.endPos = endPos;
325
	}
326

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

    
341
    /**
342
     * Entity class dependent attributes
343
     * @param entity
344
     * @return
345
     */
346
    private String otherAttributes(IIntextReferenceTarget entity) {
347
        return "";
348
    }
349

    
350

    
351
}
(33-33/56)