Project

General

Profile

Download (34.5 KB) Statistics
| Branch: | Tag: | Revision:
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.util.List;
15

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

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

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

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

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

    
151
//  from E+M import (still needed?)
152
//	@Column(length=255)
153
//  private String refAuthorString;
154
//	public String getRefAuthorString() {return refAuthorString;}
155
//  public void setRefAuthorString(String refAuthorString) {this.refAuthorString = refAuthorString;}
156

    
157
    @XmlAttribute(name ="type")
158
	@Column(name="refType")
159
	@NotNull
160
    @Type(type = "eu.etaxonomy.cdm.hibernate.EnumUserType",
161
    	parameters = {@Parameter(name  = "enumClass",
162
    	value = "eu.etaxonomy.cdm.model.reference.ReferenceType")}
163
    )
164
	@Audited
165
	protected ReferenceType type;
166

    
167
	//Title of the reference
168
	@XmlElement(name ="Title" )
169
	@Column(length=4096, name="title")
170
	@Lob
171
	@Field
172
	@Match(MatchMode.EQUAL_REQUIRED) //TODO correct? was EQUAL_REQUIRED before, but with abbrevTitle this is not realistic anymore, see also #6427
173
    //TODO Val #3379
174
//	@NullOrNotEmpty
175
	private String title;
176

    
177
	//Title of the reference
178
	@XmlElement(name ="AbbrevTitle" )
179
	@Field
180
	@Match(MatchMode.EQUAL)  //TODO check if this is correct
181
	@NullOrNotEmpty
182
	@Column(length=255)
183
	private String abbrevTitle;
184

    
185
	//Title of the reference
186
	@XmlElement(name ="AbbrevTitleCache" )
187
	@Field
188
	@Match(MatchMode.CACHE)
189
    //TODO Val #3379
190
//	@NotNull
191
	@Column(length=1024)
192
	private String abbrevTitleCache;
193

    
194
	@XmlElement(name = "protectedAbbrevTitleCache")
195
	@Merge(MergeMode.OR)
196
	private boolean protectedAbbrevTitleCache;
197

    
198
//********************************************************/
199

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

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

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

    
221
    @XmlElement(name = "Edition")
222
    @Field
223
    //TODO Val #3379
224
//    @NullOrNotEmpty
225
    @Column(length=255)
226
	protected String edition;
227

    
228
    @XmlElement(name = "ISBN")
229
    @Field
230
    //TODO Val #3379
231
//    @NullOrNotEmpty
232
    @Column(length=255)
233
	@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}")
234
	protected String isbn;
235

    
236
    @XmlElement(name = "Doi")
237
    @Field
238
    @FieldBridge(impl = DoiBridge.class)
239
    @Type(type="doiUserType")
240
    @Column(length=DOI.MAX_LENGTH)
241
    protected DOI doi;
242

    
243

    
244
	@XmlElement(name = "ISSN")
245
    @Field
246
    //TODO Val #3379
247
//	@NullOrNotEmpty
248
    @Column(length=255)
249
	@Pattern(regexp = "(?=.{9}$)\\d{4}([- ])\\d{4} (\\d|X)$", groups = Level2.class, message = "{eu.etaxonomy.cdm.model.reference.Reference.issn.message}")
250
	protected String issn;
251

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

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

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

    
273

    
274
	@XmlElement(name = "PlacePublished")
275
    @Field
276
    //TODO Val #3379
277
//	@NullOrNotEmpty
278
    @Column(length=255)
279
	protected String placePublished;
280

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

    
289
	@XmlElement(name = "School")
290
    @XmlIDREF
291
    @XmlSchemaType(name = "IDREF")
292
	@ManyToOne(fetch = FetchType.LAZY)
293
	@IndexedEmbedded
294
	@Cascade({CascadeType.SAVE_UPDATE,CascadeType.MERGE})
295
	protected Institution school;
296

    
297
    @XmlElement(name = "InReference")
298
    @XmlIDREF
299
    @XmlSchemaType(name = "IDREF")
300
    @ManyToOne(fetch = FetchType.LAZY)
301
    @Cascade({CascadeType.SAVE_UPDATE,CascadeType.MERGE})
302
//  @InReference(groups=Level2.class)
303
   	protected Reference inReference;
304

    
305
//********************************************************/
306

    
307
	//The date range assigned to the reference. ISO Date range like. Flexible, year can be left out, etc
308
	@XmlElement(name ="DatePublished" )
309
	@Embedded
310
	@IndexedEmbedded
311
	private VerbatimTimePeriod datePublished = VerbatimTimePeriod.NewVerbatimInstance();
312

    
313
    //#5258
314
    @XmlElement(name = "Accessed", type= String.class)
315
    @XmlJavaTypeAdapter(DateTimeAdapter.class)
316
    @Type(type="dateTimeUserType")
317
    @Basic(fetch = FetchType.LAZY)
318
    @Match(MatchMode.EQUAL)
319
    @FieldBridge(impl = DateTimeBridge.class)
320
    private DateTime accessed;
321

    
322
    @XmlElement(name ="Abstract" )
323
	@Column(length=CLOB_LENGTH, name="referenceAbstract")
324
	@Lob
325
    @Field
326
    //TODO Val #3379
327
//	@NullOrNotEmpty
328
	private String referenceAbstract;  //abstract is a reserved term in Java
329

    
330

    
331
	//URIs like DOIs, LSIDs or Handles for this reference
332
	@XmlElement(name = "URI")
333
	@Field(analyze = Analyze.NO)
334
    @FieldBridge(impl = UriBridge.class)
335
	@Type(type="uriUserType")
336
	private URI uri;
337

    
338
	//flag to subselect only references that could be useful for nomenclatural citations.
339
	//If a reference is used as a
340
	//nomenclatural reference in a name this flag should be automatically set
341
	@XmlElement(name = "IsNomenclaturallyRelevant")
342
	@Merge(MergeMode.OR)
343
	@Match(MatchMode.IGNORE)
344
	private boolean nomenclaturallyRelevant;
345

    
346
	@XmlElement(name = "Authorship")
347
	@XmlIDREF
348
	@XmlSchemaType(name = "IDREF")
349
	@ManyToOne(fetch = FetchType.LAZY)
350
	@IndexedEmbedded
351
	@Cascade({CascadeType.SAVE_UPDATE,CascadeType.MERGE})
352
	private TeamOrPersonBase<?> authorship;
353

    
354
    private ExternallyManaged externallyManaged;
355

    
356
	@XmlAttribute
357
    @Match(MatchMode.IGNORE)
358
	private int parsingProblem = 0;
359

    
360
	@XmlAttribute
361
    @Match(MatchMode.IGNORE)
362
    private int problemStarts = -1;
363

    
364
    @XmlAttribute
365
    @Match(MatchMode.IGNORE)
366
    private int problemEnds = -1;
367

    
368

    
369
// *********************** CONSTRUCTOR ************************/
370

    
371
    //for hibernate use only, *packet* private required by bytebuddy
372
    //TODO currenctly still protected as OpenUrlReference inherits from Reference
373
    //     this should be fixed
374
    protected Reference(){
375
		this(ReferenceType.Generic);  //just in case someone uses constructor
376
	}
377

    
378
	protected Reference(ReferenceType type) {
379
		super();
380
	    if (type == null){
381
			this.type = ReferenceType.Generic;
382
		} else{
383
			this.type = type;
384
		}
385
	}
386

    
387
// *********************** LISTENER ************************/
388

    
389

    
390
	@Override
391
    public void initListener(){
392
        PropertyChangeListener listener = new PropertyChangeListener() {
393
            @Override
394
            public void propertyChange(PropertyChangeEvent ev) {
395
            	if (!ev.getPropertyName().equals("titleCache") && !ev.getPropertyName().equals("abbrevTitleCache") && !ev.getPropertyName().equals("cacheStrategy")){
396
            		if (! isProtectedTitleCache()){
397
            			titleCache = null;
398
            		}
399
            		if (! isProtectedAbbrevTitleCache()){
400
            			abbrevTitleCache = null;
401
            		}
402
            	}
403
            }
404
        };
405
        addPropertyChangeListener(listener);
406
    }
407

    
408
//*************************** GETTER / SETTER ******************************************/
409

    
410
    // @Transient - must not be transient, since this property needs to be included in all serializations produced by the remote layer
411
    @Override
412
    public String getTitleCache(){
413
        String result = super.getTitleCache();
414
        if (isBlank(result) && !isProtectedTitleCache()){
415
            this.titleCache = this.getAbbrevTitleCache(true);
416
        }
417
        return titleCache;
418
    }
419

    
420
	@Override
421
	public String getAbbrevTitleCache() {
422
		return getAbbrevTitleCache(false);
423
	}
424

    
425
	/**
426
	 * Implements {@link #getAbbrevTitleCache()} but allows to
427
	 * avoid never ending recursions if both caches are empty
428
	 * avoidRecursion should only be <code>true</code> if called
429
	 * by {@link #getTitleCache()}
430
	 * @param avoidRecursion
431
	 * @return
432
	 */
433
	private String getAbbrevTitleCache(boolean avoidRecursion) {
434
        if (protectedAbbrevTitleCache){
435
            return this.abbrevTitleCache;
436
        }
437
        // is reference dirty, i.e. equal NULL?
438
        if (abbrevTitleCache == null){
439
            this.abbrevTitleCache = generateAbbrevTitle();
440
            this.abbrevTitleCache = getTruncatedCache(this.abbrevTitleCache) ;
441
        }
442
        if (isBlank(abbrevTitleCache) && !avoidRecursion){
443
            this.abbrevTitleCache = this.getTitleCache();
444
        }
445
        return abbrevTitleCache;
446
    }
447

    
448

    
449
    @Override
450
	@Deprecated
451
	public void setAbbrevTitleCache(String abbrevTitleCache) {
452
		this.abbrevTitleCache = abbrevTitleCache;
453
	}
454

    
455
	@Override
456
	public void setAbbrevTitleCache(String abbrevTitleCache, boolean isProtected) {
457
		this.protectedAbbrevTitleCache = isProtected;
458
		setAbbrevTitleCache(abbrevTitleCache);
459
	}
460

    
461
	@Override
462
	public boolean isProtectedAbbrevTitleCache() {
463
		return protectedAbbrevTitleCache;
464
	}
465

    
466
	@Override
467
	public void setProtectedAbbrevTitleCache(boolean protectedAbbrevTitleCache) {
468
		this.protectedAbbrevTitleCache = protectedAbbrevTitleCache;
469
	}
470

    
471
	@Override
472
	public String getAbbrevTitle() {
473
		return abbrevTitle;
474
	}
475

    
476
	@Override
477
	public void setAbbrevTitle(String abbrevTitle) {
478
		this.abbrevTitle = isBlank(abbrevTitle) ? null : abbrevTitle;
479
	}
480

    
481

    
482
	@Override
483
    public String getEditor() {
484
		return editor;
485
	}
486

    
487

    
488
	@Override
489
    public void setEditor(String editor) {
490
		this.editor = isBlank(editor)? null : editor;
491
	}
492

    
493
	@Override
494
    public String getVolume() {
495
		return volume;
496
	}
497

    
498
	@Override
499
    public void setVolume(String volume) {
500
		this.volume = isBlank(volume)? null : volume;
501
	}
502

    
503
	@Override
504
    public String getPages() {
505
		return pages;
506
	}
507

    
508
	@Override
509
    public void setPages(String pages) {
510
		this.pages = isBlank(pages)? null : pages;
511
	}
512

    
513
	@Override
514
    public String getEdition() {
515
		return edition;
516
	}
517

    
518
	@Override
519
    public void setEdition(String edition) {
520
		this.edition = isBlank(edition)? null : edition;
521
	}
522

    
523
	@Override
524
    public String getIsbn() {
525
		return isbn;
526
	}
527

    
528
	@Override
529
    public void setIsbn(String isbn) {
530
		this.isbn = isBlank(isbn)? null : isbn;
531
	}
532

    
533
	@Override
534
    public String getIssn() {
535
		return issn;
536
	}
537

    
538
	@Override
539
    public void setIssn(String issn) {
540
		this.issn = isBlank(issn)? null : issn;
541
	}
542

    
543
    @Override
544
	public DOI getDoi() {
545
		return doi;
546
	}
547
    @Override
548
	public void setDoi(DOI doi) {
549
		this.doi = doi;
550
	}
551
    /**
552
     * Convenience method to retrieve doi as string
553
     */
554
    @Transient @XmlTransient @java.beans.Transient
555
    public String getDoiString() {
556
        return doi == null? null : doi.toString();
557
    }
558

    
559
	@Override
560
    public String getSeriesPart() {
561
		return seriesPart;
562
	}
563
	@Override
564
    public void setSeriesPart(String seriesPart) {
565
		this.seriesPart = isBlank(seriesPart)? null : seriesPart;
566
	}
567

    
568
	@Override
569
    public String getOrganization() {
570
		return organization;
571
	}
572

    
573
	@Override
574
    public void setOrganization(String organization) {
575
		this.organization = isBlank(organization)? null : organization;
576
	}
577

    
578
	@Override
579
    public String getPublisher() {
580
		return publisher;
581
	}
582

    
583
	@Override
584
    public void setPublisher(String publisher) {
585
		this.publisher = StringUtils.truncate(isBlank(publisher)? null : publisher, 255);
586
	}
587

    
588
	@Override
589
    public void setPublisher(String publisher, String placePublished){
590
		this.publisher = publisher;
591
		this.placePublished = placePublished;
592
	}
593

    
594
	@Override
595
    public String getPlacePublished() {
596
		return placePublished;
597
	}
598

    
599
	@Override
600
    public void setPlacePublished(String placePublished) {
601
		this.placePublished = isBlank(placePublished)? null: placePublished;
602
	}
603

    
604
	@Override
605
    public Institution getInstitution() {
606
		return institution;
607
	}
608

    
609
	@Override
610
    public void setInstitution(Institution institution) {
611
		this.institution = institution;
612
	}
613

    
614
	@Override
615
    public Institution getSchool() {
616
		return school;
617
	}
618

    
619
	@Override
620
    public void setSchool(Institution school) {
621
		this.school = school;
622
	}
623

    
624
	@Override
625
    public Reference getInReference() {
626
		return inReference;
627
	}
628

    
629
	@Override
630
    public void setInReference(Reference inReference) {
631
		this.inReference = inReference;
632
	}
633

    
634
	@Override
635
    public void setType(ReferenceType type) {
636
		if (type == null){
637
			this.type = ReferenceType.Generic;
638
		} else{
639
			this.type = type;
640
		}
641
	}
642
	@Override
643
    public ReferenceType getType() {
644
		return type;
645
	}
646

    
647
	/**
648
	 * Whether this reference is of the given type
649
	 *
650
	 * @param type
651
	 * @return
652
	 */
653
	@Override
654
    public boolean isOfType(ReferenceType type){
655
		return type == getType();
656
	}
657

    
658
	/**
659
	 * Returns a string representing the title of <i>this</i> reference. If a
660
	 * reference has different titles (for instance abbreviated and not
661
	 * abbreviated) then for each title a new instance must be created.
662
	 *
663
	 * @return  the title string of <i>this</i> reference
664
	 * @see 	#getCitation()
665
	 */
666
	@Override
667
    public String getTitle(){
668
		return this.title;
669
	}
670
	/**
671
	 * @see 	#getTitle()
672
	 */
673
	@Override
674
    public void setTitle(String title){
675
		this.title = isBlank(title)? null : title;
676
	}
677

    
678
	/**
679
	 * Returns the date (mostly only the year) of publication / creation of
680
	 * <i>this</i> reference.
681
	 */
682
	@Override
683
    public VerbatimTimePeriod getDatePublished(){
684
		return this.datePublished;
685
	}
686
	/**
687
	 * @see 	#getDatePublished()
688
	 */
689
	@Override
690
    public void setDatePublished(VerbatimTimePeriod datePublished){
691
		this.datePublished = datePublished;
692
	}
693
    @Override
694
    @Transient
695
    @Deprecated
696
    public VerbatimTimePeriod setDatePublished(TimePeriod datePublished){
697
        VerbatimTimePeriod newTimePeriod = VerbatimTimePeriod.toVerbatim(datePublished);
698
        setDatePublished(newTimePeriod);
699
        return newTimePeriod;
700
    }
701

    
702
	public boolean hasDatePublished(){
703
		boolean result = !((this.datePublished == null) || isBlank(datePublished.toString()));
704
		return result;
705
	}
706

    
707

    
708
	@Override
709
    public DateTime getAccessed() {
710
        return accessed;
711
    }
712

    
713
	@Override
714
    public void setAccessed(DateTime accessed) {
715
        this.accessed = accessed;
716
    }
717

    
718
	/**
719
	 * Returns the {@link eu.etaxonomy.cdm.model.agent.TeamOrPersonBase author (team)} who created the
720
	 * content of <i>this</i> reference.
721
	 *
722
	 * @return  the author (team) of <i>this</i> reference
723
	 * @see 	eu.etaxonomy.cdm.model.agent.TeamOrPersonBase
724
	 */
725
	@Override
726
    public TeamOrPersonBase getAuthorship(){
727
		return this.authorship;
728
	}
729

    
730
	/**
731
	 * @see #getAuthorship()
732
	 */
733
	@Override
734
    public void setAuthorship(TeamOrPersonBase authorship){
735
		this.authorship = authorship;
736
	}
737

    
738
	/**
739
	 * Returns the Uniform Resource Identifier (URI) corresponding to <i>this</i>
740
	 * reference. An URI is a string of characters used to identify a resource
741
	 * on the Internet.
742
	 *
743
	 * @return  the URI of <i>this</i> reference
744
	 */
745
	@Override
746
    public URI getUri(){
747
		return this.uri;
748
	}
749
	/**
750
	 * @see #getUri()
751
	 */
752
	@Override
753
    public void setUri(URI uri){
754
		this.uri = uri;
755
	}
756

    
757
	/**
758
	 * @return the referenceAbstract
759
	 */
760
	@Override
761
    public String getReferenceAbstract() {
762
		return referenceAbstract;
763
	}
764

    
765
	/**
766
	 * @param referenceAbstract the referenceAbstract to set
767
	 */
768
	@Override
769
    public void setReferenceAbstract(String referenceAbstract) {
770
		this.referenceAbstract = isBlank(referenceAbstract)? null : referenceAbstract;
771
	}
772

    
773

    
774
	/**
775
	 * Returns "true" if the isNomenclaturallyRelevant flag is set. This
776
	 * indicates that a {@link TaxonName taxon name} has been originally
777
	 * published in <i>this</i> reference following the rules of a
778
	 * {@link eu.etaxonomy.cdm.model.name.NomenclaturalCode nomenclature code} and is therefore used for
779
	 * nomenclatural citations. This flag will be set as soon as <i>this</i>
780
	 * reference is used as a nomenclatural reference for any taxon name.<BR>
781
	 * FIXME what happens if the only taxon name referencing this reference is not
782
	 * any longer using this reference as a nomenclatural reference. How does the
783
	 * reference get informed about the fact that it is not nomenclaturally relevant
784
	 * anymore?
785
	 * @deprecated currently not supported and not in use, may be removed in future
786
	 */
787
	@Deprecated
788
    public boolean isNomenclaturallyRelevant(){
789
		return this.nomenclaturallyRelevant;
790
	}
791

    
792
	/**
793
	 * @see #isNomenclaturallyRelevant()
794
	 * @deprecated currently not supported and not in use, may be removed in future
795
	 */
796
	@Deprecated
797
	public void setNomenclaturallyRelevant(boolean nomenclaturallyRelevant){
798
		this.nomenclaturallyRelevant = nomenclaturallyRelevant;
799
	}
800

    
801

    
802
//****************************************************  /
803

    
804
	@Transient
805
	@Override
806
	public void setTitleCaches(String cache){
807
	    this.setAbbrevTitleCache(cache, true);
808
	    this.setTitleCache(cache, true);
809
	}
810

    
811

    
812
	/**
813
	 * Returns a formatted string containing the entire reference citation,
814
	 * including authors, corresponding to <i>this</i> reference.
815
	 *
816
	 * @see  #generateTitle()
817
	 */
818
	// TODO implement
819
	@Transient
820
	public String getCitation(){
821
		if (cacheStrategy() == null){
822
			logger.warn("No CacheStrategy defined for "+ this.getClass() + ": " + this.getUuid());
823
			return null;
824
		}else{
825
			return cacheStrategy().getTitleCache(this);
826
		}
827
	}
828

    
829

    
830
	@Override
831
    public String generateTitle() {
832
		return super.generateTitle();
833
	}
834

    
835
    public String generateAbbrevTitle() {
836
		return cacheStrategy().getNomenclaturalTitleCache(this);
837
	}
838

    
839
	/**
840
	 * Returns a string representation for the year of publication / creation
841
	 * of <i>this</i> reference. If the {@link #getDatePublished() datePublished}
842
	 * of this reference contains more date information then (starting) year
843
	 * only the year is returned.
844
	 */
845
	@Override
846
    @Transient
847
	public String getYear(){
848
		VerbatimTimePeriod datePublished = this.getDatePublished();
849
		if (datePublished != null ){
850
			String result = getDatePublished().getYear();
851
			return result;
852
		}else{
853
			return null;
854
		}
855
	}
856

    
857
	/**
858
	 * Convenience method that returns a string representation for the publication date / creation
859
	 * of <i>this</i> reference. The string is obtained by
860
	 * {@link #getDatePublished()#toString() the string representation
861
	 * of the date published}.
862
	 */
863
	@Transient
864
	public String getDatePublishedString(){
865
		VerbatimTimePeriod datePublished = this.getDatePublished();
866
		if (datePublished != null ){
867
			return getDatePublished().toString();
868
		}else{
869
			return null;
870
		}
871
	}
872

    
873
	/**
874
     * Convenience method that returns a string representation for the publication date / creation
875
     * of <i>this</i> reference. The string is obtained by
876
     * {@link #getDatePublished()#toString() the string representation
877
     * of the date published}.
878
     */
879
    @Transient
880
    public String getTimePeriodPublishedString(){
881
        VerbatimTimePeriod datePublished = this.getDatePublished();
882
        if (datePublished != null ){
883
            return getDatePublished().getTimePeriod();
884
        }else{
885
            return null;
886
        }
887
    }
888

    
889
	@Override
890
    public int getParsingProblem(){
891
		return this.parsingProblem;
892
	}
893

    
894
	@Override
895
    public void setParsingProblem(int parsingProblem){
896
		this.parsingProblem = parsingProblem;
897
	}
898

    
899
	@Override
900
    public boolean hasProblem(){
901
		return parsingProblem != 0;
902
	}
903

    
904
	@Override
905
    public boolean hasProblem(ParserProblem problem) {
906
		return getParsingProblems().contains(problem);
907
	}
908

    
909
	@Override
910
    public int getProblemStarts(){
911
		return this.problemStarts;
912
	}
913

    
914
	@Override
915
    public void setProblemStarts(int start) {
916
		this.problemStarts = start;
917
	}
918

    
919
	@Override
920
    public int getProblemEnds(){
921
		return this.problemEnds;
922
	}
923

    
924
	@Override
925
    public void setProblemEnds(int end) {
926
		this.problemEnds = end;
927
	}
928

    
929
	@Override
930
    public void addParsingProblem(ParserProblem warning){
931
		parsingProblem = ParserProblem.addProblem(parsingProblem, warning);
932
	}
933

    
934
	@Override
935
    public void removeParsingProblem(ParserProblem problem) {
936
		parsingProblem = ParserProblem.removeProblem(parsingProblem, problem);
937
	}
938

    
939
	@Override
940
    @Transient
941
	public List<ParserProblem> getParsingProblems() {
942
		return ParserProblem.warningList(this.parsingProblem);
943
	}
944

    
945

    
946
	@Override
947
    @Transient
948
    public String getNomenclaturalCitation(String microReference) {
949
		String typeName = this.getType()== null ? "(no type defined)" : this.getType().getLabel();
950
		if (cacheStrategy() == null){
951
		    throw new IllegalStateException("No CacheStrategy defined for "+ typeName + ": " + this.getUuid());
952
		}else{
953
		    return NomenclaturalSourceFormatter.INSTANCE().format(this, microReference);
954
		}
955
	}
956

    
957
	/**
958
	 * Generates, according to the {@link eu.etaxonomy.cdm.strategy.strategy.cache.reference.IReferenceBaseCacheStrategy cache strategy}
959
	 * assigned to <i>this</i> reference, a string that identifies <i>this</i>
960
	 * reference and returns it. This string may be stored in the inherited
961
	 * {@link eu.etaxonomy.cdm.model.common.IdentifiableEntity#getTitleCache() titleCache} attribute.<BR>
962
	 * This method overrides the generic and inherited generateTitle method
963
	 * from {@link eu.etaxonomy.cdm.model.common.IdentifiableEntity IdentifiableEntity}.
964
	 *
965
	 * @return  the string identifying <i>this</i> reference
966
	 * @see  	#getCitation()
967
	 * @see  	eu.etaxonomy.cdm.model.common.IdentifiableEntity#getTitleCache()
968
	 * @see  	eu.etaxonomy.cdm.model.common.IdentifiableEntity#generateTitle()
969
	 * @see  	eu.etaxonomy.cdm.strategy.strategy.cache.common.IIdentifiableEntityCacheStrategy#getTitleCache()
970
	 */
971
//	@Override
972
//	public String generateTitle(){
973
//		if (cacheStrategy == null){
974
//			logger.warn("No CacheStrategy defined for Reference: " + this.getUuid());
975
//			return null;
976
//		}else{
977
//			return cacheStrategy.getTitleCache(this);
978
//		}
979
//	}
980

    
981

    
982

    
983
//********** Casting methods ***********************************/
984

    
985
	/**
986
	 * @return
987
	 */
988
	public IArticle castReferenceToArticle(){
989
		setType(ReferenceType.Article);
990
		return this;
991
	}
992

    
993
	public IBook castReferenceToBook(){
994
		setType(ReferenceType.Book);
995
		return this;
996
	}
997

    
998
	public IBookSection castReferenceToBookSection(){
999
		setType(ReferenceType.BookSection);
1000
		return this;
1001
	}
1002

    
1003
	public ICdDvd castReferenceToCdDvd(){
1004
		setType(ReferenceType.CdDvd);
1005
		return this;
1006
	}
1007

    
1008
	public IDatabase castReferenceToDatabase(){
1009
		setType(ReferenceType.Database);
1010
		return this;
1011
	}
1012

    
1013
	public IGeneric castReferenceToGeneric(){
1014
		setType(ReferenceType.Generic);
1015
		return this;
1016
	}
1017

    
1018
	public IInProceedings castReferenceToInProceedings(){
1019
		setType(ReferenceType.InProceedings);
1020
		return this;
1021
	}
1022

    
1023
	public IJournal castReferenceToJournal(){
1024
		setType(ReferenceType.Journal);
1025
		return this;
1026
	}
1027

    
1028
	public IMap castReferenceToMap(){
1029
		setType(ReferenceType.Map);
1030
		return (IMap) this;
1031
	}
1032

    
1033
	public IPatent castReferenceToPatent(){
1034
		setType(ReferenceType.Patent);
1035
		return this;
1036
	}
1037

    
1038
	public IPersonalCommunication castReferenceToPersonalCommunication(){
1039
		setType(ReferenceType.PersonalCommunication);
1040
		return this;
1041
	}
1042

    
1043
	public IPrintSeries castReferenceToPrintSeries(){
1044
		setType(ReferenceType.PrintSeries);
1045
		return this;
1046
	}
1047

    
1048
	public IWebPage castReferenceToWebPage(){
1049
		setType(ReferenceType.WebPage);
1050
		return this;
1051
	}
1052

    
1053
	public IProceedings castReferenceToProceedings(){
1054
		setType(ReferenceType.Proceedings);
1055
		return this;
1056
	}
1057

    
1058
	public IReport castReferenceToReport(){
1059
		setType(ReferenceType.Report);
1060
		return this;
1061
	}
1062

    
1063
	public IThesis castReferenceToThesis(){
1064
		setType(ReferenceType.Thesis);
1065
		return this;
1066
	}
1067

    
1068

    
1069
	@Override
1070
    @Transient // prevent from being serialized by webservice
1071
	public IJournal getInJournal() {
1072
		IJournal journal = this.inReference;
1073
		return journal;
1074
	}
1075

    
1076
	@Override
1077
    public void setInJournal(IJournal journal) {
1078
		setInReference((Reference)journal);  //user setter to invoke aspect #1815
1079
	}
1080

    
1081
	@Override
1082
    @Transient // prevent from being serialized by webservice
1083
	public IPrintSeries getInSeries() {
1084
		return this.inReference;
1085
	}
1086

    
1087
	@Override
1088
    public void setInSeries(IPrintSeries inSeries) {
1089
	    setInReference((Reference)inSeries);  //user setter to invoke aspect  #1815
1090
	}
1091

    
1092
	@Override
1093
    @Transient // prevent from being serialized by webservice
1094
	public IBook getInBook() {
1095
		IBook book = this.inReference;
1096
		return book;
1097
	}
1098

    
1099
//********************** In-References *****************************************
1100

    
1101
	@Override
1102
    public void setInBook(IBook book) {
1103
	    setInReference((Reference)book);  //user setter to invoke aspect #1815
1104
	}
1105

    
1106
	@Override
1107
    @Transient // prevent from being serialized by webservice
1108
	public IProceedings getInProceedings() {
1109
		IProceedings proceedings = this.inReference;
1110
		return proceedings;
1111
	}
1112

    
1113
	@Override
1114
    public void setInProceedings(IProceedings proceeding) {
1115
        setInReference((Reference)proceeding);  //user setter to invoke aspect #1815
1116
	}
1117

    
1118
//**************************** Type *****************************************/
1119

    
1120
    public boolean isArticle() {
1121
        return this.getType().isArticle();
1122
    }
1123
    public boolean isBook() {
1124
        return this.getType().isBook();
1125
    }
1126
    public boolean isBookSection() {
1127
        return this.getType().isBookSection();
1128
    }
1129
    public boolean isWebPage() {
1130
        return this.getType().isWebPage();
1131
    }
1132
    public boolean isDatabase() {
1133
        return this.getType().isDatabase();
1134
    }
1135
    public boolean isMap() {
1136
        return this.getType().isMap();
1137
    }
1138
    public boolean isPatent() {
1139
        return this.getType().isPatent();
1140
    }
1141
    public boolean isGeneric() {
1142
        return this.getType().isGeneric();
1143
    }
1144
    public boolean isCdDvd() {
1145
        return this.getType().isCdDvd();
1146
    }
1147
    public boolean isProceedings() {
1148
        return this.getType().isProceedings();
1149
    }
1150
    public boolean isInProceedings() {
1151
        return this.getType().isInProceedings();
1152
    }
1153
    public boolean isJournal() {
1154
        return this.getType().isJournal();
1155
    }
1156
    public boolean isPersonalCommunication() {
1157
        return this.getType().isPersonalCommunication();
1158
    }
1159
    public boolean isThesis() {
1160
        return this.getType().isThesis();
1161
    }
1162
    public boolean isPrintSeries() {
1163
        return this.getType().isPrintSeries();
1164
    }
1165
    /**
1166
     * @return <code>true</code> if this type is exactly {@link ReferenceType#Section}
1167
     * @see ReferenceType#isSection()
1168
     */
1169
    public boolean isSectionOnly() {
1170
        return this.getType().isSectionOnly();
1171
    }
1172
    /**
1173
     * Returns <code>true</code> if this reference is part of another reference
1174
     * (inheriting from {@link ISection}) and therefore may have an in-reference and pages.
1175
     * @see ReferenceType#isSection()
1176
     */
1177
    public boolean isSection() {
1178
        return this.getType().isSection();
1179
    }
1180
    /**
1181
     * @see ReferenceType#isPrintedUnit()
1182
     */
1183
    public boolean isPrintedUnit() {
1184
        return this.getType().isPrintedUnit();
1185
    }
1186

    
1187
//*************************** CACHE STRATEGIES ******************************/
1188

    
1189
    @Override
1190
    protected void initDefaultCacheStrategy() {
1191
        this.setCacheStrategy(ReferenceDefaultCacheStrategy.NewInstance());
1192
    }
1193

    
1194
   @Override
1195
   public boolean updateCaches(){
1196
       //TODO shouldn't this be moved to the cache strategy?
1197
       if (this.equals(this.getInReference())){
1198
           String message = "-- invalid inreference (self-referencing) --";
1199
           String oldTitleCache = this.titleCache;
1200
           this.titleCache = message;
1201
           return !message.equals(oldTitleCache);
1202
       }
1203
       boolean result = super.updateCaches();
1204
       if (this.protectedAbbrevTitleCache == false){
1205
           String oldAbbrevTitleCache = this.abbrevTitleCache;
1206

    
1207
           String newAbbrevTitleCache = getTruncatedCache(cacheStrategy().getNomenclaturalTitleCache(this));
1208
           if (newAbbrevTitleCache.equals("")){
1209
               newAbbrevTitleCache = cacheStrategy().getTitleCache(this);
1210
           }
1211

    
1212
           if ( oldAbbrevTitleCache == null || ! oldAbbrevTitleCache.equals(newAbbrevTitleCache) ){
1213
                this.setAbbrevTitleCache(null, false);
1214
                String newCache = this.getAbbrevTitleCache();
1215

    
1216
                if (newCache == null){
1217
                    logger.warn("New abbrevCache should never be null");
1218
                }
1219
                if (oldAbbrevTitleCache == null){
1220
                    logger.info("oldAbbrevTitleCache was illegaly null and has been fixed");
1221
                }
1222
                result = true;
1223
            }
1224
        }
1225
        return result;
1226
    }
1227

    
1228
//*********************** CLONE ********************************************************/
1229

    
1230
	/**
1231
	 * Clones <i>this</i> reference. This is a shortcut that enables to create
1232
	 * a new instance that differs only slightly from <i>this</i> reference by
1233
	 * modifying only some of the attributes.
1234
	 *
1235
	 * @see eu.etaxonomy.cdm.model.media.IdentifiableMediaEntity#clone()
1236
	 * @see java.lang.Object#clone()
1237
	 */
1238
	@Override
1239
	public Reference clone() {
1240
		try {
1241
			Reference result = (Reference)super.clone();
1242
			result.setDatePublished(datePublished != null? (VerbatimTimePeriod)datePublished.clone(): null);
1243
			//no changes to: title, authorship, hasProblem, nomenclaturallyRelevant, uri
1244
			return result;
1245
		} catch (CloneNotSupportedException e) {
1246
			logger.warn("Object does not implement cloneable");
1247
			e.printStackTrace();
1248
			return null;
1249
		}
1250
	}
1251

    
1252
//******************************* toString *****************************/
1253

    
1254
	@Override
1255
	public String toString() {
1256
		if (type != null){
1257
			String result = "Reference [type=" + type  ;
1258
			result += title == null ? "" : ", title=" + title;
1259
			result += abbrevTitle == null ? "" : ", abbrevTitle=" + abbrevTitle;
1260
			result += ", id= " + this.getId() + ", uuid=" + this.uuid;
1261
			result += "]";
1262
			return result;
1263
		}else{
1264
			return super.toString();
1265
		}
1266
	}
1267
}
(36-36/41)