Some further cleaning up for single reference cache strategy #5833
[cdmlib.git] / cdmlib-model / src / main / java / eu / etaxonomy / cdm / model / reference / Reference.java
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.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.Transient;
26 import javax.validation.constraints.NotNull;
27 import javax.validation.constraints.Pattern;
28 import javax.xml.bind.annotation.XmlAccessType;
29 import javax.xml.bind.annotation.XmlAccessorType;
30 import javax.xml.bind.annotation.XmlAttribute;
31 import javax.xml.bind.annotation.XmlElement;
32 import javax.xml.bind.annotation.XmlIDREF;
33 import javax.xml.bind.annotation.XmlRootElement;
34 import javax.xml.bind.annotation.XmlSchemaType;
35 import javax.xml.bind.annotation.XmlType;
36
37 import org.apache.commons.lang.StringUtils;
38 import org.apache.log4j.Logger;
39 import org.hibernate.annotations.Cascade;
40 import org.hibernate.annotations.CascadeType;
41 import org.hibernate.annotations.Table;
42 import org.hibernate.annotations.Type;
43 import org.hibernate.envers.Audited;
44 import org.hibernate.search.annotations.Analyze;
45 import org.hibernate.search.annotations.Field;
46 import org.hibernate.search.annotations.FieldBridge;
47 import org.hibernate.search.annotations.IndexedEmbedded;
48
49 import eu.etaxonomy.cdm.common.DOI;
50 import eu.etaxonomy.cdm.hibernate.search.DoiBridge;
51 import eu.etaxonomy.cdm.model.agent.Institution;
52 import eu.etaxonomy.cdm.model.agent.TeamOrPersonBase;
53 import eu.etaxonomy.cdm.model.common.TimePeriod;
54 import eu.etaxonomy.cdm.model.media.IdentifiableMediaEntity;
55 import eu.etaxonomy.cdm.model.name.TaxonNameBase;
56 import eu.etaxonomy.cdm.strategy.cache.reference.INomenclaturalReferenceCacheStrategy;
57 import eu.etaxonomy.cdm.strategy.cache.reference.IReferenceCacheStrategy;
58 import eu.etaxonomy.cdm.strategy.cache.reference.NewDefaultReferenceCacheStrategy;
59 import eu.etaxonomy.cdm.strategy.match.Match;
60 import eu.etaxonomy.cdm.strategy.match.MatchMode;
61 import eu.etaxonomy.cdm.strategy.merge.Merge;
62 import eu.etaxonomy.cdm.strategy.merge.MergeMode;
63 import eu.etaxonomy.cdm.strategy.parser.ParserProblem;
64 import eu.etaxonomy.cdm.validation.Level2;
65 import eu.etaxonomy.cdm.validation.Level3;
66 import eu.etaxonomy.cdm.validation.annotation.InReference;
67 import eu.etaxonomy.cdm.validation.annotation.NoRecursiveInReference;
68 import eu.etaxonomy.cdm.validation.annotation.NullOrNotEmpty;
69 import eu.etaxonomy.cdm.validation.annotation.ReferenceCheck;
70
71 /**
72 * The class for references (information sources). Originally
73 * an abstract class with many subclasses. Not it is only
74 * one class implementing many interfaces for safe use.
75 * <P>
76 * This class corresponds to: <ul>
77 * <li> PublicationCitation according to the TDWG ontology
78 * <li> Publication according to the TCS
79 * <li> Reference according to the ABCD schema
80 * </ul>
81 *
82 * @author m.doering
83 * @created 08-Nov-2007 13:06:47
84 */
85 @XmlAccessorType(XmlAccessType.FIELD)
86 @XmlType(name = "Reference", propOrder = {
87 "type",
88 "uri",
89 "abbrevTitleCache",
90 "protectedAbbrevTitleCache",
91 "nomenclaturallyRelevant",
92 "authorship",
93 "referenceAbstract",
94 "title",
95 "abbrevTitle",
96 "editor",
97 "volume",
98 "pages",
99 "edition",
100 "isbn",
101 "issn",
102 "doi",
103 "seriesPart",
104 "datePublished",
105 "publisher",
106 "placePublished",
107 "institution",
108 "school",
109 "organization",
110 "inReference"
111 })
112 @XmlRootElement(name = "Reference")
113 @Entity
114 @Inheritance(strategy=InheritanceType.SINGLE_TABLE)
115 @Audited
116 @Table(appliesTo="Reference", indexes = { @org.hibernate.annotations.Index(name = "ReferenceTitleCacheIndex", columnNames = { "titleCache" }) })
117 //@InReference(groups=Level3.class)
118 @ReferenceCheck(groups=Level2.class)
119 @InReference(groups=Level3.class)
120 @NoRecursiveInReference(groups=Level3.class) //may become Level1 in future #
121 public class Reference
122 extends IdentifiableMediaEntity<IReferenceCacheStrategy>
123 implements IArticle, IBook, IPatent, IDatabase, IJournal, IBookSection,ICdDvd,
124 IGeneric,IInProceedings, IProceedings, IPrintSeries, IReport,
125 IThesis,IWebPage, IPersonalCommunication,
126 INomenclaturalReference, IReference,
127 Cloneable {
128
129 private static final long serialVersionUID = -2034764545042691295L;
130 private static final Logger logger = Logger.getLogger(Reference.class);
131
132 @XmlAttribute(name ="type")
133 @Column(name="refType")
134 @NotNull
135 @Type(type = "eu.etaxonomy.cdm.hibernate.EnumUserType",
136 parameters = {@org.hibernate.annotations.Parameter(name = "enumClass", value = "eu.etaxonomy.cdm.model.reference.ReferenceType")}
137 )
138 @Audited
139 protected ReferenceType type;
140
141 //Title of the reference
142 @XmlElement(name ="Title" )
143 @Column(length=4096, name="title")
144 @Lob
145 @Field
146 @Match(MatchMode.EQUAL_REQUIRED)
147 //TODO Val #3379
148 // @NullOrNotEmpty
149 private String title;
150
151 //Title of the reference
152 @XmlElement(name ="AbbrevTitle" )
153 @Field
154 @Match(MatchMode.EQUAL) //TODO check if this is correct
155 @NullOrNotEmpty
156 @Column(length=255)
157 private String abbrevTitle;
158
159 //Title of the reference
160 @XmlElement(name ="AbbrevTitleCache" )
161 @Field
162 @Match(MatchMode.CACHE)
163 //TODO Val #3379
164 // @NotNull
165 @Column(length=1024)
166 private String abbrevTitleCache;
167
168 @XmlElement(name = "protectedAbbrevTitleCache")
169 @Merge(MergeMode.OR)
170 private boolean protectedAbbrevTitleCache;
171
172 //********************************************************/
173
174
175 @XmlElement(name = "Editor")
176 @Field
177 //TODO Val #3379
178 // @NullOrNotEmpty
179 @Column(length=255)
180 protected String editor;
181
182 @XmlElement(name = "Volume")
183 @Field
184 //TODO Val #3379
185 // @NullOrNotEmpty
186 @Column(length=255)
187 protected String volume;
188
189 @XmlElement(name = "Pages")
190 @Field
191 //TODO Val #3379
192 // @NullOrNotEmpty
193 @Column(length=255)
194 protected String pages;
195
196 @XmlElement(name = "Edition")
197 @Field
198 //TODO Val #3379
199 // @NullOrNotEmpty
200 @Column(length=255)
201 protected String edition;
202
203 @XmlElement(name = "ISBN")
204 @Field
205 //TODO Val #3379
206 // @NullOrNotEmpty
207 @Column(length=255)
208 @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}")
209 protected String isbn;
210
211 @XmlElement(name = "Doi")
212 @Field
213 @FieldBridge(impl = DoiBridge.class)
214 @Type(type="doiUserType")
215 @Column(length=DOI.MAX_LENGTH)
216 protected DOI doi;
217
218
219 @XmlElement(name = "ISSN")
220 @Field
221 //TODO Val #3379
222 // @NullOrNotEmpty
223 @Column(length=255)
224 @Pattern(regexp = "(?=.{9}$)\\d{4}([- ])\\d{4} (\\d|X)$", groups = Level2.class, message = "{eu.etaxonomy.cdm.model.reference.Reference.issn.message}")
225 protected String issn;
226
227 @XmlElement(name = "SeriesPart")
228 @Field
229 //TODO Val #3379
230 // @NullOrNotEmpty
231 @Column(length=255)
232 protected String seriesPart;
233
234 @XmlElement(name = "Organization")
235 @Field
236 //TODO Val #3379
237 // @NullOrNotEmpty
238 @Column(length=255)
239 protected String organization;
240
241 @XmlElement(name = "Publisher")
242 @Field
243 //TODO Val #3379
244 // @NullOrNotEmpty
245 @Column(length=255)
246 protected String publisher;
247
248
249 @XmlElement(name = "PlacePublished")
250 @Field
251 //TODO Val #3379
252 // @NullOrNotEmpty
253 @Column(length=255)
254 protected String placePublished;
255
256 @XmlElement(name = "Institution")
257 @XmlIDREF
258 @XmlSchemaType(name = "IDREF")
259 @ManyToOne(fetch = FetchType.LAZY)
260 @IndexedEmbedded
261 @Cascade({CascadeType.SAVE_UPDATE,CascadeType.MERGE})
262 protected Institution institution;
263
264 @XmlElement(name = "School")
265 @XmlIDREF
266 @XmlSchemaType(name = "IDREF")
267 @ManyToOne(fetch = FetchType.LAZY)
268 @IndexedEmbedded
269 @Cascade({CascadeType.SAVE_UPDATE,CascadeType.MERGE})
270 protected Institution school;
271
272 @XmlElement(name = "InReference")
273 @XmlIDREF
274 @XmlSchemaType(name = "IDREF")
275 @ManyToOne(fetch = FetchType.LAZY)
276 // @IndexedEmbedded
277 @Cascade({CascadeType.SAVE_UPDATE,CascadeType.MERGE})
278 // @InReference(groups=Level2.class)
279 protected Reference inReference;
280
281 //********************************************************/
282
283 //The date range assigned to the reference. ISO Date range like. Flexible, year can be left out, etc
284 @XmlElement(name ="DatePublished" )
285 @Embedded
286 @IndexedEmbedded
287 private TimePeriod datePublished = TimePeriod.NewInstance();
288
289 @XmlElement(name ="Abstract" )
290 @Column(length=65536, name="referenceAbstract")
291 @Lob
292 @Field
293 //TODO Val #3379
294 // @NullOrNotEmpty
295 private String referenceAbstract; //abstract is a reserved term in Java
296
297
298 //URIs like DOIs, LSIDs or Handles for this reference
299 @XmlElement(name = "URI")
300 @Field(analyze = Analyze.NO)
301 @Type(type="uriUserType")
302 private URI uri;
303
304 //flag to subselect only references that could be useful for nomenclatural citations. If a reference is used as a
305 //nomenclatural reference in a name this flag should be automatically set
306 @XmlElement(name = "IsNomenclaturallyRelevant")
307 @Merge(MergeMode.OR)
308 private boolean nomenclaturallyRelevant;
309
310 @XmlElement(name = "Authorship")
311 @XmlIDREF
312 @XmlSchemaType(name = "IDREF")
313 @ManyToOne(fetch = FetchType.LAZY)
314 @IndexedEmbedded
315 @Cascade({CascadeType.SAVE_UPDATE,CascadeType.MERGE})
316 private TeamOrPersonBase<?> authorship;
317
318 @XmlAttribute
319 @Match(MatchMode.IGNORE)
320 private int parsingProblem = 0;
321
322 @XmlAttribute
323 @Match(MatchMode.IGNORE)
324 private int problemStarts = -1;
325
326 @XmlAttribute
327 @Match(MatchMode.IGNORE)
328 private int problemEnds = -1;
329
330 @Transient
331 @XmlAttribute
332 @Match(MatchMode.IGNORE)
333 private boolean cacheStrategyRectified = false;
334
335 protected Reference(){
336 this(ReferenceType.Generic); //just in case someone uses constructor
337 }
338
339 protected Reference(ReferenceType type) {
340 super();
341 if (type == null){
342 this.type = ReferenceType.Generic;
343 } else{
344 this.type = type;
345 }
346 this.setCacheStrategy(NewDefaultReferenceCacheStrategy.NewInstance());
347 }
348
349 @Override
350 public void initListener(){
351 PropertyChangeListener listener = new PropertyChangeListener() {
352 @Override
353 public void propertyChange(PropertyChangeEvent ev) {
354 if (!ev.getPropertyName().equals("titleCache") && !ev.getPropertyName().equals("abbrevTitleCache") && !ev.getPropertyName().equals("cacheStrategy")){
355 if (! isProtectedTitleCache()){
356 titleCache = null;
357 }
358 if (! isProtectedAbbrevTitleCache()){
359 abbrevTitleCache = null;
360 }
361 }
362 }
363 };
364 addPropertyChangeListener(listener);
365 }
366
367
368 //*************************** GETTER / SETTER ******************************************/
369
370
371 @Override
372 public String getAbbrevTitleCache() {
373 if (protectedAbbrevTitleCache){
374 return this.abbrevTitleCache;
375 }
376 // is reference dirty, i.e. equal NULL?
377 if (abbrevTitleCache == null){
378 this.abbrevTitleCache = generateAbbrevTitle();
379 this.abbrevTitleCache = getTruncatedCache(this.abbrevTitleCache) ;
380 }
381 return abbrevTitleCache;
382 }
383
384 @Override
385 @Deprecated
386 public void setAbbrevTitleCache(String abbrevTitleCache) {
387 this.abbrevTitleCache = abbrevTitleCache;
388 }
389
390 @Override
391 public void setAbbrevTitleCache(String abbrevTitleCache, boolean isProtected) {
392 this.protectedAbbrevTitleCache = isProtected;
393 setAbbrevTitleCache(abbrevTitleCache);
394 }
395
396 @Override
397 public boolean isProtectedAbbrevTitleCache() {
398 return protectedAbbrevTitleCache;
399 }
400
401 @Override
402 public void setProtectedAbbrevTitleCache(boolean protectedAbbrevTitleCache) {
403 this.protectedAbbrevTitleCache = protectedAbbrevTitleCache;
404 }
405
406 @Override
407 public String getAbbrevTitle() {
408 return abbrevTitle;
409 }
410
411 @Override
412 public void setAbbrevTitle(String abbrevTitle) {
413 this.abbrevTitle = StringUtils.isBlank(abbrevTitle) ? null : abbrevTitle;
414 }
415
416
417 @Override
418 public String getEditor() {
419 return editor;
420 }
421
422
423 @Override
424 public void setEditor(String editor) {
425 this.editor = StringUtils.isBlank(editor)? null : editor;
426 }
427
428 @Override
429 public String getVolume() {
430 return volume;
431 }
432
433 @Override
434 public void setVolume(String volume) {
435 this.volume = StringUtils.isBlank(volume)? null : volume;
436 }
437
438 @Override
439 public String getPages() {
440 return pages;
441 }
442
443 @Override
444 public void setPages(String pages) {
445 this.pages = StringUtils.isBlank(pages)? null : pages;
446 }
447
448 @Override
449 public String getEdition() {
450 return edition;
451 }
452
453 @Override
454 public void setEdition(String edition) {
455 this.edition = StringUtils.isBlank(edition)? null : edition;
456 }
457
458 @Override
459 public String getIsbn() {
460 return isbn;
461 }
462
463 @Override
464 public void setIsbn(String isbn) {
465 this.isbn = StringUtils.isBlank(isbn)? null : isbn;
466 }
467
468 @Override
469 public String getIssn() {
470 return issn;
471 }
472
473 @Override
474 public void setIssn(String issn) {
475 this.issn = StringUtils.isBlank(issn)? null : issn;
476 }
477
478 @Override
479 public DOI getDoi() {
480 return doi;
481 }
482
483 @Override
484 public void setDoi(DOI doi) {
485 this.doi = doi;
486 }
487
488 @Override
489 public String getSeriesPart() {
490 return seriesPart;
491 }
492
493 @Override
494 public void setSeriesPart(String seriesPart) {
495 this.seriesPart = StringUtils.isBlank(seriesPart)? null : seriesPart;
496 }
497
498 @Override
499 public String getOrganization() {
500 return organization;
501 }
502
503 @Override
504 public void setOrganization(String organization) {
505 this.organization = StringUtils.isBlank(organization)? null : organization;
506 }
507
508 @Override
509 public String getPublisher() {
510 return publisher;
511 }
512
513 @Override
514 public void setPublisher(String publisher) {
515 this.publisher = StringUtils.isBlank(publisher)? null : publisher;
516 }
517
518 @Override
519 public void setPublisher(String publisher, String placePublished){
520 this.publisher = publisher;
521 this.placePublished = placePublished;
522 }
523
524 @Override
525 public String getPlacePublished() {
526 return placePublished;
527 }
528
529 @Override
530 public void setPlacePublished(String placePublished) {
531 this.placePublished = StringUtils.isBlank(placePublished)? null: placePublished;
532 }
533
534 @Override
535 public Institution getInstitution() {
536 return institution;
537 }
538
539 @Override
540 public void setInstitution(Institution institution) {
541 this.institution = institution;
542 }
543
544 @Override
545 public Institution getSchool() {
546 return school;
547 }
548
549 @Override
550 public void setSchool(Institution school) {
551 this.school = school;
552 }
553
554 @Override
555 public Reference getInReference() {
556 return inReference;
557 }
558
559 @Override
560 public void setInReference(Reference inReference) {
561 this.inReference = inReference;
562 }
563
564 @Override
565 public void setType(ReferenceType type) {
566 if (type == null){
567 this.type = ReferenceType.Generic;
568 } else{
569 this.type = type;
570 }
571 this.setCacheStrategy(type.getCacheStrategy());
572 }
573 @Override
574 public ReferenceType getType() {
575 return type;
576 }
577
578 /**
579 * Whether this reference is of the given type
580 *
581 * @param type
582 * @return
583 */
584 @Override
585 public boolean isOfType(ReferenceType type){
586 return type == getType();
587 }
588
589 /**
590 * Returns a string representing the title of <i>this</i> reference. If a
591 * reference has different titles (for instance abbreviated and not
592 * abbreviated) then for each title a new instance must be created.
593 *
594 * @return the title string of <i>this</i> reference
595 * @see #getCitation()
596 */
597 @Override
598 public String getTitle(){
599 return this.title;
600 }
601 /**
602 * @see #getTitle()
603 */
604 @Override
605 public void setTitle(String title){
606 this.title = StringUtils.isBlank(title)? null : title;
607 }
608
609 /**
610 * Returns the date (mostly only the year) of publication / creation of
611 * <i>this</i> reference.
612 */
613 @Override
614 public TimePeriod getDatePublished(){
615 return this.datePublished;
616 }
617 /**
618 * @see #getDatePublished()
619 */
620 @Override
621 public void setDatePublished(TimePeriod datePublished){
622 this.datePublished = datePublished;
623 }
624
625 public boolean hasDatePublished(){
626 boolean result = ! ( (this.datePublished == null) || StringUtils.isBlank(datePublished.toString()));
627 return result;
628 }
629
630 /**
631 * Returns the {@link eu.etaxonomy.cdm.model.agent.TeamOrPersonBase author (team)} who created the
632 * content of <i>this</i> reference.
633 *
634 * @return the author (team) of <i>this</i> reference
635 * @see eu.etaxonomy.cdm.model.agent.TeamOrPersonBase
636 */
637 @Override
638 public TeamOrPersonBase getAuthorship(){
639 return this.authorship;
640 }
641
642 /**
643 * @see #getAuthorship()
644 */
645 @Override
646 public void setAuthorship(TeamOrPersonBase authorship){
647 this.authorship = authorship;
648 }
649
650 /**
651 * Returns the Uniform Resource Identifier (URI) corresponding to <i>this</i>
652 * reference. An URI is a string of characters used to identify a resource
653 * on the Internet.
654 *
655 * @return the URI of <i>this</i> reference
656 */
657 @Override
658 public URI getUri(){
659 return this.uri;
660 }
661 /**
662 * @see #getUri()
663 */
664 @Override
665 public void setUri(URI uri){
666 this.uri = uri;
667 }
668
669 /**
670 * @return the referenceAbstract
671 */
672 @Override
673 public String getReferenceAbstract() {
674 return referenceAbstract;
675 }
676
677 /**
678 * @param referenceAbstract the referenceAbstract to set
679 */
680 @Override
681 public void setReferenceAbstract(String referenceAbstract) {
682 this.referenceAbstract = StringUtils.isBlank(referenceAbstract)? null : referenceAbstract;
683 }
684
685
686 /**
687 * Returns "true" if the isNomenclaturallyRelevant flag is set. This
688 * indicates that a {@link TaxonNameBase taxon name} has been originally
689 * published in <i>this</i> reference following the rules of a
690 * {@link eu.etaxonomy.cdm.model.name.NomenclaturalCode nomenclature code} and is therefore used for
691 * nomenclatural citations. This flag will be set as soon as <i>this</i>
692 * reference is used as a nomenclatural reference for any taxon name.<BR>
693 * FIXME what happens if the only taxon name referencing this reference is not
694 * any longer using this reference as a nomenclatural reference. How does the
695 * reference get informed about the fact that it is not nomenclaturally relevant
696 * anymore?
697 */
698 public boolean isNomenclaturallyRelevant(){
699 return this.nomenclaturallyRelevant;
700 }
701
702 /**
703 * @see #isNomenclaturallyRelevant()
704 */
705 public void setNomenclaturallyRelevant(boolean nomenclaturallyRelevant){
706 this.nomenclaturallyRelevant = nomenclaturallyRelevant;
707 }
708
709
710 //**************************************************** /
711
712
713 /**
714 * Returns a formatted string containing the entire reference citation,
715 * including authors, corresponding to <i>this</i> reference.
716 *
717 * @see #generateTitle()
718 */
719 // TODO implement
720 @Transient
721 public String getCitation(){
722 rectifyCacheStrategy();
723 if (getCacheStrategy() == null){
724 logger.warn("No CacheStrategy defined for "+ this.getClass() + ": " + this.getUuid());
725 return null;
726 }else{
727 return getCacheStrategy().getTitleCache(this);
728 }
729 }
730
731
732 @Override
733 public String generateTitle() {
734 rectifyCacheStrategy();
735 return super.generateTitle();
736 }
737
738 public String generateAbbrevTitle() {
739 rectifyCacheStrategy(); //TODO needed, is called by getCacheStrategy already
740 return getCacheStrategy().getFullAbbrevTitleString(this);
741 }
742
743 /**
744 * Returns a string representation for the year of publication / creation
745 * of <i>this</i> reference. If the {@link #getDatePublished() datePublished}
746 * of this reference contains more date information then (starting) year
747 * only the year is returned.
748 * than attribute.
749 */
750 @Override
751 @Transient
752 public String getYear(){
753 TimePeriod datePublished = this.getDatePublished();
754 if (datePublished != null ){
755 String result = getDatePublished().getYear();
756 return result;
757 }else{
758 return null;
759 }
760 }
761
762 /**
763 * Convenience method that returns a string representation for the publication date / creation
764 * of <i>this</i> reference. The string is obtained by
765 * {@link #getDatePublished()#toString() the string representation
766 * of the date published}.
767 */
768 @Transient
769 public String getDatePublishedString(){
770 TimePeriod datePublished = this.getDatePublished();
771 if (datePublished != null ){
772 return getDatePublished().toString();
773 }else{
774 return null;
775 }
776 }
777
778
779 @Override
780 public int getParsingProblem(){
781 return this.parsingProblem;
782 }
783
784 @Override
785 public void setParsingProblem(int parsingProblem){
786 this.parsingProblem = parsingProblem;
787 }
788
789 @Override
790 public boolean hasProblem(){
791 return parsingProblem != 0;
792 }
793
794 @Override
795 public boolean hasProblem(ParserProblem problem) {
796 return getParsingProblems().contains(problem);
797 }
798
799 @Override
800 public int getProblemStarts(){
801 return this.problemStarts;
802 }
803
804 @Override
805 public void setProblemStarts(int start) {
806 this.problemStarts = start;
807 }
808
809 @Override
810 public int getProblemEnds(){
811 return this.problemEnds;
812 }
813
814 @Override
815 public void setProblemEnds(int end) {
816 this.problemEnds = end;
817 }
818
819 @Override
820 public void addParsingProblem(ParserProblem warning){
821 parsingProblem = ParserProblem.addProblem(parsingProblem, warning);
822 }
823
824 @Override
825 public void removeParsingProblem(ParserProblem problem) {
826 parsingProblem = ParserProblem.removeProblem(parsingProblem, problem);
827 }
828
829 @Override
830 @Transient
831 public List<ParserProblem> getParsingProblems() {
832 return ParserProblem.warningList(this.parsingProblem);
833 }
834
835
836 @Override
837 @Transient
838 public String getNomenclaturalCitation(String microReference) {
839 rectifyCacheStrategy();
840 String typeName = this.getType()== null ? "(no type defined)" : this.getType().getMessage();
841 if (getCacheStrategy() == null){
842 logger.warn("No CacheStrategy defined for "+ typeName + ": " + this.getUuid());
843 return null;
844 }else{
845 if (getCacheStrategy() instanceof INomenclaturalReferenceCacheStrategy){
846 return ((INomenclaturalReferenceCacheStrategy)cacheStrategy).getNomenclaturalCitation(this, microReference);
847 }else {
848 logger.warn("No INomenclaturalReferenceCacheStrategy defined for "+ typeName + ": " + this.getUuid());
849 return null;
850 }
851 }
852 }
853
854
855 /**
856 * Generates, according to the {@link eu.etaxonomy.cdm.strategy.strategy.cache.reference.IReferenceBaseCacheStrategy cache strategy}
857 * assigned to <i>this</i> reference, a string that identifies <i>this</i>
858 * reference and returns it. This string may be stored in the inherited
859 * {@link eu.etaxonomy.cdm.model.common.IdentifiableEntity#getTitleCache() titleCache} attribute.<BR>
860 * This method overrides the generic and inherited generateTitle method
861 * from {@link eu.etaxonomy.cdm.model.common.IdentifiableEntity IdentifiableEntity}.
862 *
863 * @return the string identifying <i>this</i> reference
864 * @see #getCitation()
865 * @see eu.etaxonomy.cdm.model.common.IdentifiableEntity#getTitleCache()
866 * @see eu.etaxonomy.cdm.model.common.IdentifiableEntity#generateTitle()
867 * @see eu.etaxonomy.cdm.strategy.strategy.cache.common.IIdentifiableEntityCacheStrategy#getTitleCache()
868 */
869 // @Override
870 // public String generateTitle(){
871 // if (cacheStrategy == null){
872 // logger.warn("No CacheStrategy defined for Reference: " + this.getUuid());
873 // return null;
874 // }else{
875 // return cacheStrategy.getTitleCache(this);
876 // }
877 // }
878
879
880
881 //********** Casting methods ***********************************/
882
883 /**
884 * @return
885 */
886 public IArticle castReferenceToArticle(){
887 setType(ReferenceType.Article);
888 return this;
889 }
890
891 public IBook castReferenceToBook(){
892 setType(ReferenceType.Book);
893 return this;
894 }
895
896 public IBookSection castReferenceToBookSection(){
897 setType(ReferenceType.BookSection);
898 return this;
899 }
900
901 public ICdDvd castReferenceToCdDvd(){
902 setType(ReferenceType.CdDvd);
903 return this;
904 }
905
906 public IDatabase castReferenceToDatabase(){
907 setType(ReferenceType.Database);
908 return this;
909 }
910
911 public IGeneric castReferenceToGeneric(){
912 setType(ReferenceType.Generic);
913 return this;
914 }
915
916 public IInProceedings castReferenceToInProceedings(){
917 setType(ReferenceType.InProceedings);
918 return this;
919 }
920
921 public IJournal castReferenceToJournal(){
922 setType(ReferenceType.Journal);
923 return this;
924 }
925
926 public IMap castReferenceToMap(){
927 setType(ReferenceType.Map);
928 return (IMap) this;
929 }
930
931 public IPatent castReferenceToPatent(){
932 setType(ReferenceType.Patent);
933 return this;
934 }
935
936 public IPersonalCommunication castReferenceToPersonalCommunication(){
937 setType(ReferenceType.PersonalCommunication);
938 return this;
939 }
940
941 public IPrintSeries castReferenceToPrintSeries(){
942 setType(ReferenceType.PrintSeries);
943 return this;
944 }
945
946 public IWebPage castReferenceToWebPage(){
947 setType(ReferenceType.WebPage);
948 return this;
949 }
950
951 public IProceedings castReferenceToProceedings(){
952 setType(ReferenceType.Proceedings);
953 return this;
954 }
955
956 public IReport castReferenceToReport(){
957 setType(ReferenceType.Report);
958 return this;
959 }
960
961 public IThesis castReferenceToThesis(){
962 setType(ReferenceType.Thesis);
963 return this;
964 }
965
966
967 @Override
968 @Transient // prevent from being serialized by webservice
969 public IJournal getInJournal() {
970 IJournal journal = this.inReference;
971 return journal;
972 }
973
974 @Override
975 public void setInJournal(IJournal journal) {
976 this.inReference = (Reference)journal;
977
978 }
979
980 @Override
981 @Transient // prevent from being serialized by webservice
982 public IPrintSeries getInSeries() {
983 IPrintSeries printSeries = this.inReference;
984 return printSeries;
985 }
986
987 @Override
988 public void setInSeries(IPrintSeries inSeries) {
989 this.inReference = (Reference) inSeries;
990 }
991
992 @Override
993 @Transient // prevent from being serialized by webservice
994 public IBook getInBook() {
995 IBook book = this.inReference;
996 return book;
997 }
998
999 //********************** In-References *****************************************
1000
1001 @Override
1002 public void setInBook(IBook book) {
1003 this.inReference = (Reference) book;
1004 }
1005
1006 @Override
1007 @Transient // prevent from being serialized by webservice
1008 public IProceedings getInProceedings() {
1009 IProceedings proceedings = this.inReference;
1010 return proceedings;
1011 }
1012
1013 @Override
1014 public void setInProceedings(IProceedings proceeding) {
1015 this.inReference = (Reference) proceeding;
1016 }
1017
1018 //*************************** CACHE STRATEGIES ******************************/
1019
1020 @Override
1021 public IReferenceCacheStrategy getCacheStrategy() {
1022 rectifyCacheStrategy();
1023 return this.cacheStrategy;
1024 }
1025
1026 /**
1027 * The type property of this class is mapped on the field level to the data base column, so
1028 * Hibernate will consequently use the {@link org.hibernate.property.DirectPropertyAccessor}
1029 * to set the property. This PropertyAccessor directly sets the field instead of using the according setter so
1030 * the CacheStrategy is not correctly set after the initialization of the bean. Thus we need to
1031 * validate the CacheStrategy before it is to be used.
1032 */
1033 private void rectifyCacheStrategy() {
1034 if(!cacheStrategyRectified ){
1035 setType(getType());
1036 cacheStrategyRectified = true;
1037 }
1038 }
1039
1040
1041 @Override
1042 public void setCacheStrategy(IReferenceCacheStrategy iReferenceBaseCacheStrategy) {
1043 this.cacheStrategy = iReferenceBaseCacheStrategy;
1044
1045 }
1046
1047
1048
1049
1050 // @Override
1051 // protected void initListener(){
1052 // PropertyChangeListener listener = new PropertyChangeListener() {
1053 // @Override
1054 // public void propertyChange(PropertyChangeEvent e) {
1055 // boolean protectedByLowerCache = false;
1056 // //authorship cache
1057 // if (fieldHasCacheUpdateProperty(e.getPropertyName(), "authorshipCache")){
1058 // if (protectedAuthorshipCache){
1059 // protectedByLowerCache = true;
1060 // }else{
1061 // authorshipCache = null;
1062 // }
1063 // }
1064 //
1065 // //title cache
1066 // if (! fieldHasNoUpdateProperty(e.getPropertyName(), "titleCache")){
1067 // if (isProtectedTitleCache()|| protectedByLowerCache == true ){
1068 // protectedByLowerCache = true;
1069 // }else{
1070 // titleCache = null;
1071 // }
1072 // }
1073 // //full title cache
1074 // if (! fieldHasNoUpdateProperty(e.getPropertyName(), "fullTitleCache")){
1075 // if (isProtectedFullTitleCache()|| protectedByLowerCache == true ){
1076 // protectedByLowerCache = true;
1077 // }else{
1078 // fullTitleCache = null;
1079 // }
1080 // }
1081 // }
1082 // };
1083 // addPropertyChangeListener(listener); //didn't use this.addXXX to make lsid.AssemblerTest run in cdmlib-remote
1084 // }
1085
1086
1087 //*********************** CLONE ********************************************************/
1088
1089 /**
1090 * Clones <i>this</i> reference. This is a shortcut that enables to create
1091 * a new instance that differs only slightly from <i>this</i> reference by
1092 * modifying only some of the attributes.
1093 *
1094 * @see eu.etaxonomy.cdm.model.media.IdentifiableMediaEntity#clone()
1095 * @see java.lang.Object#clone()
1096 */
1097 @Override
1098 public Object clone() {
1099 try {
1100 Reference result = (Reference)super.clone();
1101 result.setDatePublished(datePublished != null? (TimePeriod)datePublished.clone(): null);
1102 //no changes to: title, authorship, hasProblem, nomenclaturallyRelevant, uri
1103 return result;
1104 } catch (CloneNotSupportedException e) {
1105 logger.warn("Object does not implement cloneable");
1106 e.printStackTrace();
1107 return null;
1108 }
1109 }
1110
1111 //******************************* toString *****************************/
1112
1113 @Override
1114 public String toString() {
1115 if (type != null){
1116 String result = "Reference [type=" + type + ", id= " + this.getId() + ", uuid=" + this.uuid ;
1117 result += title == null ? "" : ", title=" + title;
1118 result += abbrevTitle == null ? "" : ", abbrevTitle=" + abbrevTitle;
1119 result += "]";
1120 return result;
1121 }else{
1122 return super.toString();
1123 }
1124 }
1125
1126
1127
1128
1129 }
1130