Project

General

Profile

Statistics
| Branch: | Tag: | Revision:

cdmlib / cdmlib-model / src / main / java / eu / etaxonomy / cdm / model / reference / Reference.java @ bfa30d38

History | View | Annotate | Download (33.1 KB)

1
/**
2
* Copyright (C) 2007 EDIT
3
* European Distributed Institute of Taxonomy
4
* http://www.e-taxonomy.eu
5
*
6
* The contents of this file are subject to the Mozilla Public License Version 1.1
7
* See LICENSE.TXT at the top of this package for the full license terms.
8
*/
9

    
10
package eu.etaxonomy.cdm.model.reference;
11

    
12
import java.beans.PropertyChangeEvent;
13
import java.beans.PropertyChangeListener;
14
import java.net.URI;
15
import java.util.List;
16

    
17
import javax.persistence.Basic;
18
import javax.persistence.Column;
19
import javax.persistence.Embedded;
20
import javax.persistence.Entity;
21
import javax.persistence.FetchType;
22
import javax.persistence.Inheritance;
23
import javax.persistence.InheritanceType;
24
import javax.persistence.Lob;
25
import javax.persistence.ManyToOne;
26
import javax.persistence.Table;
27
import javax.persistence.Transient;
28
import javax.validation.constraints.NotNull;
29
import javax.validation.constraints.Pattern;
30
import javax.xml.bind.annotation.XmlAccessType;
31
import javax.xml.bind.annotation.XmlAccessorType;
32
import javax.xml.bind.annotation.XmlAttribute;
33
import javax.xml.bind.annotation.XmlElement;
34
import javax.xml.bind.annotation.XmlIDREF;
35
import javax.xml.bind.annotation.XmlRootElement;
36
import javax.xml.bind.annotation.XmlSchemaType;
37
import javax.xml.bind.annotation.XmlTransient;
38
import javax.xml.bind.annotation.XmlType;
39
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
40

    
41
import org.apache.commons.lang.StringUtils;
42
import org.apache.log4j.Logger;
43
import org.hibernate.annotations.Cascade;
44
import org.hibernate.annotations.CascadeType;
45
import org.hibernate.annotations.Type;
46
import org.hibernate.envers.Audited;
47
import org.hibernate.search.annotations.Analyze;
48
import org.hibernate.search.annotations.Field;
49
import org.hibernate.search.annotations.FieldBridge;
50
import org.hibernate.search.annotations.IndexedEmbedded;
51
import org.joda.time.DateTime;
52

    
53
import eu.etaxonomy.cdm.common.DOI;
54
import eu.etaxonomy.cdm.hibernate.search.DateTimeBridge;
55
import eu.etaxonomy.cdm.hibernate.search.DoiBridge;
56
import eu.etaxonomy.cdm.jaxb.DateTimeAdapter;
57
import eu.etaxonomy.cdm.model.agent.Institution;
58
import eu.etaxonomy.cdm.model.agent.TeamOrPersonBase;
59
import eu.etaxonomy.cdm.model.common.IIntextReferenceTarget;
60
import eu.etaxonomy.cdm.model.common.TimePeriod;
61
import eu.etaxonomy.cdm.model.common.VerbatimTimePeriod;
62
import eu.etaxonomy.cdm.model.media.IdentifiableMediaEntity;
63
import eu.etaxonomy.cdm.model.name.TaxonName;
64
import eu.etaxonomy.cdm.strategy.cache.reference.DefaultReferenceCacheStrategy;
65
import eu.etaxonomy.cdm.strategy.cache.reference.INomenclaturalReferenceCacheStrategy;
66
import eu.etaxonomy.cdm.strategy.match.Match;
67
import eu.etaxonomy.cdm.strategy.match.MatchMode;
68
import eu.etaxonomy.cdm.strategy.merge.Merge;
69
import eu.etaxonomy.cdm.strategy.merge.MergeMode;
70
import eu.etaxonomy.cdm.strategy.parser.ParserProblem;
71
import eu.etaxonomy.cdm.validation.Level2;
72
import eu.etaxonomy.cdm.validation.Level3;
73
import eu.etaxonomy.cdm.validation.annotation.InReference;
74
import eu.etaxonomy.cdm.validation.annotation.NoRecursiveInReference;
75
import eu.etaxonomy.cdm.validation.annotation.NullOrNotEmpty;
76
import eu.etaxonomy.cdm.validation.annotation.ReferenceCheck;
77

    
78
/**
79
 * The class for references (information sources). Originally
80
 * an abstract class with many subclasses. Now it is only
81
 * one class implementing many interfaces for safe use of different
82
 * types of references. E.g. if you want to edit a journal
83
 * you create a journal with {@link ReferenceFactory#newJournal()}
84
 * which returns an IJournal. Though this instance is an ordinary instance
85
 * of {@link Reference} by using IJournal you may not use attributes
86
 * not allowed for journals.<p>
87
 * References can be created via {@link ReferenceFactory} methods.
88
 * <P>
89
 * This class corresponds to: <ul>
90
 * <li> PublicationCitation according to the TDWG ontology
91
 * <li> Publication according to the TCS
92
 * <li> Reference according to the ABCD schema
93
 * </ul>
94
 *
95
 * @author m.doering
96
 * @since 08-Nov-2007 13:06:47
97
 */
98
@XmlAccessorType(XmlAccessType.FIELD)
99
@XmlType(name = "Reference", propOrder = {
100
        "type",
101
        "uri",
102
    "abbrevTitleCache",
103
    "protectedAbbrevTitleCache",
104
        "nomenclaturallyRelevant",
105
    "authorship",
106
    "referenceAbstract",
107
    "title",
108
    "abbrevTitle",
109
    "editor",
110
        "volume",
111
        "pages",
112
        "edition",
113
    "isbn",
114
    "issn",
115
    "doi",
116
    "seriesPart",
117
    "datePublished",
118
    "publisher",
119
    "placePublished",
120
    "institution",
121
    "school",
122
    "organization",
123
    "inReference",
124
    "accessed",
125
    "lastRetrieved",
126
    "externalId",
127
    "externalLink",
128
    "authorityType"
129
})
130
@XmlRootElement(name = "Reference")
131
@Entity
132
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
133
@Audited
134
@Table(name="Reference", indexes = { @javax.persistence.Index(name = "ReferenceTitleCacheIndex", columnList = "titleCache") })
135
//@InReference(groups=Level3.class)
136
@ReferenceCheck(groups=Level2.class)
137
@InReference(groups=Level3.class)
138
@NoRecursiveInReference(groups=Level3.class)  //may become Level1 in future  #
139
public class Reference
140
        extends IdentifiableMediaEntity<INomenclaturalReferenceCacheStrategy>
141
        implements IArticle, IBook, IPatent, IDatabase, IJournal, IBookSection,ICdDvd,
142
                   IGeneric,IInProceedings, IProceedings, IPrintSeries, IReport,
143
                   IThesis,IWebPage, IPersonalCommunication,
144
                   INomenclaturalReference, IReference, IIntextReferenceTarget,
145
                   Cloneable {
146

    
147
    private static final long serialVersionUID = -2034764545042691295L;
148
        private static final Logger logger = Logger.getLogger(Reference.class);
149

    
150
        @XmlAttribute(name ="type")
151
        @Column(name="refType")
152
        @NotNull
153
    @Type(type = "eu.etaxonomy.cdm.hibernate.EnumUserType",
154
            parameters = {@org.hibernate.annotations.Parameter(name  = "enumClass", value = "eu.etaxonomy.cdm.model.reference.ReferenceType")}
155
    )
156
        @Audited
157
        protected ReferenceType type;
158

    
159
        //Title of the reference
160
        @XmlElement(name ="Title" )
161
        @Column(length=4096, name="title")
162
        @Lob
163
        @Field
164
        @Match(MatchMode.EQUAL_REQUIRED) //TODO correct? was EQUAL_REQUIRED before, but with abbrevTitle this is not realistic anymore
165
    //TODO Val #3379
166
//        @NullOrNotEmpty
167
        private String title;
168

    
169
        //Title of the reference
170
        @XmlElement(name ="AbbrevTitle" )
171
        @Field
172
        @Match(MatchMode.EQUAL)  //TODO check if this is correct
173
        @NullOrNotEmpty
174
        @Column(length=255)
175
        private String abbrevTitle;
176

    
177
        //Title of the reference
178
        @XmlElement(name ="AbbrevTitleCache" )
179
        @Field
180
        @Match(MatchMode.CACHE)
181
    //TODO Val #3379
182
//        @NotNull
183
        @Column(length=1024)
184
        private String abbrevTitleCache;
185

    
186
        @XmlElement(name = "protectedAbbrevTitleCache")
187
        @Merge(MergeMode.OR)
188
        private boolean protectedAbbrevTitleCache;
189

    
190
//********************************************************/
191

    
192

    
193
    @XmlElement(name = "Editor")
194
    @Field
195
    //TODO Val #3379
196
//    @NullOrNotEmpty
197
    @Column(length=255)
198
        protected String editor;
199

    
200
    @XmlElement(name = "Volume")
201
    @Field
202
    //TODO Val #3379
203
//    @NullOrNotEmpty
204
    @Column(length=255)
205
        protected String volume;
206

    
207
    @XmlElement(name = "Pages")
208
    @Field
209
    //TODO Val #3379
210
//    @NullOrNotEmpty
211
    @Column(length=255)
212
        protected String pages;
213

    
214
    @XmlElement(name = "Edition")
215
    @Field
216
    //TODO Val #3379
217
//    @NullOrNotEmpty
218
    @Column(length=255)
219
        protected String edition;
220

    
221
    @XmlElement(name = "ISBN")
222
    @Field
223
    //TODO Val #3379
224
//    @NullOrNotEmpty
225
    @Column(length=255)
226
        @Pattern(regexp = "(?=.{13}$)\\d{1,5}([- ])\\d{1,7}\\1\\d{1,6}\\1(\\d|X)$", groups = Level2.class, message = "{eu.etaxonomy.cdm.model.reference.Reference.isbn.message}")
227
        protected String isbn;
228

    
229
    @XmlElement(name = "Doi")
230
    @Field
231
    @FieldBridge(impl = DoiBridge.class)
232
    @Type(type="doiUserType")
233
    @Column(length=DOI.MAX_LENGTH)
234
    protected DOI doi;
235

    
236

    
237
        @XmlElement(name = "ISSN")
238
    @Field
239
    //TODO Val #3379
240
//        @NullOrNotEmpty
241
    @Column(length=255)
242
        @Pattern(regexp = "(?=.{9}$)\\d{4}([- ])\\d{4} (\\d|X)$", groups = Level2.class, message = "{eu.etaxonomy.cdm.model.reference.Reference.issn.message}")
243
        protected String issn;
244

    
245
    @XmlElement(name = "SeriesPart")
246
    @Field
247
    //TODO Val #3379
248
//    @NullOrNotEmpty
249
    @Column(length=255)
250
        protected String seriesPart;
251

    
252
        @XmlElement(name = "Organization")
253
    @Field
254
    //TODO Val #3379
255
//        @NullOrNotEmpty
256
    @Column(length=255)
257
        protected String organization;
258

    
259
        @XmlElement(name = "Publisher")
260
    @Field
261
    //TODO Val #3379
262
//        @NullOrNotEmpty
263
    @Column(length=255)
264
        protected String publisher;
265

    
266

    
267
        @XmlElement(name = "PlacePublished")
268
    @Field
269
    //TODO Val #3379
270
//        @NullOrNotEmpty
271
    @Column(length=255)
272
        protected String placePublished;
273

    
274
        @XmlElement(name = "Institution")
275
        @XmlIDREF
276
        @XmlSchemaType(name = "IDREF")
277
        @ManyToOne(fetch = FetchType.LAZY)
278
        @IndexedEmbedded
279
        @Cascade({CascadeType.SAVE_UPDATE,CascadeType.MERGE})
280
        protected Institution institution;
281

    
282
        @XmlElement(name = "School")
283
    @XmlIDREF
284
    @XmlSchemaType(name = "IDREF")
285
        @ManyToOne(fetch = FetchType.LAZY)
286
        @IndexedEmbedded
287
        @Cascade({CascadeType.SAVE_UPDATE,CascadeType.MERGE})
288
        protected Institution school;
289

    
290
    @XmlElement(name = "InReference")
291
    @XmlIDREF
292
    @XmlSchemaType(name = "IDREF")
293
    @ManyToOne(fetch = FetchType.LAZY)
294
    @Cascade({CascadeType.SAVE_UPDATE,CascadeType.MERGE})
295
//  @InReference(groups=Level2.class)
296
           protected Reference inReference;
297

    
298
//********************************************************/
299

    
300
        //The date range assigned to the reference. ISO Date range like. Flexible, year can be left out, etc
301
        @XmlElement(name ="DatePublished" )
302
        @Embedded
303
        @IndexedEmbedded
304
        private VerbatimTimePeriod datePublished = VerbatimTimePeriod.NewVerbatimInstance();
305

    
306
    //#5258
307
    @XmlElement(name = "Accessed", type= String.class)
308
    @XmlJavaTypeAdapter(DateTimeAdapter.class)
309
    @Type(type="dateTimeUserType")
310
    @Basic(fetch = FetchType.LAZY)
311
    @Match(MatchMode.EQUAL)
312
    @FieldBridge(impl = DateTimeBridge.class)
313
    private DateTime accessed;
314

    
315
    @XmlElement(name ="Abstract" )
316
        @Column(length=65536, name="referenceAbstract")
317
        @Lob
318
    @Field
319
    //TODO Val #3379
320
//        @NullOrNotEmpty
321
        private String referenceAbstract;  //abstract is a reserved term in Java
322

    
323

    
324
        //URIs like DOIs, LSIDs or Handles for this reference
325
        @XmlElement(name = "URI")
326
        @Field(analyze = Analyze.NO)
327
        @Type(type="uriUserType")
328
        private URI uri;
329

    
330
        //flag to subselect only references that could be useful for nomenclatural citations.
331
        //If a reference is used as a
332
        //nomenclatural reference in a name this flag should be automatically set
333
        @XmlElement(name = "IsNomenclaturallyRelevant")
334
        @Merge(MergeMode.OR)
335
        @Match(MatchMode.IGNORE)
336
        private boolean nomenclaturallyRelevant;
337

    
338
        @XmlElement(name = "Authorship")
339
        @XmlIDREF
340
        @XmlSchemaType(name = "IDREF")
341
        @ManyToOne(fetch = FetchType.LAZY)
342
        @IndexedEmbedded
343
        @Cascade({CascadeType.SAVE_UPDATE,CascadeType.MERGE})
344
        private TeamOrPersonBase<?> authorship;
345

    
346
        @XmlAttribute
347
    @Match(MatchMode.IGNORE)
348
        private int parsingProblem = 0;
349

    
350
        @XmlAttribute
351
    @Match(MatchMode.IGNORE)
352
    private int problemStarts = -1;
353

    
354
    @XmlAttribute
355
    @Match(MatchMode.IGNORE)
356
    private int problemEnds = -1;
357

    
358
    @Transient
359
    @XmlAttribute
360
    @Match(MatchMode.IGNORE)
361
        private boolean cacheStrategyRectified = false;
362

    
363
    //attributes for externally managed
364

    
365
//    @XmlElement (name = "LastRetrieved", type= String.class)
366
    @XmlJavaTypeAdapter(DateTimeAdapter.class)
367
    @Type(type="dateTimeUserType")
368
    //TODO needed??
369
    @Basic(fetch = FetchType.LAZY)
370
    private DateTime lastRetrieved;
371

    
372
    @XmlElement(name ="ExternalId" )
373
//    @Field
374
//    @Match(MatchMode.EQUAL)  //TODO check if this is correct
375
    @NullOrNotEmpty
376
    @Column(length=255)
377
    private String externalId;
378

    
379
    //Actionable link on e.g. on a webservice
380
    @XmlElement(name = "ExternalLink")
381
    @Field(analyze = Analyze.NO)
382
    @Type(type="uriUserType")
383
    private URI externalLink;
384

    
385
    @XmlAttribute(name ="authority")
386
    @Column(name="authorityType", length=10)
387
    @Type(type = "eu.etaxonomy.cdm.hibernate.EnumUserType",
388
        parameters = {@org.hibernate.annotations.Parameter(name  = "enumClass", value = "eu.etaxonomy.cdm.model.reference.AuthorityType")}
389
    )
390
//    @NotNull
391
    private AuthorityType authorityType;
392

    
393
// *********************** CONSTRUCTOR ************************/
394

    
395
    protected Reference(){
396
                this(ReferenceType.Generic);  //just in case someone uses constructor
397
        }
398

    
399
        protected Reference(ReferenceType type) {
400
                super();
401
            if (type == null){
402
                        this.type = ReferenceType.Generic;
403
                } else{
404
                        this.type = type;
405
                }
406
                this.setCacheStrategy(DefaultReferenceCacheStrategy.NewInstance());
407
        }
408

    
409
// *********************** LISTENER ************************/
410

    
411

    
412
        @Override
413
    public void initListener(){
414
        PropertyChangeListener listener = new PropertyChangeListener() {
415
            @Override
416
            public void propertyChange(PropertyChangeEvent ev) {
417
                    if (!ev.getPropertyName().equals("titleCache") && !ev.getPropertyName().equals("abbrevTitleCache") && !ev.getPropertyName().equals("cacheStrategy")){
418
                            if (! isProtectedTitleCache()){
419
                                    titleCache = null;
420
                            }
421
                            if (! isProtectedAbbrevTitleCache()){
422
                                    abbrevTitleCache = null;
423
                            }
424
                    }
425
            }
426
        };
427
        addPropertyChangeListener(listener);
428
    }
429

    
430

    
431
//*************************** GETTER / SETTER ******************************************/
432

    
433

    
434

    
435
    // @Transient  - must not be transient, since this property needs to to be included in all serializations produced by the remote layer
436
    @Override
437
    public String getTitleCache(){
438
        String result = super.getTitleCache();
439
        if (isBlank(result)){
440
            this.titleCache = this.getAbbrevTitleCache(true);
441
        }
442
        return titleCache;
443
    }
444

    
445
        @Override
446
        public String getAbbrevTitleCache() {
447
                return getAbbrevTitleCache(false);
448
        }
449

    
450
        /**
451
         * Implements {@link #getAbbrevTitleCache()} but allows to
452
         * avoid never ending recursions if both caches are empty
453
         * avoidRecursion should only be <code>true</code> if called
454
         * by {@link #getTitleCache()}
455
         * @param avoidRecursion
456
         * @return
457
         */
458
        private String getAbbrevTitleCache(boolean avoidRecursion) {
459
        if (protectedAbbrevTitleCache){
460
            return this.abbrevTitleCache;
461
        }
462
        // is reference dirty, i.e. equal NULL?
463
        if (abbrevTitleCache == null){
464
            this.abbrevTitleCache = generateAbbrevTitle();
465
            this.abbrevTitleCache = getTruncatedCache(this.abbrevTitleCache) ;
466
        }
467
        if (isBlank(abbrevTitleCache) && !avoidRecursion){
468
            this.abbrevTitleCache = this.getTitleCache();
469
        }
470
        return abbrevTitleCache;
471
    }
472

    
473

    
474
    @Override
475
        @Deprecated
476
        public void setAbbrevTitleCache(String abbrevTitleCache) {
477
                this.abbrevTitleCache = abbrevTitleCache;
478
        }
479

    
480
        @Override
481
        public void setAbbrevTitleCache(String abbrevTitleCache, boolean isProtected) {
482
                this.protectedAbbrevTitleCache = isProtected;
483
                setAbbrevTitleCache(abbrevTitleCache);
484
        }
485

    
486
        @Override
487
        public boolean isProtectedAbbrevTitleCache() {
488
                return protectedAbbrevTitleCache;
489
        }
490

    
491
        @Override
492
        public void setProtectedAbbrevTitleCache(boolean protectedAbbrevTitleCache) {
493
                this.protectedAbbrevTitleCache = protectedAbbrevTitleCache;
494
        }
495

    
496
        @Override
497
        public String getAbbrevTitle() {
498
                return abbrevTitle;
499
        }
500

    
501
        @Override
502
        public void setAbbrevTitle(String abbrevTitle) {
503
                this.abbrevTitle = StringUtils.isBlank(abbrevTitle) ? null : abbrevTitle;
504
        }
505

    
506

    
507
        @Override
508
    public String getEditor() {
509
                return editor;
510
        }
511

    
512

    
513
        @Override
514
    public void setEditor(String editor) {
515
                this.editor = StringUtils.isBlank(editor)? null : editor;
516
        }
517

    
518
        @Override
519
    public String getVolume() {
520
                return volume;
521
        }
522

    
523
        @Override
524
    public void setVolume(String volume) {
525
                this.volume = StringUtils.isBlank(volume)? null : volume;
526
        }
527

    
528
        @Override
529
    public String getPages() {
530
                return pages;
531
        }
532

    
533
        @Override
534
    public void setPages(String pages) {
535
                this.pages = StringUtils.isBlank(pages)? null : pages;
536
        }
537

    
538
        @Override
539
    public String getEdition() {
540
                return edition;
541
        }
542

    
543
        @Override
544
    public void setEdition(String edition) {
545
                this.edition = StringUtils.isBlank(edition)? null : edition;
546
        }
547

    
548
        @Override
549
    public String getIsbn() {
550
                return isbn;
551
        }
552

    
553
        @Override
554
    public void setIsbn(String isbn) {
555
                this.isbn = StringUtils.isBlank(isbn)? null : isbn;
556
        }
557

    
558
        @Override
559
    public String getIssn() {
560
                return issn;
561
        }
562

    
563
        @Override
564
    public void setIssn(String issn) {
565
                this.issn = StringUtils.isBlank(issn)? null : issn;
566
        }
567

    
568
    @Override
569
        public DOI getDoi() {
570
                return doi;
571
        }
572
    @Override
573
        public void setDoi(DOI doi) {
574
                this.doi = doi;
575
        }
576
    /**
577
     * Convenience method to retrieve doi as string
578
     */
579
    @Transient @XmlTransient @java.beans.Transient
580
    public String getDoiString() {
581
        return doi == null? null : doi.toString();
582
    }
583

    
584
        @Override
585
    public String getSeriesPart() {
586
                return seriesPart;
587
        }
588
        @Override
589
    public void setSeriesPart(String seriesPart) {
590
                this.seriesPart = StringUtils.isBlank(seriesPart)? null : seriesPart;
591
        }
592

    
593
        @Override
594
    public String getOrganization() {
595
                return organization;
596
        }
597

    
598
        @Override
599
    public void setOrganization(String organization) {
600
                this.organization = StringUtils.isBlank(organization)? null : organization;
601
        }
602

    
603
        @Override
604
    public String getPublisher() {
605
                return publisher;
606
        }
607

    
608
        @Override
609
    public void setPublisher(String publisher) {
610
                this.publisher = StringUtils.isBlank(publisher)? null : publisher;
611
        }
612

    
613
        @Override
614
    public void setPublisher(String publisher, String placePublished){
615
                this.publisher = publisher;
616
                this.placePublished = placePublished;
617
        }
618

    
619
        @Override
620
    public String getPlacePublished() {
621
                return placePublished;
622
        }
623

    
624
        @Override
625
    public void setPlacePublished(String placePublished) {
626
                this.placePublished = StringUtils.isBlank(placePublished)? null: placePublished;
627
        }
628

    
629
        @Override
630
    public Institution getInstitution() {
631
                return institution;
632
        }
633

    
634
        @Override
635
    public void setInstitution(Institution institution) {
636
                this.institution = institution;
637
        }
638

    
639
        @Override
640
    public Institution getSchool() {
641
                return school;
642
        }
643

    
644
        @Override
645
    public void setSchool(Institution school) {
646
                this.school = school;
647
        }
648

    
649
        @Override
650
    public Reference getInReference() {
651
                return inReference;
652
        }
653

    
654
        @Override
655
    public void setInReference(Reference inReference) {
656
                this.inReference = inReference;
657
        }
658

    
659
        @Override
660
    public void setType(ReferenceType type) {
661
                if (type == null){
662
                        this.type = ReferenceType.Generic;
663
                } else{
664
                        this.type = type;
665
                }
666
        }
667
        @Override
668
    public ReferenceType getType() {
669
                return type;
670
        }
671

    
672
        /**
673
         * Whether this reference is of the given type
674
         *
675
         * @param type
676
         * @return
677
         */
678
        @Override
679
    public boolean isOfType(ReferenceType type){
680
                return type == getType();
681
        }
682

    
683
        /**
684
         * Returns a string representing the title of <i>this</i> reference. If a
685
         * reference has different titles (for instance abbreviated and not
686
         * abbreviated) then for each title a new instance must be created.
687
         *
688
         * @return  the title string of <i>this</i> reference
689
         * @see         #getCitation()
690
         */
691
        @Override
692
    public String getTitle(){
693
                return this.title;
694
        }
695
        /**
696
         * @see         #getTitle()
697
         */
698
        @Override
699
    public void setTitle(String title){
700
                this.title = StringUtils.isBlank(title)? null : title;
701
        }
702

    
703
        /**
704
         * Returns the date (mostly only the year) of publication / creation of
705
         * <i>this</i> reference.
706
         */
707
        @Override
708
    public VerbatimTimePeriod getDatePublished(){
709
                return this.datePublished;
710
        }
711
        /**
712
         * @see         #getDatePublished()
713
         */
714
        @Override
715
    public void setDatePublished(VerbatimTimePeriod datePublished){
716
                this.datePublished = datePublished;
717
        }
718
    @Override
719
    @Transient
720
    @Deprecated
721
    public VerbatimTimePeriod setDatePublished(TimePeriod datePublished){
722
        VerbatimTimePeriod newTimePeriod = VerbatimTimePeriod.toVerbatim(datePublished);
723
        setDatePublished(newTimePeriod);
724
        return newTimePeriod;
725
    }
726

    
727
        public boolean hasDatePublished(){
728
                boolean result =  ! ( (this.datePublished == null) || StringUtils.isBlank(datePublished.toString()));
729
                return result;
730
        }
731

    
732

    
733
        @Override
734
    public DateTime getAccessed() {
735
        return accessed;
736
    }
737

    
738
        @Override
739
    public void setAccessed(DateTime accessed) {
740
        this.accessed = accessed;
741
    }
742

    
743
        /**
744
         * Returns the {@link eu.etaxonomy.cdm.model.agent.TeamOrPersonBase author (team)} who created the
745
         * content of <i>this</i> reference.
746
         *
747
         * @return  the author (team) of <i>this</i> reference
748
         * @see         eu.etaxonomy.cdm.model.agent.TeamOrPersonBase
749
         */
750
        @Override
751
    public TeamOrPersonBase getAuthorship(){
752
                return this.authorship;
753
        }
754

    
755
        /**
756
         * @see #getAuthorship()
757
         */
758
        @Override
759
    public void setAuthorship(TeamOrPersonBase authorship){
760
                this.authorship = authorship;
761
        }
762

    
763
        /**
764
         * Returns the Uniform Resource Identifier (URI) corresponding to <i>this</i>
765
         * reference. An URI is a string of characters used to identify a resource
766
         * on the Internet.
767
         *
768
         * @return  the URI of <i>this</i> reference
769
         */
770
        @Override
771
    public URI getUri(){
772
                return this.uri;
773
        }
774
        /**
775
         * @see #getUri()
776
         */
777
        @Override
778
    public void setUri(URI uri){
779
                this.uri = uri;
780
        }
781

    
782
        /**
783
         * @return the referenceAbstract
784
         */
785
        @Override
786
    public String getReferenceAbstract() {
787
                return referenceAbstract;
788
        }
789

    
790
        /**
791
         * @param referenceAbstract the referenceAbstract to set
792
         */
793
        @Override
794
    public void setReferenceAbstract(String referenceAbstract) {
795
                this.referenceAbstract = StringUtils.isBlank(referenceAbstract)? null : referenceAbstract;
796
        }
797

    
798

    
799
        /**
800
         * Returns "true" if the isNomenclaturallyRelevant flag is set. This
801
         * indicates that a {@link TaxonName taxon name} has been originally
802
         * published in <i>this</i> reference following the rules of a
803
         * {@link eu.etaxonomy.cdm.model.name.NomenclaturalCode nomenclature code} and is therefore used for
804
         * nomenclatural citations. This flag will be set as soon as <i>this</i>
805
         * reference is used as a nomenclatural reference for any taxon name.<BR>
806
         * FIXME what happens if the only taxon name referencing this reference is not
807
         * any longer using this reference as a nomenclatural reference. How does the
808
         * reference get informed about the fact that it is not nomenclaturally relevant
809
         * anymore?
810
         */
811
        public boolean isNomenclaturallyRelevant(){
812
                return this.nomenclaturallyRelevant;
813
        }
814

    
815
        /**
816
         * @see #isNomenclaturallyRelevant()
817
         */
818
        public void setNomenclaturallyRelevant(boolean nomenclaturallyRelevant){
819
                this.nomenclaturallyRelevant = nomenclaturallyRelevant;
820
        }
821

    
822

    
823
//****************************************************  /
824

    
825
        @Transient
826
        @Override
827
        public void setTitleCaches(String cache){
828
            this.setAbbrevTitleCache(cache, true);
829
            this.setTitleCache(cache, true);
830
        }
831

    
832

    
833
        /**
834
         * Returns a formatted string containing the entire reference citation,
835
         * including authors, corresponding to <i>this</i> reference.
836
         *
837
         * @see  #generateTitle()
838
         */
839
        // TODO implement
840
        @Transient
841
        public String getCitation(){
842
                if (getCacheStrategy() == null){
843
                        logger.warn("No CacheStrategy defined for "+ this.getClass() + ": " + this.getUuid());
844
                        return null;
845
                }else{
846
                        return getCacheStrategy().getTitleCache(this);
847
                }
848
        }
849

    
850

    
851
        @Override
852
    public String generateTitle() {
853
                return super.generateTitle();
854
        }
855

    
856
    public String generateAbbrevTitle() {
857
                return getCacheStrategy().getFullAbbrevTitleString(this);
858
        }
859

    
860
        /**
861
         * Returns a string representation for the year of publication / creation
862
         * of <i>this</i> reference. If the {@link #getDatePublished() datePublished}
863
         * of this reference contains more date information then (starting) year
864
         * only the year is returned.
865
         * than  attribute.
866
         */
867
        @Override
868
    @Transient
869
        public String getYear(){
870
                VerbatimTimePeriod datePublished = this.getDatePublished();
871
                if (datePublished != null ){
872
                        String result = getDatePublished().getYear();
873
                        return result;
874
                }else{
875
                        return null;
876
                }
877
        }
878

    
879
        /**
880
         * Convenience method that returns a string representation for the publication date / creation
881
         * of <i>this</i> reference. The string is obtained by
882
         * {@link #getDatePublished()#toString() the string representation
883
         * of the date published}.
884
         */
885
        @Transient
886
        public String getDatePublishedString(){
887
                VerbatimTimePeriod datePublished = this.getDatePublished();
888
                if (datePublished != null ){
889
                        return getDatePublished().toString();
890
                }else{
891
                        return null;
892
                }
893
        }
894

    
895
        /**
896
     * Convenience method that returns a string representation for the publication date / creation
897
     * of <i>this</i> reference. The string is obtained by
898
     * {@link #getDatePublished()#toString() the string representation
899
     * of the date published}.
900
     */
901
    @Transient
902
    public String getTimePeriodPublishedString(){
903
        VerbatimTimePeriod datePublished = this.getDatePublished();
904
        if (datePublished != null ){
905
            return getDatePublished().getTimePeriod();
906
        }else{
907
            return null;
908
        }
909
    }
910

    
911

    
912

    
913
        @Override
914
    public int getParsingProblem(){
915
                return this.parsingProblem;
916
        }
917

    
918
        @Override
919
    public void setParsingProblem(int parsingProblem){
920
                this.parsingProblem = parsingProblem;
921
        }
922

    
923
        @Override
924
    public boolean hasProblem(){
925
                return parsingProblem != 0;
926
        }
927

    
928
        @Override
929
    public boolean hasProblem(ParserProblem problem) {
930
                return getParsingProblems().contains(problem);
931
        }
932

    
933
        @Override
934
    public int getProblemStarts(){
935
                return this.problemStarts;
936
        }
937

    
938
        @Override
939
    public void setProblemStarts(int start) {
940
                this.problemStarts = start;
941
        }
942

    
943
        @Override
944
    public int getProblemEnds(){
945
                return this.problemEnds;
946
        }
947

    
948
        @Override
949
    public void setProblemEnds(int end) {
950
                this.problemEnds = end;
951
        }
952

    
953
        @Override
954
    public void addParsingProblem(ParserProblem warning){
955
                parsingProblem = ParserProblem.addProblem(parsingProblem, warning);
956
        }
957

    
958
        @Override
959
    public void removeParsingProblem(ParserProblem problem) {
960
                parsingProblem = ParserProblem.removeProblem(parsingProblem, problem);
961
        }
962

    
963
        @Override
964
    @Transient
965
        public List<ParserProblem> getParsingProblems() {
966
                return ParserProblem.warningList(this.parsingProblem);
967
        }
968

    
969

    
970
        @Override
971
    @Transient
972
    public String getNomenclaturalCitation(String microReference) {
973
                String typeName = this.getType()== null ? "(no type defined)" : this.getType().getMessage();
974
                if (getCacheStrategy() == null){
975
                        logger.warn("No CacheStrategy defined for "+ typeName + ": " + this.getUuid());
976
                        return null;
977
                }else{
978
                    if (getCacheStrategy() instanceof INomenclaturalReferenceCacheStrategy){
979
                                return cacheStrategy.getNomenclaturalCitation(this, microReference);
980
                        }else {
981
                                logger.warn("No INomenclaturalReferenceCacheStrategy defined for "+ typeName + ": " + this.getUuid());
982
                                return null;
983
                        }
984
                }
985
        }
986

    
987

    
988
        /**
989
         * Generates, according to the {@link eu.etaxonomy.cdm.strategy.strategy.cache.reference.IReferenceBaseCacheStrategy cache strategy}
990
         * assigned to <i>this</i> reference, a string that identifies <i>this</i>
991
         * reference and returns it. This string may be stored in the inherited
992
         * {@link eu.etaxonomy.cdm.model.common.IdentifiableEntity#getTitleCache() titleCache} attribute.<BR>
993
         * This method overrides the generic and inherited generateTitle method
994
         * from {@link eu.etaxonomy.cdm.model.common.IdentifiableEntity IdentifiableEntity}.
995
         *
996
         * @return  the string identifying <i>this</i> reference
997
         * @see          #getCitation()
998
         * @see          eu.etaxonomy.cdm.model.common.IdentifiableEntity#getTitleCache()
999
         * @see          eu.etaxonomy.cdm.model.common.IdentifiableEntity#generateTitle()
1000
         * @see          eu.etaxonomy.cdm.strategy.strategy.cache.common.IIdentifiableEntityCacheStrategy#getTitleCache()
1001
         */
1002
//        @Override
1003
//        public String generateTitle(){
1004
//                if (cacheStrategy == null){
1005
//                        logger.warn("No CacheStrategy defined for Reference: " + this.getUuid());
1006
//                        return null;
1007
//                }else{
1008
//                        return cacheStrategy.getTitleCache(this);
1009
//                }
1010
//        }
1011

    
1012

    
1013

    
1014
//********** Casting methods ***********************************/
1015

    
1016
        /**
1017
         * @return
1018
         */
1019
        public IArticle castReferenceToArticle(){
1020
                setType(ReferenceType.Article);
1021
                return this;
1022
        }
1023

    
1024
        public IBook castReferenceToBook(){
1025
                setType(ReferenceType.Book);
1026
                return this;
1027
        }
1028

    
1029
        public IBookSection castReferenceToBookSection(){
1030
                setType(ReferenceType.BookSection);
1031
                return this;
1032
        }
1033

    
1034
        public ICdDvd castReferenceToCdDvd(){
1035
                setType(ReferenceType.CdDvd);
1036
                return this;
1037
        }
1038

    
1039
        public IDatabase castReferenceToDatabase(){
1040
                setType(ReferenceType.Database);
1041
                return this;
1042
        }
1043

    
1044
        public IGeneric castReferenceToGeneric(){
1045
                setType(ReferenceType.Generic);
1046
                return this;
1047
        }
1048

    
1049
        public IInProceedings castReferenceToInProceedings(){
1050
                setType(ReferenceType.InProceedings);
1051
                return this;
1052
        }
1053

    
1054
        public IJournal castReferenceToJournal(){
1055
                setType(ReferenceType.Journal);
1056
                return this;
1057
        }
1058

    
1059
        public IMap castReferenceToMap(){
1060
                setType(ReferenceType.Map);
1061
                return (IMap) this;
1062
        }
1063

    
1064
        public IPatent castReferenceToPatent(){
1065
                setType(ReferenceType.Patent);
1066
                return this;
1067
        }
1068

    
1069
        public IPersonalCommunication castReferenceToPersonalCommunication(){
1070
                setType(ReferenceType.PersonalCommunication);
1071
                return this;
1072
        }
1073

    
1074
        public IPrintSeries castReferenceToPrintSeries(){
1075
                setType(ReferenceType.PrintSeries);
1076
                return this;
1077
        }
1078

    
1079
        public IWebPage castReferenceToWebPage(){
1080
                setType(ReferenceType.WebPage);
1081
                return this;
1082
        }
1083

    
1084
        public IProceedings castReferenceToProceedings(){
1085
                setType(ReferenceType.Proceedings);
1086
                return this;
1087
        }
1088

    
1089
        public IReport castReferenceToReport(){
1090
                setType(ReferenceType.Report);
1091
                return this;
1092
        }
1093

    
1094
        public IThesis castReferenceToThesis(){
1095
                setType(ReferenceType.Thesis);
1096
                return this;
1097
        }
1098

    
1099

    
1100
        @Override
1101
    @Transient // prevent from being serialized by webservice
1102
        public IJournal getInJournal() {
1103
                IJournal journal = this.inReference;
1104
                return journal;
1105
        }
1106

    
1107
        @Override
1108
    public void setInJournal(IJournal journal) {
1109
                setInReference((Reference)journal);  //user setter to invoke aspect #1815
1110
        }
1111

    
1112
        @Override
1113
    @Transient // prevent from being serialized by webservice
1114
        public IPrintSeries getInSeries() {
1115
                return this.inReference;
1116
        }
1117

    
1118
        @Override
1119
    public void setInSeries(IPrintSeries inSeries) {
1120
            setInReference((Reference)inSeries);  //user setter to invoke aspect  #1815
1121
        }
1122

    
1123
        @Override
1124
    @Transient // prevent from being serialized by webservice
1125
        public IBook getInBook() {
1126
                IBook book = this.inReference;
1127
                return book;
1128
        }
1129

    
1130
//********************** In-References *****************************************
1131

    
1132
        @Override
1133
    public void setInBook(IBook book) {
1134
            setInReference((Reference)book);  //user setter to invoke aspect #1815
1135
        }
1136

    
1137
        @Override
1138
    @Transient // prevent from being serialized by webservice
1139
        public IProceedings getInProceedings() {
1140
                IProceedings proceedings = this.inReference;
1141
                return proceedings;
1142
        }
1143

    
1144
        @Override
1145
    public void setInProceedings(IProceedings proceeding) {
1146
        setInReference((Reference)proceeding);  //user setter to invoke aspect #1815
1147
        }
1148

    
1149
//*************************** CACHE STRATEGIES ******************************/
1150

    
1151
    @Override
1152
    public INomenclaturalReferenceCacheStrategy getCacheStrategy() {
1153
            return this.cacheStrategy;
1154
    }
1155

    
1156
        @Override
1157
    public void setCacheStrategy(INomenclaturalReferenceCacheStrategy referenceCacheStrategy) {
1158
                this.cacheStrategy = referenceCacheStrategy;
1159
        }
1160

    
1161
   @Override
1162
   public boolean updateCaches(){
1163
       //TODO shouldn't this be moved to the cache strategy?
1164
       if (this.equals(this.getInReference())){
1165
           String message = "-- invalid inreference (self-referencing) --";
1166
           String oldTitleCache = this.titleCache;
1167
           this.titleCache = message;
1168
           return !message.equals(oldTitleCache);
1169
       }
1170
       boolean result = super.updateCaches();
1171
       if (this.protectedAbbrevTitleCache == false){
1172
           String oldAbbrevTitleCache = this.abbrevTitleCache;
1173

    
1174
           String newAbbrevTitleCache = cacheStrategy.getFullAbbrevTitleString(this);
1175

    
1176
           if ( oldAbbrevTitleCache == null   || ! oldAbbrevTitleCache.equals(newAbbrevTitleCache) ){
1177
                this.setAbbrevTitleCache(null, false);
1178
                String newCache = this.getAbbrevTitleCache();
1179

    
1180
                if (newCache == null){
1181
                    logger.warn("New abbrevCache should never be null");
1182
                }
1183
                if (oldAbbrevTitleCache == null){
1184
                    logger.info("oldAbbrevTitleCache was illegaly null and has been fixed");
1185
                }
1186
                result = true;
1187
            }
1188
        }
1189
        return result;
1190
    }
1191

    
1192

    
1193
//*********************** CLONE ********************************************************/
1194

    
1195
        /**
1196
         * Clones <i>this</i> reference. This is a shortcut that enables to create
1197
         * a new instance that differs only slightly from <i>this</i> reference by
1198
         * modifying only some of the attributes.
1199
         *
1200
         * @see eu.etaxonomy.cdm.model.media.IdentifiableMediaEntity#clone()
1201
         * @see java.lang.Object#clone()
1202
         */
1203
        @Override
1204
        public Object clone() {
1205
                try {
1206
                        Reference result = (Reference)super.clone();
1207
                        result.setDatePublished(datePublished != null? (VerbatimTimePeriod)datePublished.clone(): null);
1208
                        //no changes to: title, authorship, hasProblem, nomenclaturallyRelevant, uri
1209
                        return result;
1210
                } catch (CloneNotSupportedException e) {
1211
                        logger.warn("Object does not implement cloneable");
1212
                        e.printStackTrace();
1213
                        return null;
1214
                }
1215
        }
1216

    
1217
//******************************* toString *****************************/
1218

    
1219
        @Override
1220
        public String toString() {
1221
                if (type != null){
1222
                        String result = "Reference [type=" + type  ;
1223
                        result += title == null ? "" : ", title=" + title;
1224
                        result += abbrevTitle == null ? "" : ", abbrevTitle=" + abbrevTitle;
1225
                        result += ", id= " + this.getId() + ", uuid=" + this.uuid;
1226
                        result += "]";
1227
                        return result;
1228
                }else{
1229
                        return super.toString();
1230
                }
1231
        }
1232

    
1233

    
1234

    
1235

    
1236
}
1237

    
Add picture from clipboard (Maximum size: 40 MB)