Project

General

Profile

Download (33.1 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.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("Old abbrevTitleCache should never be null");
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

    
(28-28/33)