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
.beans
.PropertyChangeSupport
;
15 import java
.text
.ParseException
;
16 import java
.util
.ArrayList
;
17 import java
.util
.HashMap
;
18 import java
.util
.HashSet
;
19 import java
.util
.List
;
23 import javax
.mail
.MethodNotSupportedException
; //FIMXE use other execption class
24 import javax
.persistence
.Transient
;
27 import org
.apache
.log4j
.Logger
;
28 import org
.springframework
.beans
.factory
.annotation
.Autowired
;
30 import eu
.etaxonomy
.cdm
.api
.service
.IOccurrenceService
;
31 import eu
.etaxonomy
.cdm
.model
.agent
.AgentBase
;
32 import eu
.etaxonomy
.cdm
.model
.common
.Annotation
;
33 import eu
.etaxonomy
.cdm
.model
.common
.CdmBase
;
34 import eu
.etaxonomy
.cdm
.model
.common
.IdentifiableSource
;
35 import eu
.etaxonomy
.cdm
.model
.common
.Language
;
36 import eu
.etaxonomy
.cdm
.model
.common
.LanguageString
;
37 import eu
.etaxonomy
.cdm
.model
.common
.TimePeriod
;
38 import eu
.etaxonomy
.cdm
.model
.description
.DescriptionElementBase
;
39 import eu
.etaxonomy
.cdm
.model
.description
.Feature
;
40 import eu
.etaxonomy
.cdm
.model
.description
.Sex
;
41 import eu
.etaxonomy
.cdm
.model
.description
.SpecimenDescription
;
42 import eu
.etaxonomy
.cdm
.model
.description
.Stage
;
43 import eu
.etaxonomy
.cdm
.model
.description
.TextData
;
44 import eu
.etaxonomy
.cdm
.model
.location
.NamedArea
;
45 import eu
.etaxonomy
.cdm
.model
.location
.Point
;
46 import eu
.etaxonomy
.cdm
.model
.location
.ReferenceSystem
;
47 import eu
.etaxonomy
.cdm
.model
.media
.Media
;
48 import eu
.etaxonomy
.cdm
.model
.name
.TaxonNameBase
;
49 import eu
.etaxonomy
.cdm
.model
.occurrence
.Collection
;
50 import eu
.etaxonomy
.cdm
.model
.occurrence
.DerivationEvent
;
51 import eu
.etaxonomy
.cdm
.model
.occurrence
.DerivedUnitBase
;
52 import eu
.etaxonomy
.cdm
.model
.occurrence
.DeterminationEvent
;
53 import eu
.etaxonomy
.cdm
.model
.occurrence
.FieldObservation
;
54 import eu
.etaxonomy
.cdm
.model
.occurrence
.GatheringEvent
;
55 import eu
.etaxonomy
.cdm
.model
.occurrence
.PreservationMethod
;
56 import eu
.etaxonomy
.cdm
.model
.occurrence
.Specimen
;
57 import eu
.etaxonomy
.cdm
.model
.occurrence
.SpecimenOrObservationBase
;
58 import eu
.etaxonomy
.cdm
.model
.reference
.ReferenceBase
;
61 * This class is a facade to the eu.etaxonomy.cdm.model.occurrence package from
62 * a specimen based view. It does not support all functionality available in the
63 * occurrence package.<BR>
64 * The most significant restriction is that a specimen may derive only from
65 * one direct derivation event and there must be only one field observation (gathering event)
66 * it derives from.<BR>
71 public class DerivedUnitFacade
{
72 private static final Logger logger
= Logger
.getLogger(DerivedUnitFacade
.class);
74 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 ";
77 * Enum that defines the class the "Specimen" belongs to.
78 * Some methods of the facade are not available for certain classes
79 * and will throw an Exception when invoking them.
81 public enum DerivedUnitType
{
82 Specimen ("Specimen"),
83 Observation("Observation"),
84 LivingBeing("Living Being"),
86 DerivedUnit("Derived Unit");
88 String representation
;
89 private DerivedUnitType(String representation
){
90 this.representation
= representation
;
94 * @return the representation
96 public String
getRepresentation() {
97 return representation
;
100 private DerivedUnitBase
getNewDerivedUnitInstance(){
101 if (this == DerivedUnitType
.Specimen
){
102 return eu
.etaxonomy
.cdm
.model
.occurrence
.Specimen
.NewInstance();
103 }else if (this == DerivedUnitType
.Observation
){
104 return eu
.etaxonomy
.cdm
.model
.occurrence
.Observation
.NewInstance();
105 }else if (this == DerivedUnitType
.LivingBeing
){
106 return eu
.etaxonomy
.cdm
.model
.occurrence
.LivingBeing
.NewInstance();
107 }else if (this == DerivedUnitType
.Fossil
){
108 return eu
.etaxonomy
.cdm
.model
.occurrence
.Fossil
.NewInstance();
109 }else if (this == DerivedUnitType
.DerivedUnit
){
110 return eu
.etaxonomy
.cdm
.model
.occurrence
.DerivedUnit
.NewInstance();
112 throw new IllegalStateException("Unknown derived unit type " + this.getRepresentation());
119 private DerivedUnitFacadeConfigurator config
;
121 //private GatheringEvent gatheringEvent;
122 private DerivedUnitType type
; //needed?
124 private FieldObservation fieldObservation
;
126 private DerivedUnitBase derivedUnit
;
128 //media - the text data holding the media
129 private TextData derivedUnitMediaTextData
;
130 private TextData fieldObjectMediaTextData
;
133 private TextData ecology
;
134 private TextData plantDescription
;
138 * Creates a derived unit facade for a new derived unit of type <code>type</code>.
142 public static DerivedUnitFacade
NewInstance(DerivedUnitType type
){
143 return new DerivedUnitFacade(type
);
147 * Creates a derived unit facade for a given derived unit using the default configuation.
150 * @throws DerivedUnitFacadeNotSupportedException
152 public static DerivedUnitFacade
NewInstance(DerivedUnitBase derivedUnit
) throws DerivedUnitFacadeNotSupportedException
{
153 return new DerivedUnitFacade(derivedUnit
, null);
156 public static DerivedUnitFacade
NewInstance(DerivedUnitBase derivedUnit
, DerivedUnitFacadeConfigurator config
) throws DerivedUnitFacadeNotSupportedException
{
157 return new DerivedUnitFacade(derivedUnit
, config
);
162 // ****************** CONSTRUCTOR ****************************************************
164 private DerivedUnitFacade(DerivedUnitType type
){
165 this.config
= DerivedUnitFacadeConfigurator
.NewInstance();
168 derivedUnit
= type
.getNewDerivedUnitInstance();
172 private DerivedUnitFacade(DerivedUnitBase derivedUnit
, DerivedUnitFacadeConfigurator config
) throws DerivedUnitFacadeNotSupportedException
{
175 config
= DerivedUnitFacadeConfigurator
.NewInstance();
177 this.config
= config
;
180 this.derivedUnit
= derivedUnit
;
184 if (this.derivedUnit
.getDerivedFrom() != null){
185 DerivationEvent derivationEvent
= getDerivationEvent(true);
187 Set
<FieldObservation
> fieldOriginals
= getFieldObservationsOriginals(derivationEvent
, null);
188 if (fieldOriginals
.size() > 1){
189 throw new DerivedUnitFacadeNotSupportedException("Specimen must not have more than 1 derivation event");
190 }else if (fieldOriginals
.size() == 0){
191 //fieldObservation = FieldObservation.NewInstance();
192 }else if (fieldOriginals
.size() == 1){
193 fieldObservation
= fieldOriginals
.iterator().next();
194 //###fieldObservation = getInitializedFieldObservation(fieldObservation);
195 fieldObservation
.addPropertyChangeListener(getNewEventPropagationListener());
197 throw new IllegalStateException("Illegal state");
200 // #### derivedUnit = getInitializedDerivedUnit(derivedUnit);
202 //test if unsupported
206 // String objectTypeExceptionText = "Specimen";
207 // SpecimenDescription imageGallery = getImageGalleryWithSupportTest(derivedUnit, objectTypeExceptionText, false);
208 // getImageTextDataWithSupportTest(imageGallery, objectTypeExceptionText);
209 this.derivedUnitMediaTextData
= inititialzeTextDataWithSupportTest(Feature
.IMAGE(), this.derivedUnit
, false, true);
212 // objectTypeExceptionText = "Field observation";
213 // imageGallery = getImageGalleryWithSupportTest(fieldObservation, objectTypeExceptionText, false);
214 // getImageTextDataWithSupportTest(imageGallery, objectTypeExceptionText);
215 fieldObjectMediaTextData
= initializeFieldObjectTextDataWithSupportTest(Feature
.IMAGE(), false, true);
217 //handle derivedUnit.getMedia()
218 if (derivedUnit
.getMedia().size() > 0){
219 //TODO better changed model here to allow only one place for images
220 if (this.config
.isMoveDerivedUnitMediaToGallery()){
221 Set
<Media
> mediaSet
= derivedUnit
.getMedia();
222 for (Media media
: mediaSet
){
223 this.addDerivedUnitMedia(media
);
225 mediaSet
.removeAll(getDerivedUnitMedia());
227 throw new DerivedUnitFacadeNotSupportedException("Specimen may not have direct media. Only (one) image gallery is allowed");
231 //handle fieldObservation.getMedia()
232 if (fieldObservation
!= null && fieldObservation
.getMedia() != null && fieldObservation
.getMedia().size() > 0){
233 //TODO better changed model here to allow only one place for images
234 if (this.config
.isMoveFieldObjectMediaToGallery()){
235 Set
<Media
> mediaSet
= fieldObservation
.getMedia();
236 for (Media media
: mediaSet
){
237 this.addFieldObjectMedia(media
);
239 mediaSet
.removeAll(getFieldObjectMedia());
241 throw new DerivedUnitFacadeNotSupportedException("Field object may not have direct media. Only (one) image gallery is allowed");
245 //test if descriptions are supported
246 ecology
= initializeFieldObjectTextDataWithSupportTest(Feature
.ECOLOGY(), false, false);
247 plantDescription
= initializeFieldObjectTextDataWithSupportTest(Feature
.DESCRIPTION(), false, false);
251 private DerivedUnitBase
getInitializedDerivedUnit(DerivedUnitBase derivedUnit
) {
252 IOccurrenceService occurrenceService
= this.config
.getOccurrenceService();
253 if (occurrenceService
== null){
256 List
<String
> propertyPaths
= this.config
.getPropertyPaths();
257 if (propertyPaths
== null){
260 propertyPaths
= getDerivedUnitPropertyPaths(propertyPaths
);
261 DerivedUnitBase result
= (DerivedUnitBase
)occurrenceService
.load(derivedUnit
.getUuid(), propertyPaths
);
266 * Initializes the derived unit according to the configuartions property path.
267 * If the property path is <code>null</code> or no occurrence service is given the
268 * returned object is the same as the input parameter.
269 * @param fieldObservation2
272 private FieldObservation
getInitializedFieldObservation(FieldObservation fieldObservation
) {
273 IOccurrenceService occurrenceService
= this.config
.getOccurrenceService();
274 if (occurrenceService
== null){
275 return fieldObservation
;
277 List
<String
> propertyPaths
= this.config
.getPropertyPaths();
278 if (propertyPaths
== null){
279 return fieldObservation
;
281 propertyPaths
= getFieldObjectPropertyPaths(propertyPaths
);
282 FieldObservation result
= (FieldObservation
)occurrenceService
.load(fieldObservation
.getUuid(), propertyPaths
);
287 * Transforms the property paths in a way that the facade is handled just like an
288 * ordinary CdmBase object.<BR>
289 * E.g. a property path "collectinAreas" will be translated into gatheringEvent.collectingAreas
290 * @param propertyPaths
293 private List
<String
> getFieldObjectPropertyPaths(List
<String
> propertyPaths
) {
294 List
<String
> result
= new ArrayList
<String
>();
295 for (String facadePath
: propertyPaths
){
296 // collecting areas (named area)
297 if (facadePath
.startsWith("collectingAreas")){
298 facadePath
= "gatheringEvent." + facadePath
;
299 result
.add(facadePath
);
301 // collector (agentBase)
302 else if (facadePath
.startsWith("collector")){
303 facadePath
= facadePath
.replace("collector", "gatheringEvent.actor");
304 result
.add(facadePath
);
306 // exactLocation (agentBase)
307 else if (facadePath
.startsWith("exactLocation")){
308 facadePath
= "gatheringEvent." + facadePath
;
309 result
.add(facadePath
);
311 // gatheringPeriod (TimePeriod)
312 else if (facadePath
.startsWith("gatheringPeriod")){
313 facadePath
= facadePath
.replace("gatheringPeriod", "gatheringEvent.timeperiod");
314 result
.add(facadePath
);
316 // (locality/ localityLanguage , LanguageString)
317 else if (facadePath
.startsWith("locality")){
318 facadePath
= "gatheringEvent." + facadePath
;
319 result
.add(facadePath
);
322 //*********** FIELD OBJECT ************
323 // fieldObjectDefinitions (Map<language, languageString)
324 else if (facadePath
.startsWith("fieldObjectDefinitions")){
325 // TODO or definition ???
326 facadePath
= facadePath
.replace("fieldObjectDefinitions", "description");
327 result
.add(facadePath
);
329 // fieldObjectMedia (Media)
330 else if (facadePath
.startsWith("fieldObjectMedia")){
332 facadePath
= facadePath
.replace("fieldObjectMedia", "descriptions.elements.media");
333 result
.add(facadePath
);
336 //Gathering Event will always be added
337 result
.add("gatheringEvent");
344 - gatheringEvent (GatheringEvent)
348 - ecology/ ecologyAll (String) ???
349 - plant description (like ecology)
351 - fieldObjectImageGallery (SpecimenDescription) - is automatically initialized via fieldObjectMedia
359 * Transforms the property paths in a way that the facade is handled just like an
360 * ordinary CdmBase object.<BR>
361 * E.g. a property path "collectinAreas" will be translated into gatheringEvent.collectingAreas
362 * @param propertyPaths
365 private List
<String
> getDerivedUnitPropertyPaths(List
<String
> propertyPaths
) {
366 List
<String
> result
= new ArrayList
<String
>();
367 for (String facadePath
: propertyPaths
){
368 // determinations (DeterminationEvent)
369 if (facadePath
.startsWith("determinations")){
370 facadePath
= "" + facadePath
; //no change
371 result
.add(facadePath
);
373 // storedUnder (TaxonNameBase)
374 else if (facadePath
.startsWith("storedUnder")){
375 facadePath
= "" + facadePath
; //no change
376 result
.add(facadePath
);
378 // sources (IdentifiableSource)
379 else if (facadePath
.startsWith("sources")){
380 facadePath
= "" + facadePath
; //no change
381 result
.add(facadePath
);
383 // collection (Collection)
384 else if (facadePath
.startsWith("collection")){
385 facadePath
= "" + facadePath
; //no change
386 result
.add(facadePath
);
388 // (locality/ localityLanguage , LanguageString)
389 else if (facadePath
.startsWith("locality")){
390 facadePath
= "gatheringEvent." + facadePath
;
391 result
.add(facadePath
);
394 //*********** FIELD OBJECT ************
395 // derivedUnitDefinitions (Map<language, languageString)
396 else if (facadePath
.startsWith("derivedUnitDefinitions")){
397 // TODO or definition ???
398 facadePath
= facadePath
.replace("derivedUnitDefinitions", "description");
399 result
.add(facadePath
);
402 // derivedUnitMedia (Media)
403 else if (facadePath
.startsWith("derivedUnitMedia")){
405 facadePath
= facadePath
.replace("derivedUnitMedia", "descriptions.elements.media");
406 result
.add(facadePath
);
414 =====================
416 - derivedUnitImageGallery (SpecimenDescription) - is automatically initialized via derivedUnitMedia
418 - derivationEvent (DerivationEvent) - will always be initialized
419 - duplicates (??? Specimen???) ???
428 private void setCacheStrategy() {
429 derivedUnit
.setCacheStrategy(new DerivedUnitFacadeCacheStrategy());
435 * @param createIfNotExists
436 * @param isImageGallery
438 * @throws DerivedUnitFacadeNotSupportedException
440 private TextData
initializeFieldObjectTextDataWithSupportTest(Feature feature
, boolean createIfNotExists
, boolean isImageGallery
) throws DerivedUnitFacadeNotSupportedException
{
442 FieldObservation fieldObject
= getFieldObservation(createIfNotExists
) ;
443 if (fieldObject
== null){
446 return inititialzeTextDataWithSupportTest(feature
, fieldObject
, createIfNotExists
, isImageGallery
);
453 * @param createIfNotExists
454 * @param isImageGallery
456 * @throws DerivedUnitFacadeNotSupportedException
458 private TextData
inititialzeTextDataWithSupportTest(Feature feature
, SpecimenOrObservationBase specimen
, boolean createIfNotExists
,
459 boolean isImageGallery
) throws DerivedUnitFacadeNotSupportedException
{
460 if (feature
== null ){
463 TextData textData
= null;
464 if (createIfNotExists
){
465 textData
= TextData
.NewInstance(feature
);
468 Set
<SpecimenDescription
> descriptions
;
470 descriptions
= specimen
.getSpecimenDescriptionImageGallery();
472 descriptions
= specimen
.getSpecimenDescriptions(false);
474 if (descriptions
.size() == 0){
475 if (createIfNotExists
){
476 SpecimenDescription newSpecimenDescription
= SpecimenDescription
.NewInstance(specimen
);
477 newSpecimenDescription
.addElement(textData
);
483 Set
<DescriptionElementBase
> existingTextData
= new HashSet
<DescriptionElementBase
>();
484 for (SpecimenDescription description
: descriptions
){
485 for (DescriptionElementBase element
: description
.getElements()){
486 if (element
.isInstanceOf(TextData
.class) && ( feature
.equals(element
.getFeature() )|| isImageGallery
) ){
487 existingTextData
.add(element
);
491 if (existingTextData
.size() > 1){
492 throw new DerivedUnitFacadeNotSupportedException("Specimen facade does not support more than one description text data of type " + feature
.getLabel());
494 }else if (existingTextData
.size() == 1){
495 return CdmBase
.deproxy(existingTextData
.iterator().next(), TextData
.class);
497 SpecimenDescription description
= descriptions
.iterator().next();
498 description
.addElement(textData
);
503 //************************** METHODS *****************************************
505 private TextData
getDerivedUnitImageGalleryTextData(boolean createIfNotExists
) throws DerivedUnitFacadeNotSupportedException
{
506 if (this.derivedUnitMediaTextData
== null && createIfNotExists
){
507 this.derivedUnitMediaTextData
= getImageGalleryTextData(derivedUnit
, "Specimen");
509 return this.derivedUnitMediaTextData
;
512 private TextData
getObservationImageGalleryTextData(boolean createIfNotExists
) throws DerivedUnitFacadeNotSupportedException
{
513 if (this.fieldObjectMediaTextData
== null && createIfNotExists
){
514 this.fieldObjectMediaTextData
= getImageGalleryTextData(fieldObservation
, "Field observation");
516 return this.fieldObjectMediaTextData
;
522 * @param derivationEvent2
524 * @throws DerivedUnitFacadeNotSupportedException
526 private Set
<FieldObservation
> getFieldObservationsOriginals(DerivationEvent derivationEvent
, Set
<SpecimenOrObservationBase
> recursionAvoidSet
) throws DerivedUnitFacadeNotSupportedException
{
527 if (recursionAvoidSet
== null){
528 recursionAvoidSet
= new HashSet
<SpecimenOrObservationBase
>();
530 Set
<FieldObservation
> result
= new HashSet
<FieldObservation
>();
531 Set
<SpecimenOrObservationBase
> originals
= derivationEvent
.getOriginals();
532 for (SpecimenOrObservationBase original
: originals
){
533 if (original
.isInstanceOf(FieldObservation
.class)){
534 result
.add(CdmBase
.deproxy(original
, FieldObservation
.class));
535 }else if (original
.isInstanceOf(DerivedUnitBase
.class)){
536 //if specimen has already been tested exclude it from further recursion
537 if (recursionAvoidSet
.contains(original
)){
540 DerivedUnitBase derivedUnit
= CdmBase
.deproxy(original
, DerivedUnitBase
.class);
541 DerivationEvent originalDerivation
= derivedUnit
.getDerivedFrom();
542 // Set<DerivationEvent> derivationEvents = original.getDerivationEvents();
543 // for (DerivationEvent originalDerivation : derivationEvents){
544 Set
<FieldObservation
> fieldObservations
= getFieldObservationsOriginals(originalDerivation
, recursionAvoidSet
);
545 result
.addAll(fieldObservations
);
548 throw new DerivedUnitFacadeNotSupportedException("Unhandled specimen or observation base type: " + original
.getClass().getName() );
555 //*********** MEDIA METHODS ******************************
558 // * Returns the media list for a specimen. Throws an exception if the existing specimen descriptions
559 // * are not supported by this facade.
560 // * @param specimen the specimen the media belongs to
561 // * @param specimenExceptionText text describing the specimen for exception messages
563 // * @throws DerivedUnitFacadeNotSupportedException
565 // private List<Media> getImageGalleryMedia(SpecimenOrObservationBase specimen, String specimenExceptionText) throws DerivedUnitFacadeNotSupportedException{
566 // List<Media> result;
567 // SpecimenDescription imageGallery = getImageGalleryWithSupportTest(specimen, specimenExceptionText, true);
568 // TextData textData = getImageTextDataWithSupportTest(imageGallery, specimenExceptionText);
569 // result = textData.getMedia();
574 * Returns the media list for a specimen. Throws an exception if the existing specimen descriptions
575 * are not supported by this facade.
576 * @param specimen the specimen the media belongs to
577 * @param specimenExceptionText text describing the specimen for exception messages
579 * @throws DerivedUnitFacadeNotSupportedException
581 private TextData
getImageGalleryTextData(SpecimenOrObservationBase specimen
, String specimenExceptionText
) throws DerivedUnitFacadeNotSupportedException
{
583 SpecimenDescription imageGallery
= getImageGalleryWithSupportTest(specimen
, specimenExceptionText
, true);
584 result
= getImageTextDataWithSupportTest(imageGallery
, specimenExceptionText
);
590 * Returns the image gallery of the according specimen. Throws an exception if the attached
591 * image gallerie(s) are not supported by this facade.
592 * If no image gallery exists a new one is created if <code>createNewIfNotExists</code> is true and
593 * if specimen is not <code>null</code>.
595 * @param specimenText
596 * @param createNewIfNotExists
598 * @throws DerivedUnitFacadeNotSupportedException
600 private SpecimenDescription
getImageGalleryWithSupportTest(SpecimenOrObservationBase
<?
> specimen
, String specimenText
, boolean createNewIfNotExists
) throws DerivedUnitFacadeNotSupportedException
{
601 if (specimen
== null){
604 SpecimenDescription imageGallery
;
605 if (hasMultipleImageGalleries(specimen
)){
606 throw new DerivedUnitFacadeNotSupportedException( specimenText
+ " must not have more than 1 image gallery");
608 imageGallery
= getImageGallery(specimen
, createNewIfNotExists
);
609 getImageTextDataWithSupportTest(imageGallery
, specimenText
);
615 * Returns the media holding text data element of the image gallery. Throws an exception if multiple
616 * such text data already exist.
617 * Creates a new text data if none exists and adds it to the image gallery.
618 * If image gallery is <code>null</code> nothing happens.
619 * @param imageGallery
622 * @throws DerivedUnitFacadeNotSupportedException
624 private TextData
getImageTextDataWithSupportTest(SpecimenDescription imageGallery
, String specimenText
) throws DerivedUnitFacadeNotSupportedException
{
625 if (imageGallery
== null){
628 TextData textData
= null;
629 for (DescriptionElementBase element
: imageGallery
.getElements()){
630 if (element
.isInstanceOf(TextData
.class) && element
.getFeature().equals(Feature
.IMAGE())){
631 if (textData
!= null){
632 throw new DerivedUnitFacadeNotSupportedException( specimenText
+ " must not have more than 1 image text data element in image gallery");
634 textData
= CdmBase
.deproxy(element
, TextData
.class);
637 if (textData
== null){
638 textData
= TextData
.NewInstance(Feature
.IMAGE());
639 imageGallery
.addElement(textData
);
645 * Checks, if a specimen belongs to more than one description that is an image gallery
649 private boolean hasMultipleImageGalleries(SpecimenOrObservationBase
<?
> derivedUnit
){
651 Set
<SpecimenDescription
> descriptions
= derivedUnit
.getSpecimenDescriptions();
652 for (SpecimenDescription description
: descriptions
){
653 if (description
.isImageGallery()){
662 * Returns the image gallery for a specimen. If there are multiple specimen descriptions
663 * marked as image galleries an arbitrary one is chosen.
664 * If no image gallery exists, a new one is created if <code>createNewIfNotExists</code>
665 * is <code>true</code>.<Br>
666 * If specimen is <code>null</code> a null pointer exception is thrown.
667 * @param createNewIfNotExists
670 private SpecimenDescription
getImageGallery(SpecimenOrObservationBase
<?
> specimen
, boolean createIfNotExists
) {
671 SpecimenDescription result
= null;
672 Set
<SpecimenDescription
> descriptions
= specimen
.getSpecimenDescriptions();
673 for (SpecimenDescription description
: descriptions
){
674 if (description
.isImageGallery()){
675 result
= description
;
679 if (result
== null && createIfNotExists
){
680 result
= SpecimenDescription
.NewInstance(specimen
);
681 result
.setImageGallery(true);
687 * Adds a media to the specimens image gallery. If media is <code>null</code> nothing happens.
690 * @return true if media is not null (as specified by {@link java.util.Collection#add(Object) Collection.add(E e)}
691 * @throws DerivedUnitFacadeNotSupportedException
693 private boolean addMedia(Media media
, SpecimenOrObservationBase
<?
> specimen
) throws DerivedUnitFacadeNotSupportedException
{
695 List
<Media
> mediaList
= getMedia(specimen
, true);
696 return mediaList
.add(media
);
703 * Removes a media from the specimens image gallery.
706 * @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)}
707 * @throws DerivedUnitFacadeNotSupportedException
709 private boolean removeMedia(Media media
, SpecimenOrObservationBase
<?
> specimen
) throws DerivedUnitFacadeNotSupportedException
{
710 List
<Media
> mediaList
= getMedia(specimen
, true);
711 return mediaList
== null ?
null : mediaList
.remove(media
);
714 private List
<Media
> getMedia(SpecimenOrObservationBase
<?
> specimen
, boolean createIfNotExists
) throws DerivedUnitFacadeNotSupportedException
{
715 TextData textData
= getMediaTextData(specimen
, createIfNotExists
);
716 return textData
== null ?
null : textData
.getMedia();
720 * Returns the one media list of a specimen which is part of the only image gallery that
721 * this specimen is part of.<BR>
722 * If these conditions are not hold an exception is thrwon.
725 * @throws DerivedUnitFacadeNotSupportedException
727 // private List<Media> getMedia(SpecimenOrObservationBase<?> specimen) throws DerivedUnitFacadeNotSupportedException {
728 // if (specimen == null){
731 // if (specimen == this.derivedUnit){
732 // return getDerivedUnitImageGalleryMedia();
733 // }else if (specimen == this.fieldObservation){
734 // return getObservationImageGalleryTextData();
736 // return getImageGalleryMedia(specimen, "Undefined specimen ");
741 * Returns the one media list of a specimen which is part of the only image gallery that
742 * this specimen is part of.<BR>
743 * If these conditions are not hold an exception is thrwon.
746 * @throws DerivedUnitFacadeNotSupportedException
748 private TextData
getMediaTextData(SpecimenOrObservationBase
<?
> specimen
, boolean createIfNotExists
) throws DerivedUnitFacadeNotSupportedException
{
749 if (specimen
== null){
752 if (specimen
== this.derivedUnit
){
753 return getDerivedUnitImageGalleryTextData(createIfNotExists
);
754 }else if (specimen
== this.fieldObservation
){
755 return getObservationImageGalleryTextData(createIfNotExists
);
757 return getImageGalleryTextData(specimen
, "Undefined specimen ");
762 //****************** GETTER / SETTER / ADDER / REMOVER ***********************/
764 // ****************** Gathering Event *********************************/
767 public void addCollectingArea(NamedArea area
) {
768 getGatheringEvent(true).addCollectingArea(area
);
770 public void addCollectingAreas(java
.util
.Collection
<NamedArea
> areas
) {
771 for (NamedArea area
: areas
){
772 getGatheringEvent(true).addCollectingArea(area
);
775 public Set
<NamedArea
> getCollectingAreas() {
776 return (hasGatheringEvent() ?
getGatheringEvent(true).getCollectingAreas() : null);
778 public void removeCollectingArea(NamedArea area
) {
779 if (hasGatheringEvent()){
780 getGatheringEvent(true).removeCollectingArea(area
);
785 /** meter above/below sea level of the surface
786 * @see #getAbsoluteElevationError()
787 * @see #getAbsoluteElevationRange()
790 public Integer
getAbsoluteElevation() {
791 return (hasGatheringEvent() ?
getGatheringEvent(true).getAbsoluteElevation() : null);
793 public void setAbsoluteElevation(Integer absoluteElevation
) {
794 getGatheringEvent(true).setAbsoluteElevation(absoluteElevation
);
797 //absolute elevation error
799 public Integer
getAbsoluteElevationError() {
800 return (hasGatheringEvent() ?
getGatheringEvent(true).getAbsoluteElevationError() : null);
802 public void setAbsoluteElevationError(Integer absoluteElevationError
) {
803 getGatheringEvent(true).setAbsoluteElevationError(absoluteElevationError
);
807 * @see #getAbsoluteElevation()
808 * @see #getAbsoluteElevationError()
809 * @see #setAbsoluteElevationRange(Integer, Integer)
810 * @see #getAbsoluteElevationMaximum()
813 public Integer
getAbsoluteElevationMinimum(){
814 if ( ! hasGatheringEvent() ){
817 Integer minimum
= getGatheringEvent(true).getAbsoluteElevation();
818 if (getGatheringEvent(true).getAbsoluteElevationError() != null){
819 minimum
= minimum
- getGatheringEvent(true).getAbsoluteElevationError();
824 * @see #getAbsoluteElevation()
825 * @see #getAbsoluteElevationError()
826 * @see #setAbsoluteElevationRange(Integer, Integer)
827 * @see #getAbsoluteElevationMinimum()
830 public Integer
getAbsoluteElevationMaximum(){
831 if ( ! hasGatheringEvent() ){
834 Integer maximum
= getGatheringEvent(true).getAbsoluteElevation();
835 if (getGatheringEvent(true).getAbsoluteElevationError() != null){
836 maximum
= maximum
+ getGatheringEvent(true).getAbsoluteElevationError();
843 * This method replaces absoluteElevation and absoulteElevationError by
844 * internally translating minimum and maximum values into
845 * average and error values. As all these values are integer based
846 * it is necessary that the distance is between minimum and maximum is <b>even</b>,
847 * otherwise we will get a rounding error resulting in a maximum that is increased
849 * @see #setAbsoluteElevation(Integer)
850 * @see #setAbsoluteElevationError(Integer)
851 * @param minimumElevation minimum of the range
852 * @param maximumElevation maximum of the range
854 public void setAbsoluteElevationRange(Integer minimumElevation
, Integer maximumElevation
){
855 if (minimumElevation
== null || maximumElevation
== null){
856 Integer elevation
= minimumElevation
;
858 if (minimumElevation
== null){
859 elevation
= maximumElevation
;
860 if (elevation
== null){
864 getGatheringEvent(true).setAbsoluteElevation(elevation
);
865 getGatheringEvent(true).setAbsoluteElevationError(error
);
867 if (! isEvenDistance(minimumElevation
, maximumElevation
) ){
868 throw new IllegalArgumentException("Distance between minimum and maximum elevation must be even but was " + Math
.abs(minimumElevation
- maximumElevation
));
870 Integer absoluteElevationError
= Math
.abs(maximumElevation
- minimumElevation
);
871 absoluteElevationError
= absoluteElevationError
/ 2;
872 Integer absoluteElevation
= minimumElevation
+ absoluteElevationError
;
873 getGatheringEvent(true).setAbsoluteElevation(absoluteElevation
);
874 getGatheringEvent(true).setAbsoluteElevationError(absoluteElevationError
);
879 * @param minimumElevation
880 * @param maximumElevation
883 private boolean isEvenDistance(Integer minimumElevation
, Integer maximumElevation
) {
884 Integer diff
= ( maximumElevation
- minimumElevation
);
885 Integer testDiff
= (diff
/2) *2 ;
886 return (testDiff
== diff
);
890 public AgentBase
getCollector() {
891 return (hasGatheringEvent() ?
getGatheringEvent(true).getCollector() : null);
893 public void setCollector(AgentBase collector
){
894 getGatheringEvent(true).setCollector(collector
);
898 public String
getCollectingMethod() {
899 return (hasGatheringEvent() ?
getGatheringEvent(true).getCollectingMethod() : null);
901 public void setCollectingMethod(String collectingMethod
) {
902 getGatheringEvent(true).setCollectingMethod(collectingMethod
);
907 public Integer
getDistanceToGround() {
908 return (hasGatheringEvent() ?
getGatheringEvent(true).getDistanceToGround() : null);
910 public void setDistanceToGround(Integer distanceToGround
) {
911 getGatheringEvent(true).setDistanceToGround(distanceToGround
);
914 //distance to water surface
916 public Integer
getDistanceToWaterSurface() {
917 return (hasGatheringEvent() ?
getGatheringEvent(true).getDistanceToWaterSurface() : null);
919 public void setDistanceToWaterSurface(Integer distanceToWaterSurface
) {
920 getGatheringEvent(true).setDistanceToWaterSurface(distanceToWaterSurface
);
924 public Point
getExactLocation() {
925 return (hasGatheringEvent() ?
getGatheringEvent(true).getExactLocation() : null );
929 * Returns a sexagesimal representation of the exact location (e.g. 12°59'N, 35°23E).
930 * If the exact location is <code>null</code> the empty string is returned.
931 * @param includeEmptySeconds
932 * @param includeReferenceSystem
935 public String
getExactLocationText(boolean includeEmptySeconds
, boolean includeReferenceSystem
){
936 return (this.getExactLocation() == null ?
"" : this.getExactLocation().toSexagesimalString(includeEmptySeconds
, includeReferenceSystem
));
938 public void setExactLocation(Point exactLocation
) {
939 getGatheringEvent(true).setExactLocation(exactLocation
);
941 public void setExactLocationByParsing(String longitudeToParse
, String latitudeToParse
, ReferenceSystem referenceSystem
, Integer errorRadius
) throws ParseException
{
942 Point point
= Point
.NewInstance(null, null, referenceSystem
, errorRadius
);
943 point
.setLongitudeByParsing(longitudeToParse
);
944 point
.setLatitudeByParsing(latitudeToParse
);
945 setExactLocation(point
);
948 //gathering event description
949 public String
getGatheringEventDescription() {
950 return (hasGatheringEvent() ?
getGatheringEvent(true).getDescription() : null);
952 public void setGatheringEventDescription(String description
) {
953 getGatheringEvent(true).setDescription(description
);
957 public TimePeriod
getGatheringPeriod() {
958 return (hasGatheringEvent() ?
getGatheringEvent(true).getTimeperiod() : null);
960 public void setGatheringPeriod(TimePeriod timeperiod
) {
961 getGatheringEvent(true).setTimeperiod(timeperiod
);
965 public LanguageString
getLocality(){
966 return (hasGatheringEvent() ?
getGatheringEvent(true).getLocality() : null);
969 public String
getLocalityText(){
970 LanguageString locality
= getLocality();
971 if(locality
!= null){
972 return locality
.getText();
977 public Language
getLocalityLanguage(){
978 LanguageString locality
= getLocality();
979 if(locality
!= null){
980 return locality
.getLanguage();
986 * Sets the locality string in the default language
989 public void setLocality(String locality
){
990 Language language
= Language
.DEFAULT();
991 setLocality(locality
, language
);
993 public void setLocality(String locality
, Language language
){
994 LanguageString langString
= LanguageString
.NewInstance(locality
, language
);
995 setLocality(langString
);
997 public void setLocality(LanguageString locality
){
998 getGatheringEvent(true).setLocality(locality
);
1002 * The gathering event will be used for the field object instead of the old gathering event.<BR>
1003 * <B>This method will override all gathering values (see below).</B>
1004 * @see #getAbsoluteElevation()
1005 * @see #getAbsoluteElevationError()
1006 * @see #getDistanceToGround()
1007 * @see #getDistanceToWaterSurface()
1008 * @see #getExactLocation()
1009 * @see #getGatheringEventDescription()
1010 * @see #getGatheringPeriod()
1011 * @see #getCollectingAreas()
1012 * @see #getCollectingMethod()
1013 * @see #getLocality()
1014 * @see #getCollector()
1015 * @param gatheringEvent
1017 public void setGatheringEvent(GatheringEvent gatheringEvent
) {
1018 getFieldObservation(true).setGatheringEvent(gatheringEvent
);
1020 public boolean hasGatheringEvent(){
1021 return (getGatheringEvent(false) != null);
1024 public GatheringEvent
getGatheringEvent() {
1025 return getGatheringEvent(false);
1028 public GatheringEvent
getGatheringEvent(boolean createIfNotExists
) {
1029 if (! hasFieldObservation() && ! createIfNotExists
){
1032 if (createIfNotExists
&& getFieldObservation(true).getGatheringEvent() == null ){
1033 GatheringEvent gatheringEvent
= GatheringEvent
.NewInstance();
1034 getFieldObservation(true).setGatheringEvent(gatheringEvent
);
1036 return getFieldObservation(true).getGatheringEvent();
1039 // ****************** Field Object ************************************/
1042 * Returns true if a field observation exists (even if all attributes are empty or <code>null<code>.
1045 public boolean hasFieldObject(){
1046 return this.fieldObservation
!= null;
1051 public String
getEcology(){
1052 return getEcology(Language
.DEFAULT());
1054 public String
getEcology(Language language
){
1055 LanguageString languageString
= getEcologyAll().get(language
);
1056 return (languageString
== null ?
null : languageString
.getText());
1058 // public String getEcologyPreferred(List<Language> languages){
1059 // LanguageString languageString = getEcologyAll().getPreferredLanguageString(languages);
1060 // return languageString.getText();
1062 public Map
<Language
, LanguageString
> getEcologyAll(){
1063 if (ecology
== null){
1065 ecology
= initializeFieldObjectTextDataWithSupportTest(Feature
.ECOLOGY(), false, false);
1066 } catch (DerivedUnitFacadeNotSupportedException e
) {
1067 throw new IllegalStateException(notSupportMessage
, e
);
1069 if (ecology
== null){
1070 return new HashMap
<Language
, LanguageString
>();
1073 return ecology
.getMultilanguageText();
1076 public void setEcology(String ecology
){
1077 setEcology(ecology
, null);
1079 public void setEcology(String ecologyText
, Language language
){
1080 if (language
== null){
1081 language
= Language
.DEFAULT();
1083 if (ecology
== null){
1085 ecology
= initializeFieldObjectTextDataWithSupportTest(Feature
.ECOLOGY(), true, false);
1086 } catch (DerivedUnitFacadeNotSupportedException e
) {
1087 throw new IllegalStateException(notSupportMessage
, e
);
1090 if (ecologyText
== null){
1091 ecology
.removeText(language
);
1093 ecology
.putText(ecologyText
, language
);
1096 public void removeEcology(Language language
){
1097 setEcology(null, language
);
1100 * Removes ecology for the default language
1102 public void removeEcology(){
1103 setEcology(null, null);
1105 public void removeEcologyAll(){
1112 public String
getPlantDescription(){
1113 return getPlantDescription(null);
1115 public String
getPlantDescription(Language language
){
1116 if (language
== null){
1117 language
= Language
.DEFAULT();
1119 LanguageString languageString
= getPlantDescriptionAll().get(language
);
1120 return (languageString
== null ?
null : languageString
.getText());
1122 // public String getPlantDescriptionPreferred(List<Language> languages){
1123 // LanguageString languageString = getPlantDescriptionAll().getPreferredLanguageString(languages);
1124 // return languageString.getText();
1126 public Map
<Language
, LanguageString
> getPlantDescriptionAll(){
1127 if (plantDescription
== null){
1129 plantDescription
= initializeFieldObjectTextDataWithSupportTest(Feature
.DESCRIPTION(), false, false);
1130 } catch (DerivedUnitFacadeNotSupportedException e
) {
1131 throw new IllegalStateException(notSupportMessage
, e
);
1133 if (plantDescription
== null){
1134 return new HashMap
<Language
, LanguageString
>();
1137 return plantDescription
.getMultilanguageText();
1139 public void setPlantDescription(String plantDescription
){
1140 setPlantDescription(plantDescription
, null);
1142 public void setPlantDescription(String plantDescriptionText
, Language language
){
1143 if (language
== null){
1144 language
= Language
.DEFAULT();
1146 if (plantDescription
== null){
1148 plantDescription
= initializeFieldObjectTextDataWithSupportTest(Feature
.DESCRIPTION(), true, false);
1149 } catch (DerivedUnitFacadeNotSupportedException e
) {
1150 throw new IllegalStateException(notSupportMessage
, e
);
1153 if (plantDescriptionText
== null){
1154 plantDescription
.removeText(language
);
1156 plantDescription
.putText(plantDescriptionText
, language
);
1159 public void removePlantDescription(Language language
){
1160 setPlantDescription(null, language
);
1163 //field object definition
1164 public void addFieldObjectDefinition(String text
, Language language
) {
1165 getFieldObservation(true).addDefinition(text
, language
);
1168 public Map
<Language
, LanguageString
> getFieldObjectDefinition() {
1169 if (! hasFieldObservation()){
1170 return new HashMap
<Language
, LanguageString
>();
1172 return getFieldObservation(true).getDefinition();
1175 public String
getFieldObjectDefinition(Language language
) {
1176 Map
<Language
, LanguageString
> map
= getFieldObjectDefinition();
1177 LanguageString languageString
= (map
== null?
null : map
.get(language
));
1178 if (languageString
!= null){
1179 return languageString
.getText();
1184 public void removeFieldObjectDefinition(Language lang
) {
1185 if (hasFieldObservation()){
1186 getFieldObservation(true).removeDefinition(lang
);
1192 public boolean addFieldObjectMedia(Media media
) {
1194 return addMedia(media
, getFieldObservation(true));
1195 } catch (DerivedUnitFacadeNotSupportedException e
) {
1196 throw new IllegalStateException(notSupportMessage
, e
);
1200 * Returns true, if an image gallery for the field object exists.<BR>
1201 * Returns also <code>true</code> if the image gallery is empty.
1204 public boolean hasFieldObjectImageGallery(){
1205 if (! hasFieldObject()){
1208 return (getImageGallery(fieldObservation
, false) != null);
1213 * @param createIfNotExists
1216 public SpecimenDescription
getFieldObjectImageGallery(boolean createIfNotExists
){
1219 textData
= initializeFieldObjectTextDataWithSupportTest(Feature
.IMAGE(), createIfNotExists
, true);
1220 } catch (DerivedUnitFacadeNotSupportedException e
) {
1221 throw new IllegalStateException(notSupportMessage
, e
);
1223 if (textData
!= null){
1224 return CdmBase
.deproxy(textData
.getInDescription(), SpecimenDescription
.class);
1230 * Returns the media for the field object.<BR>
1233 public List
<Media
> getFieldObjectMedia() {
1235 List
<Media
> result
= getMedia(getFieldObservation(false), false);
1236 return result
== null ?
new ArrayList
<Media
>() : result
;
1237 } catch (DerivedUnitFacadeNotSupportedException e
) {
1238 throw new IllegalStateException(notSupportMessage
, e
);
1241 public boolean removeFieldObjectMedia(Media media
) {
1243 return removeMedia(media
, getFieldObservation(false));
1244 } catch (DerivedUnitFacadeNotSupportedException e
) {
1245 throw new IllegalStateException(notSupportMessage
, e
);
1250 public String
getFieldNumber() {
1251 if (! hasFieldObservation()){
1254 return getFieldObservation(true).getFieldNumber();
1257 public void setFieldNumber(String fieldNumber
) {
1258 getFieldObservation(true).setFieldNumber(fieldNumber
);
1263 public String
getFieldNotes() {
1264 if (! hasFieldObservation()){
1267 return getFieldObservation(true).getFieldNotes();
1270 public void setFieldNotes(String fieldNotes
) {
1271 getFieldObservation(true).setFieldNotes(fieldNotes
);
1276 public Integer
getIndividualCount() {
1277 return (hasFieldObservation()?
getFieldObservation(true).getIndividualCount() : null );
1279 public void setIndividualCount(Integer individualCount
) {
1280 getFieldObservation(true).setIndividualCount(individualCount
);
1284 public Stage
getLifeStage() {
1285 return (hasFieldObservation()?
getFieldObservation(true).getLifeStage() : null );
1287 public void setLifeStage(Stage lifeStage
) {
1288 getFieldObservation(true).setLifeStage(lifeStage
);
1292 public Sex
getSex() {
1293 return (hasFieldObservation()?
getFieldObservation(true).getSex() : null );
1295 public void setSex(Sex sex
) {
1296 getFieldObservation(true).setSex(sex
);
1301 public boolean hasFieldObservation(){
1302 return (getFieldObservation(false) != null);
1306 * Returns the field observation as an object.
1310 public FieldObservation
getFieldObservation(){
1311 return getFieldObservation(false);
1315 * Returns the field observation as an object.
1318 public FieldObservation
getFieldObservation(boolean createIfNotExists
){
1319 if (fieldObservation
== null && createIfNotExists
){
1320 fieldObservation
= FieldObservation
.NewInstance();
1321 fieldObservation
.addPropertyChangeListener(getNewEventPropagationListener());
1322 DerivationEvent derivationEvent
= getDerivationEvent(true);
1323 derivationEvent
.addOriginal(fieldObservation
);
1325 return this.fieldObservation
;
1332 //****************** Specimen **************************************************
1335 public void addDerivedUnitDefinition(String text
, Language language
) {
1336 derivedUnit
.addDefinition(text
, language
);
1338 public Map
<Language
, LanguageString
> getDerivedUnitDefinitions(){
1339 return this.derivedUnit
.getDefinition();
1341 public String
getDerivedUnitDefinition(Language language
) {
1342 Map
<Language
,LanguageString
> languageMap
= derivedUnit
.getDefinition();
1343 LanguageString languageString
= languageMap
.get(language
);
1344 if (languageString
!= null){
1345 return languageString
.getText();
1350 public void removeDerivedUnitDefinition(Language lang
) {
1351 derivedUnit
.removeDefinition(lang
);
1355 public void addDetermination(DeterminationEvent determination
) {
1356 derivedUnit
.addDetermination(determination
);
1359 public Set
<DeterminationEvent
> getDeterminations() {
1360 return derivedUnit
.getDeterminations();
1362 public void removeDetermination(DeterminationEvent determination
) {
1363 derivedUnit
.removeDetermination(determination
);
1367 public boolean addDerivedUnitMedia(Media media
) {
1369 return addMedia(media
, derivedUnit
);
1370 } catch (DerivedUnitFacadeNotSupportedException e
) {
1371 throw new IllegalStateException(notSupportMessage
, e
);
1375 * Returns true, if an image gallery exists for the specimen.<BR>
1376 * Returns also <code>true</code> if the image gallery is empty.
1378 public boolean hasDerivedUnitImageGallery(){
1379 return (getImageGallery(derivedUnit
, false) != null);
1382 public SpecimenDescription
getDerivedUnitImageGallery(boolean createIfNotExists
){
1385 textData
= inititialzeTextDataWithSupportTest(Feature
.IMAGE(), derivedUnit
, createIfNotExists
, true);
1386 } catch (DerivedUnitFacadeNotSupportedException e
) {
1387 throw new IllegalStateException(notSupportMessage
, e
);
1389 if (textData
!= null){
1390 return CdmBase
.deproxy(textData
.getInDescription(), SpecimenDescription
.class);
1397 * Returns the media for the specimen.<BR>
1400 public List
<Media
> getDerivedUnitMedia() {
1402 List
<Media
> result
= getMedia(derivedUnit
, false);
1403 return result
== null ?
new ArrayList
<Media
>() : result
;
1404 } catch (DerivedUnitFacadeNotSupportedException e
) {
1405 throw new IllegalStateException(notSupportMessage
, e
);
1408 public boolean removeDerivedUnitMedia(Media media
) {
1410 return removeMedia(media
, derivedUnit
);
1411 } catch (DerivedUnitFacadeNotSupportedException e
) {
1412 throw new IllegalStateException(notSupportMessage
, e
);
1419 public String
getAccessionNumber() {
1420 return derivedUnit
.getAccessionNumber();
1422 public void setAccessionNumber(String accessionNumber
) {
1423 derivedUnit
.setAccessionNumber(accessionNumber
);
1427 public String
getCatalogNumber() {
1428 return derivedUnit
.getCatalogNumber();
1430 public void setCatalogNumber(String catalogNumber
) {
1431 derivedUnit
.setCatalogNumber(catalogNumber
);
1434 //Preservation Method
1437 * Only supported by specimen and fossils
1438 * @see #DerivedUnitType
1441 public PreservationMethod
getPreservationMethod() throws MethodNotSupportedByDerivedUnitTypeException
{
1442 if (derivedUnit
.isInstanceOf(Specimen
.class)){
1443 return CdmBase
.deproxy(derivedUnit
, Specimen
.class).getPreservation();
1445 if (this.config
.isThrowExceptionForNonSpecimenPreservationMethodRequest()){
1446 throw new MethodNotSupportedByDerivedUnitTypeException("A preservation method is only available in derived units of type 'Specimen' or 'Fossil'");
1453 * Only supported by specimen and fossils
1454 * @see #DerivedUnitType
1457 public void setPreservationMethod(PreservationMethod preservation
)throws MethodNotSupportedByDerivedUnitTypeException
{
1458 if (derivedUnit
.isInstanceOf(Specimen
.class)){
1459 CdmBase
.deproxy(derivedUnit
, Specimen
.class).setPreservation(preservation
);
1461 if (this.config
.isThrowExceptionForNonSpecimenPreservationMethodRequest()){
1462 throw new MethodNotSupportedByDerivedUnitTypeException("A preservation method is only available in derived units of type 'Specimen' or 'Fossil'");
1470 public TaxonNameBase
getStoredUnder() {
1471 return derivedUnit
.getStoredUnder();
1473 public void setStoredUnder(TaxonNameBase storedUnder
) {
1474 derivedUnit
.setStoredUnder(storedUnder
);
1478 public String
getCollectorsNumber() {
1479 return derivedUnit
.getCollectorsNumber();
1481 public void setCollectorsNumber(String collectorsNumber
) {
1482 this.derivedUnit
.setCollectorsNumber(collectorsNumber
);
1486 public String
getTitleCache() {
1487 if (! derivedUnit
.isProtectedTitleCache()){
1488 //always compute title cache anew as long as there are no property change listeners on
1489 //field observation, gathering event etc
1490 derivedUnit
.setTitleCache(null, false);
1492 return this.derivedUnit
.getTitleCache();
1494 public void setTitleCache(String titleCache
, boolean isProtected
) {
1495 this.derivedUnit
.setTitleCache(titleCache
, isProtected
);
1500 * Returns the derived unit itself.
1501 * @return the derived unit
1504 public DerivedUnitBase
getDerivedUnit() {
1505 return this.derivedUnit
;
1508 private boolean hasDerivationEvent(){
1509 return getDerivationEvent() == null ?
false : true;
1511 private DerivationEvent
getDerivationEvent(){
1512 return getDerivationEvent(false);
1514 private DerivationEvent
getDerivationEvent(boolean createIfNotExists
){
1515 DerivationEvent result
= derivedUnit
.getDerivedFrom();
1516 if (result
== null){
1517 result
= DerivationEvent
.NewInstance();
1518 derivedUnit
.setDerivedFrom(result
);
1523 public String
getExsiccatum() {
1524 logger
.warn("Exsiccatum method not yet supported. Needs model change");
1528 public String
setExsiccatum() throws MethodNotSupportedException
{
1529 throw new MethodNotSupportedException("Exsiccatum method not yet supported. Needs model change");
1534 public void addSource(IdentifiableSource source
){
1535 this.derivedUnit
.addSource(source
);
1538 * Creates an orignal source, adds it to the specimen and returns it.
1540 * @param microReference
1541 * @param originalNameString
1544 public IdentifiableSource
addSource(ReferenceBase reference
, String microReference
, String originalNameString
){
1545 IdentifiableSource source
= IdentifiableSource
.NewInstance(reference
, microReference
);
1546 source
.setOriginalNameString(originalNameString
);
1547 derivedUnit
.addSource(source
);
1551 public Set
<IdentifiableSource
> getSources(){
1552 return derivedUnit
.getSources();
1555 public void removeSource(IdentifiableSource source
){
1556 this.derivedUnit
.removeSource(source
);
1561 * @return the collection
1563 public Collection
getCollection() {
1564 return derivedUnit
.getCollection();
1569 * @param collection the collection to set
1571 public void setCollection(Collection collection
) {
1572 derivedUnit
.setCollection(collection
);
1576 public void addAnnotation(Annotation annotation
){
1577 this.derivedUnit
.addAnnotation(annotation
);
1581 public void getAnnotations(){
1582 this.derivedUnit
.getAnnotations();
1585 public void removeAnnotation(Annotation annotation
){
1586 this.derivedUnit
.removeAnnotation(annotation
);
1590 // ******************************* Events *********************************************
1595 private PropertyChangeListener
getNewEventPropagationListener() {
1596 PropertyChangeListener listener
= new PropertyChangeListener(){
1598 public void propertyChange(PropertyChangeEvent event
) {
1599 derivedUnit
.firePropertyChange(event
);
1609 //**************** Other Collections ***************************************************
1612 * Creates a duplicate specimen which derives from the same derivation event
1613 * as the facade specimen and adds collection data to it (all data available in
1614 * DerivedUnitBase and Specimen. Data from SpecimenOrObservationBase and above
1615 * are not yet shared at the moment.
1617 * @param catalogNumber
1618 * @param accessionNumber
1619 * @param collectorsNumber
1620 * @param storedUnder
1621 * @param preservation
1624 public Specimen
addDuplicate(Collection collection
, String catalogNumber
, String accessionNumber
,
1625 String collectorsNumber
, TaxonNameBase storedUnder
, PreservationMethod preservation
){
1626 Specimen duplicate
= Specimen
.NewInstance();
1627 duplicate
.setDerivedFrom(getDerivationEvent(true));
1628 duplicate
.setCollection(collection
);
1629 duplicate
.setCatalogNumber(catalogNumber
);
1630 duplicate
.setAccessionNumber(accessionNumber
);
1631 duplicate
.setCollectorsNumber(collectorsNumber
);
1632 duplicate
.setStoredUnder(storedUnder
);
1633 duplicate
.setPreservation(preservation
);
1637 public void addDuplicate(DerivedUnitBase duplicateSpecimen
){
1638 //TODO check derivedUnitType
1639 getDerivationEvent(true).addDerivative(duplicateSpecimen
);
1643 public Set
<Specimen
> getDuplicates(){
1644 Set
<Specimen
> result
= new HashSet
<Specimen
>();
1645 if (hasDerivationEvent()){
1646 for (DerivedUnitBase derivedUnit
: getDerivationEvent(true).getDerivatives()){
1647 if (derivedUnit
.isInstanceOf(Specimen
.class) && ! derivedUnit
.equals(this.derivedUnit
)){
1648 result
.add(CdmBase
.deproxy(derivedUnit
, Specimen
.class));
1654 public void removeDuplicate(Specimen duplicateSpecimen
){
1655 if (hasDerivationEvent()){
1656 getDerivationEvent(true).removeDerivative(duplicateSpecimen
);