2 * Copyright (C) 2007 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
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.
10 package eu
.etaxonomy
.cdm
.api
.facade
;
12 import java
.beans
.PropertyChangeEvent
;
13 import java
.beans
.PropertyChangeListener
;
14 import java
.text
.ParseException
;
15 import java
.util
.ArrayList
;
16 import java
.util
.HashMap
;
17 import java
.util
.HashSet
;
18 import java
.util
.List
;
22 import javax
.persistence
.Transient
;
24 import org
.apache
.log4j
.Logger
;
26 import eu
.etaxonomy
.cdm
.api
.service
.IOccurrenceService
;
27 import eu
.etaxonomy
.cdm
.model
.agent
.AgentBase
;
28 import eu
.etaxonomy
.cdm
.model
.agent
.Person
;
29 import eu
.etaxonomy
.cdm
.model
.common
.Annotation
;
30 import eu
.etaxonomy
.cdm
.model
.common
.CdmBase
;
31 import eu
.etaxonomy
.cdm
.model
.common
.IdentifiableSource
;
32 import eu
.etaxonomy
.cdm
.model
.common
.Language
;
33 import eu
.etaxonomy
.cdm
.model
.common
.LanguageString
;
34 import eu
.etaxonomy
.cdm
.model
.common
.TimePeriod
;
35 import eu
.etaxonomy
.cdm
.model
.description
.DescriptionElementBase
;
36 import eu
.etaxonomy
.cdm
.model
.description
.Feature
;
37 import eu
.etaxonomy
.cdm
.model
.description
.Sex
;
38 import eu
.etaxonomy
.cdm
.model
.description
.SpecimenDescription
;
39 import eu
.etaxonomy
.cdm
.model
.description
.Stage
;
40 import eu
.etaxonomy
.cdm
.model
.description
.TextData
;
41 import eu
.etaxonomy
.cdm
.model
.location
.NamedArea
;
42 import eu
.etaxonomy
.cdm
.model
.location
.Point
;
43 import eu
.etaxonomy
.cdm
.model
.location
.ReferenceSystem
;
44 import eu
.etaxonomy
.cdm
.model
.media
.Media
;
45 import eu
.etaxonomy
.cdm
.model
.name
.TaxonNameBase
;
46 import eu
.etaxonomy
.cdm
.model
.occurrence
.Collection
;
47 import eu
.etaxonomy
.cdm
.model
.occurrence
.DerivationEvent
;
48 import eu
.etaxonomy
.cdm
.model
.occurrence
.DerivedUnit
;
49 import eu
.etaxonomy
.cdm
.model
.occurrence
.DerivedUnitBase
;
50 import eu
.etaxonomy
.cdm
.model
.occurrence
.DeterminationEvent
;
51 import eu
.etaxonomy
.cdm
.model
.occurrence
.FieldObservation
;
52 import eu
.etaxonomy
.cdm
.model
.occurrence
.GatheringEvent
;
53 import eu
.etaxonomy
.cdm
.model
.occurrence
.PreservationMethod
;
54 import eu
.etaxonomy
.cdm
.model
.occurrence
.Specimen
;
55 import eu
.etaxonomy
.cdm
.model
.occurrence
.SpecimenOrObservationBase
;
56 import eu
.etaxonomy
.cdm
.model
.reference
.Reference
;
59 * This class is a facade to the eu.etaxonomy.cdm.model.occurrence package from
60 * a specimen based view. It does not support all functionality available in the
61 * occurrence package.<BR>
62 * The most significant restriction is that a specimen may derive only from one
63 * direct derivation event and there must be only one field observation
64 * (gathering event) it derives from.<BR>
69 public class DerivedUnitFacade
{
70 @SuppressWarnings("unused")
71 private static final Logger logger
= Logger
.getLogger(DerivedUnitFacade
.class);
73 private static final String notSupportMessage
= "A specimen facade not supported exception has occurred at a place where this should not have happened. The developer should implement not support check properly during class initialization ";
75 private static final boolean CREATE
= true;
76 private static final boolean CREATE_NOT
= false;
79 * Enum that defines the class the "Specimen" belongs to. Some methods of
80 * the facade are not available for certain classes and will throw an
81 * Exception when invoking them.
83 public enum DerivedUnitType
{
85 Observation("Observation"),
86 LivingBeing("Living Being"),
88 DerivedUnit("Derived Unit"),
89 //Field Observation is experimental, please handle with care (it is the only type which does not
90 //have a derivedUnit and therefore throws exceptions for all method on derivedUnit attributes
91 FieldObservation("FieldObservation");
93 String representation
;
95 private DerivedUnitType(String representation
) {
96 this.representation
= representation
;
100 * @return the representation
102 public String
getRepresentation() {
103 return representation
;
106 private DerivedUnitBase
getNewDerivedUnitInstance() {
107 if (this == DerivedUnitType
.Specimen
) {
108 return eu
.etaxonomy
.cdm
.model
.occurrence
.Specimen
.NewInstance();
109 } else if (this == DerivedUnitType
.Observation
) {
110 return eu
.etaxonomy
.cdm
.model
.occurrence
.Observation
.NewInstance();
111 } else if (this == DerivedUnitType
.LivingBeing
) {
112 return eu
.etaxonomy
.cdm
.model
.occurrence
.LivingBeing
.NewInstance();
113 } else if (this == DerivedUnitType
.Fossil
) {
114 return eu
.etaxonomy
.cdm
.model
.occurrence
.Fossil
.NewInstance();
115 } else if (this == DerivedUnitType
.DerivedUnit
) {
116 return eu
.etaxonomy
.cdm
.model
.occurrence
.DerivedUnit
.NewInstance();
117 } else if (this == DerivedUnitType
.FieldObservation
) {
120 String message
= "Unknown derived unit type %s";
121 message
= String
.format(message
, this.getRepresentation());
122 throw new IllegalStateException(message
);
126 public static DerivedUnitType
valueOf2(String type
) {
130 type
= type
.replace(" ", "").toLowerCase();
131 if (type
.equals("specimen")) {
133 } else if (type
.equals("livingbeing")) {
135 } else if (type
.equals("observation")) {
137 } else if (type
.equals("fossil")) {
139 } else if (type
.equals("fieldobservation")) {
140 return DerivedUnitType
.FieldObservation
;
141 } else if (type
.equals("unknown")) {
142 return DerivedUnitType
.DerivedUnit
;
143 } else if (type
.equals("derivedunit")) {
144 return DerivedUnitType
.DerivedUnit
;
149 public static DerivedUnitType
valueOf2(Class
<?
extends SpecimenOrObservationBase
> clazz
) {
153 if (clazz
.equals(Specimen
.class)) {
155 } else if (clazz
.equals(eu
.etaxonomy
.cdm
.model
.occurrence
.LivingBeing
.class)) {
157 } else if (clazz
.equals(eu
.etaxonomy
.cdm
.model
.occurrence
.Observation
.class)) {
159 } else if (clazz
.equals(eu
.etaxonomy
.cdm
.model
.occurrence
.Fossil
.class)) {
161 } else if (clazz
.equals(FieldObservation
.class)) {
162 return DerivedUnitType
.FieldObservation
;
163 } else if (clazz
.equals(DerivedUnit
.class)) {
164 return DerivedUnitType
.DerivedUnit
;
171 private final DerivedUnitFacadeConfigurator config
;
173 // private GatheringEvent gatheringEvent;
174 private DerivedUnitType type
; // needed?
176 private FieldObservation fieldObservation
;
178 private final DerivedUnitBase derivedUnit
;
180 // media - the text data holding the media
181 private TextData derivedUnitMediaTextData
;
182 private TextData fieldObjectMediaTextData
;
184 private TextData ecology
;
185 private TextData plantDescription
;
188 * Creates a derived unit facade for a new derived unit of type
194 public static DerivedUnitFacade
NewInstance(DerivedUnitType type
) {
195 return new DerivedUnitFacade(type
, null);
199 * Creates a derived unit facade for a new derived unit of type
205 public static DerivedUnitFacade
NewInstance(DerivedUnitType type
, FieldObservation fieldObservation
) {
206 return new DerivedUnitFacade(type
, fieldObservation
);
210 * Creates a derived unit facade for a given derived unit using the default
215 * @throws DerivedUnitFacadeNotSupportedException
217 public static DerivedUnitFacade
NewInstance(DerivedUnitBase derivedUnit
)
218 throws DerivedUnitFacadeNotSupportedException
{
219 return new DerivedUnitFacade(derivedUnit
, null);
222 public static DerivedUnitFacade
NewInstance(DerivedUnitBase derivedUnit
,
223 DerivedUnitFacadeConfigurator config
)
224 throws DerivedUnitFacadeNotSupportedException
{
225 return new DerivedUnitFacade(derivedUnit
, config
);
228 // ****************** CONSTRUCTOR ******************************************
230 private DerivedUnitFacade(DerivedUnitType type
, FieldObservation fieldObservation
) {
231 this.config
= DerivedUnitFacadeConfigurator
.NewInstance();
234 derivedUnit
= type
.getNewDerivedUnitInstance();
235 setFieldObservation(fieldObservation
);
236 if (derivedUnit
!= null){
239 setFieldObservationCacheStrategy();
243 private DerivedUnitFacade(DerivedUnitBase derivedUnit
,
244 DerivedUnitFacadeConfigurator config
)
245 throws DerivedUnitFacadeNotSupportedException
{
247 if (config
== null) {
248 config
= DerivedUnitFacadeConfigurator
.NewInstance();
250 this.config
= config
;
253 this.derivedUnit
= derivedUnit
;
254 this.type
= DerivedUnitType
.valueOf2(this.derivedUnit
.getClass());
257 if (this.derivedUnit
.getDerivedFrom() != null) {
258 DerivationEvent derivationEvent
= getDerivationEvent(CREATE
);
260 Set
<FieldObservation
> fieldOriginals
= getFieldObservationsOriginals(
261 derivationEvent
, null);
262 if (fieldOriginals
.size() > 1) {
263 throw new DerivedUnitFacadeNotSupportedException(
264 "Specimen must not have more than 1 derivation event");
265 } else if (fieldOriginals
.size() == 0) {
266 // fieldObservation = FieldObservation.NewInstance();
267 } else if (fieldOriginals
.size() == 1) {
268 fieldObservation
= fieldOriginals
.iterator().next();
269 // ###fieldObservation =
270 // getInitializedFieldObservation(fieldObservation);
272 .addPropertyChangeListener(getNewEventPropagationListener());
274 throw new IllegalStateException("Illegal state");
278 this.derivedUnitMediaTextData
= inititializeTextDataWithSupportTest(
279 Feature
.IMAGE(), this.derivedUnit
, false, true);
281 fieldObjectMediaTextData
= initializeFieldObjectTextDataWithSupportTest(
282 Feature
.IMAGE(), false, true);
284 // handle derivedUnit.getMedia()
285 if (derivedUnit
.getMedia().size() > 0) {
286 // TODO better changed model here to allow only one place for images
287 if (this.config
.isMoveDerivedUnitMediaToGallery()) {
288 Set
<Media
> mediaSet
= derivedUnit
.getMedia();
289 for (Media media
: mediaSet
) {
290 this.addDerivedUnitMedia(media
);
292 mediaSet
.removeAll(getDerivedUnitMedia());
294 throw new DerivedUnitFacadeNotSupportedException(
295 "Specimen may not have direct media. Only (one) image gallery is allowed");
299 // handle fieldObservation.getMedia()
300 if (fieldObservation
!= null && fieldObservation
.getMedia() != null
301 && fieldObservation
.getMedia().size() > 0) {
302 // TODO better changed model here to allow only one place for images
303 if (this.config
.isMoveFieldObjectMediaToGallery()) {
304 Set
<Media
> mediaSet
= fieldObservation
.getMedia();
305 for (Media media
: mediaSet
) {
306 this.addFieldObjectMedia(media
);
308 mediaSet
.removeAll(getFieldObjectMedia());
310 throw new DerivedUnitFacadeNotSupportedException(
311 "Field object may not have direct media. Only (one) image gallery is allowed");
315 // test if descriptions are supported
316 ecology
= initializeFieldObjectTextDataWithSupportTest(
317 Feature
.ECOLOGY(), false, false);
318 plantDescription
= initializeFieldObjectTextDataWithSupportTest(
319 Feature
.DESCRIPTION(), false, false);
325 private DerivedUnitBase
getInitializedDerivedUnit(
326 DerivedUnitBase derivedUnit
) {
327 IOccurrenceService occurrenceService
= this.config
328 .getOccurrenceService();
329 if (occurrenceService
== null) {
332 List
<String
> propertyPaths
= this.config
.getPropertyPaths();
333 if (propertyPaths
== null) {
336 propertyPaths
= getDerivedUnitPropertyPaths(propertyPaths
);
337 DerivedUnitBase result
= (DerivedUnitBase
) occurrenceService
.load(
338 derivedUnit
.getUuid(), propertyPaths
);
343 * Initializes the derived unit according to the configuartions property
344 * path. If the property path is <code>null</code> or no occurrence service
345 * is given the returned object is the same as the input parameter.
347 * @param fieldObservation2
350 private FieldObservation
getInitializedFieldObservation(
351 FieldObservation fieldObservation
) {
352 IOccurrenceService occurrenceService
= this.config
353 .getOccurrenceService();
354 if (occurrenceService
== null) {
355 return fieldObservation
;
357 List
<String
> propertyPaths
= this.config
.getPropertyPaths();
358 if (propertyPaths
== null) {
359 return fieldObservation
;
361 propertyPaths
= getFieldObjectPropertyPaths(propertyPaths
);
362 FieldObservation result
= (FieldObservation
) occurrenceService
.load(
363 fieldObservation
.getUuid(), propertyPaths
);
368 * Transforms the property paths in a way that the facade is handled just
369 * like an ordinary CdmBase object.<BR>
370 * E.g. a property path "collectinAreas" will be translated into
371 * gatheringEvent.collectingAreas
373 * @param propertyPaths
376 private List
<String
> getFieldObjectPropertyPaths(List
<String
> propertyPaths
) {
377 List
<String
> result
= new ArrayList
<String
>();
378 for (String facadePath
: propertyPaths
) {
379 // collecting areas (named area)
380 if (facadePath
.startsWith("collectingAreas")) {
381 facadePath
= "gatheringEvent." + facadePath
;
382 result
.add(facadePath
);
384 // collector (agentBase)
385 else if (facadePath
.startsWith("collector")) {
386 facadePath
= facadePath
.replace("collector",
387 "gatheringEvent.actor");
388 result
.add(facadePath
);
390 // exactLocation (agentBase)
391 else if (facadePath
.startsWith("exactLocation")) {
392 facadePath
= "gatheringEvent." + facadePath
;
393 result
.add(facadePath
);
395 // gatheringPeriod (TimePeriod)
396 else if (facadePath
.startsWith("gatheringPeriod")) {
397 facadePath
= facadePath
.replace("gatheringPeriod",
398 "gatheringEvent.timeperiod");
399 result
.add(facadePath
);
401 // (locality/ localityLanguage , LanguageString)
402 else if (facadePath
.startsWith("locality")) {
403 facadePath
= "gatheringEvent." + facadePath
;
404 result
.add(facadePath
);
407 // *********** FIELD OBJECT ************
408 // fieldObjectDefinitions (Map<language, languageString)
409 else if (facadePath
.startsWith("fieldObjectDefinitions")) {
410 // TODO or definition ???
411 facadePath
= facadePath
.replace("fieldObjectDefinitions",
413 result
.add(facadePath
);
415 // fieldObjectMedia (Media)
416 else if (facadePath
.startsWith("fieldObjectMedia")) {
418 facadePath
= facadePath
.replace("fieldObjectMedia",
419 "descriptions.elements.media");
420 result
.add(facadePath
);
423 // Gathering Event will always be added
424 result
.add("gatheringEvent");
429 * Gathering Event ==================== - gatheringEvent
432 * Field Object ================= - ecology/ ecologyAll (String) ??? -
433 * plant description (like ecology)
435 * - fieldObjectImageGallery (SpecimenDescription) - is automatically
436 * initialized via fieldObjectMedia
443 * Transforms the property paths in a way that the facade is handled just
444 * like an ordinary CdmBase object.<BR>
445 * E.g. a property path "collectinAreas" will be translated into
446 * gatheringEvent.collectingAreas
448 * Not needed (?) as the facade works with REST service property paths
449 * without using this method.
451 * @param propertyPaths
454 private List
<String
> getDerivedUnitPropertyPaths(List
<String
> propertyPaths
) {
455 List
<String
> result
= new ArrayList
<String
>();
456 for (String facadePath
: propertyPaths
) {
457 // determinations (DeterminationEvent)
458 if (facadePath
.startsWith("determinations")) {
459 facadePath
= "" + facadePath
; // no change
460 result
.add(facadePath
);
462 // storedUnder (TaxonNameBase)
463 else if (facadePath
.startsWith("storedUnder")) {
464 facadePath
= "" + facadePath
; // no change
465 result
.add(facadePath
);
467 // sources (IdentifiableSource)
468 else if (facadePath
.startsWith("sources")) {
469 facadePath
= "" + facadePath
; // no change
470 result
.add(facadePath
);
472 // collection (Collection)
473 else if (facadePath
.startsWith("collection")) {
474 facadePath
= "" + facadePath
; // no change
475 result
.add(facadePath
);
477 // (locality/ localityLanguage , LanguageString)
478 else if (facadePath
.startsWith("locality")) {
479 facadePath
= "gatheringEvent." + facadePath
;
480 result
.add(facadePath
);
483 // *********** FIELD OBJECT ************
484 // derivedUnitDefinitions (Map<language, languageString)
485 else if (facadePath
.startsWith("derivedUnitDefinitions")) {
486 // TODO or definition ???
487 facadePath
= facadePath
.replace("derivedUnitDefinitions",
489 result
.add(facadePath
);
492 // derivedUnitMedia (Media)
493 else if (facadePath
.startsWith("derivedUnitMedia")) {
495 facadePath
= facadePath
.replace("derivedUnitMedia",
496 "descriptions.elements.media");
497 result
.add(facadePath
);
503 * //TODO Derived Unit =====================
505 * - derivedUnitImageGallery (SpecimenDescription) - is automatically
506 * initialized via derivedUnitMedia
508 * - derivationEvent (DerivationEvent) - will always be initialized -
509 * duplicates (??? Specimen???) ???
518 private void setCacheStrategy() {
519 if (derivedUnit
== null) {
520 throw new NullPointerException(
521 "Facade's derviedUnit must not be null to set cache strategy");
523 derivedUnit
.setCacheStrategy(new DerivedUnitFacadeCacheStrategy());
524 setFieldObservationCacheStrategy();
528 private void setFieldObservationCacheStrategy() {
529 if (this.hasFieldObject()){
530 DerivedUnitFacadeFieldObservationCacheStrategy strategy
= new DerivedUnitFacadeFieldObservationCacheStrategy();
531 this.fieldObservation
.setCacheStrategy(strategy
);
537 * @param createIfNotExists
538 * @param isImageGallery
540 * @throws DerivedUnitFacadeNotSupportedException
542 private TextData
initializeFieldObjectTextDataWithSupportTest(
543 Feature feature
, boolean createIfNotExists
, boolean isImageGallery
)
544 throws DerivedUnitFacadeNotSupportedException
{
546 FieldObservation fieldObject
= getFieldObservation(createIfNotExists
);
547 if (fieldObject
== null) {
550 return inititializeTextDataWithSupportTest(feature
, fieldObject
,
551 createIfNotExists
, isImageGallery
);
557 * @param createIfNotExists
558 * @param isImageGallery
560 * @throws DerivedUnitFacadeNotSupportedException
562 private TextData
inititializeTextDataWithSupportTest(Feature feature
,
563 SpecimenOrObservationBase specimen
, boolean createIfNotExists
,
564 boolean isImageGallery
)
565 throws DerivedUnitFacadeNotSupportedException
{
566 if (feature
== null) {
569 TextData textData
= null;
570 if (createIfNotExists
) {
571 textData
= TextData
.NewInstance(feature
);
574 Set
<SpecimenDescription
> descriptions
;
575 if (isImageGallery
) {
576 descriptions
= specimen
.getSpecimenDescriptionImageGallery();
578 descriptions
= specimen
.getSpecimenDescriptions(false);
580 // no description exists yet for this specimen
581 if (descriptions
.size() == 0) {
582 if (createIfNotExists
) {
583 SpecimenDescription newSpecimenDescription
= SpecimenDescription
584 .NewInstance(specimen
);
585 newSpecimenDescription
.addElement(textData
);
586 newSpecimenDescription
.setImageGallery(isImageGallery
);
592 // description already exists
593 Set
<DescriptionElementBase
> existingTextData
= new HashSet
<DescriptionElementBase
>();
594 for (SpecimenDescription description
: descriptions
) {
595 // collect all existing text data
596 for (DescriptionElementBase element
: description
.getElements()) {
597 if (element
.isInstanceOf(TextData
.class)
598 && (feature
.equals(element
.getFeature()) || isImageGallery
)) {
599 existingTextData
.add(element
);
603 // use existing text data if exactly one exists
604 if (existingTextData
.size() > 1) {
605 throw new DerivedUnitFacadeNotSupportedException(
606 "Specimen facade does not support more than one description text data of type "
607 + feature
.getLabel());
609 } else if (existingTextData
.size() == 1) {
610 return CdmBase
.deproxy(existingTextData
.iterator().next(),
613 if (createIfNotExists
) {
614 SpecimenDescription description
= descriptions
.iterator()
616 description
.addElement(textData
);
623 * Tests if a given image gallery is supported by the derived unit facade.
624 * It returns the only text data attached to the given image gallery. If the
625 * given image gallery does not have text data attached, it is created and
628 * @param imageGallery
630 * @throws DerivedUnitFacadeNotSupportedException
632 private TextData
testImageGallery(SpecimenDescription imageGallery
)
633 throws DerivedUnitFacadeNotSupportedException
{
634 if (imageGallery
.isImageGallery() == false) {
635 throw new DerivedUnitFacadeNotSupportedException(
636 "Image gallery needs to have image gallery flag set");
638 if (imageGallery
.getElements().size() > 1) {
639 throw new DerivedUnitFacadeNotSupportedException(
640 "Image gallery must not have more then one description element");
643 if (imageGallery
.getElements().size() == 0) {
644 textData
= TextData
.NewInstance(Feature
.IMAGE());
645 imageGallery
.addElement(textData
);
647 if (!imageGallery
.getElements().iterator().next()
648 .isInstanceOf(TextData
.class)) {
649 throw new DerivedUnitFacadeNotSupportedException(
650 "Image gallery must only have TextData as element");
652 textData
= CdmBase
.deproxy(imageGallery
.getElements()
653 .iterator().next(), TextData
.class);
659 // ************************** METHODS
660 // *****************************************
662 private TextData
getDerivedUnitImageGalleryTextData(
663 boolean createIfNotExists
)
664 throws DerivedUnitFacadeNotSupportedException
{
665 if (this.derivedUnitMediaTextData
== null && createIfNotExists
) {
666 this.derivedUnitMediaTextData
= getImageGalleryTextData(
667 derivedUnit
, "Specimen");
669 return this.derivedUnitMediaTextData
;
672 private TextData
getObservationImageGalleryTextData(
673 boolean createIfNotExists
)
674 throws DerivedUnitFacadeNotSupportedException
{
675 if (this.fieldObjectMediaTextData
== null && createIfNotExists
) {
676 this.fieldObjectMediaTextData
= getImageGalleryTextData(
677 fieldObservation
, "Field observation");
679 return this.fieldObjectMediaTextData
;
683 * @param derivationEvent2
685 * @throws DerivedUnitFacadeNotSupportedException
687 private Set
<FieldObservation
> getFieldObservationsOriginals(
688 DerivationEvent derivationEvent
,
689 Set
<SpecimenOrObservationBase
> recursionAvoidSet
)
690 throws DerivedUnitFacadeNotSupportedException
{
691 if (recursionAvoidSet
== null) {
692 recursionAvoidSet
= new HashSet
<SpecimenOrObservationBase
>();
694 Set
<FieldObservation
> result
= new HashSet
<FieldObservation
>();
695 Set
<SpecimenOrObservationBase
> originals
= derivationEvent
697 for (SpecimenOrObservationBase original
: originals
) {
698 if (original
.isInstanceOf(FieldObservation
.class)) {
699 result
.add(CdmBase
.deproxy(original
, FieldObservation
.class));
700 } else if (original
.isInstanceOf(DerivedUnitBase
.class)) {
701 // if specimen has already been tested exclude it from further
703 if (recursionAvoidSet
.contains(original
)) {
706 DerivedUnitBase derivedUnit
= CdmBase
.deproxy(original
,
707 DerivedUnitBase
.class);
708 DerivationEvent originalDerivation
= derivedUnit
710 // Set<DerivationEvent> derivationEvents =
711 // original.getDerivationEvents();
712 // for (DerivationEvent originalDerivation : derivationEvents){
713 Set
<FieldObservation
> fieldObservations
= getFieldObservationsOriginals(
714 originalDerivation
, recursionAvoidSet
);
715 result
.addAll(fieldObservations
);
718 throw new DerivedUnitFacadeNotSupportedException(
719 "Unhandled specimen or observation base type: "
720 + original
.getClass().getName());
727 // *********** MEDIA METHODS ******************************
730 // * Returns the media list for a specimen. Throws an exception if the
731 // existing specimen descriptions
732 // * are not supported by this facade.
733 // * @param specimen the specimen the media belongs to
734 // * @param specimenExceptionText text describing the specimen for exception
737 // * @throws DerivedUnitFacadeNotSupportedException
739 // private List<Media> getImageGalleryMedia(SpecimenOrObservationBase
740 // specimen, String specimenExceptionText) throws
741 // DerivedUnitFacadeNotSupportedException{
742 // List<Media> result;
743 // SpecimenDescription imageGallery =
744 // getImageGalleryWithSupportTest(specimen, specimenExceptionText, true);
745 // TextData textData = getImageTextDataWithSupportTest(imageGallery,
746 // specimenExceptionText);
747 // result = textData.getMedia();
752 * Returns the media list for a specimen. Throws an exception if the
753 * existing specimen descriptions are not supported by this facade.
756 * the specimen the media belongs to
757 * @param specimenExceptionText
758 * text describing the specimen for exception messages
760 * @throws DerivedUnitFacadeNotSupportedException
762 private TextData
getImageGalleryTextData(SpecimenOrObservationBase specimen
, String specimenExceptionText
)
763 throws DerivedUnitFacadeNotSupportedException
{
765 SpecimenDescription imageGallery
= getImageGalleryWithSupportTest(
766 specimen
, specimenExceptionText
, true);
767 result
= getImageTextDataWithSupportTest(imageGallery
,
768 specimenExceptionText
);
773 * Returns the image gallery of the according specimen. Throws an exception
774 * if the attached image gallerie(s) are not supported by this facade. If no
775 * image gallery exists a new one is created if
776 * <code>createNewIfNotExists</code> is true and if specimen is not
780 * @param specimenText
781 * @param createNewIfNotExists
783 * @throws DerivedUnitFacadeNotSupportedException
785 private SpecimenDescription
getImageGalleryWithSupportTest(
786 SpecimenOrObservationBase
<?
> specimen
, String specimenText
,
787 boolean createNewIfNotExists
)
788 throws DerivedUnitFacadeNotSupportedException
{
789 if (specimen
== null) {
792 SpecimenDescription imageGallery
;
793 if (hasMultipleImageGalleries(specimen
)) {
794 throw new DerivedUnitFacadeNotSupportedException(specimenText
795 + " must not have more than 1 image gallery");
797 imageGallery
= getImageGallery(specimen
, createNewIfNotExists
);
798 getImageTextDataWithSupportTest(imageGallery
, specimenText
);
804 * Returns the media holding text data element of the image gallery. Throws
805 * an exception if multiple such text data already exist. Creates a new text
806 * data if none exists and adds it to the image gallery. If image gallery is
807 * <code>null</code> nothing happens.
809 * @param imageGallery
812 * @throws DerivedUnitFacadeNotSupportedException
814 private TextData
getImageTextDataWithSupportTest(
815 SpecimenDescription imageGallery
, String specimenText
)
816 throws DerivedUnitFacadeNotSupportedException
{
817 if (imageGallery
== null) {
820 TextData textData
= null;
821 for (DescriptionElementBase element
: imageGallery
.getElements()) {
822 if (element
.isInstanceOf(TextData
.class)
823 && element
.getFeature().equals(Feature
.IMAGE())) {
824 if (textData
!= null) {
825 throw new DerivedUnitFacadeNotSupportedException(
827 + " must not have more than 1 image text data element in image gallery");
829 textData
= CdmBase
.deproxy(element
, TextData
.class);
832 if (textData
== null) {
833 textData
= TextData
.NewInstance(Feature
.IMAGE());
834 imageGallery
.addElement(textData
);
840 * Checks, if a specimen belongs to more than one description that is an
846 private boolean hasMultipleImageGalleries(
847 SpecimenOrObservationBase
<?
> derivedUnit
) {
849 Set
<SpecimenDescription
> descriptions
= derivedUnit
850 .getSpecimenDescriptions();
851 for (SpecimenDescription description
: descriptions
) {
852 if (description
.isImageGallery()) {
860 * Returns the image gallery for a specimen. If there are multiple specimen
861 * descriptions marked as image galleries an arbitrary one is chosen. If no
862 * image gallery exists, a new one is created if
863 * <code>createNewIfNotExists</code> is <code>true</code>.<Br>
864 * If specimen is <code>null</code> a null pointer exception is thrown.
866 * @param createNewIfNotExists
869 private SpecimenDescription
getImageGallery(SpecimenOrObservationBase
<?
> specimen
, boolean createIfNotExists
) {
870 SpecimenDescription result
= null;
871 Set
<SpecimenDescription
> descriptions
= specimen
.getSpecimenDescriptions();
872 for (SpecimenDescription description
: descriptions
) {
873 if (description
.isImageGallery()) {
874 result
= description
;
878 if (result
== null && createIfNotExists
) {
879 result
= SpecimenDescription
.NewInstance(specimen
);
880 result
.setImageGallery(true);
886 * Adds a media to the specimens image gallery. If media is
887 * <code>null</code> nothing happens.
891 * @return true if media is not null (as specified by
892 * {@link java.util.Collection#add(Object) Collection.add(E e)}
893 * @throws DerivedUnitFacadeNotSupportedException
895 private boolean addMedia(Media media
, SpecimenOrObservationBase
<?
> specimen
)
896 throws DerivedUnitFacadeNotSupportedException
{
898 List
<Media
> mediaList
= getMedia(specimen
, true);
899 return mediaList
.add(media
);
906 * Removes a media from the specimens image gallery.
910 * @return true if an element was removed as a result of this call (as
911 * specified by {@link java.util.Collection#remove(Object)
912 * Collection.remove(E e)}
913 * @throws DerivedUnitFacadeNotSupportedException
915 private boolean removeMedia(Media media
,
916 SpecimenOrObservationBase
<?
> specimen
)
917 throws DerivedUnitFacadeNotSupportedException
{
918 List
<Media
> mediaList
= getMedia(specimen
, true);
919 return mediaList
== null ?
null : mediaList
.remove(media
);
922 private List
<Media
> getMedia(SpecimenOrObservationBase
<?
> specimen
,
923 boolean createIfNotExists
)
924 throws DerivedUnitFacadeNotSupportedException
{
925 TextData textData
= getMediaTextData(specimen
, createIfNotExists
);
926 return textData
== null ?
null : textData
.getMedia();
930 * Returns the one media list of a specimen which is part of the only image
931 * gallery that this specimen is part of.<BR>
932 * If these conditions are not hold an exception is thrwon.
936 * @throws DerivedUnitFacadeNotSupportedException
938 // private List<Media> getMedia(SpecimenOrObservationBase<?> specimen)
939 // throws DerivedUnitFacadeNotSupportedException {
940 // if (specimen == null){
943 // if (specimen == this.derivedUnit){
944 // return getDerivedUnitImageGalleryMedia();
945 // }else if (specimen == this.fieldObservation){
946 // return getObservationImageGalleryTextData();
948 // return getImageGalleryMedia(specimen, "Undefined specimen ");
953 * Returns the one media list of a specimen which is part of the only image
954 * gallery that this specimen is part of.<BR>
955 * If these conditions are not hold an exception is thrwon.
959 * @throws DerivedUnitFacadeNotSupportedException
961 private TextData
getMediaTextData(SpecimenOrObservationBase
<?
> specimen
,
962 boolean createIfNotExists
)
963 throws DerivedUnitFacadeNotSupportedException
{
964 if (specimen
== null) {
967 if (specimen
== this.derivedUnit
) {
968 return getDerivedUnitImageGalleryTextData(createIfNotExists
);
969 } else if (specimen
== this.fieldObservation
) {
970 return getObservationImageGalleryTextData(createIfNotExists
);
972 return getImageGalleryTextData(specimen
, "Undefined specimen ");
976 // ****************** GETTER / SETTER / ADDER / REMOVER
977 // ***********************/
979 // ****************** Gathering Event *********************************/
983 public NamedArea
getCountry() {
984 return (hasGatheringEvent() ?
getGatheringEvent(true).getCountry()
988 public void setCountry(NamedArea country
) {
989 getGatheringEvent(true).setCountry(country
);
993 public void addCollectingArea(NamedArea area
) {
994 getGatheringEvent(true).addCollectingArea(area
);
997 public void addCollectingAreas(java
.util
.Collection
<NamedArea
> areas
) {
998 for (NamedArea area
: areas
) {
999 getGatheringEvent(true).addCollectingArea(area
);
1004 public Set
<NamedArea
> getCollectingAreas() {
1005 return (hasGatheringEvent() ?
getGatheringEvent(true)
1006 .getCollectingAreas() : null);
1009 public void removeCollectingArea(NamedArea area
) {
1010 if (hasGatheringEvent()) {
1011 getGatheringEvent(true).removeCollectingArea(area
);
1015 // absolute elevation
1017 * meter above/below sea level of the surface
1019 * @see #getAbsoluteElevationError()
1020 * @see #getAbsoluteElevationRange()
1023 public Integer
getAbsoluteElevation() {
1024 return (hasGatheringEvent() ?
getGatheringEvent(true)
1025 .getAbsoluteElevation() : null);
1028 public void setAbsoluteElevation(Integer absoluteElevation
) {
1029 getGatheringEvent(true).setAbsoluteElevation(absoluteElevation
);
1032 // absolute elevation error
1034 public Integer
getAbsoluteElevationError() {
1035 return (hasGatheringEvent() ?
getGatheringEvent(true)
1036 .getAbsoluteElevationError() : null);
1039 public void setAbsoluteElevationError(Integer absoluteElevationError
) {
1040 getGatheringEvent(true).setAbsoluteElevationError(
1041 absoluteElevationError
);
1045 * @see #getAbsoluteElevation()
1046 * @see #getAbsoluteElevationError()
1047 * @see #setAbsoluteElevationRange(Integer, Integer)
1048 * @see #getAbsoluteElevationMaximum()
1051 public Integer
getAbsoluteElevationMinimum() {
1052 if (!hasGatheringEvent()) {
1055 Integer minimum
= getGatheringEvent(true).getAbsoluteElevation();
1056 if (getGatheringEvent(true).getAbsoluteElevationError() != null) {
1058 - getGatheringEvent(true).getAbsoluteElevationError();
1064 * @see #getAbsoluteElevation()
1065 * @see #getAbsoluteElevationError()
1066 * @see #setAbsoluteElevationRange(Integer, Integer)
1067 * @see #getAbsoluteElevationMinimum()
1070 public Integer
getAbsoluteElevationMaximum() {
1071 if (!hasGatheringEvent()) {
1074 Integer maximum
= getGatheringEvent(true).getAbsoluteElevation();
1075 if (getGatheringEvent(true).getAbsoluteElevationError() != null) {
1077 + getGatheringEvent(true).getAbsoluteElevationError();
1083 * This method replaces absoluteElevation and absoulteElevationError by
1084 * internally translating minimum and maximum values into average and error
1085 * values. As all these values are integer based it is necessary that the
1086 * distance is between minimum and maximum is <b>even</b>, otherwise we will
1087 * get a rounding error resulting in a maximum that is increased by 1.
1089 * @see #setAbsoluteElevation(Integer)
1090 * @see #setAbsoluteElevationError(Integer)
1091 * @param minimumElevation
1092 * minimum of the range
1093 * @param maximumElevation
1094 * maximum of the range
1095 * @throws IllegalArgumentException
1097 public void setAbsoluteElevationRange(Integer minimumElevation
, Integer maximumElevation
) throws IllegalArgumentException
{
1098 if (minimumElevation
== null || maximumElevation
== null) {
1099 Integer elevation
= minimumElevation
;
1101 if (minimumElevation
== null) {
1102 elevation
= maximumElevation
;
1103 if (elevation
== null) {
1107 getGatheringEvent(true).setAbsoluteElevation(elevation
);
1108 getGatheringEvent(true).setAbsoluteElevationError(error
);
1110 if (!isEvenDistance(minimumElevation
, maximumElevation
)) {
1111 throw new IllegalArgumentException(
1112 "Distance between minimum and maximum elevation must be even but was "
1113 + Math
.abs(minimumElevation
- maximumElevation
));
1115 Integer absoluteElevationError
= Math
.abs(maximumElevation
1116 - minimumElevation
);
1117 absoluteElevationError
= absoluteElevationError
/ 2;
1118 Integer absoluteElevation
= minimumElevation
1119 + absoluteElevationError
;
1120 getGatheringEvent(true).setAbsoluteElevation(absoluteElevation
);
1121 getGatheringEvent(true).setAbsoluteElevationError(
1122 absoluteElevationError
);
1127 * @param minimumElevation
1128 * @param maximumElevation
1131 public boolean isEvenDistance(Integer minimumElevation
,
1132 Integer maximumElevation
) {
1133 Integer diff
= (maximumElevation
- minimumElevation
);
1134 return diff
% 2 == 0;
1139 public AgentBase
getCollector() {
1140 return (hasGatheringEvent() ?
getGatheringEvent(true).getCollector()
1144 public void setCollector(AgentBase collector
) {
1145 getGatheringEvent(true).setCollector(collector
);
1148 // collecting method
1150 public String
getCollectingMethod() {
1151 return (hasGatheringEvent() ?
getGatheringEvent(true)
1152 .getCollectingMethod() : null);
1155 public void setCollectingMethod(String collectingMethod
) {
1156 getGatheringEvent(true).setCollectingMethod(collectingMethod
);
1159 // distance to ground
1161 public Integer
getDistanceToGround() {
1162 return (hasGatheringEvent() ?
getGatheringEvent(true)
1163 .getDistanceToGround() : null);
1166 public void setDistanceToGround(Integer distanceToGround
) {
1167 getGatheringEvent(true).setDistanceToGround(distanceToGround
);
1170 // distance to water surface
1172 public Integer
getDistanceToWaterSurface() {
1173 return (hasGatheringEvent() ?
getGatheringEvent(true)
1174 .getDistanceToWaterSurface() : null);
1177 public void setDistanceToWaterSurface(Integer distanceToWaterSurface
) {
1178 getGatheringEvent(true).setDistanceToWaterSurface(
1179 distanceToWaterSurface
);
1184 public Point
getExactLocation() {
1185 return (hasGatheringEvent() ?
getGatheringEvent(true)
1186 .getExactLocation() : null);
1190 * Returns a sexagesimal representation of the exact location (e.g.
1191 * 12°59'N, 35°23E). If the exact location is <code>null</code> the empty
1192 * string is returned.
1194 * @param includeEmptySeconds
1195 * @param includeReferenceSystem
1198 public String
getExactLocationText(boolean includeEmptySeconds
,
1199 boolean includeReferenceSystem
) {
1200 return (this.getExactLocation() == null ?
"" : this.getExactLocation()
1201 .toSexagesimalString(includeEmptySeconds
,
1202 includeReferenceSystem
));
1205 public void setExactLocation(Point exactLocation
) {
1206 getGatheringEvent(true).setExactLocation(exactLocation
);
1209 public void setExactLocationByParsing(String longitudeToParse
,
1210 String latitudeToParse
, ReferenceSystem referenceSystem
,
1211 Integer errorRadius
) throws ParseException
{
1212 Point point
= Point
.NewInstance(null, null, referenceSystem
,
1214 point
.setLongitudeByParsing(longitudeToParse
);
1215 point
.setLatitudeByParsing(latitudeToParse
);
1216 setExactLocation(point
);
1219 // gathering event description
1221 public String
getGatheringEventDescription() {
1222 return (hasGatheringEvent() ?
getGatheringEvent(true).getDescription()
1226 public void setGatheringEventDescription(String description
) {
1227 getGatheringEvent(true).setDescription(description
);
1232 public TimePeriod
getGatheringPeriod() {
1233 return (hasGatheringEvent() ?
getGatheringEvent(true).getTimeperiod()
1237 public void setGatheringPeriod(TimePeriod timeperiod
) {
1238 getGatheringEvent(true).setTimeperiod(timeperiod
);
1243 public LanguageString
getLocality() {
1244 return (hasGatheringEvent() ?
getGatheringEvent(true).getLocality()
1249 * convienience method for {@link #getLocality()}.
1250 * {@link LanguageString#getText() getText()}
1255 public String
getLocalityText() {
1256 LanguageString locality
= getLocality();
1257 if (locality
!= null) {
1258 return locality
.getText();
1264 * convienience method for {@link #getLocality()}.
1265 * {@link LanguageString#getLanguage() getLanguage()}
1270 public Language
getLocalityLanguage() {
1271 LanguageString locality
= getLocality();
1272 if (locality
!= null) {
1273 return locality
.getLanguage();
1279 * Sets the locality string in the default language
1283 public void setLocality(String locality
) {
1284 Language language
= Language
.DEFAULT();
1285 setLocality(locality
, language
);
1288 public void setLocality(String locality
, Language language
) {
1289 LanguageString langString
= LanguageString
.NewInstance(locality
,
1291 setLocality(langString
);
1294 public void setLocality(LanguageString locality
) {
1295 getGatheringEvent(true).setLocality(locality
);
1299 * The gathering event will be used for the field object instead of the old
1300 * gathering event.<BR>
1301 * <B>This method will override all gathering values (see below).</B>
1303 * @see #getAbsoluteElevation()
1304 * @see #getAbsoluteElevationError()
1305 * @see #getDistanceToGround()
1306 * @see #getDistanceToWaterSurface()
1307 * @see #getExactLocation()
1308 * @see #getGatheringEventDescription()
1309 * @see #getGatheringPeriod()
1310 * @see #getCollectingAreas()
1311 * @see #getCollectingMethod()
1312 * @see #getLocality()
1313 * @see #getCollector()
1314 * @param gatheringEvent
1316 public void setGatheringEvent(GatheringEvent gatheringEvent
) {
1317 getFieldObservation(true).setGatheringEvent(gatheringEvent
);
1320 public boolean hasGatheringEvent() {
1321 return (getGatheringEvent(false) != null);
1324 public GatheringEvent
innerGatheringEvent() {
1325 return getGatheringEvent(false);
1328 public GatheringEvent
getGatheringEvent(boolean createIfNotExists
) {
1329 if (!hasFieldObservation() && !createIfNotExists
) {
1332 if (createIfNotExists
1333 && getFieldObservation(true).getGatheringEvent() == null) {
1334 GatheringEvent gatheringEvent
= GatheringEvent
.NewInstance();
1335 getFieldObservation(true).setGatheringEvent(gatheringEvent
);
1337 return getFieldObservation(true).getGatheringEvent();
1340 // ****************** Field Object ************************************/
1343 * Returns true if a field observation exists (even if all attributes are
1344 * empty or <code>null<code>.
1348 public boolean hasFieldObject() {
1349 return this.fieldObservation
!= null;
1354 public String
getEcology() {
1355 return getEcology(Language
.DEFAULT());
1358 public String
getEcology(Language language
) {
1359 LanguageString languageString
= getEcologyAll().get(language
);
1360 return (languageString
== null ?
null : languageString
.getText());
1363 // public String getEcologyPreferred(List<Language> languages){
1364 // LanguageString languageString =
1365 // getEcologyAll().getPreferredLanguageString(languages);
1366 // return languageString.getText();
1369 * Returns a copy of the multilanguage text holding the ecology data.
1371 * @see {@link TextData#getMultilanguageText()}
1375 public Map
<Language
, LanguageString
> getEcologyAll() {
1376 if (ecology
== null) {
1378 ecology
= initializeFieldObjectTextDataWithSupportTest(
1379 Feature
.ECOLOGY(), false, false);
1380 } catch (DerivedUnitFacadeNotSupportedException e
) {
1381 throw new IllegalStateException(notSupportMessage
, e
);
1383 if (ecology
== null) {
1384 return new HashMap
<Language
, LanguageString
>();
1387 return ecology
.getMultilanguageText();
1390 public void setEcology(String ecology
) {
1391 setEcology(ecology
, null);
1394 public void setEcology(String ecologyText
, Language language
) {
1395 if (language
== null) {
1396 language
= Language
.DEFAULT();
1398 if (ecology
== null) {
1400 ecology
= initializeFieldObjectTextDataWithSupportTest(
1401 Feature
.ECOLOGY(), true, false);
1402 } catch (DerivedUnitFacadeNotSupportedException e
) {
1403 throw new IllegalStateException(notSupportMessage
, e
);
1406 if (ecologyText
== null) {
1407 ecology
.removeText(language
);
1409 ecology
.putText(language
, ecologyText
);
1413 public void removeEcology(Language language
) {
1414 setEcology(null, language
);
1418 * Removes ecology for the default language
1420 public void removeEcology() {
1421 setEcology(null, null);
1424 public void removeEcologyAll() {
1428 // plant description
1430 public String
getPlantDescription() {
1431 return getPlantDescription(null);
1434 public String
getPlantDescription(Language language
) {
1435 if (language
== null) {
1436 language
= Language
.DEFAULT();
1438 LanguageString languageString
= getPlantDescriptionAll().get(language
);
1439 return (languageString
== null ?
null : languageString
.getText());
1442 // public String getPlantDescriptionPreferred(List<Language> languages){
1443 // LanguageString languageString =
1444 // getPlantDescriptionAll().getPreferredLanguageString(languages);
1445 // return languageString.getText();
1448 * Returns a copy of the multilanguage text holding the description data.
1450 * @see {@link TextData#getMultilanguageText()}
1454 public Map
<Language
, LanguageString
> getPlantDescriptionAll() {
1455 if (plantDescription
== null) {
1457 plantDescription
= initializeFieldObjectTextDataWithSupportTest(
1458 Feature
.DESCRIPTION(), false, false);
1459 } catch (DerivedUnitFacadeNotSupportedException e
) {
1460 throw new IllegalStateException(notSupportMessage
, e
);
1462 if (plantDescription
== null) {
1463 return new HashMap
<Language
, LanguageString
>();
1466 return plantDescription
.getMultilanguageText();
1469 public void setPlantDescription(String plantDescription
) {
1470 setPlantDescription(plantDescription
, null);
1473 public void setPlantDescription(String plantDescriptionText
,
1474 Language language
) {
1475 if (language
== null) {
1476 language
= Language
.DEFAULT();
1478 if (plantDescription
== null) {
1480 plantDescription
= initializeFieldObjectTextDataWithSupportTest(
1481 Feature
.DESCRIPTION(), true, false);
1482 } catch (DerivedUnitFacadeNotSupportedException e
) {
1483 throw new IllegalStateException(notSupportMessage
, e
);
1486 if (plantDescriptionText
== null) {
1487 plantDescription
.removeText(language
);
1489 plantDescription
.putText(language
, plantDescriptionText
);
1493 public void removePlantDescription(Language language
) {
1494 setPlantDescription(null, language
);
1497 // field object definition
1498 public void addFieldObjectDefinition(String text
, Language language
) {
1499 getFieldObservation(true).addDefinition(text
, language
);
1503 public Map
<Language
, LanguageString
> getFieldObjectDefinition() {
1504 if (!hasFieldObservation()) {
1505 return new HashMap
<Language
, LanguageString
>();
1507 return getFieldObservation(true).getDefinition();
1511 public String
getFieldObjectDefinition(Language language
) {
1512 Map
<Language
, LanguageString
> map
= getFieldObjectDefinition();
1513 LanguageString languageString
= (map
== null ?
null : map
.get(language
));
1514 if (languageString
!= null) {
1515 return languageString
.getText();
1521 public void removeFieldObjectDefinition(Language lang
) {
1522 if (hasFieldObservation()) {
1523 getFieldObservation(true).removeDefinition(lang
);
1528 public boolean addFieldObjectMedia(Media media
) {
1530 return addMedia(media
, getFieldObservation(true));
1531 } catch (DerivedUnitFacadeNotSupportedException e
) {
1532 throw new IllegalStateException(notSupportMessage
, e
);
1537 * Returns true, if an image gallery for the field object exists.<BR>
1538 * Returns also <code>true</code> if the image gallery is empty.
1542 public boolean hasFieldObjectImageGallery() {
1543 if (!hasFieldObject()) {
1546 return (getImageGallery(fieldObservation
, false) != null);
1550 public void setFieldObjectImageGallery(SpecimenDescription imageGallery
)
1551 throws DerivedUnitFacadeNotSupportedException
{
1552 SpecimenDescription existingGallery
= getFieldObjectImageGallery(false);
1554 // test attached specimens contain this.derivedUnit
1555 SpecimenOrObservationBase
<?
> facadeFieldObservation
= innerFieldObservation();
1556 testSpecimenInImageGallery(imageGallery
, facadeFieldObservation
);
1558 if (existingGallery
!= null) {
1559 if (existingGallery
!= imageGallery
) {
1560 throw new DerivedUnitFacadeNotSupportedException(
1561 "DerivedUnitFacade does not allow more than one image gallery");
1566 TextData textData
= testImageGallery(imageGallery
);
1567 this.fieldObjectMediaTextData
= textData
;
1572 * Returns the field object image gallery. If no such image gallery exists
1573 * and createIfNotExists is true an new one is created. Otherwise null is
1576 * @param createIfNotExists
1579 public SpecimenDescription
getFieldObjectImageGallery(
1580 boolean createIfNotExists
) {
1583 textData
= initializeFieldObjectTextDataWithSupportTest(
1584 Feature
.IMAGE(), createIfNotExists
, true);
1585 } catch (DerivedUnitFacadeNotSupportedException e
) {
1586 throw new IllegalStateException(notSupportMessage
, e
);
1588 if (textData
!= null) {
1589 return CdmBase
.deproxy(textData
.getInDescription(),
1590 SpecimenDescription
.class);
1597 * Returns the media for the field object.<BR>
1602 public List
<Media
> getFieldObjectMedia() {
1604 List
<Media
> result
= getMedia(getFieldObservation(false), false);
1605 return result
== null ?
new ArrayList
<Media
>() : result
;
1606 } catch (DerivedUnitFacadeNotSupportedException e
) {
1607 throw new IllegalStateException(notSupportMessage
, e
);
1611 public boolean removeFieldObjectMedia(Media media
) {
1613 return removeMedia(media
, getFieldObservation(false));
1614 } catch (DerivedUnitFacadeNotSupportedException e
) {
1615 throw new IllegalStateException(notSupportMessage
, e
);
1621 public String
getFieldNumber() {
1622 if (!hasFieldObservation()) {
1625 return getFieldObservation(true).getFieldNumber();
1629 public void setFieldNumber(String fieldNumber
) {
1630 getFieldObservation(true).setFieldNumber(fieldNumber
);
1633 // primary collector
1635 public Person
getPrimaryCollector() {
1636 if (!hasFieldObservation()) {
1639 return getFieldObservation(true).getPrimaryCollector();
1643 public void setPrimaryCollector(Person primaryCollector
) {
1644 getFieldObservation(true).setPrimaryCollector(primaryCollector
);
1649 public String
getFieldNotes() {
1650 if (!hasFieldObservation()) {
1653 return getFieldObservation(true).getFieldNotes();
1657 public void setFieldNotes(String fieldNotes
) {
1658 getFieldObservation(true).setFieldNotes(fieldNotes
);
1661 // individual counts
1663 public Integer
getIndividualCount() {
1664 return (hasFieldObservation() ?
getFieldObservation(true)
1665 .getIndividualCount() : null);
1668 public void setIndividualCount(Integer individualCount
) {
1669 getFieldObservation(true).setIndividualCount(individualCount
);
1674 public Stage
getLifeStage() {
1675 return (hasFieldObservation() ?
getFieldObservation(true)
1676 .getLifeStage() : null);
1679 public void setLifeStage(Stage lifeStage
) {
1680 getFieldObservation(true).setLifeStage(lifeStage
);
1685 public Sex
getSex() {
1686 return (hasFieldObservation() ?
getFieldObservation(true).getSex()
1690 public void setSex(Sex sex
) {
1691 getFieldObservation(true).setSex(sex
);
1694 // field observation
1695 public boolean hasFieldObservation() {
1696 return (getFieldObservation(false) != null);
1700 * Returns the field observation as an object.
1704 public FieldObservation
innerFieldObservation() {
1705 return getFieldObservation(false);
1709 * Returns the field observation as an object.
1713 public FieldObservation
getFieldObservation(boolean createIfNotExists
) {
1714 if (fieldObservation
== null && createIfNotExists
) {
1715 setFieldObservation(FieldObservation
.NewInstance());
1717 return this.fieldObservation
;
1721 private void setFieldObservation(FieldObservation fieldObservation
) {
1722 this.fieldObservation
= fieldObservation
;
1723 if (fieldObservation
!= null){
1724 fieldObservation
.addPropertyChangeListener(getNewEventPropagationListener());
1725 if (derivedUnit
!= null){
1726 DerivationEvent derivationEvent
= getDerivationEvent(CREATE
);
1727 derivationEvent
.addOriginal(fieldObservation
);
1729 setFieldObservationCacheStrategy();
1733 // ****************** Specimen *******************************************
1736 public void addDerivedUnitDefinition(String text
, Language language
) {
1737 innerDerivedUnit().putDefinition(language
, text
);
1741 public Map
<Language
, LanguageString
> getDerivedUnitDefinitions() {
1743 return this.derivedUnit
.getDefinition();
1747 public String
getDerivedUnitDefinition(Language language
) {
1749 Map
<Language
, LanguageString
> languageMap
= derivedUnit
.getDefinition();
1750 LanguageString languageString
= languageMap
.get(language
);
1751 if (languageString
!= null) {
1752 return languageString
.getText();
1758 public void removeDerivedUnitDefinition(Language lang
) {
1760 derivedUnit
.removeDefinition(lang
);
1764 public void addDetermination(DeterminationEvent determination
) {
1766 determination
.setIdentifiedUnit(derivedUnit
);
1767 derivedUnit
.addDetermination(determination
);
1771 public DeterminationEvent
getPreferredDetermination() {
1773 Set
<DeterminationEvent
> events
= derivedUnit
.getDeterminations();
1774 for (DeterminationEvent event
: events
){
1775 if (event
.getPreferredFlag() == true){
1783 * This method returns the preferred determination.
1784 * @see #getOtherDeterminations()
1785 * @see #getDeterminations()
1789 public void setPreferredDetermination(DeterminationEvent newEvent
) {
1791 Set
<DeterminationEvent
> events
= derivedUnit
.getDeterminations();
1792 for (DeterminationEvent event
: events
){
1793 if (event
.getPreferredFlag() == true){
1794 event
.setPreferredFlag(false);
1797 newEvent
.setPreferredFlag(true);
1798 events
.add(newEvent
);
1802 * This method returns all determinations except for the preferred one.
1803 * @see #getPreferredDetermination()
1804 * @see #getDeterminations()
1808 public Set
<DeterminationEvent
> getOtherDeterminations() {
1810 Set
<DeterminationEvent
> events
= derivedUnit
.getDeterminations();
1811 Set
<DeterminationEvent
> result
= new HashSet
<DeterminationEvent
>();
1812 for (DeterminationEvent event
: events
){
1813 if (event
.getPreferredFlag() != true){
1821 * This method returns all determination events. The preferred one {@link #getPreferredDetermination()}
1822 * and all others {@link #getOtherDeterminations()}.
1826 public Set
<DeterminationEvent
> getDeterminations() {
1828 return derivedUnit
.getDeterminations();
1831 public void removeDetermination(DeterminationEvent determination
) {
1833 derivedUnit
.removeDetermination(determination
);
1837 public boolean addDerivedUnitMedia(Media media
) {
1840 return addMedia(media
, derivedUnit
);
1841 } catch (DerivedUnitFacadeNotSupportedException e
) {
1842 throw new IllegalStateException(notSupportMessage
, e
);
1847 * Returns true, if an image gallery exists for the specimen.<BR>
1848 * Returns also <code>true</code> if the image gallery is empty.
1850 public boolean hasDerivedUnitImageGallery() {
1851 return (getImageGallery(derivedUnit
, false) != null);
1854 public SpecimenDescription
getDerivedUnitImageGallery(boolean createIfNotExists
) {
1858 textData
= inititializeTextDataWithSupportTest(Feature
.IMAGE(),
1859 derivedUnit
, createIfNotExists
, true);
1860 } catch (DerivedUnitFacadeNotSupportedException e
) {
1861 throw new IllegalStateException(notSupportMessage
, e
);
1863 if (textData
!= null) {
1864 return CdmBase
.deproxy(textData
.getInDescription(),
1865 SpecimenDescription
.class);
1871 public void setDerivedUnitImageGallery(SpecimenDescription imageGallery
)
1872 throws DerivedUnitFacadeNotSupportedException
{
1874 SpecimenDescription existingGallery
= getDerivedUnitImageGallery(false);
1876 // test attached specimens contain this.derivedUnit
1877 SpecimenOrObservationBase facadeDerivedUnit
= innerDerivedUnit();
1878 testSpecimenInImageGallery(imageGallery
, facadeDerivedUnit
);
1880 if (existingGallery
!= null) {
1881 if (existingGallery
!= imageGallery
) {
1882 throw new DerivedUnitFacadeNotSupportedException(
1883 "DerivedUnitFacade does not allow more than one image gallery");
1888 TextData textData
= testImageGallery(imageGallery
);
1889 this.derivedUnitMediaTextData
= textData
;
1894 * @param imageGallery
1895 * @throws DerivedUnitFacadeNotSupportedException
1897 private void testSpecimenInImageGallery(SpecimenDescription imageGallery
, SpecimenOrObservationBase specimen
)
1898 throws DerivedUnitFacadeNotSupportedException
{
1899 Set
<SpecimenOrObservationBase
> imageGallerySpecimens
= imageGallery
.getDescribedSpecimenOrObservations();
1900 if (imageGallerySpecimens
.size() < 1) {
1901 throw new DerivedUnitFacadeNotSupportedException(
1902 "Image Gallery has no Specimen attached. Please attache according specimen or field observation.");
1904 if (!imageGallerySpecimens
.contains(specimen
)) {
1905 throw new DerivedUnitFacadeNotSupportedException(
1906 "Image Gallery has not the facade's field object attached. Please add field object first to image gallery specimenOrObservation list.");
1911 * Returns the media for the specimen.<BR>
1916 public List
<Media
> getDerivedUnitMedia() {
1919 List
<Media
> result
= getMedia(derivedUnit
, false);
1920 return result
== null ?
new ArrayList
<Media
>() : result
;
1921 } catch (DerivedUnitFacadeNotSupportedException e
) {
1922 throw new IllegalStateException(notSupportMessage
, e
);
1926 public boolean removeDerivedUnitMedia(Media media
) {
1929 return removeMedia(media
, derivedUnit
);
1930 } catch (DerivedUnitFacadeNotSupportedException e
) {
1931 throw new IllegalStateException(notSupportMessage
, e
);
1937 public String
getAccessionNumber() {
1939 return derivedUnit
.getAccessionNumber();
1942 public void setAccessionNumber(String accessionNumber
) {
1944 derivedUnit
.setAccessionNumber(accessionNumber
);
1948 public String
getCatalogNumber() {
1950 return derivedUnit
.getCatalogNumber();
1953 public void setCatalogNumber(String catalogNumber
) {
1955 derivedUnit
.setCatalogNumber(catalogNumber
);
1959 public String
getBarcode() {
1961 return derivedUnit
.getBarcode();
1964 public void setBarcode(String barcode
) {
1966 derivedUnit
.setBarcode(barcode
);
1969 // Preservation Method
1972 * Only supported by specimen and fossils
1974 * @see #DerivedUnitType
1978 public PreservationMethod
getPreservationMethod() throws MethodNotSupportedByDerivedUnitTypeException
{
1980 if (derivedUnit
.isInstanceOf(Specimen
.class)) {
1981 return CdmBase
.deproxy(derivedUnit
, Specimen
.class)
1985 .isThrowExceptionForNonSpecimenPreservationMethodRequest()) {
1986 throw new MethodNotSupportedByDerivedUnitTypeException(
1987 "A preservation method is only available in derived units of type 'Specimen' or 'Fossil'");
1995 * Only supported by specimen and fossils
1997 * @see #DerivedUnitType
2000 public void setPreservationMethod(PreservationMethod preservation
)
2001 throws MethodNotSupportedByDerivedUnitTypeException
{
2003 if (derivedUnit
.isInstanceOf(Specimen
.class)) {
2004 CdmBase
.deproxy(derivedUnit
, Specimen
.class).setPreservation(
2008 .isThrowExceptionForNonSpecimenPreservationMethodRequest()) {
2009 throw new MethodNotSupportedByDerivedUnitTypeException(
2010 "A preservation method is only available in derived units of type 'Specimen' or 'Fossil'");
2017 // Stored under name
2019 public TaxonNameBase
getStoredUnder() {
2021 return derivedUnit
.getStoredUnder();
2024 public void setStoredUnder(TaxonNameBase storedUnder
) {
2026 derivedUnit
.setStoredUnder(storedUnder
);
2030 public String
getTitleCache() {
2031 SpecimenOrObservationBase
<?
> titledUnit
= getTitledUnit();
2033 if (!titledUnit
.isProtectedTitleCache()) {
2034 // always compute title cache anew as long as there are no property
2035 // change listeners on
2036 // field observation, gathering event etc
2037 titledUnit
.setTitleCache(null, false);
2039 return titledUnit
.getTitleCache();
2042 private SpecimenOrObservationBase
<?
> getTitledUnit(){
2043 return (derivedUnit
!= null )? derivedUnit
: fieldObservation
;
2046 public boolean isProtectedTitleCache() {
2047 return getTitledUnit().isProtectedTitleCache();
2050 public void setTitleCache(String titleCache
, boolean isProtected
) {
2051 this.getTitledUnit().setTitleCache(titleCache
, isProtected
);
2055 * Returns the derived unit itself.
2057 * @return the derived unit
2059 public DerivedUnitBase
innerDerivedUnit() {
2060 return this.derivedUnit
;
2064 // * Returns the derived unit itself.
2066 // * @return the derived unit
2068 // public DerivedUnitBase innerDerivedUnit(boolean createIfNotExists) {
2069 // DerivedUnit result = this.derivedUnit;
2070 // if (result == null && createIfNotExists){
2071 // if (this.fieldObservation == null){
2072 // String message = "Field observation must exist to create derived unit.";
2073 // throw new IllegalStateException(message);
2076 // DerivationEvent derivationEvent = getDerivationEvent(true);
2077 // derivationEvent.addOriginal(fieldObservation);
2078 // return this.derivedUnit;
2083 private boolean hasDerivationEvent() {
2084 return getDerivationEvent() == null ?
false : true;
2087 private DerivationEvent
getDerivationEvent() {
2088 return getDerivationEvent(false);
2092 * Returns the derivation event. If no derivation event exists and <code>createIfNotExists</code>
2093 * is <code>true</code> a new derivation event is created and returned.
2094 * Otherwise <code>null</code> is returned.
2095 * @param createIfNotExists
2097 private DerivationEvent
getDerivationEvent(boolean createIfNotExists
) {
2098 DerivationEvent result
= null;
2099 if (derivedUnit
!= null){
2100 result
= derivedUnit
.getDerivedFrom();
2104 if (result
== null && createIfNotExists
) {
2105 result
= DerivationEvent
.NewInstance();
2106 derivedUnit
.setDerivedFrom(result
);
2112 public String
getExsiccatum()
2113 throws MethodNotSupportedByDerivedUnitTypeException
{
2115 if (derivedUnit
.isInstanceOf(Specimen
.class)) {
2116 return CdmBase
.deproxy(derivedUnit
, Specimen
.class).getExsiccatum();
2119 .isThrowExceptionForNonSpecimenPreservationMethodRequest()) {
2120 throw new MethodNotSupportedByDerivedUnitTypeException(
2121 "An exsiccatum is only available in derived units of type 'Specimen' or 'Fossil'");
2128 public void setExsiccatum(String exsiccatum
) throws Exception
{
2130 if (derivedUnit
.isInstanceOf(Specimen
.class)) {
2131 CdmBase
.deproxy(derivedUnit
, Specimen
.class).setExsiccatum(
2135 .isThrowExceptionForNonSpecimenPreservationMethodRequest()) {
2136 throw new MethodNotSupportedByDerivedUnitTypeException(
2137 "An exsiccatum is only available in derived units of type 'Specimen' or 'Fossil'");
2145 public void addSource(IdentifiableSource source
) {
2147 this.derivedUnit
.addSource(source
);
2151 * Creates an orignal source, adds it to the specimen and returns it.
2154 * @param microReference
2155 * @param originalNameString
2158 public IdentifiableSource
addSource(Reference reference
,
2159 String microReference
, String originalNameString
) {
2160 IdentifiableSource source
= IdentifiableSource
.NewInstance(reference
, microReference
);
2161 source
.setOriginalNameString(originalNameString
);
2167 public Set
<IdentifiableSource
> getSources() {
2169 return derivedUnit
.getSources();
2172 public void removeSource(IdentifiableSource source
) {
2174 this.derivedUnit
.removeSource(source
);
2178 * @return the collection
2181 public Collection
getCollection() {
2183 return derivedUnit
.getCollection();
2188 * the collection to set
2190 public void setCollection(Collection collection
) {
2192 derivedUnit
.setCollection(collection
);
2196 public void addAnnotation(Annotation annotation
) {
2198 this.derivedUnit
.addAnnotation(annotation
);
2202 public void getAnnotations() {
2204 this.derivedUnit
.getAnnotations();
2207 public void removeAnnotation(Annotation annotation
) {
2209 this.derivedUnit
.removeAnnotation(annotation
);
2212 // ******************************* Events ***************************
2217 private PropertyChangeListener
getNewEventPropagationListener() {
2218 PropertyChangeListener listener
= new PropertyChangeListener() {
2220 public void propertyChange(PropertyChangeEvent event
) {
2221 if (derivedUnit
!= null){
2222 derivedUnit
.firePropertyChange(event
);
2224 if (! event
.getSource().equals(fieldObservation
)){
2225 fieldObservation
.firePropertyChange(event
);
2233 // **************** Other Collections
2234 // ***************************************************
2237 * Creates a duplicate specimen which derives from the same derivation event
2238 * as the facade specimen and adds collection data to it (all data available
2239 * in DerivedUnitBase and Specimen. Data from SpecimenOrObservationBase and
2240 * above are not yet shared at the moment.
2243 * @param catalogNumber
2244 * @param accessionNumber
2245 * @param collectorsNumber
2246 * @param storedUnder
2247 * @param preservation
2250 public Specimen
addDuplicate(Collection collection
, String catalogNumber
,
2251 String accessionNumber
,
2252 TaxonNameBase storedUnder
, PreservationMethod preservation
) {
2254 Specimen duplicate
= Specimen
.NewInstance();
2255 duplicate
.setDerivedFrom(getDerivationEvent(CREATE
));
2256 duplicate
.setCollection(collection
);
2257 duplicate
.setCatalogNumber(catalogNumber
);
2258 duplicate
.setAccessionNumber(accessionNumber
);
2259 duplicate
.setStoredUnder(storedUnder
);
2260 duplicate
.setPreservation(preservation
);
2264 public void addDuplicate(DerivedUnitBase duplicateSpecimen
) {
2265 // TODO check derivedUnitType
2267 getDerivationEvent(CREATE
).addDerivative(duplicateSpecimen
);
2271 public Set
<Specimen
> getDuplicates() {
2273 Set
<Specimen
> result
= new HashSet
<Specimen
>();
2274 if (hasDerivationEvent()) {
2275 for (DerivedUnitBase derivedUnit
: getDerivationEvent(CREATE
)
2276 .getDerivatives()) {
2277 if (derivedUnit
.isInstanceOf(Specimen
.class)
2278 && !derivedUnit
.equals(this.derivedUnit
)) {
2279 result
.add(CdmBase
.deproxy(derivedUnit
, Specimen
.class));
2286 public void removeDuplicate(Specimen duplicateSpecimen
) {
2288 if (hasDerivationEvent()) {
2289 getDerivationEvent(CREATE
).removeDerivative(duplicateSpecimen
);
2295 private void testDerivedUnit() {
2296 if (derivedUnit
== null){
2297 throw new IllegalStateException("This method is not allowed for this specimen or observation type. Probably you have tried to add specimen(derived unit) information to a field observation");
2301 public void setType(DerivedUnitType type
) {
2305 public DerivedUnitType
getType() {