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
.common
.Annotation
;
29 import eu
.etaxonomy
.cdm
.model
.common
.CdmBase
;
30 import eu
.etaxonomy
.cdm
.model
.common
.IdentifiableSource
;
31 import eu
.etaxonomy
.cdm
.model
.common
.Language
;
32 import eu
.etaxonomy
.cdm
.model
.common
.LanguageString
;
33 import eu
.etaxonomy
.cdm
.model
.common
.TimePeriod
;
34 import eu
.etaxonomy
.cdm
.model
.description
.DescriptionElementBase
;
35 import eu
.etaxonomy
.cdm
.model
.description
.Feature
;
36 import eu
.etaxonomy
.cdm
.model
.description
.Sex
;
37 import eu
.etaxonomy
.cdm
.model
.description
.SpecimenDescription
;
38 import eu
.etaxonomy
.cdm
.model
.description
.Stage
;
39 import eu
.etaxonomy
.cdm
.model
.description
.TextData
;
40 import eu
.etaxonomy
.cdm
.model
.location
.NamedArea
;
41 import eu
.etaxonomy
.cdm
.model
.location
.Point
;
42 import eu
.etaxonomy
.cdm
.model
.location
.ReferenceSystem
;
43 import eu
.etaxonomy
.cdm
.model
.media
.Media
;
44 import eu
.etaxonomy
.cdm
.model
.name
.TaxonNameBase
;
45 import eu
.etaxonomy
.cdm
.model
.occurrence
.Collection
;
46 import eu
.etaxonomy
.cdm
.model
.occurrence
.DerivationEvent
;
47 import eu
.etaxonomy
.cdm
.model
.occurrence
.DerivedUnitBase
;
48 import eu
.etaxonomy
.cdm
.model
.occurrence
.DeterminationEvent
;
49 import eu
.etaxonomy
.cdm
.model
.occurrence
.FieldObservation
;
50 import eu
.etaxonomy
.cdm
.model
.occurrence
.GatheringEvent
;
51 import eu
.etaxonomy
.cdm
.model
.occurrence
.PreservationMethod
;
52 import eu
.etaxonomy
.cdm
.model
.occurrence
.Specimen
;
53 import eu
.etaxonomy
.cdm
.model
.occurrence
.SpecimenOrObservationBase
;
54 import eu
.etaxonomy
.cdm
.model
.reference
.ReferenceBase
;
57 * This class is a facade to the eu.etaxonomy.cdm.model.occurrence package from
58 * a specimen based view. It does not support all functionality available in the
59 * occurrence package.<BR>
60 * The most significant restriction is that a specimen may derive only from
61 * one direct derivation event and there must be only one field observation (gathering event)
62 * it derives from.<BR>
67 public class DerivedUnitFacade
{
68 private static final Logger logger
= Logger
.getLogger(DerivedUnitFacade
.class);
70 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 ";
73 * Enum that defines the class the "Specimen" belongs to.
74 * Some methods of the facade are not available for certain classes
75 * and will throw an Exception when invoking them.
77 public enum DerivedUnitType
{
78 Specimen ("Specimen"),
79 Observation("Observation"),
80 LivingBeing("Living Being"),
82 DerivedUnit("Derived Unit");
84 String representation
;
85 private DerivedUnitType(String representation
){
86 this.representation
= representation
;
90 * @return the representation
92 public String
getRepresentation() {
93 return representation
;
96 private DerivedUnitBase
getNewDerivedUnitInstance(){
97 if (this == DerivedUnitType
.Specimen
){
98 return eu
.etaxonomy
.cdm
.model
.occurrence
.Specimen
.NewInstance();
99 }else if (this == DerivedUnitType
.Observation
){
100 return eu
.etaxonomy
.cdm
.model
.occurrence
.Observation
.NewInstance();
101 }else if (this == DerivedUnitType
.LivingBeing
){
102 return eu
.etaxonomy
.cdm
.model
.occurrence
.LivingBeing
.NewInstance();
103 }else if (this == DerivedUnitType
.Fossil
){
104 return eu
.etaxonomy
.cdm
.model
.occurrence
.Fossil
.NewInstance();
105 }else if (this == DerivedUnitType
.DerivedUnit
){
106 return eu
.etaxonomy
.cdm
.model
.occurrence
.DerivedUnit
.NewInstance();
108 throw new IllegalStateException("Unknown derived unit type " + this.getRepresentation());
115 private DerivedUnitFacadeConfigurator config
;
117 //private GatheringEvent gatheringEvent;
118 private DerivedUnitType type
; //needed?
120 private FieldObservation fieldObservation
;
122 private DerivedUnitBase derivedUnit
;
124 //media - the text data holding the media
125 private TextData derivedUnitMediaTextData
;
126 private TextData fieldObjectMediaTextData
;
129 private TextData ecology
;
130 private TextData plantDescription
;
134 * Creates a derived unit facade for a new derived unit of type <code>type</code>.
138 public static DerivedUnitFacade
NewInstance(DerivedUnitType type
){
139 return new DerivedUnitFacade(type
);
143 * Creates a derived unit facade for a given derived unit using the default configuration.
146 * @throws DerivedUnitFacadeNotSupportedException
148 public static DerivedUnitFacade
NewInstance(DerivedUnitBase derivedUnit
) throws DerivedUnitFacadeNotSupportedException
{
149 return new DerivedUnitFacade(derivedUnit
, null);
152 public static DerivedUnitFacade
NewInstance(DerivedUnitBase derivedUnit
, DerivedUnitFacadeConfigurator config
) throws DerivedUnitFacadeNotSupportedException
{
153 return new DerivedUnitFacade(derivedUnit
, config
);
158 // ****************** CONSTRUCTOR ****************************************************
160 private DerivedUnitFacade(DerivedUnitType type
){
161 this.config
= DerivedUnitFacadeConfigurator
.NewInstance();
164 derivedUnit
= type
.getNewDerivedUnitInstance();
168 private DerivedUnitFacade(DerivedUnitBase derivedUnit
, DerivedUnitFacadeConfigurator config
) throws DerivedUnitFacadeNotSupportedException
{
171 config
= DerivedUnitFacadeConfigurator
.NewInstance();
173 this.config
= config
;
176 this.derivedUnit
= derivedUnit
;
180 if (this.derivedUnit
.getDerivedFrom() != null){
181 DerivationEvent derivationEvent
= getDerivationEvent(true);
183 Set
<FieldObservation
> fieldOriginals
= getFieldObservationsOriginals(derivationEvent
, null);
184 if (fieldOriginals
.size() > 1){
185 throw new DerivedUnitFacadeNotSupportedException("Specimen must not have more than 1 derivation event");
186 }else if (fieldOriginals
.size() == 0){
187 //fieldObservation = FieldObservation.NewInstance();
188 }else if (fieldOriginals
.size() == 1){
189 fieldObservation
= fieldOriginals
.iterator().next();
190 //###fieldObservation = getInitializedFieldObservation(fieldObservation);
191 fieldObservation
.addPropertyChangeListener(getNewEventPropagationListener());
193 throw new IllegalStateException("Illegal state");
196 // #### derivedUnit = getInitializedDerivedUnit(derivedUnit);
198 //test if unsupported
202 // String objectTypeExceptionText = "Specimen";
203 // SpecimenDescription imageGallery = getImageGalleryWithSupportTest(derivedUnit, objectTypeExceptionText, false);
204 // getImageTextDataWithSupportTest(imageGallery, objectTypeExceptionText);
205 this.derivedUnitMediaTextData
= inititializeTextDataWithSupportTest(Feature
.IMAGE(), this.derivedUnit
, false, true);
208 // objectTypeExceptionText = "Field observation";
209 // imageGallery = getImageGalleryWithSupportTest(fieldObservation, objectTypeExceptionText, false);
210 // getImageTextDataWithSupportTest(imageGallery, objectTypeExceptionText);
211 fieldObjectMediaTextData
= initializeFieldObjectTextDataWithSupportTest(Feature
.IMAGE(), false, true);
213 //handle derivedUnit.getMedia()
214 if (derivedUnit
.getMedia().size() > 0){
215 //TODO better changed model here to allow only one place for images
216 if (this.config
.isMoveDerivedUnitMediaToGallery()){
217 Set
<Media
> mediaSet
= derivedUnit
.getMedia();
218 for (Media media
: mediaSet
){
219 this.addDerivedUnitMedia(media
);
221 mediaSet
.removeAll(getDerivedUnitMedia());
223 throw new DerivedUnitFacadeNotSupportedException("Specimen may not have direct media. Only (one) image gallery is allowed");
227 //handle fieldObservation.getMedia()
228 if (fieldObservation
!= null && fieldObservation
.getMedia() != null && fieldObservation
.getMedia().size() > 0){
229 //TODO better changed model here to allow only one place for images
230 if (this.config
.isMoveFieldObjectMediaToGallery()){
231 Set
<Media
> mediaSet
= fieldObservation
.getMedia();
232 for (Media media
: mediaSet
){
233 this.addFieldObjectMedia(media
);
235 mediaSet
.removeAll(getFieldObjectMedia());
237 throw new DerivedUnitFacadeNotSupportedException("Field object may not have direct media. Only (one) image gallery is allowed");
241 //test if descriptions are supported
242 ecology
= initializeFieldObjectTextDataWithSupportTest(Feature
.ECOLOGY(), false, false);
243 plantDescription
= initializeFieldObjectTextDataWithSupportTest(Feature
.DESCRIPTION(), false, false);
247 private DerivedUnitBase
getInitializedDerivedUnit(DerivedUnitBase derivedUnit
) {
248 IOccurrenceService occurrenceService
= this.config
.getOccurrenceService();
249 if (occurrenceService
== null){
252 List
<String
> propertyPaths
= this.config
.getPropertyPaths();
253 if (propertyPaths
== null){
256 propertyPaths
= getDerivedUnitPropertyPaths(propertyPaths
);
257 DerivedUnitBase result
= (DerivedUnitBase
)occurrenceService
.load(derivedUnit
.getUuid(), propertyPaths
);
262 * Initializes the derived unit according to the configuartions property path.
263 * If the property path is <code>null</code> or no occurrence service is given the
264 * returned object is the same as the input parameter.
265 * @param fieldObservation2
268 private FieldObservation
getInitializedFieldObservation(FieldObservation fieldObservation
) {
269 IOccurrenceService occurrenceService
= this.config
.getOccurrenceService();
270 if (occurrenceService
== null){
271 return fieldObservation
;
273 List
<String
> propertyPaths
= this.config
.getPropertyPaths();
274 if (propertyPaths
== null){
275 return fieldObservation
;
277 propertyPaths
= getFieldObjectPropertyPaths(propertyPaths
);
278 FieldObservation result
= (FieldObservation
)occurrenceService
.load(fieldObservation
.getUuid(), propertyPaths
);
283 * Transforms the property paths in a way that the facade is handled just like an
284 * ordinary CdmBase object.<BR>
285 * E.g. a property path "collectinAreas" will be translated into gatheringEvent.collectingAreas
286 * @param propertyPaths
289 private List
<String
> getFieldObjectPropertyPaths(List
<String
> propertyPaths
) {
290 List
<String
> result
= new ArrayList
<String
>();
291 for (String facadePath
: propertyPaths
){
292 // collecting areas (named area)
293 if (facadePath
.startsWith("collectingAreas")){
294 facadePath
= "gatheringEvent." + facadePath
;
295 result
.add(facadePath
);
297 // collector (agentBase)
298 else if (facadePath
.startsWith("collector")){
299 facadePath
= facadePath
.replace("collector", "gatheringEvent.actor");
300 result
.add(facadePath
);
302 // exactLocation (agentBase)
303 else if (facadePath
.startsWith("exactLocation")){
304 facadePath
= "gatheringEvent." + facadePath
;
305 result
.add(facadePath
);
307 // gatheringPeriod (TimePeriod)
308 else if (facadePath
.startsWith("gatheringPeriod")){
309 facadePath
= facadePath
.replace("gatheringPeriod", "gatheringEvent.timeperiod");
310 result
.add(facadePath
);
312 // (locality/ localityLanguage , LanguageString)
313 else if (facadePath
.startsWith("locality")){
314 facadePath
= "gatheringEvent." + facadePath
;
315 result
.add(facadePath
);
318 //*********** FIELD OBJECT ************
319 // fieldObjectDefinitions (Map<language, languageString)
320 else if (facadePath
.startsWith("fieldObjectDefinitions")){
321 // TODO or definition ???
322 facadePath
= facadePath
.replace("fieldObjectDefinitions", "description");
323 result
.add(facadePath
);
325 // fieldObjectMedia (Media)
326 else if (facadePath
.startsWith("fieldObjectMedia")){
328 facadePath
= facadePath
.replace("fieldObjectMedia", "descriptions.elements.media");
329 result
.add(facadePath
);
332 //Gathering Event will always be added
333 result
.add("gatheringEvent");
340 - gatheringEvent (GatheringEvent)
344 - ecology/ ecologyAll (String) ???
345 - plant description (like ecology)
347 - fieldObjectImageGallery (SpecimenDescription) - is automatically initialized via fieldObjectMedia
355 * Transforms the property paths in a way that the facade is handled just like an
356 * ordinary CdmBase object.<BR>
357 * E.g. a property path "collectinAreas" will be translated into gatheringEvent.collectingAreas
359 * Not needed (?) as the facade works with REST service property paths without using this method.
360 * @param propertyPaths
363 private List
<String
> getDerivedUnitPropertyPaths(List
<String
> propertyPaths
) {
364 List
<String
> result
= new ArrayList
<String
>();
365 for (String facadePath
: propertyPaths
){
366 // determinations (DeterminationEvent)
367 if (facadePath
.startsWith("determinations")){
368 facadePath
= "" + facadePath
; //no change
369 result
.add(facadePath
);
371 // storedUnder (TaxonNameBase)
372 else if (facadePath
.startsWith("storedUnder")){
373 facadePath
= "" + facadePath
; //no change
374 result
.add(facadePath
);
376 // sources (IdentifiableSource)
377 else if (facadePath
.startsWith("sources")){
378 facadePath
= "" + facadePath
; //no change
379 result
.add(facadePath
);
381 // collection (Collection)
382 else if (facadePath
.startsWith("collection")){
383 facadePath
= "" + facadePath
; //no change
384 result
.add(facadePath
);
386 // (locality/ localityLanguage , LanguageString)
387 else if (facadePath
.startsWith("locality")){
388 facadePath
= "gatheringEvent." + facadePath
;
389 result
.add(facadePath
);
392 //*********** FIELD OBJECT ************
393 // derivedUnitDefinitions (Map<language, languageString)
394 else if (facadePath
.startsWith("derivedUnitDefinitions")){
395 // TODO or definition ???
396 facadePath
= facadePath
.replace("derivedUnitDefinitions", "description");
397 result
.add(facadePath
);
400 // derivedUnitMedia (Media)
401 else if (facadePath
.startsWith("derivedUnitMedia")){
403 facadePath
= facadePath
.replace("derivedUnitMedia", "descriptions.elements.media");
404 result
.add(facadePath
);
412 =====================
414 - derivedUnitImageGallery (SpecimenDescription) - is automatically initialized via derivedUnitMedia
416 - derivationEvent (DerivationEvent) - will always be initialized
417 - duplicates (??? Specimen???) ???
426 private void setCacheStrategy() {
427 derivedUnit
.setCacheStrategy(new DerivedUnitFacadeCacheStrategy());
433 * @param createIfNotExists
434 * @param isImageGallery
436 * @throws DerivedUnitFacadeNotSupportedException
438 private TextData
initializeFieldObjectTextDataWithSupportTest(Feature feature
, boolean createIfNotExists
, boolean isImageGallery
) throws DerivedUnitFacadeNotSupportedException
{
440 FieldObservation fieldObject
= getFieldObservation(createIfNotExists
) ;
441 if (fieldObject
== null){
444 return inititializeTextDataWithSupportTest(feature
, fieldObject
, createIfNotExists
, isImageGallery
);
451 * @param createIfNotExists
452 * @param isImageGallery
454 * @throws DerivedUnitFacadeNotSupportedException
456 private TextData
inititializeTextDataWithSupportTest(Feature feature
, SpecimenOrObservationBase specimen
, boolean createIfNotExists
,
457 boolean isImageGallery
) throws DerivedUnitFacadeNotSupportedException
{
458 if (feature
== null ){
461 TextData textData
= null;
462 if (createIfNotExists
){
463 textData
= TextData
.NewInstance(feature
);
466 Set
<SpecimenDescription
> descriptions
;
468 descriptions
= specimen
.getSpecimenDescriptionImageGallery();
470 descriptions
= specimen
.getSpecimenDescriptions(false);
472 if (descriptions
.size() == 0){
473 if (createIfNotExists
){
474 SpecimenDescription newSpecimenDescription
= SpecimenDescription
.NewInstance(specimen
);
475 newSpecimenDescription
.addElement(textData
);
481 Set
<DescriptionElementBase
> existingTextData
= new HashSet
<DescriptionElementBase
>();
482 for (SpecimenDescription description
: descriptions
){
483 for (DescriptionElementBase element
: description
.getElements()){
484 if (element
.isInstanceOf(TextData
.class) && ( feature
.equals(element
.getFeature() )|| isImageGallery
) ){
485 existingTextData
.add(element
);
489 if (existingTextData
.size() > 1){
490 throw new DerivedUnitFacadeNotSupportedException("Specimen facade does not support more than one description text data of type " + feature
.getLabel());
492 }else if (existingTextData
.size() == 1){
493 return CdmBase
.deproxy(existingTextData
.iterator().next(), TextData
.class);
495 SpecimenDescription description
= descriptions
.iterator().next();
496 description
.addElement(textData
);
503 * Tests if a given image gallery is supported by the derived unit facade.
504 * It returns the only text data attached to the given image gallery.
505 * It the given image gallery does not have text data attached, it is created and attached.
506 * @param imageGallery
508 * @throws DerivedUnitFacadeNotSupportedException
510 private TextData
testImageGallery(SpecimenDescription imageGallery
) throws DerivedUnitFacadeNotSupportedException
{
511 if (imageGallery
.isImageGallery() == false){
512 throw new DerivedUnitFacadeNotSupportedException("Image gallery needs to have image gallery flag set");
514 if (imageGallery
.getElements().size() > 1){
515 throw new DerivedUnitFacadeNotSupportedException("Image gallery must not have more then one description element");
518 if (imageGallery
.getElements().size() == 0){
519 textData
= TextData
.NewInstance(Feature
.IMAGE());
520 imageGallery
.addElement(textData
);
522 if (! imageGallery
.getElements().iterator().next().isInstanceOf(TextData
.class)){
523 throw new DerivedUnitFacadeNotSupportedException("Image gallery must only have TextData as element");
525 textData
= CdmBase
.deproxy(imageGallery
.getElements().iterator().next(), TextData
.class);
531 //************************** METHODS *****************************************
533 private TextData
getDerivedUnitImageGalleryTextData(boolean createIfNotExists
) throws DerivedUnitFacadeNotSupportedException
{
534 if (this.derivedUnitMediaTextData
== null && createIfNotExists
){
535 this.derivedUnitMediaTextData
= getImageGalleryTextData(derivedUnit
, "Specimen");
537 return this.derivedUnitMediaTextData
;
540 private TextData
getObservationImageGalleryTextData(boolean createIfNotExists
) throws DerivedUnitFacadeNotSupportedException
{
541 if (this.fieldObjectMediaTextData
== null && createIfNotExists
){
542 this.fieldObjectMediaTextData
= getImageGalleryTextData(fieldObservation
, "Field observation");
544 return this.fieldObjectMediaTextData
;
550 * @param derivationEvent2
552 * @throws DerivedUnitFacadeNotSupportedException
554 private Set
<FieldObservation
> getFieldObservationsOriginals(DerivationEvent derivationEvent
, Set
<SpecimenOrObservationBase
> recursionAvoidSet
) throws DerivedUnitFacadeNotSupportedException
{
555 if (recursionAvoidSet
== null){
556 recursionAvoidSet
= new HashSet
<SpecimenOrObservationBase
>();
558 Set
<FieldObservation
> result
= new HashSet
<FieldObservation
>();
559 Set
<SpecimenOrObservationBase
> originals
= derivationEvent
.getOriginals();
560 for (SpecimenOrObservationBase original
: originals
){
561 if (original
.isInstanceOf(FieldObservation
.class)){
562 result
.add(CdmBase
.deproxy(original
, FieldObservation
.class));
563 }else if (original
.isInstanceOf(DerivedUnitBase
.class)){
564 //if specimen has already been tested exclude it from further recursion
565 if (recursionAvoidSet
.contains(original
)){
568 DerivedUnitBase derivedUnit
= CdmBase
.deproxy(original
, DerivedUnitBase
.class);
569 DerivationEvent originalDerivation
= derivedUnit
.getDerivedFrom();
570 // Set<DerivationEvent> derivationEvents = original.getDerivationEvents();
571 // for (DerivationEvent originalDerivation : derivationEvents){
572 Set
<FieldObservation
> fieldObservations
= getFieldObservationsOriginals(originalDerivation
, recursionAvoidSet
);
573 result
.addAll(fieldObservations
);
576 throw new DerivedUnitFacadeNotSupportedException("Unhandled specimen or observation base type: " + original
.getClass().getName() );
583 //*********** MEDIA METHODS ******************************
586 // * Returns the media list for a specimen. Throws an exception if the existing specimen descriptions
587 // * are not supported by this facade.
588 // * @param specimen the specimen the media belongs to
589 // * @param specimenExceptionText text describing the specimen for exception messages
591 // * @throws DerivedUnitFacadeNotSupportedException
593 // private List<Media> getImageGalleryMedia(SpecimenOrObservationBase specimen, String specimenExceptionText) throws DerivedUnitFacadeNotSupportedException{
594 // List<Media> result;
595 // SpecimenDescription imageGallery = getImageGalleryWithSupportTest(specimen, specimenExceptionText, true);
596 // TextData textData = getImageTextDataWithSupportTest(imageGallery, specimenExceptionText);
597 // result = textData.getMedia();
602 * Returns the media list for a specimen. Throws an exception if the existing specimen descriptions
603 * are not supported by this facade.
604 * @param specimen the specimen the media belongs to
605 * @param specimenExceptionText text describing the specimen for exception messages
607 * @throws DerivedUnitFacadeNotSupportedException
609 private TextData
getImageGalleryTextData(SpecimenOrObservationBase specimen
, String specimenExceptionText
) throws DerivedUnitFacadeNotSupportedException
{
611 SpecimenDescription imageGallery
= getImageGalleryWithSupportTest(specimen
, specimenExceptionText
, true);
612 result
= getImageTextDataWithSupportTest(imageGallery
, specimenExceptionText
);
618 * Returns the image gallery of the according specimen. Throws an exception if the attached
619 * image gallerie(s) are not supported by this facade.
620 * If no image gallery exists a new one is created if <code>createNewIfNotExists</code> is true and
621 * if specimen is not <code>null</code>.
623 * @param specimenText
624 * @param createNewIfNotExists
626 * @throws DerivedUnitFacadeNotSupportedException
628 private SpecimenDescription
getImageGalleryWithSupportTest(SpecimenOrObservationBase
<?
> specimen
, String specimenText
, boolean createNewIfNotExists
) throws DerivedUnitFacadeNotSupportedException
{
629 if (specimen
== null){
632 SpecimenDescription imageGallery
;
633 if (hasMultipleImageGalleries(specimen
)){
634 throw new DerivedUnitFacadeNotSupportedException( specimenText
+ " must not have more than 1 image gallery");
636 imageGallery
= getImageGallery(specimen
, createNewIfNotExists
);
637 getImageTextDataWithSupportTest(imageGallery
, specimenText
);
643 * Returns the media holding text data element of the image gallery. Throws an exception if multiple
644 * such text data already exist.
645 * Creates a new text data if none exists and adds it to the image gallery.
646 * If image gallery is <code>null</code> nothing happens.
647 * @param imageGallery
650 * @throws DerivedUnitFacadeNotSupportedException
652 private TextData
getImageTextDataWithSupportTest(SpecimenDescription imageGallery
, String specimenText
) throws DerivedUnitFacadeNotSupportedException
{
653 if (imageGallery
== null){
656 TextData textData
= null;
657 for (DescriptionElementBase element
: imageGallery
.getElements()){
658 if (element
.isInstanceOf(TextData
.class) && element
.getFeature().equals(Feature
.IMAGE())){
659 if (textData
!= null){
660 throw new DerivedUnitFacadeNotSupportedException( specimenText
+ " must not have more than 1 image text data element in image gallery");
662 textData
= CdmBase
.deproxy(element
, TextData
.class);
665 if (textData
== null){
666 textData
= TextData
.NewInstance(Feature
.IMAGE());
667 imageGallery
.addElement(textData
);
673 * Checks, if a specimen belongs to more than one description that is an image gallery
677 private boolean hasMultipleImageGalleries(SpecimenOrObservationBase
<?
> derivedUnit
){
679 Set
<SpecimenDescription
> descriptions
= derivedUnit
.getSpecimenDescriptions();
680 for (SpecimenDescription description
: descriptions
){
681 if (description
.isImageGallery()){
690 * Returns the image gallery for a specimen. If there are multiple specimen descriptions
691 * marked as image galleries an arbitrary one is chosen.
692 * If no image gallery exists, a new one is created if <code>createNewIfNotExists</code>
693 * is <code>true</code>.<Br>
694 * If specimen is <code>null</code> a null pointer exception is thrown.
695 * @param createNewIfNotExists
698 private SpecimenDescription
getImageGallery(SpecimenOrObservationBase
<?
> specimen
, boolean createIfNotExists
) {
699 SpecimenDescription result
= null;
700 Set
<SpecimenDescription
> descriptions
= specimen
.getSpecimenDescriptions();
701 for (SpecimenDescription description
: descriptions
){
702 if (description
.isImageGallery()){
703 result
= description
;
707 if (result
== null && createIfNotExists
){
708 result
= SpecimenDescription
.NewInstance(specimen
);
709 result
.setImageGallery(true);
715 * Adds a media to the specimens image gallery. If media is <code>null</code> nothing happens.
718 * @return true if media is not null (as specified by {@link java.util.Collection#add(Object) Collection.add(E e)}
719 * @throws DerivedUnitFacadeNotSupportedException
721 private boolean addMedia(Media media
, SpecimenOrObservationBase
<?
> specimen
) throws DerivedUnitFacadeNotSupportedException
{
723 List
<Media
> mediaList
= getMedia(specimen
, true);
724 return mediaList
.add(media
);
731 * Removes a media from the specimens image gallery.
734 * @return true if an element was removed as a result of this call (as specified by {@link java.util.Collection#remove(Object) Collection.remove(E e)}
735 * @throws DerivedUnitFacadeNotSupportedException
737 private boolean removeMedia(Media media
, SpecimenOrObservationBase
<?
> specimen
) throws DerivedUnitFacadeNotSupportedException
{
738 List
<Media
> mediaList
= getMedia(specimen
, true);
739 return mediaList
== null ?
null : mediaList
.remove(media
);
742 private List
<Media
> getMedia(SpecimenOrObservationBase
<?
> specimen
, boolean createIfNotExists
) throws DerivedUnitFacadeNotSupportedException
{
743 TextData textData
= getMediaTextData(specimen
, createIfNotExists
);
744 return textData
== null ?
null : textData
.getMedia();
748 * Returns the one media list of a specimen which is part of the only image gallery that
749 * this specimen is part of.<BR>
750 * If these conditions are not hold an exception is thrwon.
753 * @throws DerivedUnitFacadeNotSupportedException
755 // private List<Media> getMedia(SpecimenOrObservationBase<?> specimen) throws DerivedUnitFacadeNotSupportedException {
756 // if (specimen == null){
759 // if (specimen == this.derivedUnit){
760 // return getDerivedUnitImageGalleryMedia();
761 // }else if (specimen == this.fieldObservation){
762 // return getObservationImageGalleryTextData();
764 // return getImageGalleryMedia(specimen, "Undefined specimen ");
769 * Returns the one media list of a specimen which is part of the only image gallery that
770 * this specimen is part of.<BR>
771 * If these conditions are not hold an exception is thrwon.
774 * @throws DerivedUnitFacadeNotSupportedException
776 private TextData
getMediaTextData(SpecimenOrObservationBase
<?
> specimen
, boolean createIfNotExists
) throws DerivedUnitFacadeNotSupportedException
{
777 if (specimen
== null){
780 if (specimen
== this.derivedUnit
){
781 return getDerivedUnitImageGalleryTextData(createIfNotExists
);
782 }else if (specimen
== this.fieldObservation
){
783 return getObservationImageGalleryTextData(createIfNotExists
);
785 return getImageGalleryTextData(specimen
, "Undefined specimen ");
790 //****************** GETTER / SETTER / ADDER / REMOVER ***********************/
792 // ****************** Gathering Event *********************************/
796 public NamedArea
getCountry(){
797 return (hasGatheringEvent() ?
getGatheringEvent(true).getCountry() : null);
800 public void setCountry(NamedArea country
){
801 getGatheringEvent(true).setCountry(country
);
806 public void addCollectingArea(NamedArea area
) {
807 getGatheringEvent(true).addCollectingArea(area
);
809 public void addCollectingAreas(java
.util
.Collection
<NamedArea
> areas
) {
810 for (NamedArea area
: areas
){
811 getGatheringEvent(true).addCollectingArea(area
);
815 public Set
<NamedArea
> getCollectingAreas() {
816 return (hasGatheringEvent() ?
getGatheringEvent(true).getCollectingAreas() : null);
818 public void removeCollectingArea(NamedArea area
) {
819 if (hasGatheringEvent()){
820 getGatheringEvent(true).removeCollectingArea(area
);
825 /** meter above/below sea level of the surface
826 * @see #getAbsoluteElevationError()
827 * @see #getAbsoluteElevationRange()
830 public Integer
getAbsoluteElevation() {
831 return (hasGatheringEvent() ?
getGatheringEvent(true).getAbsoluteElevation() : null);
833 public void setAbsoluteElevation(Integer absoluteElevation
) {
834 getGatheringEvent(true).setAbsoluteElevation(absoluteElevation
);
837 //absolute elevation error
839 public Integer
getAbsoluteElevationError() {
840 return (hasGatheringEvent() ?
getGatheringEvent(true).getAbsoluteElevationError() : null);
842 public void setAbsoluteElevationError(Integer absoluteElevationError
) {
843 getGatheringEvent(true).setAbsoluteElevationError(absoluteElevationError
);
847 * @see #getAbsoluteElevation()
848 * @see #getAbsoluteElevationError()
849 * @see #setAbsoluteElevationRange(Integer, Integer)
850 * @see #getAbsoluteElevationMaximum()
853 public Integer
getAbsoluteElevationMinimum(){
854 if ( ! hasGatheringEvent() ){
857 Integer minimum
= getGatheringEvent(true).getAbsoluteElevation();
858 if (getGatheringEvent(true).getAbsoluteElevationError() != null){
859 minimum
= minimum
- getGatheringEvent(true).getAbsoluteElevationError();
864 * @see #getAbsoluteElevation()
865 * @see #getAbsoluteElevationError()
866 * @see #setAbsoluteElevationRange(Integer, Integer)
867 * @see #getAbsoluteElevationMinimum()
870 public Integer
getAbsoluteElevationMaximum(){
871 if ( ! hasGatheringEvent() ){
874 Integer maximum
= getGatheringEvent(true).getAbsoluteElevation();
875 if (getGatheringEvent(true).getAbsoluteElevationError() != null){
876 maximum
= maximum
+ getGatheringEvent(true).getAbsoluteElevationError();
883 * This method replaces absoluteElevation and absoulteElevationError by
884 * internally translating minimum and maximum values into
885 * average and error values. As all these values are integer based
886 * it is necessary that the distance is between minimum and maximum is <b>even</b>,
887 * otherwise we will get a rounding error resulting in a maximum that is increased
889 * @see #setAbsoluteElevation(Integer)
890 * @see #setAbsoluteElevationError(Integer)
891 * @param minimumElevation minimum of the range
892 * @param maximumElevation maximum of the range
894 public void setAbsoluteElevationRange(Integer minimumElevation
, Integer maximumElevation
){
895 if (minimumElevation
== null || maximumElevation
== null){
896 Integer elevation
= minimumElevation
;
898 if (minimumElevation
== null){
899 elevation
= maximumElevation
;
900 if (elevation
== null){
904 getGatheringEvent(true).setAbsoluteElevation(elevation
);
905 getGatheringEvent(true).setAbsoluteElevationError(error
);
907 if (! isEvenDistance(minimumElevation
, maximumElevation
) ){
908 throw new IllegalArgumentException("Distance between minimum and maximum elevation must be even but was " + Math
.abs(minimumElevation
- maximumElevation
));
910 Integer absoluteElevationError
= Math
.abs(maximumElevation
- minimumElevation
);
911 absoluteElevationError
= absoluteElevationError
/ 2;
912 Integer absoluteElevation
= minimumElevation
+ absoluteElevationError
;
913 getGatheringEvent(true).setAbsoluteElevation(absoluteElevation
);
914 getGatheringEvent(true).setAbsoluteElevationError(absoluteElevationError
);
919 * @param minimumElevation
920 * @param maximumElevation
923 private boolean isEvenDistance(Integer minimumElevation
, Integer maximumElevation
) {
924 Integer diff
= ( maximumElevation
- minimumElevation
);
925 Integer testDiff
= (diff
/2) *2 ;
926 return (testDiff
== diff
);
931 public AgentBase
getCollector() {
932 return (hasGatheringEvent() ?
getGatheringEvent(true).getCollector() : null);
934 public void setCollector(AgentBase collector
){
935 getGatheringEvent(true).setCollector(collector
);
940 public String
getCollectingMethod() {
941 return (hasGatheringEvent() ?
getGatheringEvent(true).getCollectingMethod() : null);
943 public void setCollectingMethod(String collectingMethod
) {
944 getGatheringEvent(true).setCollectingMethod(collectingMethod
);
949 public Integer
getDistanceToGround() {
950 return (hasGatheringEvent() ?
getGatheringEvent(true).getDistanceToGround() : null);
952 public void setDistanceToGround(Integer distanceToGround
) {
953 getGatheringEvent(true).setDistanceToGround(distanceToGround
);
956 //distance to water surface
958 public Integer
getDistanceToWaterSurface() {
959 return (hasGatheringEvent() ?
getGatheringEvent(true).getDistanceToWaterSurface() : null);
961 public void setDistanceToWaterSurface(Integer distanceToWaterSurface
) {
962 getGatheringEvent(true).setDistanceToWaterSurface(distanceToWaterSurface
);
967 public Point
getExactLocation() {
968 return (hasGatheringEvent() ?
getGatheringEvent(true).getExactLocation() : null );
972 * Returns a sexagesimal representation of the exact location (e.g. 12°59'N, 35°23E).
973 * If the exact location is <code>null</code> the empty string is returned.
974 * @param includeEmptySeconds
975 * @param includeReferenceSystem
978 public String
getExactLocationText(boolean includeEmptySeconds
, boolean includeReferenceSystem
){
979 return (this.getExactLocation() == null ?
"" : this.getExactLocation().toSexagesimalString(includeEmptySeconds
, includeReferenceSystem
));
981 public void setExactLocation(Point exactLocation
) {
982 getGatheringEvent(true).setExactLocation(exactLocation
);
984 public void setExactLocationByParsing(String longitudeToParse
, String latitudeToParse
, ReferenceSystem referenceSystem
, Integer errorRadius
) throws ParseException
{
985 Point point
= Point
.NewInstance(null, null, referenceSystem
, errorRadius
);
986 point
.setLongitudeByParsing(longitudeToParse
);
987 point
.setLatitudeByParsing(latitudeToParse
);
988 setExactLocation(point
);
991 //gathering event description
993 public String
getGatheringEventDescription() {
994 return (hasGatheringEvent() ?
getGatheringEvent(true).getDescription() : null);
996 public void setGatheringEventDescription(String description
) {
997 getGatheringEvent(true).setDescription(description
);
1002 public TimePeriod
getGatheringPeriod() {
1003 return (hasGatheringEvent() ?
getGatheringEvent(true).getTimeperiod() : null);
1005 public void setGatheringPeriod(TimePeriod timeperiod
) {
1006 getGatheringEvent(true).setTimeperiod(timeperiod
);
1011 public LanguageString
getLocality(){
1012 return (hasGatheringEvent() ?
getGatheringEvent(true).getLocality() : null);
1015 * convienience method for {@link #getLocality()}.{@link LanguageString#getText() getText()}
1019 public String
getLocalityText(){
1020 LanguageString locality
= getLocality();
1021 if(locality
!= null){
1022 return locality
.getText();
1027 * convienience method for {@link #getLocality()}.{@link LanguageString#getLanguage() getLanguage()}
1031 public Language
getLocalityLanguage(){
1032 LanguageString locality
= getLocality();
1033 if(locality
!= null){
1034 return locality
.getLanguage();
1040 * Sets the locality string in the default language
1043 public void setLocality(String locality
){
1044 Language language
= Language
.DEFAULT();
1045 setLocality(locality
, language
);
1047 public void setLocality(String locality
, Language language
){
1048 LanguageString langString
= LanguageString
.NewInstance(locality
, language
);
1049 setLocality(langString
);
1051 public void setLocality(LanguageString locality
){
1052 getGatheringEvent(true).setLocality(locality
);
1056 * The gathering event will be used for the field object instead of the old gathering event.<BR>
1057 * <B>This method will override all gathering values (see below).</B>
1058 * @see #getAbsoluteElevation()
1059 * @see #getAbsoluteElevationError()
1060 * @see #getDistanceToGround()
1061 * @see #getDistanceToWaterSurface()
1062 * @see #getExactLocation()
1063 * @see #getGatheringEventDescription()
1064 * @see #getGatheringPeriod()
1065 * @see #getCollectingAreas()
1066 * @see #getCollectingMethod()
1067 * @see #getLocality()
1068 * @see #getCollector()
1069 * @param gatheringEvent
1071 public void setGatheringEvent(GatheringEvent gatheringEvent
) {
1072 getFieldObservation(true).setGatheringEvent(gatheringEvent
);
1074 public boolean hasGatheringEvent(){
1075 return (getGatheringEvent(false) != null);
1078 public GatheringEvent
innerGatheringEvent() {
1079 return getGatheringEvent(false);
1082 public GatheringEvent
getGatheringEvent(boolean createIfNotExists
) {
1083 if (! hasFieldObservation() && ! createIfNotExists
){
1086 if (createIfNotExists
&& getFieldObservation(true).getGatheringEvent() == null ){
1087 GatheringEvent gatheringEvent
= GatheringEvent
.NewInstance();
1088 getFieldObservation(true).setGatheringEvent(gatheringEvent
);
1090 return getFieldObservation(true).getGatheringEvent();
1093 // ****************** Field Object ************************************/
1096 * Returns true if a field observation exists (even if all attributes are empty or <code>null<code>.
1099 public boolean hasFieldObject(){
1100 return this.fieldObservation
!= null;
1105 public String
getEcology(){
1106 return getEcology(Language
.DEFAULT());
1108 public String
getEcology(Language language
){
1109 LanguageString languageString
= getEcologyAll().get(language
);
1110 return (languageString
== null ?
null : languageString
.getText());
1112 // public String getEcologyPreferred(List<Language> languages){
1113 // LanguageString languageString = getEcologyAll().getPreferredLanguageString(languages);
1114 // return languageString.getText();
1117 public Map
<Language
, LanguageString
> getEcologyAll(){
1118 if (ecology
== null){
1120 ecology
= initializeFieldObjectTextDataWithSupportTest(Feature
.ECOLOGY(), false, false);
1121 } catch (DerivedUnitFacadeNotSupportedException e
) {
1122 throw new IllegalStateException(notSupportMessage
, e
);
1124 if (ecology
== null){
1125 return new HashMap
<Language
, LanguageString
>();
1128 return ecology
.getMultilanguageText();
1131 public void setEcology(String ecology
){
1132 setEcology(ecology
, null);
1134 public void setEcology(String ecologyText
, Language language
){
1135 if (language
== null){
1136 language
= Language
.DEFAULT();
1138 if (ecology
== null){
1140 ecology
= initializeFieldObjectTextDataWithSupportTest(Feature
.ECOLOGY(), true, false);
1141 } catch (DerivedUnitFacadeNotSupportedException e
) {
1142 throw new IllegalStateException(notSupportMessage
, e
);
1145 if (ecologyText
== null){
1146 ecology
.removeText(language
);
1148 ecology
.putText(ecologyText
, language
);
1151 public void removeEcology(Language language
){
1152 setEcology(null, language
);
1155 * Removes ecology for the default language
1157 public void removeEcology(){
1158 setEcology(null, null);
1160 public void removeEcologyAll(){
1167 public String
getPlantDescription(){
1168 return getPlantDescription(null);
1170 public String
getPlantDescription(Language language
){
1171 if (language
== null){
1172 language
= Language
.DEFAULT();
1174 LanguageString languageString
= getPlantDescriptionAll().get(language
);
1175 return (languageString
== null ?
null : languageString
.getText());
1177 // public String getPlantDescriptionPreferred(List<Language> languages){
1178 // LanguageString languageString = getPlantDescriptionAll().getPreferredLanguageString(languages);
1179 // return languageString.getText();
1182 public Map
<Language
, LanguageString
> getPlantDescriptionAll(){
1183 if (plantDescription
== null){
1185 plantDescription
= initializeFieldObjectTextDataWithSupportTest(Feature
.DESCRIPTION(), false, false);
1186 } catch (DerivedUnitFacadeNotSupportedException e
) {
1187 throw new IllegalStateException(notSupportMessage
, e
);
1189 if (plantDescription
== null){
1190 return new HashMap
<Language
, LanguageString
>();
1193 return plantDescription
.getMultilanguageText();
1195 public void setPlantDescription(String plantDescription
){
1196 setPlantDescription(plantDescription
, null);
1198 public void setPlantDescription(String plantDescriptionText
, Language language
){
1199 if (language
== null){
1200 language
= Language
.DEFAULT();
1202 if (plantDescription
== null){
1204 plantDescription
= initializeFieldObjectTextDataWithSupportTest(Feature
.DESCRIPTION(), true, false);
1205 } catch (DerivedUnitFacadeNotSupportedException e
) {
1206 throw new IllegalStateException(notSupportMessage
, e
);
1209 if (plantDescriptionText
== null){
1210 plantDescription
.removeText(language
);
1212 plantDescription
.putText(plantDescriptionText
, language
);
1215 public void removePlantDescription(Language language
){
1216 setPlantDescription(null, language
);
1219 //field object definition
1220 public void addFieldObjectDefinition(String text
, Language language
) {
1221 getFieldObservation(true).addDefinition(text
, language
);
1224 public Map
<Language
, LanguageString
> getFieldObjectDefinition() {
1225 if (! hasFieldObservation()){
1226 return new HashMap
<Language
, LanguageString
>();
1228 return getFieldObservation(true).getDefinition();
1231 public String
getFieldObjectDefinition(Language language
) {
1232 Map
<Language
, LanguageString
> map
= getFieldObjectDefinition();
1233 LanguageString languageString
= (map
== null?
null : map
.get(language
));
1234 if (languageString
!= null){
1235 return languageString
.getText();
1240 public void removeFieldObjectDefinition(Language lang
) {
1241 if (hasFieldObservation()){
1242 getFieldObservation(true).removeDefinition(lang
);
1248 public boolean addFieldObjectMedia(Media media
) {
1250 return addMedia(media
, getFieldObservation(true));
1251 } catch (DerivedUnitFacadeNotSupportedException e
) {
1252 throw new IllegalStateException(notSupportMessage
, e
);
1256 * Returns true, if an image gallery for the field object exists.<BR>
1257 * Returns also <code>true</code> if the image gallery is empty.
1260 public boolean hasFieldObjectImageGallery(){
1261 if (! hasFieldObject()){
1264 return (getImageGallery(fieldObservation
, false) != null);
1268 public void setFieldObjectImageGallery(SpecimenDescription imageGallery
) throws DerivedUnitFacadeNotSupportedException
{
1269 SpecimenDescription existingGallery
= getFieldObjectImageGallery(false);
1270 //TODO test attached fieldObject is the same as this.getFieldObject
1272 if (existingGallery
!= null){
1273 if (existingGallery
!= imageGallery
){
1274 throw new DerivedUnitFacadeNotSupportedException("DerivedUnitFacade does not allow more than one image gallery");
1279 TextData textData
= testImageGallery(imageGallery
);
1280 this.fieldObjectMediaTextData
= textData
;
1286 * Returns the field object image gallery. If no such image gallery exists and
1287 * createIfNotExists is true an new one is created. Otherwise null is returned.
1288 * @param createIfNotExists
1291 public SpecimenDescription
getFieldObjectImageGallery(boolean createIfNotExists
){
1294 textData
= initializeFieldObjectTextDataWithSupportTest(Feature
.IMAGE(), createIfNotExists
, true);
1295 } catch (DerivedUnitFacadeNotSupportedException e
) {
1296 throw new IllegalStateException(notSupportMessage
, e
);
1298 if (textData
!= null){
1299 return CdmBase
.deproxy(textData
.getInDescription(), SpecimenDescription
.class);
1305 * Returns the media for the field object.<BR>
1309 public List
<Media
> getFieldObjectMedia() {
1311 List
<Media
> result
= getMedia(getFieldObservation(false), false);
1312 return result
== null ?
new ArrayList
<Media
>() : result
;
1313 } catch (DerivedUnitFacadeNotSupportedException e
) {
1314 throw new IllegalStateException(notSupportMessage
, e
);
1317 public boolean removeFieldObjectMedia(Media media
) {
1319 return removeMedia(media
, getFieldObservation(false));
1320 } catch (DerivedUnitFacadeNotSupportedException e
) {
1321 throw new IllegalStateException(notSupportMessage
, e
);
1327 public String
getFieldNumber() {
1328 if (! hasFieldObservation()){
1331 return getFieldObservation(true).getFieldNumber();
1334 public void setFieldNumber(String fieldNumber
) {
1335 getFieldObservation(true).setFieldNumber(fieldNumber
);
1341 public String
getFieldNotes() {
1342 if (! hasFieldObservation()){
1345 return getFieldObservation(true).getFieldNotes();
1348 public void setFieldNotes(String fieldNotes
) {
1349 getFieldObservation(true).setFieldNotes(fieldNotes
);
1355 public Integer
getIndividualCount() {
1356 return (hasFieldObservation()?
getFieldObservation(true).getIndividualCount() : null );
1358 public void setIndividualCount(Integer individualCount
) {
1359 getFieldObservation(true).setIndividualCount(individualCount
);
1364 public Stage
getLifeStage() {
1365 return (hasFieldObservation()?
getFieldObservation(true).getLifeStage() : null );
1367 public void setLifeStage(Stage lifeStage
) {
1368 getFieldObservation(true).setLifeStage(lifeStage
);
1373 public Sex
getSex() {
1374 return (hasFieldObservation()?
getFieldObservation(true).getSex() : null );
1376 public void setSex(Sex sex
) {
1377 getFieldObservation(true).setSex(sex
);
1382 public boolean hasFieldObservation(){
1383 return (getFieldObservation(false) != null);
1387 * Returns the field observation as an object.
1390 public FieldObservation
innerFieldObservation(){
1391 return getFieldObservation(false);
1395 * Returns the field observation as an object.
1398 public FieldObservation
getFieldObservation(boolean createIfNotExists
){
1399 if (fieldObservation
== null && createIfNotExists
){
1400 fieldObservation
= FieldObservation
.NewInstance();
1401 fieldObservation
.addPropertyChangeListener(getNewEventPropagationListener());
1402 DerivationEvent derivationEvent
= getDerivationEvent(true);
1403 derivationEvent
.addOriginal(fieldObservation
);
1405 return this.fieldObservation
;
1412 //****************** Specimen **************************************************
1415 public void addDerivedUnitDefinition(String text
, Language language
) {
1416 derivedUnit
.addDefinition(text
, language
);
1419 public Map
<Language
, LanguageString
> getDerivedUnitDefinitions(){
1420 return this.derivedUnit
.getDefinition();
1422 public String
getDerivedUnitDefinition(Language language
) {
1423 Map
<Language
,LanguageString
> languageMap
= derivedUnit
.getDefinition();
1424 LanguageString languageString
= languageMap
.get(language
);
1425 if (languageString
!= null){
1426 return languageString
.getText();
1431 public void removeDerivedUnitDefinition(Language lang
) {
1432 derivedUnit
.removeDefinition(lang
);
1436 public void addDetermination(DeterminationEvent determination
) {
1437 derivedUnit
.addDetermination(determination
);
1440 public Set
<DeterminationEvent
> getDeterminations() {
1441 return derivedUnit
.getDeterminations();
1443 public void removeDetermination(DeterminationEvent determination
) {
1444 derivedUnit
.removeDetermination(determination
);
1448 public boolean addDerivedUnitMedia(Media media
) {
1450 return addMedia(media
, derivedUnit
);
1451 } catch (DerivedUnitFacadeNotSupportedException e
) {
1452 throw new IllegalStateException(notSupportMessage
, e
);
1456 * Returns true, if an image gallery exists for the specimen.<BR>
1457 * Returns also <code>true</code> if the image gallery is empty.
1459 public boolean hasDerivedUnitImageGallery(){
1460 return (getImageGallery(derivedUnit
, false) != null);
1463 public SpecimenDescription
getDerivedUnitImageGallery(boolean createIfNotExists
){
1466 textData
= inititializeTextDataWithSupportTest(Feature
.IMAGE(), derivedUnit
, createIfNotExists
, true);
1467 } catch (DerivedUnitFacadeNotSupportedException e
) {
1468 throw new IllegalStateException(notSupportMessage
, e
);
1470 if (textData
!= null){
1471 return CdmBase
.deproxy(textData
.getInDescription(), SpecimenDescription
.class);
1476 public void setDerivedUnitImageGallery(SpecimenDescription imageGallery
) throws DerivedUnitFacadeNotSupportedException
{
1477 SpecimenDescription existingGallery
= getDerivedUnitImageGallery(false);
1478 //TODO test attached fieldObject is the same as this.getFieldObject
1480 if (existingGallery
!= null){
1481 if (existingGallery
!= imageGallery
){
1482 throw new DerivedUnitFacadeNotSupportedException("DerivedUnitFacade does not allow more than one image gallery");
1487 TextData textData
= testImageGallery(imageGallery
);
1488 this.derivedUnitMediaTextData
= textData
;
1493 * Returns the media for the specimen.<BR>
1497 public List
<Media
> getDerivedUnitMedia() {
1499 List
<Media
> result
= getMedia(derivedUnit
, false);
1500 return result
== null ?
new ArrayList
<Media
>() : result
;
1501 } catch (DerivedUnitFacadeNotSupportedException e
) {
1502 throw new IllegalStateException(notSupportMessage
, e
);
1505 public boolean removeDerivedUnitMedia(Media media
) {
1507 return removeMedia(media
, derivedUnit
);
1508 } catch (DerivedUnitFacadeNotSupportedException e
) {
1509 throw new IllegalStateException(notSupportMessage
, e
);
1516 public String
getAccessionNumber() {
1517 return derivedUnit
.getAccessionNumber();
1519 public void setAccessionNumber(String accessionNumber
) {
1520 derivedUnit
.setAccessionNumber(accessionNumber
);
1524 public String
getCatalogNumber() {
1525 return derivedUnit
.getCatalogNumber();
1527 public void setCatalogNumber(String catalogNumber
) {
1528 derivedUnit
.setCatalogNumber(catalogNumber
);
1532 public String
getBarcode() {
1533 return derivedUnit
.getBarcode();
1535 public void setBarcode(String barcode
) {
1536 derivedUnit
.setCatalogNumber(barcode
);
1540 //Preservation Method
1543 * Only supported by specimen and fossils
1544 * @see #DerivedUnitType
1548 public PreservationMethod
getPreservationMethod() throws MethodNotSupportedByDerivedUnitTypeException
{
1549 if (derivedUnit
.isInstanceOf(Specimen
.class)){
1550 return CdmBase
.deproxy(derivedUnit
, Specimen
.class).getPreservation();
1552 if (this.config
.isThrowExceptionForNonSpecimenPreservationMethodRequest()){
1553 throw new MethodNotSupportedByDerivedUnitTypeException("A preservation method is only available in derived units of type 'Specimen' or 'Fossil'");
1560 * Only supported by specimen and fossils
1561 * @see #DerivedUnitType
1564 public void setPreservationMethod(PreservationMethod preservation
)throws MethodNotSupportedByDerivedUnitTypeException
{
1565 if (derivedUnit
.isInstanceOf(Specimen
.class)){
1566 CdmBase
.deproxy(derivedUnit
, Specimen
.class).setPreservation(preservation
);
1568 if (this.config
.isThrowExceptionForNonSpecimenPreservationMethodRequest()){
1569 throw new MethodNotSupportedByDerivedUnitTypeException("A preservation method is only available in derived units of type 'Specimen' or 'Fossil'");
1578 public TaxonNameBase
getStoredUnder() {
1579 return derivedUnit
.getStoredUnder();
1581 public void setStoredUnder(TaxonNameBase storedUnder
) {
1582 derivedUnit
.setStoredUnder(storedUnder
);
1587 public String
getCollectorsNumber() {
1588 return derivedUnit
.getCollectorsNumber();
1590 public void setCollectorsNumber(String collectorsNumber
) {
1591 this.derivedUnit
.setCollectorsNumber(collectorsNumber
);
1595 public String
getTitleCache() {
1596 if (! derivedUnit
.isProtectedTitleCache()){
1597 //always compute title cache anew as long as there are no property change listeners on
1598 //field observation, gathering event etc
1599 derivedUnit
.setTitleCache(null, false);
1601 return this.derivedUnit
.getTitleCache();
1603 public void setTitleCache(String titleCache
, boolean isProtected
) {
1604 this.derivedUnit
.setTitleCache(titleCache
, isProtected
);
1609 * Returns the derived unit itself.
1610 * @return the derived unit
1612 public DerivedUnitBase
innerDerivedUnit() {
1613 return this.derivedUnit
;
1616 private boolean hasDerivationEvent(){
1617 return getDerivationEvent() == null ?
false : true;
1619 private DerivationEvent
getDerivationEvent(){
1620 return getDerivationEvent(false);
1622 private DerivationEvent
getDerivationEvent(boolean createIfNotExists
){
1623 DerivationEvent result
= derivedUnit
.getDerivedFrom();
1624 if (result
== null){
1625 result
= DerivationEvent
.NewInstance();
1626 derivedUnit
.setDerivedFrom(result
);
1631 public String
getExsiccatum() {
1632 logger
.warn("Exsiccatum method not yet supported. Needs model change");
1636 public void setExsiccatum(String exsiccatum
) throws Exception
{
1637 throw new Exception("Exsiccatum method not yet supported. Needs model change");
1642 public void addSource(IdentifiableSource source
){
1643 this.derivedUnit
.addSource(source
);
1646 * Creates an orignal source, adds it to the specimen and returns it.
1648 * @param microReference
1649 * @param originalNameString
1652 public IdentifiableSource
addSource(ReferenceBase reference
, String microReference
, String originalNameString
){
1653 IdentifiableSource source
= IdentifiableSource
.NewInstance(reference
, microReference
);
1654 source
.setOriginalNameString(originalNameString
);
1655 derivedUnit
.addSource(source
);
1660 public Set
<IdentifiableSource
> getSources(){
1661 return derivedUnit
.getSources();
1664 public void removeSource(IdentifiableSource source
){
1665 this.derivedUnit
.removeSource(source
);
1670 * @return the collection
1673 public Collection
getCollection() {
1674 return derivedUnit
.getCollection();
1679 * @param collection the collection to set
1681 public void setCollection(Collection collection
) {
1682 derivedUnit
.setCollection(collection
);
1686 public void addAnnotation(Annotation annotation
){
1687 this.derivedUnit
.addAnnotation(annotation
);
1691 public void getAnnotations(){
1692 this.derivedUnit
.getAnnotations();
1695 public void removeAnnotation(Annotation annotation
){
1696 this.derivedUnit
.removeAnnotation(annotation
);
1700 // ******************************* Events *********************************************
1705 private PropertyChangeListener
getNewEventPropagationListener() {
1706 PropertyChangeListener listener
= new PropertyChangeListener(){
1708 public void propertyChange(PropertyChangeEvent event
) {
1709 derivedUnit
.firePropertyChange(event
);
1719 //**************** Other Collections ***************************************************
1722 * Creates a duplicate specimen which derives from the same derivation event
1723 * as the facade specimen and adds collection data to it (all data available in
1724 * DerivedUnitBase and Specimen. Data from SpecimenOrObservationBase and above
1725 * are not yet shared at the moment.
1727 * @param catalogNumber
1728 * @param accessionNumber
1729 * @param collectorsNumber
1730 * @param storedUnder
1731 * @param preservation
1734 public Specimen
addDuplicate(Collection collection
, String catalogNumber
, String accessionNumber
,
1735 String collectorsNumber
, TaxonNameBase storedUnder
, PreservationMethod preservation
){
1736 Specimen duplicate
= Specimen
.NewInstance();
1737 duplicate
.setDerivedFrom(getDerivationEvent(true));
1738 duplicate
.setCollection(collection
);
1739 duplicate
.setCatalogNumber(catalogNumber
);
1740 duplicate
.setAccessionNumber(accessionNumber
);
1741 duplicate
.setCollectorsNumber(collectorsNumber
);
1742 duplicate
.setStoredUnder(storedUnder
);
1743 duplicate
.setPreservation(preservation
);
1747 public void addDuplicate(DerivedUnitBase duplicateSpecimen
){
1748 //TODO check derivedUnitType
1749 getDerivationEvent(true).addDerivative(duplicateSpecimen
);
1753 public Set
<Specimen
> getDuplicates(){
1754 Set
<Specimen
> result
= new HashSet
<Specimen
>();
1755 if (hasDerivationEvent()){
1756 for (DerivedUnitBase derivedUnit
: getDerivationEvent(true).getDerivatives()){
1757 if (derivedUnit
.isInstanceOf(Specimen
.class) && ! derivedUnit
.equals(this.derivedUnit
)){
1758 result
.add(CdmBase
.deproxy(derivedUnit
, Specimen
.class));
1764 public void removeDuplicate(Specimen duplicateSpecimen
){
1765 if (hasDerivationEvent()){
1766 getDerivationEvent(true).removeDerivative(duplicateSpecimen
);