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
.DerivedUnitBase
;
49 import eu
.etaxonomy
.cdm
.model
.occurrence
.DeterminationEvent
;
50 import eu
.etaxonomy
.cdm
.model
.occurrence
.FieldObservation
;
51 import eu
.etaxonomy
.cdm
.model
.occurrence
.GatheringEvent
;
52 import eu
.etaxonomy
.cdm
.model
.occurrence
.PreservationMethod
;
53 import eu
.etaxonomy
.cdm
.model
.occurrence
.Specimen
;
54 import eu
.etaxonomy
.cdm
.model
.occurrence
.SpecimenOrObservationBase
;
55 import eu
.etaxonomy
.cdm
.model
.reference
.Reference
;
58 * This class is a facade to the eu.etaxonomy.cdm.model.occurrence package from
59 * a specimen based view. It does not support all functionality available in the
60 * occurrence package.<BR>
61 * The most significant restriction is that a specimen may derive only from one
62 * direct derivation event and there must be only one field observation
63 * (gathering event) it derives from.<BR>
68 public class DerivedUnitFacade
{
69 @SuppressWarnings("unused")
70 private static final Logger logger
= Logger
71 .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 ";
76 * Enum that defines the class the "Specimen" belongs to. Some methods of
77 * the facade are not available for certain classes and will throw an
78 * Exception when invoking them.
80 public enum DerivedUnitType
{
81 Specimen("Specimen"), Observation("Observation"), LivingBeing(
82 "Living Being"), Fossil("Fossil"), DerivedUnit("Derived Unit");
84 String representation
;
86 private DerivedUnitType(String representation
) {
87 this.representation
= representation
;
91 * @return the representation
93 public String
getRepresentation() {
94 return representation
;
97 private DerivedUnitBase
getNewDerivedUnitInstance() {
98 if (this == DerivedUnitType
.Specimen
) {
99 return eu
.etaxonomy
.cdm
.model
.occurrence
.Specimen
.NewInstance();
100 } else if (this == DerivedUnitType
.Observation
) {
101 return eu
.etaxonomy
.cdm
.model
.occurrence
.Observation
103 } else if (this == DerivedUnitType
.LivingBeing
) {
104 return eu
.etaxonomy
.cdm
.model
.occurrence
.LivingBeing
106 } else if (this == DerivedUnitType
.Fossil
) {
107 return eu
.etaxonomy
.cdm
.model
.occurrence
.Fossil
.NewInstance();
108 } else if (this == DerivedUnitType
.DerivedUnit
) {
109 return eu
.etaxonomy
.cdm
.model
.occurrence
.DerivedUnit
112 throw new IllegalStateException("Unknown derived unit type "
113 + this.getRepresentation());
117 public static DerivedUnitType
valueOf2(String type
) {
121 type
= type
.replace(" ", "").toLowerCase();
122 if (type
.equals("specimen")) {
124 } else if (type
.equals("livingbeing")) {
126 } else if (type
.equals("observation")) {
128 } else if (type
.equals("fossil")) {
130 } else if (type
.equals("unknown")) {
131 return DerivedUnitType
.DerivedUnit
;
132 } else if (type
.equals("derivedunit")) {
133 return DerivedUnitType
.DerivedUnit
;
140 private final DerivedUnitFacadeConfigurator config
;
142 // private GatheringEvent gatheringEvent;
143 private DerivedUnitType type
; // needed?
145 private FieldObservation fieldObservation
;
147 private final DerivedUnitBase derivedUnit
;
149 // media - the text data holding the media
150 private TextData derivedUnitMediaTextData
;
151 private TextData fieldObjectMediaTextData
;
153 private TextData ecology
;
154 private TextData plantDescription
;
157 * Creates a derived unit facade for a new derived unit of type
163 public static DerivedUnitFacade
NewInstance(DerivedUnitType type
) {
164 return new DerivedUnitFacade(type
);
168 * Creates a derived unit facade for a given derived unit using the default
173 * @throws DerivedUnitFacadeNotSupportedException
175 public static DerivedUnitFacade
NewInstance(DerivedUnitBase derivedUnit
)
176 throws DerivedUnitFacadeNotSupportedException
{
177 return new DerivedUnitFacade(derivedUnit
, null);
180 public static DerivedUnitFacade
NewInstance(DerivedUnitBase derivedUnit
,
181 DerivedUnitFacadeConfigurator config
)
182 throws DerivedUnitFacadeNotSupportedException
{
183 return new DerivedUnitFacade(derivedUnit
, config
);
186 // ****************** CONSTRUCTOR
187 // ****************************************************
189 private DerivedUnitFacade(DerivedUnitType type
) {
190 this.config
= DerivedUnitFacadeConfigurator
.NewInstance();
193 derivedUnit
= type
.getNewDerivedUnitInstance();
197 private DerivedUnitFacade(DerivedUnitBase derivedUnit
,
198 DerivedUnitFacadeConfigurator config
)
199 throws DerivedUnitFacadeNotSupportedException
{
201 if (config
== null) {
202 config
= DerivedUnitFacadeConfigurator
.NewInstance();
204 this.config
= config
;
207 this.derivedUnit
= derivedUnit
;
211 if (this.derivedUnit
.getDerivedFrom() != null) {
212 DerivationEvent derivationEvent
= getDerivationEvent(true);
214 Set
<FieldObservation
> fieldOriginals
= getFieldObservationsOriginals(
215 derivationEvent
, null);
216 if (fieldOriginals
.size() > 1) {
217 throw new DerivedUnitFacadeNotSupportedException(
218 "Specimen must not have more than 1 derivation event");
219 } else if (fieldOriginals
.size() == 0) {
220 // fieldObservation = FieldObservation.NewInstance();
221 } else if (fieldOriginals
.size() == 1) {
222 fieldObservation
= fieldOriginals
.iterator().next();
223 // ###fieldObservation =
224 // getInitializedFieldObservation(fieldObservation);
226 .addPropertyChangeListener(getNewEventPropagationListener());
228 throw new IllegalStateException("Illegal state");
231 // #### derivedUnit = getInitializedDerivedUnit(derivedUnit);
233 // test if unsupported
237 // String objectTypeExceptionText = "Specimen";
238 // SpecimenDescription imageGallery =
239 // getImageGalleryWithSupportTest(derivedUnit, objectTypeExceptionText,
241 // getImageTextDataWithSupportTest(imageGallery,
242 // objectTypeExceptionText);
243 this.derivedUnitMediaTextData
= inititializeTextDataWithSupportTest(
244 Feature
.IMAGE(), this.derivedUnit
, false, true);
247 // objectTypeExceptionText = "Field observation";
248 // imageGallery = getImageGalleryWithSupportTest(fieldObservation,
249 // objectTypeExceptionText, false);
250 // getImageTextDataWithSupportTest(imageGallery,
251 // objectTypeExceptionText);
252 fieldObjectMediaTextData
= initializeFieldObjectTextDataWithSupportTest(
253 Feature
.IMAGE(), false, true);
255 // handle derivedUnit.getMedia()
256 if (derivedUnit
.getMedia().size() > 0) {
257 // TODO better changed model here to allow only one place for images
258 if (this.config
.isMoveDerivedUnitMediaToGallery()) {
259 Set
<Media
> mediaSet
= derivedUnit
.getMedia();
260 for (Media media
: mediaSet
) {
261 this.addDerivedUnitMedia(media
);
263 mediaSet
.removeAll(getDerivedUnitMedia());
265 throw new DerivedUnitFacadeNotSupportedException(
266 "Specimen may not have direct media. Only (one) image gallery is allowed");
270 // handle fieldObservation.getMedia()
271 if (fieldObservation
!= null && fieldObservation
.getMedia() != null
272 && fieldObservation
.getMedia().size() > 0) {
273 // TODO better changed model here to allow only one place for images
274 if (this.config
.isMoveFieldObjectMediaToGallery()) {
275 Set
<Media
> mediaSet
= fieldObservation
.getMedia();
276 for (Media media
: mediaSet
) {
277 this.addFieldObjectMedia(media
);
279 mediaSet
.removeAll(getFieldObjectMedia());
281 throw new DerivedUnitFacadeNotSupportedException(
282 "Field object may not have direct media. Only (one) image gallery is allowed");
286 // test if descriptions are supported
287 ecology
= initializeFieldObjectTextDataWithSupportTest(
288 Feature
.ECOLOGY(), false, false);
289 plantDescription
= initializeFieldObjectTextDataWithSupportTest(
290 Feature
.DESCRIPTION(), false, false);
293 private DerivedUnitBase
getInitializedDerivedUnit(
294 DerivedUnitBase derivedUnit
) {
295 IOccurrenceService occurrenceService
= this.config
296 .getOccurrenceService();
297 if (occurrenceService
== null) {
300 List
<String
> propertyPaths
= this.config
.getPropertyPaths();
301 if (propertyPaths
== null) {
304 propertyPaths
= getDerivedUnitPropertyPaths(propertyPaths
);
305 DerivedUnitBase result
= (DerivedUnitBase
) occurrenceService
.load(
306 derivedUnit
.getUuid(), propertyPaths
);
311 * Initializes the derived unit according to the configuartions property
312 * path. If the property path is <code>null</code> or no occurrence service
313 * is given the returned object is the same as the input parameter.
315 * @param fieldObservation2
318 private FieldObservation
getInitializedFieldObservation(
319 FieldObservation fieldObservation
) {
320 IOccurrenceService occurrenceService
= this.config
321 .getOccurrenceService();
322 if (occurrenceService
== null) {
323 return fieldObservation
;
325 List
<String
> propertyPaths
= this.config
.getPropertyPaths();
326 if (propertyPaths
== null) {
327 return fieldObservation
;
329 propertyPaths
= getFieldObjectPropertyPaths(propertyPaths
);
330 FieldObservation result
= (FieldObservation
) occurrenceService
.load(
331 fieldObservation
.getUuid(), propertyPaths
);
336 * Transforms the property paths in a way that the facade is handled just
337 * like an ordinary CdmBase object.<BR>
338 * E.g. a property path "collectinAreas" will be translated into
339 * gatheringEvent.collectingAreas
341 * @param propertyPaths
344 private List
<String
> getFieldObjectPropertyPaths(List
<String
> propertyPaths
) {
345 List
<String
> result
= new ArrayList
<String
>();
346 for (String facadePath
: propertyPaths
) {
347 // collecting areas (named area)
348 if (facadePath
.startsWith("collectingAreas")) {
349 facadePath
= "gatheringEvent." + facadePath
;
350 result
.add(facadePath
);
352 // collector (agentBase)
353 else if (facadePath
.startsWith("collector")) {
354 facadePath
= facadePath
.replace("collector",
355 "gatheringEvent.actor");
356 result
.add(facadePath
);
358 // exactLocation (agentBase)
359 else if (facadePath
.startsWith("exactLocation")) {
360 facadePath
= "gatheringEvent." + facadePath
;
361 result
.add(facadePath
);
363 // gatheringPeriod (TimePeriod)
364 else if (facadePath
.startsWith("gatheringPeriod")) {
365 facadePath
= facadePath
.replace("gatheringPeriod",
366 "gatheringEvent.timeperiod");
367 result
.add(facadePath
);
369 // (locality/ localityLanguage , LanguageString)
370 else if (facadePath
.startsWith("locality")) {
371 facadePath
= "gatheringEvent." + facadePath
;
372 result
.add(facadePath
);
375 // *********** FIELD OBJECT ************
376 // fieldObjectDefinitions (Map<language, languageString)
377 else if (facadePath
.startsWith("fieldObjectDefinitions")) {
378 // TODO or definition ???
379 facadePath
= facadePath
.replace("fieldObjectDefinitions",
381 result
.add(facadePath
);
383 // fieldObjectMedia (Media)
384 else if (facadePath
.startsWith("fieldObjectMedia")) {
386 facadePath
= facadePath
.replace("fieldObjectMedia",
387 "descriptions.elements.media");
388 result
.add(facadePath
);
391 // Gathering Event will always be added
392 result
.add("gatheringEvent");
397 * Gathering Event ==================== - gatheringEvent
400 * Field Object ================= - ecology/ ecologyAll (String) ??? -
401 * plant description (like ecology)
403 * - fieldObjectImageGallery (SpecimenDescription) - is automatically
404 * initialized via fieldObjectMedia
411 * Transforms the property paths in a way that the facade is handled just
412 * like an ordinary CdmBase object.<BR>
413 * E.g. a property path "collectinAreas" will be translated into
414 * gatheringEvent.collectingAreas
416 * Not needed (?) as the facade works with REST service property paths
417 * without using this method.
419 * @param propertyPaths
422 private List
<String
> getDerivedUnitPropertyPaths(List
<String
> propertyPaths
) {
423 List
<String
> result
= new ArrayList
<String
>();
424 for (String facadePath
: propertyPaths
) {
425 // determinations (DeterminationEvent)
426 if (facadePath
.startsWith("determinations")) {
427 facadePath
= "" + facadePath
; // no change
428 result
.add(facadePath
);
430 // storedUnder (TaxonNameBase)
431 else if (facadePath
.startsWith("storedUnder")) {
432 facadePath
= "" + facadePath
; // no change
433 result
.add(facadePath
);
435 // sources (IdentifiableSource)
436 else if (facadePath
.startsWith("sources")) {
437 facadePath
= "" + facadePath
; // no change
438 result
.add(facadePath
);
440 // collection (Collection)
441 else if (facadePath
.startsWith("collection")) {
442 facadePath
= "" + facadePath
; // no change
443 result
.add(facadePath
);
445 // (locality/ localityLanguage , LanguageString)
446 else if (facadePath
.startsWith("locality")) {
447 facadePath
= "gatheringEvent." + facadePath
;
448 result
.add(facadePath
);
451 // *********** FIELD OBJECT ************
452 // derivedUnitDefinitions (Map<language, languageString)
453 else if (facadePath
.startsWith("derivedUnitDefinitions")) {
454 // TODO or definition ???
455 facadePath
= facadePath
.replace("derivedUnitDefinitions",
457 result
.add(facadePath
);
460 // derivedUnitMedia (Media)
461 else if (facadePath
.startsWith("derivedUnitMedia")) {
463 facadePath
= facadePath
.replace("derivedUnitMedia",
464 "descriptions.elements.media");
465 result
.add(facadePath
);
471 * //TODO Derived Unit =====================
473 * - derivedUnitImageGallery (SpecimenDescription) - is automatically
474 * initialized via derivedUnitMedia
476 * - derivationEvent (DerivationEvent) - will always be initialized -
477 * duplicates (??? Specimen???) ???
486 private void setCacheStrategy() {
487 if (derivedUnit
== null) {
488 throw new NullPointerException(
489 "Facade's derviedUnit must not be null to set cache strategy");
491 derivedUnit
.setCacheStrategy(new DerivedUnitFacadeCacheStrategy());
496 * @param createIfNotExists
497 * @param isImageGallery
499 * @throws DerivedUnitFacadeNotSupportedException
501 private TextData
initializeFieldObjectTextDataWithSupportTest(
502 Feature feature
, boolean createIfNotExists
, boolean isImageGallery
)
503 throws DerivedUnitFacadeNotSupportedException
{
505 FieldObservation fieldObject
= getFieldObservation(createIfNotExists
);
506 if (fieldObject
== null) {
509 return inititializeTextDataWithSupportTest(feature
, fieldObject
,
510 createIfNotExists
, isImageGallery
);
516 * @param createIfNotExists
517 * @param isImageGallery
519 * @throws DerivedUnitFacadeNotSupportedException
521 private TextData
inititializeTextDataWithSupportTest(Feature feature
,
522 SpecimenOrObservationBase specimen
, boolean createIfNotExists
,
523 boolean isImageGallery
)
524 throws DerivedUnitFacadeNotSupportedException
{
525 if (feature
== null) {
528 TextData textData
= null;
529 if (createIfNotExists
) {
530 textData
= TextData
.NewInstance(feature
);
533 Set
<SpecimenDescription
> descriptions
;
534 if (isImageGallery
) {
535 descriptions
= specimen
.getSpecimenDescriptionImageGallery();
537 descriptions
= specimen
.getSpecimenDescriptions(false);
539 // no description exists yet for this specimen
540 if (descriptions
.size() == 0) {
541 if (createIfNotExists
) {
542 SpecimenDescription newSpecimenDescription
= SpecimenDescription
543 .NewInstance(specimen
);
544 newSpecimenDescription
.addElement(textData
);
545 newSpecimenDescription
.setImageGallery(isImageGallery
);
551 // description already exists
552 Set
<DescriptionElementBase
> existingTextData
= new HashSet
<DescriptionElementBase
>();
553 for (SpecimenDescription description
: descriptions
) {
554 // collect all existing text data
555 for (DescriptionElementBase element
: description
.getElements()) {
556 if (element
.isInstanceOf(TextData
.class)
557 && (feature
.equals(element
.getFeature()) || isImageGallery
)) {
558 existingTextData
.add(element
);
562 // use existing text data if exactly one exists
563 if (existingTextData
.size() > 1) {
564 throw new DerivedUnitFacadeNotSupportedException(
565 "Specimen facade does not support more than one description text data of type "
566 + feature
.getLabel());
568 } else if (existingTextData
.size() == 1) {
569 return CdmBase
.deproxy(existingTextData
.iterator().next(),
572 if (createIfNotExists
) {
573 SpecimenDescription description
= descriptions
.iterator()
575 description
.addElement(textData
);
582 * Tests if a given image gallery is supported by the derived unit facade.
583 * It returns the only text data attached to the given image gallery. If the
584 * given image gallery does not have text data attached, it is created and
587 * @param imageGallery
589 * @throws DerivedUnitFacadeNotSupportedException
591 private TextData
testImageGallery(SpecimenDescription imageGallery
)
592 throws DerivedUnitFacadeNotSupportedException
{
593 if (imageGallery
.isImageGallery() == false) {
594 throw new DerivedUnitFacadeNotSupportedException(
595 "Image gallery needs to have image gallery flag set");
597 if (imageGallery
.getElements().size() > 1) {
598 throw new DerivedUnitFacadeNotSupportedException(
599 "Image gallery must not have more then one description element");
602 if (imageGallery
.getElements().size() == 0) {
603 textData
= TextData
.NewInstance(Feature
.IMAGE());
604 imageGallery
.addElement(textData
);
606 if (!imageGallery
.getElements().iterator().next()
607 .isInstanceOf(TextData
.class)) {
608 throw new DerivedUnitFacadeNotSupportedException(
609 "Image gallery must only have TextData as element");
611 textData
= CdmBase
.deproxy(imageGallery
.getElements()
612 .iterator().next(), TextData
.class);
618 // ************************** METHODS
619 // *****************************************
621 private TextData
getDerivedUnitImageGalleryTextData(
622 boolean createIfNotExists
)
623 throws DerivedUnitFacadeNotSupportedException
{
624 if (this.derivedUnitMediaTextData
== null && createIfNotExists
) {
625 this.derivedUnitMediaTextData
= getImageGalleryTextData(
626 derivedUnit
, "Specimen");
628 return this.derivedUnitMediaTextData
;
631 private TextData
getObservationImageGalleryTextData(
632 boolean createIfNotExists
)
633 throws DerivedUnitFacadeNotSupportedException
{
634 if (this.fieldObjectMediaTextData
== null && createIfNotExists
) {
635 this.fieldObjectMediaTextData
= getImageGalleryTextData(
636 fieldObservation
, "Field observation");
638 return this.fieldObjectMediaTextData
;
642 * @param derivationEvent2
644 * @throws DerivedUnitFacadeNotSupportedException
646 private Set
<FieldObservation
> getFieldObservationsOriginals(
647 DerivationEvent derivationEvent
,
648 Set
<SpecimenOrObservationBase
> recursionAvoidSet
)
649 throws DerivedUnitFacadeNotSupportedException
{
650 if (recursionAvoidSet
== null) {
651 recursionAvoidSet
= new HashSet
<SpecimenOrObservationBase
>();
653 Set
<FieldObservation
> result
= new HashSet
<FieldObservation
>();
654 Set
<SpecimenOrObservationBase
> originals
= derivationEvent
656 for (SpecimenOrObservationBase original
: originals
) {
657 if (original
.isInstanceOf(FieldObservation
.class)) {
658 result
.add(CdmBase
.deproxy(original
, FieldObservation
.class));
659 } else if (original
.isInstanceOf(DerivedUnitBase
.class)) {
660 // if specimen has already been tested exclude it from further
662 if (recursionAvoidSet
.contains(original
)) {
665 DerivedUnitBase derivedUnit
= CdmBase
.deproxy(original
,
666 DerivedUnitBase
.class);
667 DerivationEvent originalDerivation
= derivedUnit
669 // Set<DerivationEvent> derivationEvents =
670 // original.getDerivationEvents();
671 // for (DerivationEvent originalDerivation : derivationEvents){
672 Set
<FieldObservation
> fieldObservations
= getFieldObservationsOriginals(
673 originalDerivation
, recursionAvoidSet
);
674 result
.addAll(fieldObservations
);
677 throw new DerivedUnitFacadeNotSupportedException(
678 "Unhandled specimen or observation base type: "
679 + original
.getClass().getName());
686 // *********** MEDIA METHODS ******************************
689 // * Returns the media list for a specimen. Throws an exception if the
690 // existing specimen descriptions
691 // * are not supported by this facade.
692 // * @param specimen the specimen the media belongs to
693 // * @param specimenExceptionText text describing the specimen for exception
696 // * @throws DerivedUnitFacadeNotSupportedException
698 // private List<Media> getImageGalleryMedia(SpecimenOrObservationBase
699 // specimen, String specimenExceptionText) throws
700 // DerivedUnitFacadeNotSupportedException{
701 // List<Media> result;
702 // SpecimenDescription imageGallery =
703 // getImageGalleryWithSupportTest(specimen, specimenExceptionText, true);
704 // TextData textData = getImageTextDataWithSupportTest(imageGallery,
705 // specimenExceptionText);
706 // result = textData.getMedia();
711 * Returns the media list for a specimen. Throws an exception if the
712 * existing specimen descriptions are not supported by this facade.
715 * the specimen the media belongs to
716 * @param specimenExceptionText
717 * text describing the specimen for exception messages
719 * @throws DerivedUnitFacadeNotSupportedException
721 private TextData
getImageGalleryTextData(
722 SpecimenOrObservationBase specimen
, String specimenExceptionText
)
723 throws DerivedUnitFacadeNotSupportedException
{
725 SpecimenDescription imageGallery
= getImageGalleryWithSupportTest(
726 specimen
, specimenExceptionText
, true);
727 result
= getImageTextDataWithSupportTest(imageGallery
,
728 specimenExceptionText
);
733 * Returns the image gallery of the according specimen. Throws an exception
734 * if the attached image gallerie(s) are not supported by this facade. If no
735 * image gallery exists a new one is created if
736 * <code>createNewIfNotExists</code> is true and if specimen is not
740 * @param specimenText
741 * @param createNewIfNotExists
743 * @throws DerivedUnitFacadeNotSupportedException
745 private SpecimenDescription
getImageGalleryWithSupportTest(
746 SpecimenOrObservationBase
<?
> specimen
, String specimenText
,
747 boolean createNewIfNotExists
)
748 throws DerivedUnitFacadeNotSupportedException
{
749 if (specimen
== null) {
752 SpecimenDescription imageGallery
;
753 if (hasMultipleImageGalleries(specimen
)) {
754 throw new DerivedUnitFacadeNotSupportedException(specimenText
755 + " must not have more than 1 image gallery");
757 imageGallery
= getImageGallery(specimen
, createNewIfNotExists
);
758 getImageTextDataWithSupportTest(imageGallery
, specimenText
);
764 * Returns the media holding text data element of the image gallery. Throws
765 * an exception if multiple such text data already exist. Creates a new text
766 * data if none exists and adds it to the image gallery. If image gallery is
767 * <code>null</code> nothing happens.
769 * @param imageGallery
772 * @throws DerivedUnitFacadeNotSupportedException
774 private TextData
getImageTextDataWithSupportTest(
775 SpecimenDescription imageGallery
, String specimenText
)
776 throws DerivedUnitFacadeNotSupportedException
{
777 if (imageGallery
== null) {
780 TextData textData
= null;
781 for (DescriptionElementBase element
: imageGallery
.getElements()) {
782 if (element
.isInstanceOf(TextData
.class)
783 && element
.getFeature().equals(Feature
.IMAGE())) {
784 if (textData
!= null) {
785 throw new DerivedUnitFacadeNotSupportedException(
787 + " must not have more than 1 image text data element in image gallery");
789 textData
= CdmBase
.deproxy(element
, TextData
.class);
792 if (textData
== null) {
793 textData
= TextData
.NewInstance(Feature
.IMAGE());
794 imageGallery
.addElement(textData
);
800 * Checks, if a specimen belongs to more than one description that is an
806 private boolean hasMultipleImageGalleries(
807 SpecimenOrObservationBase
<?
> derivedUnit
) {
809 Set
<SpecimenDescription
> descriptions
= derivedUnit
810 .getSpecimenDescriptions();
811 for (SpecimenDescription description
: descriptions
) {
812 if (description
.isImageGallery()) {
820 * Returns the image gallery for a specimen. If there are multiple specimen
821 * descriptions marked as image galleries an arbitrary one is chosen. If no
822 * image gallery exists, a new one is created if
823 * <code>createNewIfNotExists</code> is <code>true</code>.<Br>
824 * If specimen is <code>null</code> a null pointer exception is thrown.
826 * @param createNewIfNotExists
829 private SpecimenDescription
getImageGallery(
830 SpecimenOrObservationBase
<?
> specimen
, boolean createIfNotExists
) {
831 SpecimenDescription result
= null;
832 Set
<SpecimenDescription
> descriptions
= specimen
833 .getSpecimenDescriptions();
834 for (SpecimenDescription description
: descriptions
) {
835 if (description
.isImageGallery()) {
836 result
= description
;
840 if (result
== null && createIfNotExists
) {
841 result
= SpecimenDescription
.NewInstance(specimen
);
842 result
.setImageGallery(true);
848 * Adds a media to the specimens image gallery. If media is
849 * <code>null</code> nothing happens.
853 * @return true if media is not null (as specified by
854 * {@link java.util.Collection#add(Object) Collection.add(E e)}
855 * @throws DerivedUnitFacadeNotSupportedException
857 private boolean addMedia(Media media
, SpecimenOrObservationBase
<?
> specimen
)
858 throws DerivedUnitFacadeNotSupportedException
{
860 List
<Media
> mediaList
= getMedia(specimen
, true);
861 return mediaList
.add(media
);
868 * Removes a media from the specimens image gallery.
872 * @return true if an element was removed as a result of this call (as
873 * specified by {@link java.util.Collection#remove(Object)
874 * Collection.remove(E e)}
875 * @throws DerivedUnitFacadeNotSupportedException
877 private boolean removeMedia(Media media
,
878 SpecimenOrObservationBase
<?
> specimen
)
879 throws DerivedUnitFacadeNotSupportedException
{
880 List
<Media
> mediaList
= getMedia(specimen
, true);
881 return mediaList
== null ?
null : mediaList
.remove(media
);
884 private List
<Media
> getMedia(SpecimenOrObservationBase
<?
> specimen
,
885 boolean createIfNotExists
)
886 throws DerivedUnitFacadeNotSupportedException
{
887 TextData textData
= getMediaTextData(specimen
, createIfNotExists
);
888 return textData
== null ?
null : textData
.getMedia();
892 * Returns the one media list of a specimen which is part of the only image
893 * gallery that this specimen is part of.<BR>
894 * If these conditions are not hold an exception is thrwon.
898 * @throws DerivedUnitFacadeNotSupportedException
900 // private List<Media> getMedia(SpecimenOrObservationBase<?> specimen)
901 // throws DerivedUnitFacadeNotSupportedException {
902 // if (specimen == null){
905 // if (specimen == this.derivedUnit){
906 // return getDerivedUnitImageGalleryMedia();
907 // }else if (specimen == this.fieldObservation){
908 // return getObservationImageGalleryTextData();
910 // return getImageGalleryMedia(specimen, "Undefined specimen ");
915 * Returns the one media list of a specimen which is part of the only image
916 * gallery that this specimen is part of.<BR>
917 * If these conditions are not hold an exception is thrwon.
921 * @throws DerivedUnitFacadeNotSupportedException
923 private TextData
getMediaTextData(SpecimenOrObservationBase
<?
> specimen
,
924 boolean createIfNotExists
)
925 throws DerivedUnitFacadeNotSupportedException
{
926 if (specimen
== null) {
929 if (specimen
== this.derivedUnit
) {
930 return getDerivedUnitImageGalleryTextData(createIfNotExists
);
931 } else if (specimen
== this.fieldObservation
) {
932 return getObservationImageGalleryTextData(createIfNotExists
);
934 return getImageGalleryTextData(specimen
, "Undefined specimen ");
938 // ****************** GETTER / SETTER / ADDER / REMOVER
939 // ***********************/
941 // ****************** Gathering Event *********************************/
945 public NamedArea
getCountry() {
946 return (hasGatheringEvent() ?
getGatheringEvent(true).getCountry()
950 public void setCountry(NamedArea country
) {
951 getGatheringEvent(true).setCountry(country
);
955 public void addCollectingArea(NamedArea area
) {
956 getGatheringEvent(true).addCollectingArea(area
);
959 public void addCollectingAreas(java
.util
.Collection
<NamedArea
> areas
) {
960 for (NamedArea area
: areas
) {
961 getGatheringEvent(true).addCollectingArea(area
);
966 public Set
<NamedArea
> getCollectingAreas() {
967 return (hasGatheringEvent() ?
getGatheringEvent(true)
968 .getCollectingAreas() : null);
971 public void removeCollectingArea(NamedArea area
) {
972 if (hasGatheringEvent()) {
973 getGatheringEvent(true).removeCollectingArea(area
);
977 // absolute elevation
979 * meter above/below sea level of the surface
981 * @see #getAbsoluteElevationError()
982 * @see #getAbsoluteElevationRange()
985 public Integer
getAbsoluteElevation() {
986 return (hasGatheringEvent() ?
getGatheringEvent(true)
987 .getAbsoluteElevation() : null);
990 public void setAbsoluteElevation(Integer absoluteElevation
) {
991 getGatheringEvent(true).setAbsoluteElevation(absoluteElevation
);
994 // absolute elevation error
996 public Integer
getAbsoluteElevationError() {
997 return (hasGatheringEvent() ?
getGatheringEvent(true)
998 .getAbsoluteElevationError() : null);
1001 public void setAbsoluteElevationError(Integer absoluteElevationError
) {
1002 getGatheringEvent(true).setAbsoluteElevationError(
1003 absoluteElevationError
);
1007 * @see #getAbsoluteElevation()
1008 * @see #getAbsoluteElevationError()
1009 * @see #setAbsoluteElevationRange(Integer, Integer)
1010 * @see #getAbsoluteElevationMaximum()
1013 public Integer
getAbsoluteElevationMinimum() {
1014 if (!hasGatheringEvent()) {
1017 Integer minimum
= getGatheringEvent(true).getAbsoluteElevation();
1018 if (getGatheringEvent(true).getAbsoluteElevationError() != null) {
1020 - getGatheringEvent(true).getAbsoluteElevationError();
1026 * @see #getAbsoluteElevation()
1027 * @see #getAbsoluteElevationError()
1028 * @see #setAbsoluteElevationRange(Integer, Integer)
1029 * @see #getAbsoluteElevationMinimum()
1032 public Integer
getAbsoluteElevationMaximum() {
1033 if (!hasGatheringEvent()) {
1036 Integer maximum
= getGatheringEvent(true).getAbsoluteElevation();
1037 if (getGatheringEvent(true).getAbsoluteElevationError() != null) {
1039 + getGatheringEvent(true).getAbsoluteElevationError();
1045 * This method replaces absoluteElevation and absoulteElevationError by
1046 * internally translating minimum and maximum values into average and error
1047 * values. As all these values are integer based it is necessary that the
1048 * distance is between minimum and maximum is <b>even</b>, otherwise we will
1049 * get a rounding error resulting in a maximum that is increased by 1.
1051 * @see #setAbsoluteElevation(Integer)
1052 * @see #setAbsoluteElevationError(Integer)
1053 * @param minimumElevation
1054 * minimum of the range
1055 * @param maximumElevation
1056 * maximum of the range
1058 public void setAbsoluteElevationRange(Integer minimumElevation
,
1059 Integer maximumElevation
) {
1060 if (minimumElevation
== null || maximumElevation
== null) {
1061 Integer elevation
= minimumElevation
;
1063 if (minimumElevation
== null) {
1064 elevation
= maximumElevation
;
1065 if (elevation
== null) {
1069 getGatheringEvent(true).setAbsoluteElevation(elevation
);
1070 getGatheringEvent(true).setAbsoluteElevationError(error
);
1072 if (!isEvenDistance(minimumElevation
, maximumElevation
)) {
1073 throw new IllegalArgumentException(
1074 "Distance between minimum and maximum elevation must be even but was "
1075 + Math
.abs(minimumElevation
- maximumElevation
));
1077 Integer absoluteElevationError
= Math
.abs(maximumElevation
1078 - minimumElevation
);
1079 absoluteElevationError
= absoluteElevationError
/ 2;
1080 Integer absoluteElevation
= minimumElevation
1081 + absoluteElevationError
;
1082 getGatheringEvent(true).setAbsoluteElevation(absoluteElevation
);
1083 getGatheringEvent(true).setAbsoluteElevationError(
1084 absoluteElevationError
);
1089 * @param minimumElevation
1090 * @param maximumElevation
1093 public boolean isEvenDistance(Integer minimumElevation
,
1094 Integer maximumElevation
) {
1095 Integer diff
= (maximumElevation
- minimumElevation
);
1096 return diff
% 2 == 0;
1101 public AgentBase
getCollector() {
1102 return (hasGatheringEvent() ?
getGatheringEvent(true).getCollector()
1106 public void setCollector(AgentBase collector
) {
1107 getGatheringEvent(true).setCollector(collector
);
1110 // collecting method
1112 public String
getCollectingMethod() {
1113 return (hasGatheringEvent() ?
getGatheringEvent(true)
1114 .getCollectingMethod() : null);
1117 public void setCollectingMethod(String collectingMethod
) {
1118 getGatheringEvent(true).setCollectingMethod(collectingMethod
);
1121 // distance to ground
1123 public Integer
getDistanceToGround() {
1124 return (hasGatheringEvent() ?
getGatheringEvent(true)
1125 .getDistanceToGround() : null);
1128 public void setDistanceToGround(Integer distanceToGround
) {
1129 getGatheringEvent(true).setDistanceToGround(distanceToGround
);
1132 // distance to water surface
1134 public Integer
getDistanceToWaterSurface() {
1135 return (hasGatheringEvent() ?
getGatheringEvent(true)
1136 .getDistanceToWaterSurface() : null);
1139 public void setDistanceToWaterSurface(Integer distanceToWaterSurface
) {
1140 getGatheringEvent(true).setDistanceToWaterSurface(
1141 distanceToWaterSurface
);
1146 public Point
getExactLocation() {
1147 return (hasGatheringEvent() ?
getGatheringEvent(true)
1148 .getExactLocation() : null);
1152 * Returns a sexagesimal representation of the exact location (e.g.
1153 * 12°59'N, 35°23E). If the exact location is <code>null</code> the empty
1154 * string is returned.
1156 * @param includeEmptySeconds
1157 * @param includeReferenceSystem
1160 public String
getExactLocationText(boolean includeEmptySeconds
,
1161 boolean includeReferenceSystem
) {
1162 return (this.getExactLocation() == null ?
"" : this.getExactLocation()
1163 .toSexagesimalString(includeEmptySeconds
,
1164 includeReferenceSystem
));
1167 public void setExactLocation(Point exactLocation
) {
1168 getGatheringEvent(true).setExactLocation(exactLocation
);
1171 public void setExactLocationByParsing(String longitudeToParse
,
1172 String latitudeToParse
, ReferenceSystem referenceSystem
,
1173 Integer errorRadius
) throws ParseException
{
1174 Point point
= Point
.NewInstance(null, null, referenceSystem
,
1176 point
.setLongitudeByParsing(longitudeToParse
);
1177 point
.setLatitudeByParsing(latitudeToParse
);
1178 setExactLocation(point
);
1181 // gathering event description
1183 public String
getGatheringEventDescription() {
1184 return (hasGatheringEvent() ?
getGatheringEvent(true).getDescription()
1188 public void setGatheringEventDescription(String description
) {
1189 getGatheringEvent(true).setDescription(description
);
1194 public TimePeriod
getGatheringPeriod() {
1195 return (hasGatheringEvent() ?
getGatheringEvent(true).getTimeperiod()
1199 public void setGatheringPeriod(TimePeriod timeperiod
) {
1200 getGatheringEvent(true).setTimeperiod(timeperiod
);
1205 public LanguageString
getLocality() {
1206 return (hasGatheringEvent() ?
getGatheringEvent(true).getLocality()
1211 * convienience method for {@link #getLocality()}.
1212 * {@link LanguageString#getText() getText()}
1217 public String
getLocalityText() {
1218 LanguageString locality
= getLocality();
1219 if (locality
!= null) {
1220 return locality
.getText();
1226 * convienience method for {@link #getLocality()}.
1227 * {@link LanguageString#getLanguage() getLanguage()}
1232 public Language
getLocalityLanguage() {
1233 LanguageString locality
= getLocality();
1234 if (locality
!= null) {
1235 return locality
.getLanguage();
1241 * Sets the locality string in the default language
1245 public void setLocality(String locality
) {
1246 Language language
= Language
.DEFAULT();
1247 setLocality(locality
, language
);
1250 public void setLocality(String locality
, Language language
) {
1251 LanguageString langString
= LanguageString
.NewInstance(locality
,
1253 setLocality(langString
);
1256 public void setLocality(LanguageString locality
) {
1257 getGatheringEvent(true).setLocality(locality
);
1261 * The gathering event will be used for the field object instead of the old
1262 * gathering event.<BR>
1263 * <B>This method will override all gathering values (see below).</B>
1265 * @see #getAbsoluteElevation()
1266 * @see #getAbsoluteElevationError()
1267 * @see #getDistanceToGround()
1268 * @see #getDistanceToWaterSurface()
1269 * @see #getExactLocation()
1270 * @see #getGatheringEventDescription()
1271 * @see #getGatheringPeriod()
1272 * @see #getCollectingAreas()
1273 * @see #getCollectingMethod()
1274 * @see #getLocality()
1275 * @see #getCollector()
1276 * @param gatheringEvent
1278 public void setGatheringEvent(GatheringEvent gatheringEvent
) {
1279 getFieldObservation(true).setGatheringEvent(gatheringEvent
);
1282 public boolean hasGatheringEvent() {
1283 return (getGatheringEvent(false) != null);
1286 public GatheringEvent
innerGatheringEvent() {
1287 return getGatheringEvent(false);
1290 public GatheringEvent
getGatheringEvent(boolean createIfNotExists
) {
1291 if (!hasFieldObservation() && !createIfNotExists
) {
1294 if (createIfNotExists
1295 && getFieldObservation(true).getGatheringEvent() == null) {
1296 GatheringEvent gatheringEvent
= GatheringEvent
.NewInstance();
1297 getFieldObservation(true).setGatheringEvent(gatheringEvent
);
1299 return getFieldObservation(true).getGatheringEvent();
1302 // ****************** Field Object ************************************/
1305 * Returns true if a field observation exists (even if all attributes are
1306 * empty or <code>null<code>.
1310 public boolean hasFieldObject() {
1311 return this.fieldObservation
!= null;
1316 public String
getEcology() {
1317 return getEcology(Language
.DEFAULT());
1320 public String
getEcology(Language language
) {
1321 LanguageString languageString
= getEcologyAll().get(language
);
1322 return (languageString
== null ?
null : languageString
.getText());
1325 // public String getEcologyPreferred(List<Language> languages){
1326 // LanguageString languageString =
1327 // getEcologyAll().getPreferredLanguageString(languages);
1328 // return languageString.getText();
1331 * Returns a copy of the multilanguage text holding the ecology data.
1333 * @see {@link TextData#getMultilanguageText()}
1337 public Map
<Language
, LanguageString
> getEcologyAll() {
1338 if (ecology
== null) {
1340 ecology
= initializeFieldObjectTextDataWithSupportTest(
1341 Feature
.ECOLOGY(), false, false);
1342 } catch (DerivedUnitFacadeNotSupportedException e
) {
1343 throw new IllegalStateException(notSupportMessage
, e
);
1345 if (ecology
== null) {
1346 return new HashMap
<Language
, LanguageString
>();
1349 return ecology
.getMultilanguageText();
1352 public void setEcology(String ecology
) {
1353 setEcology(ecology
, null);
1356 public void setEcology(String ecologyText
, Language language
) {
1357 if (language
== null) {
1358 language
= Language
.DEFAULT();
1360 if (ecology
== null) {
1362 ecology
= initializeFieldObjectTextDataWithSupportTest(
1363 Feature
.ECOLOGY(), true, false);
1364 } catch (DerivedUnitFacadeNotSupportedException e
) {
1365 throw new IllegalStateException(notSupportMessage
, e
);
1368 if (ecologyText
== null) {
1369 ecology
.removeText(language
);
1371 ecology
.putText(language
, ecologyText
);
1375 public void removeEcology(Language language
) {
1376 setEcology(null, language
);
1380 * Removes ecology for the default language
1382 public void removeEcology() {
1383 setEcology(null, null);
1386 public void removeEcologyAll() {
1390 // plant description
1392 public String
getPlantDescription() {
1393 return getPlantDescription(null);
1396 public String
getPlantDescription(Language language
) {
1397 if (language
== null) {
1398 language
= Language
.DEFAULT();
1400 LanguageString languageString
= getPlantDescriptionAll().get(language
);
1401 return (languageString
== null ?
null : languageString
.getText());
1404 // public String getPlantDescriptionPreferred(List<Language> languages){
1405 // LanguageString languageString =
1406 // getPlantDescriptionAll().getPreferredLanguageString(languages);
1407 // return languageString.getText();
1410 * Returns a copy of the multilanguage text holding the description data.
1412 * @see {@link TextData#getMultilanguageText()}
1416 public Map
<Language
, LanguageString
> getPlantDescriptionAll() {
1417 if (plantDescription
== null) {
1419 plantDescription
= initializeFieldObjectTextDataWithSupportTest(
1420 Feature
.DESCRIPTION(), false, false);
1421 } catch (DerivedUnitFacadeNotSupportedException e
) {
1422 throw new IllegalStateException(notSupportMessage
, e
);
1424 if (plantDescription
== null) {
1425 return new HashMap
<Language
, LanguageString
>();
1428 return plantDescription
.getMultilanguageText();
1431 public void setPlantDescription(String plantDescription
) {
1432 setPlantDescription(plantDescription
, null);
1435 public void setPlantDescription(String plantDescriptionText
,
1436 Language language
) {
1437 if (language
== null) {
1438 language
= Language
.DEFAULT();
1440 if (plantDescription
== null) {
1442 plantDescription
= initializeFieldObjectTextDataWithSupportTest(
1443 Feature
.DESCRIPTION(), true, false);
1444 } catch (DerivedUnitFacadeNotSupportedException e
) {
1445 throw new IllegalStateException(notSupportMessage
, e
);
1448 if (plantDescriptionText
== null) {
1449 plantDescription
.removeText(language
);
1451 plantDescription
.putText(language
, plantDescriptionText
);
1455 public void removePlantDescription(Language language
) {
1456 setPlantDescription(null, language
);
1459 // field object definition
1460 public void addFieldObjectDefinition(String text
, Language language
) {
1461 getFieldObservation(true).addDefinition(text
, language
);
1465 public Map
<Language
, LanguageString
> getFieldObjectDefinition() {
1466 if (!hasFieldObservation()) {
1467 return new HashMap
<Language
, LanguageString
>();
1469 return getFieldObservation(true).getDefinition();
1473 public String
getFieldObjectDefinition(Language language
) {
1474 Map
<Language
, LanguageString
> map
= getFieldObjectDefinition();
1475 LanguageString languageString
= (map
== null ?
null : map
.get(language
));
1476 if (languageString
!= null) {
1477 return languageString
.getText();
1483 public void removeFieldObjectDefinition(Language lang
) {
1484 if (hasFieldObservation()) {
1485 getFieldObservation(true).removeDefinition(lang
);
1490 public boolean addFieldObjectMedia(Media media
) {
1492 return addMedia(media
, getFieldObservation(true));
1493 } catch (DerivedUnitFacadeNotSupportedException e
) {
1494 throw new IllegalStateException(notSupportMessage
, e
);
1499 * Returns true, if an image gallery for the field object exists.<BR>
1500 * Returns also <code>true</code> if the image gallery is empty.
1504 public boolean hasFieldObjectImageGallery() {
1505 if (!hasFieldObject()) {
1508 return (getImageGallery(fieldObservation
, false) != null);
1512 public void setFieldObjectImageGallery(SpecimenDescription imageGallery
)
1513 throws DerivedUnitFacadeNotSupportedException
{
1514 SpecimenDescription existingGallery
= getFieldObjectImageGallery(false);
1516 // test attached specimens contain this.derivedUnit
1517 SpecimenOrObservationBase
<?
> facadeFieldObservation
= innerFieldObservation();
1518 testSpecimenInImageGallery(imageGallery
, facadeFieldObservation
);
1520 if (existingGallery
!= null) {
1521 if (existingGallery
!= imageGallery
) {
1522 throw new DerivedUnitFacadeNotSupportedException(
1523 "DerivedUnitFacade does not allow more than one image gallery");
1528 TextData textData
= testImageGallery(imageGallery
);
1529 this.fieldObjectMediaTextData
= textData
;
1534 * Returns the field object image gallery. If no such image gallery exists
1535 * and createIfNotExists is true an new one is created. Otherwise null is
1538 * @param createIfNotExists
1541 public SpecimenDescription
getFieldObjectImageGallery(
1542 boolean createIfNotExists
) {
1545 textData
= initializeFieldObjectTextDataWithSupportTest(
1546 Feature
.IMAGE(), createIfNotExists
, true);
1547 } catch (DerivedUnitFacadeNotSupportedException e
) {
1548 throw new IllegalStateException(notSupportMessage
, e
);
1550 if (textData
!= null) {
1551 return CdmBase
.deproxy(textData
.getInDescription(),
1552 SpecimenDescription
.class);
1559 * Returns the media for the field object.<BR>
1564 public List
<Media
> getFieldObjectMedia() {
1566 List
<Media
> result
= getMedia(getFieldObservation(false), false);
1567 return result
== null ?
new ArrayList
<Media
>() : result
;
1568 } catch (DerivedUnitFacadeNotSupportedException e
) {
1569 throw new IllegalStateException(notSupportMessage
, e
);
1573 public boolean removeFieldObjectMedia(Media media
) {
1575 return removeMedia(media
, getFieldObservation(false));
1576 } catch (DerivedUnitFacadeNotSupportedException e
) {
1577 throw new IllegalStateException(notSupportMessage
, e
);
1583 public String
getFieldNumber() {
1584 if (!hasFieldObservation()) {
1587 return getFieldObservation(true).getFieldNumber();
1591 public void setFieldNumber(String fieldNumber
) {
1592 getFieldObservation(true).setFieldNumber(fieldNumber
);
1595 // primary collector
1597 public Person
getPrimaryCollector() {
1598 if (!hasFieldObservation()) {
1601 return getFieldObservation(true).getPrimaryCollector();
1605 public void setPrimaryCollector(Person primaryCollector
) {
1606 getFieldObservation(true).setPrimaryCollector(primaryCollector
);
1611 public String
getFieldNotes() {
1612 if (!hasFieldObservation()) {
1615 return getFieldObservation(true).getFieldNotes();
1619 public void setFieldNotes(String fieldNotes
) {
1620 getFieldObservation(true).setFieldNotes(fieldNotes
);
1623 // individual counts
1625 public Integer
getIndividualCount() {
1626 return (hasFieldObservation() ?
getFieldObservation(true)
1627 .getIndividualCount() : null);
1630 public void setIndividualCount(Integer individualCount
) {
1631 getFieldObservation(true).setIndividualCount(individualCount
);
1636 public Stage
getLifeStage() {
1637 return (hasFieldObservation() ?
getFieldObservation(true)
1638 .getLifeStage() : null);
1641 public void setLifeStage(Stage lifeStage
) {
1642 getFieldObservation(true).setLifeStage(lifeStage
);
1647 public Sex
getSex() {
1648 return (hasFieldObservation() ?
getFieldObservation(true).getSex()
1652 public void setSex(Sex sex
) {
1653 getFieldObservation(true).setSex(sex
);
1656 // field observation
1657 public boolean hasFieldObservation() {
1658 return (getFieldObservation(false) != null);
1662 * Returns the field observation as an object.
1666 public FieldObservation
innerFieldObservation() {
1667 return getFieldObservation(false);
1671 * Returns the field observation as an object.
1675 public FieldObservation
getFieldObservation(boolean createIfNotExists
) {
1676 if (fieldObservation
== null && createIfNotExists
) {
1677 fieldObservation
= FieldObservation
.NewInstance();
1679 .addPropertyChangeListener(getNewEventPropagationListener());
1680 DerivationEvent derivationEvent
= getDerivationEvent(true);
1681 derivationEvent
.addOriginal(fieldObservation
);
1683 return this.fieldObservation
;
1686 // ****************** Specimen
1687 // **************************************************
1690 public void addDerivedUnitDefinition(String text
, Language language
) {
1691 derivedUnit
.addDefinition(text
, language
);
1695 public Map
<Language
, LanguageString
> getDerivedUnitDefinitions() {
1696 return this.derivedUnit
.getDefinition();
1699 public String
getDerivedUnitDefinition(Language language
) {
1700 Map
<Language
, LanguageString
> languageMap
= derivedUnit
.getDefinition();
1701 LanguageString languageString
= languageMap
.get(language
);
1702 if (languageString
!= null) {
1703 return languageString
.getText();
1709 public void removeDerivedUnitDefinition(Language lang
) {
1710 derivedUnit
.removeDefinition(lang
);
1714 public void addDetermination(DeterminationEvent determination
) {
1715 derivedUnit
.addDetermination(determination
);
1719 public Set
<DeterminationEvent
> getDeterminations() {
1720 return derivedUnit
.getDeterminations();
1723 public void removeDetermination(DeterminationEvent determination
) {
1724 derivedUnit
.removeDetermination(determination
);
1728 public boolean addDerivedUnitMedia(Media media
) {
1730 return addMedia(media
, derivedUnit
);
1731 } catch (DerivedUnitFacadeNotSupportedException e
) {
1732 throw new IllegalStateException(notSupportMessage
, e
);
1737 * Returns true, if an image gallery exists for the specimen.<BR>
1738 * Returns also <code>true</code> if the image gallery is empty.
1740 public boolean hasDerivedUnitImageGallery() {
1741 return (getImageGallery(derivedUnit
, false) != null);
1744 public SpecimenDescription
getDerivedUnitImageGallery(
1745 boolean createIfNotExists
) {
1748 textData
= inititializeTextDataWithSupportTest(Feature
.IMAGE(),
1749 derivedUnit
, createIfNotExists
, true);
1750 } catch (DerivedUnitFacadeNotSupportedException e
) {
1751 throw new IllegalStateException(notSupportMessage
, e
);
1753 if (textData
!= null) {
1754 return CdmBase
.deproxy(textData
.getInDescription(),
1755 SpecimenDescription
.class);
1761 public void setDerivedUnitImageGallery(SpecimenDescription imageGallery
)
1762 throws DerivedUnitFacadeNotSupportedException
{
1763 SpecimenDescription existingGallery
= getDerivedUnitImageGallery(false);
1765 // test attached specimens contain this.derivedUnit
1766 SpecimenOrObservationBase facadeDerivedUnit
= innerDerivedUnit();
1767 testSpecimenInImageGallery(imageGallery
, facadeDerivedUnit
);
1769 if (existingGallery
!= null) {
1770 if (existingGallery
!= imageGallery
) {
1771 throw new DerivedUnitFacadeNotSupportedException(
1772 "DerivedUnitFacade does not allow more than one image gallery");
1777 TextData textData
= testImageGallery(imageGallery
);
1778 this.derivedUnitMediaTextData
= textData
;
1783 * @param imageGallery
1784 * @throws DerivedUnitFacadeNotSupportedException
1786 private void testSpecimenInImageGallery(SpecimenDescription imageGallery
,
1787 SpecimenOrObservationBase specimen
)
1788 throws DerivedUnitFacadeNotSupportedException
{
1789 Set
<SpecimenOrObservationBase
> imageGallerySpecimens
= imageGallery
1790 .getDescribedSpecimenOrObservations();
1791 if (imageGallerySpecimens
.size() < 1) {
1792 throw new DerivedUnitFacadeNotSupportedException(
1793 "Image Gallery has no Specimen attached. Please attache according specimen or field observation.");
1795 if (!imageGallerySpecimens
.contains(specimen
)) {
1796 throw new DerivedUnitFacadeNotSupportedException(
1797 "Image Gallery has not the facade's field object attached. Please add field object first to image gallery specimenOrObservation list.");
1802 * Returns the media for the specimen.<BR>
1807 public List
<Media
> getDerivedUnitMedia() {
1809 List
<Media
> result
= getMedia(derivedUnit
, false);
1810 return result
== null ?
new ArrayList
<Media
>() : result
;
1811 } catch (DerivedUnitFacadeNotSupportedException e
) {
1812 throw new IllegalStateException(notSupportMessage
, e
);
1816 public boolean removeDerivedUnitMedia(Media media
) {
1818 return removeMedia(media
, derivedUnit
);
1819 } catch (DerivedUnitFacadeNotSupportedException e
) {
1820 throw new IllegalStateException(notSupportMessage
, e
);
1826 public String
getAccessionNumber() {
1827 return derivedUnit
.getAccessionNumber();
1830 public void setAccessionNumber(String accessionNumber
) {
1831 derivedUnit
.setAccessionNumber(accessionNumber
);
1835 public String
getCatalogNumber() {
1836 return derivedUnit
.getCatalogNumber();
1839 public void setCatalogNumber(String catalogNumber
) {
1840 derivedUnit
.setCatalogNumber(catalogNumber
);
1844 public String
getBarcode() {
1845 return derivedUnit
.getBarcode();
1848 public void setBarcode(String barcode
) {
1849 derivedUnit
.setBarcode(barcode
);
1852 // Preservation Method
1855 * Only supported by specimen and fossils
1857 * @see #DerivedUnitType
1861 public PreservationMethod
getPreservationMethod()
1862 throws MethodNotSupportedByDerivedUnitTypeException
{
1863 if (derivedUnit
.isInstanceOf(Specimen
.class)) {
1864 return CdmBase
.deproxy(derivedUnit
, Specimen
.class)
1868 .isThrowExceptionForNonSpecimenPreservationMethodRequest()) {
1869 throw new MethodNotSupportedByDerivedUnitTypeException(
1870 "A preservation method is only available in derived units of type 'Specimen' or 'Fossil'");
1878 * Only supported by specimen and fossils
1880 * @see #DerivedUnitType
1883 public void setPreservationMethod(PreservationMethod preservation
)
1884 throws MethodNotSupportedByDerivedUnitTypeException
{
1885 if (derivedUnit
.isInstanceOf(Specimen
.class)) {
1886 CdmBase
.deproxy(derivedUnit
, Specimen
.class).setPreservation(
1890 .isThrowExceptionForNonSpecimenPreservationMethodRequest()) {
1891 throw new MethodNotSupportedByDerivedUnitTypeException(
1892 "A preservation method is only available in derived units of type 'Specimen' or 'Fossil'");
1899 // Stored under name
1901 public TaxonNameBase
getStoredUnder() {
1902 return derivedUnit
.getStoredUnder();
1905 public void setStoredUnder(TaxonNameBase storedUnder
) {
1906 derivedUnit
.setStoredUnder(storedUnder
);
1910 // // colletors number
1912 // public String getCollectorsNumber() {
1913 // return derivedUnit.getCollectorsNumber();
1916 // public void setCollectorsNumber(String collectorsNumber) {
1917 // this.derivedUnit.setCollectorsNumber(collectorsNumber);
1921 public String
getTitleCache() {
1922 if (!derivedUnit
.isProtectedTitleCache()) {
1923 // always compute title cache anew as long as there are no property
1924 // change listeners on
1925 // field observation, gathering event etc
1926 derivedUnit
.setTitleCache(null, false);
1928 return this.derivedUnit
.getTitleCache();
1931 public boolean isProtectedTitleCache() {
1932 return derivedUnit
.isProtectedTitleCache();
1935 public void setTitleCache(String titleCache
, boolean isProtected
) {
1936 this.derivedUnit
.setTitleCache(titleCache
, isProtected
);
1940 * Returns the derived unit itself.
1942 * @return the derived unit
1944 public DerivedUnitBase
innerDerivedUnit() {
1945 return this.derivedUnit
;
1948 private boolean hasDerivationEvent() {
1949 return getDerivationEvent() == null ?
false : true;
1952 private DerivationEvent
getDerivationEvent() {
1953 return getDerivationEvent(false);
1956 private DerivationEvent
getDerivationEvent(boolean createIfNotExists
) {
1957 DerivationEvent result
= derivedUnit
.getDerivedFrom();
1958 if (result
== null) {
1959 result
= DerivationEvent
.NewInstance();
1960 derivedUnit
.setDerivedFrom(result
);
1966 public String
getExsiccatum()
1967 throws MethodNotSupportedByDerivedUnitTypeException
{
1968 if (derivedUnit
.isInstanceOf(Specimen
.class)) {
1969 return CdmBase
.deproxy(derivedUnit
, Specimen
.class).getExsiccatum();
1972 .isThrowExceptionForNonSpecimenPreservationMethodRequest()) {
1973 throw new MethodNotSupportedByDerivedUnitTypeException(
1974 "An exsiccatum is only available in derived units of type 'Specimen' or 'Fossil'");
1981 public void setExsiccatum(String exsiccatum
) throws Exception
{
1982 if (derivedUnit
.isInstanceOf(Specimen
.class)) {
1983 CdmBase
.deproxy(derivedUnit
, Specimen
.class).setExsiccatum(
1987 .isThrowExceptionForNonSpecimenPreservationMethodRequest()) {
1988 throw new MethodNotSupportedByDerivedUnitTypeException(
1989 "An exsiccatum is only available in derived units of type 'Specimen' or 'Fossil'");
1997 public void addSource(IdentifiableSource source
) {
1998 this.derivedUnit
.addSource(source
);
2002 * Creates an orignal source, adds it to the specimen and returns it.
2005 * @param microReference
2006 * @param originalNameString
2009 public IdentifiableSource
addSource(Reference reference
,
2010 String microReference
, String originalNameString
) {
2011 IdentifiableSource source
= IdentifiableSource
.NewInstance(reference
,
2013 source
.setOriginalNameString(originalNameString
);
2014 derivedUnit
.addSource(source
);
2019 public Set
<IdentifiableSource
> getSources() {
2020 return derivedUnit
.getSources();
2023 public void removeSource(IdentifiableSource source
) {
2024 this.derivedUnit
.removeSource(source
);
2028 * @return the collection
2031 public Collection
getCollection() {
2032 return derivedUnit
.getCollection();
2037 * the collection to set
2039 public void setCollection(Collection collection
) {
2040 derivedUnit
.setCollection(collection
);
2044 public void addAnnotation(Annotation annotation
) {
2045 this.derivedUnit
.addAnnotation(annotation
);
2049 public void getAnnotations() {
2050 this.derivedUnit
.getAnnotations();
2053 public void removeAnnotation(Annotation annotation
) {
2054 this.derivedUnit
.removeAnnotation(annotation
);
2057 // ******************************* Events
2058 // *********************************************
2063 private PropertyChangeListener
getNewEventPropagationListener() {
2064 PropertyChangeListener listener
= new PropertyChangeListener() {
2066 public void propertyChange(PropertyChangeEvent event
) {
2067 derivedUnit
.firePropertyChange(event
);
2074 // **************** Other Collections
2075 // ***************************************************
2078 * Creates a duplicate specimen which derives from the same derivation event
2079 * as the facade specimen and adds collection data to it (all data available
2080 * in DerivedUnitBase and Specimen. Data from SpecimenOrObservationBase and
2081 * above are not yet shared at the moment.
2084 * @param catalogNumber
2085 * @param accessionNumber
2086 * @param collectorsNumber
2087 * @param storedUnder
2088 * @param preservation
2091 public Specimen
addDuplicate(Collection collection
, String catalogNumber
,
2092 String accessionNumber
,
2093 TaxonNameBase storedUnder
, PreservationMethod preservation
) {
2094 Specimen duplicate
= Specimen
.NewInstance();
2095 duplicate
.setDerivedFrom(getDerivationEvent(true));
2096 duplicate
.setCollection(collection
);
2097 duplicate
.setCatalogNumber(catalogNumber
);
2098 duplicate
.setAccessionNumber(accessionNumber
);
2099 duplicate
.setStoredUnder(storedUnder
);
2100 duplicate
.setPreservation(preservation
);
2104 public void addDuplicate(DerivedUnitBase duplicateSpecimen
) {
2105 // TODO check derivedUnitType
2106 getDerivationEvent(true).addDerivative(duplicateSpecimen
);
2110 public Set
<Specimen
> getDuplicates() {
2111 Set
<Specimen
> result
= new HashSet
<Specimen
>();
2112 if (hasDerivationEvent()) {
2113 for (DerivedUnitBase derivedUnit
: getDerivationEvent(true)
2114 .getDerivatives()) {
2115 if (derivedUnit
.isInstanceOf(Specimen
.class)
2116 && !derivedUnit
.equals(this.derivedUnit
)) {
2117 result
.add(CdmBase
.deproxy(derivedUnit
, Specimen
.class));
2124 public void removeDuplicate(Specimen duplicateSpecimen
) {
2125 if (hasDerivationEvent()) {
2126 getDerivationEvent(true).removeDerivative(duplicateSpecimen
);