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
;
29 import eu
.etaxonomy
.cdm
.api
.service
.IOccurrenceService
;
30 import eu
.etaxonomy
.cdm
.model
.agent
.AgentBase
;
31 import eu
.etaxonomy
.cdm
.model
.common
.Annotation
;
32 import eu
.etaxonomy
.cdm
.model
.common
.CdmBase
;
33 import eu
.etaxonomy
.cdm
.model
.common
.IdentifiableSource
;
34 import eu
.etaxonomy
.cdm
.model
.common
.Language
;
35 import eu
.etaxonomy
.cdm
.model
.common
.LanguageString
;
36 import eu
.etaxonomy
.cdm
.model
.common
.TimePeriod
;
37 import eu
.etaxonomy
.cdm
.model
.description
.DescriptionElementBase
;
38 import eu
.etaxonomy
.cdm
.model
.description
.Feature
;
39 import eu
.etaxonomy
.cdm
.model
.description
.Sex
;
40 import eu
.etaxonomy
.cdm
.model
.description
.SpecimenDescription
;
41 import eu
.etaxonomy
.cdm
.model
.description
.Stage
;
42 import eu
.etaxonomy
.cdm
.model
.description
.TextData
;
43 import eu
.etaxonomy
.cdm
.model
.location
.NamedArea
;
44 import eu
.etaxonomy
.cdm
.model
.location
.Point
;
45 import eu
.etaxonomy
.cdm
.model
.location
.ReferenceSystem
;
46 import eu
.etaxonomy
.cdm
.model
.media
.Media
;
47 import eu
.etaxonomy
.cdm
.model
.name
.TaxonNameBase
;
48 import eu
.etaxonomy
.cdm
.model
.occurrence
.Collection
;
49 import eu
.etaxonomy
.cdm
.model
.occurrence
.DerivationEvent
;
50 import eu
.etaxonomy
.cdm
.model
.occurrence
.DerivedUnitBase
;
51 import eu
.etaxonomy
.cdm
.model
.occurrence
.DeterminationEvent
;
52 import eu
.etaxonomy
.cdm
.model
.occurrence
.FieldObservation
;
53 import eu
.etaxonomy
.cdm
.model
.occurrence
.GatheringEvent
;
54 import eu
.etaxonomy
.cdm
.model
.occurrence
.PreservationMethod
;
55 import eu
.etaxonomy
.cdm
.model
.occurrence
.Specimen
;
56 import eu
.etaxonomy
.cdm
.model
.occurrence
.SpecimenOrObservationBase
;
57 import eu
.etaxonomy
.cdm
.model
.reference
.ReferenceBase
;
60 * This class is a facade to the eu.etaxonomy.cdm.model.occurrence package from
61 * a specimen based view. It does not support all functionality available in the
62 * occurrence package.<BR>
63 * The most significant restriction is that a specimen may derive only from
64 * one direct derivation event and there must be only one field observation (gathering event)
65 * it derives from.<BR>
70 public class DerivedUnitFacade
{
71 private static final Logger logger
= Logger
.getLogger(DerivedUnitFacade
.class);
73 private static final String notSupportMessage
= "A specimen facade not supported exception has occurred at a place where this should not have happened. The developer should implement not support check properly during class initialization ";
76 * Enum that defines the class the "Specimen" belongs to.
77 * Some methods of the facade are not available for certain classes
78 * and will throw an Exception when invoking them.
80 public enum DerivedUnitType
{
81 Specimen ("Specimen"),
82 Observation("Observation"),
83 LivingBeing("Living Being"),
85 DerivedUnit("Derived Unit");
87 String representation
;
88 private DerivedUnitType(String representation
){
89 this.representation
= representation
;
93 * @return the representation
95 public String
getRepresentation() {
96 return representation
;
99 private DerivedUnitBase
getNewDerivedUnitInstance(){
100 if (this == DerivedUnitType
.Specimen
){
101 return eu
.etaxonomy
.cdm
.model
.occurrence
.Specimen
.NewInstance();
102 }else if (this == DerivedUnitType
.Observation
){
103 return eu
.etaxonomy
.cdm
.model
.occurrence
.Observation
.NewInstance();
104 }else if (this == DerivedUnitType
.LivingBeing
){
105 return eu
.etaxonomy
.cdm
.model
.occurrence
.LivingBeing
.NewInstance();
106 }else if (this == DerivedUnitType
.Fossil
){
107 return eu
.etaxonomy
.cdm
.model
.occurrence
.Fossil
.NewInstance();
108 }else if (this == DerivedUnitType
.DerivedUnit
){
109 return eu
.etaxonomy
.cdm
.model
.occurrence
.DerivedUnit
.NewInstance();
111 throw new IllegalStateException("Unknown derived unit type " + this.getRepresentation());
118 private DerivedUnitFacadeConfigurator config
;
120 //private GatheringEvent gatheringEvent;
121 private DerivedUnitType type
; //needed?
123 private FieldObservation fieldObservation
;
125 private DerivedUnitBase derivedUnit
;
127 //media - the text data holding the media
128 private TextData derivedUnitMediaTextData
;
129 private TextData fieldObjectMediaTextData
;
132 private TextData ecology
;
133 private TextData plantDescription
;
137 * Creates a derived unit facade for a new derived unit of type <code>type</code>.
141 public static DerivedUnitFacade
NewInstance(DerivedUnitType type
){
142 return new DerivedUnitFacade(type
);
146 * Creates a derived unit facade for a given derived unit using the default configuation.
149 * @throws DerivedUnitFacadeNotSupportedException
151 public static DerivedUnitFacade
NewInstance(DerivedUnitBase derivedUnit
) throws DerivedUnitFacadeNotSupportedException
{
152 return new DerivedUnitFacade(derivedUnit
, null);
155 public static DerivedUnitFacade
NewInstance(DerivedUnitBase derivedUnit
, DerivedUnitFacadeConfigurator config
) throws DerivedUnitFacadeNotSupportedException
{
156 return new DerivedUnitFacade(derivedUnit
, config
);
161 // ****************** CONSTRUCTOR ****************************************************
163 private DerivedUnitFacade(DerivedUnitType type
){
164 this.config
= DerivedUnitFacadeConfigurator
.NewInstance();
167 derivedUnit
= type
.getNewDerivedUnitInstance();
171 private DerivedUnitFacade(DerivedUnitBase derivedUnit
, DerivedUnitFacadeConfigurator config
) throws DerivedUnitFacadeNotSupportedException
{
174 config
= DerivedUnitFacadeConfigurator
.NewInstance();
176 this.config
= config
;
179 this.derivedUnit
= derivedUnit
;
183 if (this.derivedUnit
.getDerivedFrom() != null){
184 DerivationEvent derivationEvent
= getDerivationEvent(true);
186 Set
<FieldObservation
> fieldOriginals
= getFieldObservationsOriginals(derivationEvent
, null);
187 if (fieldOriginals
.size() > 1){
188 throw new DerivedUnitFacadeNotSupportedException("Specimen must not have more than 1 derivation event");
189 }else if (fieldOriginals
.size() == 0){
190 //fieldObservation = FieldObservation.NewInstance();
191 }else if (fieldOriginals
.size() == 1){
192 fieldObservation
= fieldOriginals
.iterator().next();
193 //###fieldObservation = getInitializedFieldObservation(fieldObservation);
194 fieldObservation
.addPropertyChangeListener(getNewEventPropagationListener());
196 throw new IllegalStateException("Illegal state");
199 // #### derivedUnit = getInitializedDerivedUnit(derivedUnit);
201 //test if unsupported
205 // String objectTypeExceptionText = "Specimen";
206 // SpecimenDescription imageGallery = getImageGalleryWithSupportTest(derivedUnit, objectTypeExceptionText, false);
207 // getImageTextDataWithSupportTest(imageGallery, objectTypeExceptionText);
208 this.derivedUnitMediaTextData
= inititialzeTextDataWithSupportTest(Feature
.IMAGE(), this.derivedUnit
, false, true);
211 // objectTypeExceptionText = "Field observation";
212 // imageGallery = getImageGalleryWithSupportTest(fieldObservation, objectTypeExceptionText, false);
213 // getImageTextDataWithSupportTest(imageGallery, objectTypeExceptionText);
214 fieldObjectMediaTextData
= initializeFieldObjectTextDataWithSupportTest(Feature
.IMAGE(), false, true);
216 //handle derivedUnit.getMedia()
217 if (derivedUnit
.getMedia().size() > 0){
218 //TODO better changed model here to allow only one place for images
219 if (this.config
.isMoveDerivedUnitMediaToGallery()){
220 Set
<Media
> mediaSet
= derivedUnit
.getMedia();
221 for (Media media
: mediaSet
){
222 this.addDerivedUnitMedia(media
);
224 mediaSet
.removeAll(getDerivedUnitMedia());
226 throw new DerivedUnitFacadeNotSupportedException("Specimen may not have direct media. Only (one) image gallery is allowed");
230 //handle fieldObservation.getMedia()
231 if (fieldObservation
!= null && fieldObservation
.getMedia() != null && fieldObservation
.getMedia().size() > 0){
232 //TODO better changed model here to allow only one place for images
233 if (this.config
.isMoveFieldObjectMediaToGallery()){
234 Set
<Media
> mediaSet
= fieldObservation
.getMedia();
235 for (Media media
: mediaSet
){
236 this.addFieldObjectMedia(media
);
238 mediaSet
.removeAll(getFieldObjectMedia());
240 throw new DerivedUnitFacadeNotSupportedException("Field object may not have direct media. Only (one) image gallery is allowed");
244 //test if descriptions are supported
245 ecology
= initializeFieldObjectTextDataWithSupportTest(Feature
.ECOLOGY(), false, false);
246 plantDescription
= initializeFieldObjectTextDataWithSupportTest(Feature
.DESCRIPTION(), false, false);
250 private DerivedUnitBase
getInitializedDerivedUnit(DerivedUnitBase derivedUnit
) {
251 IOccurrenceService occurrenceService
= this.config
.getOccurrenceService();
252 if (occurrenceService
== null){
255 List
<String
> propertyPaths
= this.config
.getPropertyPaths();
256 if (propertyPaths
== null){
259 propertyPaths
= getDerivedUnitPropertyPaths(propertyPaths
);
260 DerivedUnitBase result
= (DerivedUnitBase
)occurrenceService
.load(derivedUnit
.getUuid(), propertyPaths
);
265 * Initializes the derived unit according to the configuartions property path.
266 * If the property path is <code>null</code> or no occurrence service is given the
267 * returned object is the same as the input parameter.
268 * @param fieldObservation2
271 private FieldObservation
getInitializedFieldObservation(FieldObservation fieldObservation
) {
272 IOccurrenceService occurrenceService
= this.config
.getOccurrenceService();
273 if (occurrenceService
== null){
274 return fieldObservation
;
276 List
<String
> propertyPaths
= this.config
.getPropertyPaths();
277 if (propertyPaths
== null){
278 return fieldObservation
;
280 propertyPaths
= getFieldObjectPropertyPaths(propertyPaths
);
281 FieldObservation result
= (FieldObservation
)occurrenceService
.load(fieldObservation
.getUuid(), propertyPaths
);
286 * Transforms the property paths in a way that the facade is handled just like an
287 * ordinary CdmBase object.<BR>
288 * E.g. a property path "collectinAreas" will be translated into gatheringEvent.collectingAreas
289 * @param propertyPaths
292 private List
<String
> getFieldObjectPropertyPaths(List
<String
> propertyPaths
) {
293 List
<String
> result
= new ArrayList
<String
>();
294 for (String facadePath
: propertyPaths
){
295 // collecting areas (named area)
296 if (facadePath
.startsWith("collectingAreas")){
297 facadePath
= "gatheringEvent." + facadePath
;
298 result
.add(facadePath
);
300 // collector (agentBase)
301 else if (facadePath
.startsWith("collector")){
302 facadePath
= facadePath
.replace("collector", "gatheringEvent.actor");
303 result
.add(facadePath
);
305 // exactLocation (agentBase)
306 else if (facadePath
.startsWith("exactLocation")){
307 facadePath
= "gatheringEvent." + facadePath
;
308 result
.add(facadePath
);
310 // gatheringPeriod (TimePeriod)
311 else if (facadePath
.startsWith("gatheringPeriod")){
312 facadePath
= facadePath
.replace("gatheringPeriod", "gatheringEvent.timeperiod");
313 result
.add(facadePath
);
315 // (locality/ localityLanguage , LanguageString)
316 else if (facadePath
.startsWith("locality")){
317 facadePath
= "gatheringEvent." + facadePath
;
318 result
.add(facadePath
);
321 //*********** FIELD OBJECT ************
322 // fieldObjectDefinitions (Map<language, languageString)
323 else if (facadePath
.startsWith("fieldObjectDefinitions")){
324 // TODO or definition ???
325 facadePath
= facadePath
.replace("fieldObjectDefinitions", "description");
326 result
.add(facadePath
);
328 // fieldObjectMedia (Media)
329 else if (facadePath
.startsWith("fieldObjectMedia")){
331 facadePath
= facadePath
.replace("fieldObjectMedia", "descriptions.elements.media");
332 result
.add(facadePath
);
335 //Gathering Event will always be added
336 result
.add("gatheringEvent");
343 - gatheringEvent (GatheringEvent)
347 - ecology/ ecologyAll (String) ???
348 - plant description (like ecology)
350 - fieldObjectImageGallery (SpecimenDescription) - is automatically initialized via fieldObjectMedia
358 * Transforms the property paths in a way that the facade is handled just like an
359 * ordinary CdmBase object.<BR>
360 * E.g. a property path "collectinAreas" will be translated into gatheringEvent.collectingAreas
361 * @param propertyPaths
364 private List
<String
> getDerivedUnitPropertyPaths(List
<String
> propertyPaths
) {
365 List
<String
> result
= new ArrayList
<String
>();
366 for (String facadePath
: propertyPaths
){
367 // determinations (DeterminationEvent)
368 if (facadePath
.startsWith("determinations")){
369 facadePath
= "" + facadePath
; //no change
370 result
.add(facadePath
);
372 // storedUnder (TaxonNameBase)
373 else if (facadePath
.startsWith("storedUnder")){
374 facadePath
= "" + facadePath
; //no change
375 result
.add(facadePath
);
377 // sources (IdentifiableSource)
378 else if (facadePath
.startsWith("sources")){
379 facadePath
= "" + facadePath
; //no change
380 result
.add(facadePath
);
382 // collection (Collection)
383 else if (facadePath
.startsWith("collection")){
384 facadePath
= "" + facadePath
; //no change
385 result
.add(facadePath
);
387 // (locality/ localityLanguage , LanguageString)
388 else if (facadePath
.startsWith("locality")){
389 facadePath
= "gatheringEvent." + facadePath
;
390 result
.add(facadePath
);
393 //*********** FIELD OBJECT ************
394 // derivedUnitDefinitions (Map<language, languageString)
395 else if (facadePath
.startsWith("derivedUnitDefinitions")){
396 // TODO or definition ???
397 facadePath
= facadePath
.replace("derivedUnitDefinitions", "description");
398 result
.add(facadePath
);
401 // derivedUnitMedia (Media)
402 else if (facadePath
.startsWith("derivedUnitMedia")){
404 facadePath
= facadePath
.replace("derivedUnitMedia", "descriptions.elements.media");
405 result
.add(facadePath
);
413 =====================
415 - derivedUnitImageGallery (SpecimenDescription) - is automatically initialized via derivedUnitMedia
417 - derivationEvent (DerivationEvent) - will always be initialized
418 - duplicates (??? Specimen???) ???
427 private void setCacheStrategy() {
428 derivedUnit
.setCacheStrategy(new DerivedUnitFacadeCacheStrategy());
434 * @param createIfNotExists
435 * @param isImageGallery
437 * @throws DerivedUnitFacadeNotSupportedException
439 private TextData
initializeFieldObjectTextDataWithSupportTest(Feature feature
, boolean createIfNotExists
, boolean isImageGallery
) throws DerivedUnitFacadeNotSupportedException
{
441 FieldObservation fieldObject
= getFieldObservation(createIfNotExists
) ;
442 if (fieldObject
== null){
445 return inititialzeTextDataWithSupportTest(feature
, fieldObject
, createIfNotExists
, isImageGallery
);
452 * @param createIfNotExists
453 * @param isImageGallery
455 * @throws DerivedUnitFacadeNotSupportedException
457 private TextData
inititialzeTextDataWithSupportTest(Feature feature
, SpecimenOrObservationBase specimen
, boolean createIfNotExists
,
458 boolean isImageGallery
) throws DerivedUnitFacadeNotSupportedException
{
459 if (feature
== null ){
462 TextData textData
= null;
463 if (createIfNotExists
){
464 textData
= TextData
.NewInstance(feature
);
467 Set
<SpecimenDescription
> descriptions
;
469 descriptions
= specimen
.getSpecimenDescriptionImageGallery();
471 descriptions
= specimen
.getSpecimenDescriptions(false);
473 if (descriptions
.size() == 0){
474 if (createIfNotExists
){
475 SpecimenDescription newSpecimenDescription
= SpecimenDescription
.NewInstance(specimen
);
476 newSpecimenDescription
.addElement(textData
);
482 Set
<DescriptionElementBase
> existingTextData
= new HashSet
<DescriptionElementBase
>();
483 for (SpecimenDescription description
: descriptions
){
484 for (DescriptionElementBase element
: description
.getElements()){
485 if (element
.isInstanceOf(TextData
.class) && ( feature
.equals(element
.getFeature() )|| isImageGallery
) ){
486 existingTextData
.add(element
);
490 if (existingTextData
.size() > 1){
491 throw new DerivedUnitFacadeNotSupportedException("Specimen facade does not support more than one description text data of type " + feature
.getLabel());
493 }else if (existingTextData
.size() == 1){
494 return CdmBase
.deproxy(existingTextData
.iterator().next(), TextData
.class);
496 SpecimenDescription description
= descriptions
.iterator().next();
497 description
.addElement(textData
);
502 //************************** METHODS *****************************************
504 private TextData
getDerivedUnitImageGalleryTextData(boolean createIfNotExists
) throws DerivedUnitFacadeNotSupportedException
{
505 if (this.derivedUnitMediaTextData
== null && createIfNotExists
){
506 this.derivedUnitMediaTextData
= getImageGalleryTextData(derivedUnit
, "Specimen");
508 return this.derivedUnitMediaTextData
;
511 private TextData
getObservationImageGalleryTextData(boolean createIfNotExists
) throws DerivedUnitFacadeNotSupportedException
{
512 if (this.fieldObjectMediaTextData
== null && createIfNotExists
){
513 this.fieldObjectMediaTextData
= getImageGalleryTextData(fieldObservation
, "Field observation");
515 return this.fieldObjectMediaTextData
;
521 * @param derivationEvent2
523 * @throws DerivedUnitFacadeNotSupportedException
525 private Set
<FieldObservation
> getFieldObservationsOriginals(DerivationEvent derivationEvent
, Set
<SpecimenOrObservationBase
> recursionAvoidSet
) throws DerivedUnitFacadeNotSupportedException
{
526 if (recursionAvoidSet
== null){
527 recursionAvoidSet
= new HashSet
<SpecimenOrObservationBase
>();
529 Set
<FieldObservation
> result
= new HashSet
<FieldObservation
>();
530 Set
<SpecimenOrObservationBase
> originals
= derivationEvent
.getOriginals();
531 for (SpecimenOrObservationBase original
: originals
){
532 if (original
.isInstanceOf(FieldObservation
.class)){
533 result
.add(CdmBase
.deproxy(original
, FieldObservation
.class));
534 }else if (original
.isInstanceOf(DerivedUnitBase
.class)){
535 //if specimen has already been tested exclude it from further recursion
536 if (recursionAvoidSet
.contains(original
)){
539 DerivedUnitBase derivedUnit
= CdmBase
.deproxy(original
, DerivedUnitBase
.class);
540 DerivationEvent originalDerivation
= derivedUnit
.getDerivedFrom();
541 // Set<DerivationEvent> derivationEvents = original.getDerivationEvents();
542 // for (DerivationEvent originalDerivation : derivationEvents){
543 Set
<FieldObservation
> fieldObservations
= getFieldObservationsOriginals(originalDerivation
, recursionAvoidSet
);
544 result
.addAll(fieldObservations
);
547 throw new DerivedUnitFacadeNotSupportedException("Unhandled specimen or observation base type: " + original
.getClass().getName() );
554 //*********** MEDIA METHODS ******************************
557 // * Returns the media list for a specimen. Throws an exception if the existing specimen descriptions
558 // * are not supported by this facade.
559 // * @param specimen the specimen the media belongs to
560 // * @param specimenExceptionText text describing the specimen for exception messages
562 // * @throws DerivedUnitFacadeNotSupportedException
564 // private List<Media> getImageGalleryMedia(SpecimenOrObservationBase specimen, String specimenExceptionText) throws DerivedUnitFacadeNotSupportedException{
565 // List<Media> result;
566 // SpecimenDescription imageGallery = getImageGalleryWithSupportTest(specimen, specimenExceptionText, true);
567 // TextData textData = getImageTextDataWithSupportTest(imageGallery, specimenExceptionText);
568 // result = textData.getMedia();
573 * Returns the media list for a specimen. Throws an exception if the existing specimen descriptions
574 * are not supported by this facade.
575 * @param specimen the specimen the media belongs to
576 * @param specimenExceptionText text describing the specimen for exception messages
578 * @throws DerivedUnitFacadeNotSupportedException
580 private TextData
getImageGalleryTextData(SpecimenOrObservationBase specimen
, String specimenExceptionText
) throws DerivedUnitFacadeNotSupportedException
{
582 SpecimenDescription imageGallery
= getImageGalleryWithSupportTest(specimen
, specimenExceptionText
, true);
583 result
= getImageTextDataWithSupportTest(imageGallery
, specimenExceptionText
);
589 * Returns the image gallery of the according specimen. Throws an exception if the attached
590 * image gallerie(s) are not supported by this facade.
591 * If no image gallery exists a new one is created if <code>createNewIfNotExists</code> is true and
592 * if specimen is not <code>null</code>.
594 * @param specimenText
595 * @param createNewIfNotExists
597 * @throws DerivedUnitFacadeNotSupportedException
599 private SpecimenDescription
getImageGalleryWithSupportTest(SpecimenOrObservationBase
<?
> specimen
, String specimenText
, boolean createNewIfNotExists
) throws DerivedUnitFacadeNotSupportedException
{
600 if (specimen
== null){
603 SpecimenDescription imageGallery
;
604 if (hasMultipleImageGalleries(specimen
)){
605 throw new DerivedUnitFacadeNotSupportedException( specimenText
+ " must not have more than 1 image gallery");
607 imageGallery
= getImageGallery(specimen
, createNewIfNotExists
);
608 getImageTextDataWithSupportTest(imageGallery
, specimenText
);
614 * Returns the media holding text data element of the image gallery. Throws an exception if multiple
615 * such text data already exist.
616 * Creates a new text data if none exists and adds it to the image gallery.
617 * If image gallery is <code>null</code> nothing happens.
618 * @param imageGallery
621 * @throws DerivedUnitFacadeNotSupportedException
623 private TextData
getImageTextDataWithSupportTest(SpecimenDescription imageGallery
, String specimenText
) throws DerivedUnitFacadeNotSupportedException
{
624 if (imageGallery
== null){
627 TextData textData
= null;
628 for (DescriptionElementBase element
: imageGallery
.getElements()){
629 if (element
.isInstanceOf(TextData
.class) && element
.getFeature().equals(Feature
.IMAGE())){
630 if (textData
!= null){
631 throw new DerivedUnitFacadeNotSupportedException( specimenText
+ " must not have more than 1 image text data element in image gallery");
633 textData
= CdmBase
.deproxy(element
, TextData
.class);
636 if (textData
== null){
637 textData
= TextData
.NewInstance(Feature
.IMAGE());
638 imageGallery
.addElement(textData
);
644 * Checks, if a specimen belongs to more than one description that is an image gallery
648 private boolean hasMultipleImageGalleries(SpecimenOrObservationBase
<?
> derivedUnit
){
650 Set
<SpecimenDescription
> descriptions
= derivedUnit
.getSpecimenDescriptions();
651 for (SpecimenDescription description
: descriptions
){
652 if (description
.isImageGallery()){
661 * Returns the image gallery for a specimen. If there are multiple specimen descriptions
662 * marked as image galleries an arbitrary one is chosen.
663 * If no image gallery exists, a new one is created if <code>createNewIfNotExists</code>
664 * is <code>true</code>.<Br>
665 * If specimen is <code>null</code> a null pointer exception is thrown.
666 * @param createNewIfNotExists
669 private SpecimenDescription
getImageGallery(SpecimenOrObservationBase
<?
> specimen
, boolean createIfNotExists
) {
670 SpecimenDescription result
= null;
671 Set
<SpecimenDescription
> descriptions
= specimen
.getSpecimenDescriptions();
672 for (SpecimenDescription description
: descriptions
){
673 if (description
.isImageGallery()){
674 result
= description
;
678 if (result
== null && createIfNotExists
){
679 result
= SpecimenDescription
.NewInstance(specimen
);
680 result
.setImageGallery(true);
686 * Adds a media to the specimens image gallery. If media is <code>null</code> nothing happens.
689 * @return true if media is not null (as specified by {@link java.util.Collection#add(Object) Collection.add(E e)}
690 * @throws DerivedUnitFacadeNotSupportedException
692 private boolean addMedia(Media media
, SpecimenOrObservationBase
<?
> specimen
) throws DerivedUnitFacadeNotSupportedException
{
694 List
<Media
> mediaList
= getMedia(specimen
, true);
695 return mediaList
.add(media
);
702 * Removes a media from the specimens image gallery.
705 * @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)}
706 * @throws DerivedUnitFacadeNotSupportedException
708 private boolean removeMedia(Media media
, SpecimenOrObservationBase
<?
> specimen
) throws DerivedUnitFacadeNotSupportedException
{
709 List
<Media
> mediaList
= getMedia(specimen
, true);
710 return mediaList
== null ?
null : mediaList
.remove(media
);
713 private List
<Media
> getMedia(SpecimenOrObservationBase
<?
> specimen
, boolean createIfNotExists
) throws DerivedUnitFacadeNotSupportedException
{
714 TextData textData
= getMediaTextData(specimen
, createIfNotExists
);
715 return textData
== null ?
null : textData
.getMedia();
719 * Returns the one media list of a specimen which is part of the only image gallery that
720 * this specimen is part of.<BR>
721 * If these conditions are not hold an exception is thrwon.
724 * @throws DerivedUnitFacadeNotSupportedException
726 // private List<Media> getMedia(SpecimenOrObservationBase<?> specimen) throws DerivedUnitFacadeNotSupportedException {
727 // if (specimen == null){
730 // if (specimen == this.derivedUnit){
731 // return getDerivedUnitImageGalleryMedia();
732 // }else if (specimen == this.fieldObservation){
733 // return getObservationImageGalleryTextData();
735 // return getImageGalleryMedia(specimen, "Undefined specimen ");
740 * Returns the one media list of a specimen which is part of the only image gallery that
741 * this specimen is part of.<BR>
742 * If these conditions are not hold an exception is thrwon.
745 * @throws DerivedUnitFacadeNotSupportedException
747 private TextData
getMediaTextData(SpecimenOrObservationBase
<?
> specimen
, boolean createIfNotExists
) throws DerivedUnitFacadeNotSupportedException
{
748 if (specimen
== null){
751 if (specimen
== this.derivedUnit
){
752 return getDerivedUnitImageGalleryTextData(createIfNotExists
);
753 }else if (specimen
== this.fieldObservation
){
754 return getObservationImageGalleryTextData(createIfNotExists
);
756 return getImageGalleryTextData(specimen
, "Undefined specimen ");
761 //****************** GETTER / SETTER / ADDER / REMOVER ***********************/
763 // ****************** Gathering Event *********************************/
766 public NamedArea
getCountry(){
767 return (hasGatheringEvent() ?
getGatheringEvent(true).getCountry() : null);
770 public void setCountry(NamedArea country
){
771 getGatheringEvent(true).setCountry(country
);
776 public void addCollectingArea(NamedArea area
) {
777 getGatheringEvent(true).addCollectingArea(area
);
779 public void addCollectingAreas(java
.util
.Collection
<NamedArea
> areas
) {
780 for (NamedArea area
: areas
){
781 getGatheringEvent(true).addCollectingArea(area
);
784 public Set
<NamedArea
> getCollectingAreas() {
785 return (hasGatheringEvent() ?
getGatheringEvent(true).getCollectingAreas() : null);
787 public void removeCollectingArea(NamedArea area
) {
788 if (hasGatheringEvent()){
789 getGatheringEvent(true).removeCollectingArea(area
);
794 /** meter above/below sea level of the surface
795 * @see #getAbsoluteElevationError()
796 * @see #getAbsoluteElevationRange()
798 public Integer
getAbsoluteElevation() {
799 return (hasGatheringEvent() ?
getGatheringEvent(true).getAbsoluteElevation() : null);
801 public void setAbsoluteElevation(Integer absoluteElevation
) {
802 getGatheringEvent(true).setAbsoluteElevation(absoluteElevation
);
805 //absolute elevation error
806 public Integer
getAbsoluteElevationError() {
807 return (hasGatheringEvent() ?
getGatheringEvent(true).getAbsoluteElevationError() : null);
809 public void setAbsoluteElevationError(Integer absoluteElevationError
) {
810 getGatheringEvent(true).setAbsoluteElevationError(absoluteElevationError
);
814 * @see #getAbsoluteElevation()
815 * @see #getAbsoluteElevationError()
816 * @see #setAbsoluteElevationRange(Integer, Integer)
817 * @see #getAbsoluteElevationMaximum()
819 public Integer
getAbsoluteElevationMinimum(){
820 if ( ! hasGatheringEvent() ){
823 Integer minimum
= getGatheringEvent(true).getAbsoluteElevation();
824 if (getGatheringEvent(true).getAbsoluteElevationError() != null){
825 minimum
= minimum
- getGatheringEvent(true).getAbsoluteElevationError();
830 * @see #getAbsoluteElevation()
831 * @see #getAbsoluteElevationError()
832 * @see #setAbsoluteElevationRange(Integer, Integer)
833 * @see #getAbsoluteElevationMinimum()
835 public Integer
getAbsoluteElevationMaximum(){
836 if ( ! hasGatheringEvent() ){
839 Integer maximum
= getGatheringEvent(true).getAbsoluteElevation();
840 if (getGatheringEvent(true).getAbsoluteElevationError() != null){
841 maximum
= maximum
+ getGatheringEvent(true).getAbsoluteElevationError();
848 * This method replaces absoluteElevation and absoulteElevationError by
849 * internally translating minimum and maximum values into
850 * average and error values. As all these values are integer based
851 * it is necessary that the distance is between minimum and maximum is <b>even</b>,
852 * otherwise we will get a rounding error resulting in a maximum that is increased
854 * @see #setAbsoluteElevation(Integer)
855 * @see #setAbsoluteElevationError(Integer)
856 * @param minimumElevation minimum of the range
857 * @param maximumElevation maximum of the range
859 public void setAbsoluteElevationRange(Integer minimumElevation
, Integer maximumElevation
){
860 if (minimumElevation
== null || maximumElevation
== null){
861 Integer elevation
= minimumElevation
;
863 if (minimumElevation
== null){
864 elevation
= maximumElevation
;
865 if (elevation
== null){
869 getGatheringEvent(true).setAbsoluteElevation(elevation
);
870 getGatheringEvent(true).setAbsoluteElevationError(error
);
872 if (! isEvenDistance(minimumElevation
, maximumElevation
) ){
873 throw new IllegalArgumentException("Distance between minimum and maximum elevation must be even but was " + Math
.abs(minimumElevation
- maximumElevation
));
875 Integer absoluteElevationError
= Math
.abs(maximumElevation
- minimumElevation
);
876 absoluteElevationError
= absoluteElevationError
/ 2;
877 Integer absoluteElevation
= minimumElevation
+ absoluteElevationError
;
878 getGatheringEvent(true).setAbsoluteElevation(absoluteElevation
);
879 getGatheringEvent(true).setAbsoluteElevationError(absoluteElevationError
);
884 * @param minimumElevation
885 * @param maximumElevation
888 private boolean isEvenDistance(Integer minimumElevation
, Integer maximumElevation
) {
889 Integer diff
= ( maximumElevation
- minimumElevation
);
890 Integer testDiff
= (diff
/2) *2 ;
891 return (testDiff
== diff
);
895 public AgentBase
getCollector() {
896 return (hasGatheringEvent() ?
getGatheringEvent(true).getCollector() : null);
898 public void setCollector(AgentBase collector
){
899 getGatheringEvent(true).setCollector(collector
);
903 public String
getCollectingMethod() {
904 return (hasGatheringEvent() ?
getGatheringEvent(true).getCollectingMethod() : null);
906 public void setCollectingMethod(String collectingMethod
) {
907 getGatheringEvent(true).setCollectingMethod(collectingMethod
);
911 public Integer
getDistanceToGround() {
912 return (hasGatheringEvent() ?
getGatheringEvent(true).getDistanceToGround() : null);
914 public void setDistanceToGround(Integer distanceToGround
) {
915 getGatheringEvent(true).setDistanceToGround(distanceToGround
);
918 //distance to water surface
919 public Integer
getDistanceToWaterSurface() {
920 return (hasGatheringEvent() ?
getGatheringEvent(true).getDistanceToWaterSurface() : null);
922 public void setDistanceToWaterSurface(Integer distanceToWaterSurface
) {
923 getGatheringEvent(true).setDistanceToWaterSurface(distanceToWaterSurface
);
927 public Point
getExactLocation() {
928 return (hasGatheringEvent() ?
getGatheringEvent(true).getExactLocation() : null );
932 * Returns a sexagesimal representation of the exact location (e.g. 12°59'N, 35°23E).
933 * If the exact location is <code>null</code> the empty string is returned.
934 * @param includeEmptySeconds
935 * @param includeReferenceSystem
938 public String
getExactLocationText(boolean includeEmptySeconds
, boolean includeReferenceSystem
){
939 return (this.getExactLocation() == null ?
"" : this.getExactLocation().toSexagesimalString(includeEmptySeconds
, includeReferenceSystem
));
941 public void setExactLocation(Point exactLocation
) {
942 getGatheringEvent(true).setExactLocation(exactLocation
);
944 public void setExactLocationByParsing(String longitudeToParse
, String latitudeToParse
, ReferenceSystem referenceSystem
, Integer errorRadius
) throws ParseException
{
945 Point point
= Point
.NewInstance(null, null, referenceSystem
, errorRadius
);
946 point
.setLongitudeByParsing(longitudeToParse
);
947 point
.setLatitudeByParsing(latitudeToParse
);
948 setExactLocation(point
);
951 //gathering event description
952 public String
getGatheringEventDescription() {
953 return (hasGatheringEvent() ?
getGatheringEvent(true).getDescription() : null);
955 public void setGatheringEventDescription(String description
) {
956 getGatheringEvent(true).setDescription(description
);
960 public TimePeriod
getGatheringPeriod() {
961 return (hasGatheringEvent() ?
getGatheringEvent(true).getTimeperiod() : null);
963 public void setGatheringPeriod(TimePeriod timeperiod
) {
964 getGatheringEvent(true).setTimeperiod(timeperiod
);
968 public LanguageString
getLocality(){
969 return (hasGatheringEvent() ?
getGatheringEvent(true).getLocality() : null);
972 public String
getLocalityText(){
973 LanguageString locality
= getLocality();
974 if(locality
!= null){
975 return locality
.getText();
980 public Language
getLocalityLanguage(){
981 LanguageString locality
= getLocality();
982 if(locality
!= null){
983 return locality
.getLanguage();
989 * Sets the locality string in the default language
992 public void setLocality(String locality
){
993 Language language
= Language
.DEFAULT();
994 setLocality(locality
, language
);
996 public void setLocality(String locality
, Language language
){
997 LanguageString langString
= LanguageString
.NewInstance(locality
, language
);
998 setLocality(langString
);
1000 public void setLocality(LanguageString locality
){
1001 getGatheringEvent(true).setLocality(locality
);
1005 * The gathering event will be used for the field object instead of the old gathering event.<BR>
1006 * <B>This method will override all gathering values (see below).</B>
1007 * @see #getAbsoluteElevation()
1008 * @see #getAbsoluteElevationError()
1009 * @see #getDistanceToGround()
1010 * @see #getDistanceToWaterSurface()
1011 * @see #getExactLocation()
1012 * @see #getGatheringEventDescription()
1013 * @see #getGatheringPeriod()
1014 * @see #getCollectingAreas()
1015 * @see #getCollectingMethod()
1016 * @see #getLocality()
1017 * @see #getCollector()
1018 * @param gatheringEvent
1020 public void setGatheringEvent(GatheringEvent gatheringEvent
) {
1021 getFieldObservation(true).setGatheringEvent(gatheringEvent
);
1023 public boolean hasGatheringEvent(){
1024 return (getGatheringEvent(false) != null);
1027 public GatheringEvent
getGatheringEvent() {
1028 return getGatheringEvent(false);
1031 public GatheringEvent
getGatheringEvent(boolean createIfNotExists
) {
1032 if (! hasFieldObservation() && ! createIfNotExists
){
1035 if (createIfNotExists
&& getFieldObservation(true).getGatheringEvent() == null ){
1036 GatheringEvent gatheringEvent
= GatheringEvent
.NewInstance();
1037 getFieldObservation(true).setGatheringEvent(gatheringEvent
);
1039 return getFieldObservation(true).getGatheringEvent();
1042 // ****************** Field Object ************************************/
1045 * Returns true if a field observation exists (even if all attributes are empty or <code>null<code>.
1048 public boolean hasFieldObject(){
1049 return this.fieldObservation
!= null;
1054 public String
getEcology(){
1055 return getEcology(Language
.DEFAULT());
1057 public String
getEcology(Language language
){
1058 LanguageString languageString
= getEcologyAll().get(language
);
1059 return (languageString
== null ?
null : languageString
.getText());
1061 // public String getEcologyPreferred(List<Language> languages){
1062 // LanguageString languageString = getEcologyAll().getPreferredLanguageString(languages);
1063 // return languageString.getText();
1065 public Map
<Language
, LanguageString
> getEcologyAll(){
1066 if (ecology
== null){
1068 ecology
= initializeFieldObjectTextDataWithSupportTest(Feature
.ECOLOGY(), false, false);
1069 } catch (DerivedUnitFacadeNotSupportedException e
) {
1070 throw new IllegalStateException(notSupportMessage
, e
);
1072 if (ecology
== null){
1073 return new HashMap
<Language
, LanguageString
>();
1076 return ecology
.getMultilanguageText();
1079 public void setEcology(String ecology
){
1080 setEcology(ecology
, null);
1082 public void setEcology(String ecologyText
, Language language
){
1083 if (language
== null){
1084 language
= Language
.DEFAULT();
1086 if (ecology
== null){
1088 ecology
= initializeFieldObjectTextDataWithSupportTest(Feature
.ECOLOGY(), true, false);
1089 } catch (DerivedUnitFacadeNotSupportedException e
) {
1090 throw new IllegalStateException(notSupportMessage
, e
);
1093 if (ecologyText
== null){
1094 ecology
.removeText(language
);
1096 ecology
.putText(ecologyText
, language
);
1099 public void removeEcology(Language language
){
1100 setEcology(null, language
);
1103 * Removes ecology for the default language
1105 public void removeEcology(){
1106 setEcology(null, null);
1108 public void removeEcologyAll(){
1115 public String
getPlantDescription(){
1116 return getPlantDescription(null);
1118 public String
getPlantDescription(Language language
){
1119 if (language
== null){
1120 language
= Language
.DEFAULT();
1122 LanguageString languageString
= getPlantDescriptionAll().get(language
);
1123 return (languageString
== null ?
null : languageString
.getText());
1125 // public String getPlantDescriptionPreferred(List<Language> languages){
1126 // LanguageString languageString = getPlantDescriptionAll().getPreferredLanguageString(languages);
1127 // return languageString.getText();
1129 public Map
<Language
, LanguageString
> getPlantDescriptionAll(){
1130 if (plantDescription
== null){
1132 plantDescription
= initializeFieldObjectTextDataWithSupportTest(Feature
.DESCRIPTION(), false, false);
1133 } catch (DerivedUnitFacadeNotSupportedException e
) {
1134 throw new IllegalStateException(notSupportMessage
, e
);
1136 if (plantDescription
== null){
1137 return new HashMap
<Language
, LanguageString
>();
1140 return plantDescription
.getMultilanguageText();
1142 public void setPlantDescription(String plantDescription
){
1143 setPlantDescription(plantDescription
, null);
1145 public void setPlantDescription(String plantDescriptionText
, Language language
){
1146 if (language
== null){
1147 language
= Language
.DEFAULT();
1149 if (plantDescription
== null){
1151 plantDescription
= initializeFieldObjectTextDataWithSupportTest(Feature
.DESCRIPTION(), true, false);
1152 } catch (DerivedUnitFacadeNotSupportedException e
) {
1153 throw new IllegalStateException(notSupportMessage
, e
);
1156 if (plantDescriptionText
== null){
1157 plantDescription
.removeText(language
);
1159 plantDescription
.putText(plantDescriptionText
, language
);
1162 public void removePlantDescription(Language language
){
1163 setPlantDescription(null, language
);
1166 //field object definition
1167 public void addFieldObjectDefinition(String text
, Language language
) {
1168 getFieldObservation(true).addDefinition(text
, language
);
1171 public Map
<Language
, LanguageString
> getFieldObjectDefinition() {
1172 if (! hasFieldObservation()){
1173 return new HashMap
<Language
, LanguageString
>();
1175 return getFieldObservation(true).getDefinition();
1178 public String
getFieldObjectDefinition(Language language
) {
1179 Map
<Language
, LanguageString
> map
= getFieldObjectDefinition();
1180 LanguageString languageString
= (map
== null?
null : map
.get(language
));
1181 if (languageString
!= null){
1182 return languageString
.getText();
1187 public void removeFieldObjectDefinition(Language lang
) {
1188 if (hasFieldObservation()){
1189 getFieldObservation(true).removeDefinition(lang
);
1195 public boolean addFieldObjectMedia(Media media
) {
1197 return addMedia(media
, getFieldObservation(true));
1198 } catch (DerivedUnitFacadeNotSupportedException e
) {
1199 throw new IllegalStateException(notSupportMessage
, e
);
1203 * Returns true, if an image gallery for the field object exists.<BR>
1204 * Returns also <code>true</code> if the image gallery is empty.
1207 public boolean hasFieldObjectImageGallery(){
1208 if (! hasFieldObject()){
1211 return (getImageGallery(fieldObservation
, false) != null);
1216 * @param createIfNotExists
1219 public SpecimenDescription
getFieldObjectImageGallery(boolean createIfNotExists
){
1222 textData
= initializeFieldObjectTextDataWithSupportTest(Feature
.IMAGE(), createIfNotExists
, true);
1223 } catch (DerivedUnitFacadeNotSupportedException e
) {
1224 throw new IllegalStateException(notSupportMessage
, e
);
1226 if (textData
!= null){
1227 return CdmBase
.deproxy(textData
.getInDescription(), SpecimenDescription
.class);
1233 * Returns the media for the field object.<BR>
1236 public List
<Media
> getFieldObjectMedia() {
1238 List
<Media
> result
= getMedia(getFieldObservation(false), false);
1239 return result
== null ?
new ArrayList
<Media
>() : result
;
1240 } catch (DerivedUnitFacadeNotSupportedException e
) {
1241 throw new IllegalStateException(notSupportMessage
, e
);
1244 public boolean removeFieldObjectMedia(Media media
) {
1246 return removeMedia(media
, getFieldObservation(false));
1247 } catch (DerivedUnitFacadeNotSupportedException e
) {
1248 throw new IllegalStateException(notSupportMessage
, e
);
1253 public String
getFieldNumber() {
1254 if (! hasFieldObservation()){
1257 return getFieldObservation(true).getFieldNumber();
1260 public void setFieldNumber(String fieldNumber
) {
1261 getFieldObservation(true).setFieldNumber(fieldNumber
);
1266 public String
getFieldNotes() {
1267 if (! hasFieldObservation()){
1270 return getFieldObservation(true).getFieldNotes();
1273 public void setFieldNotes(String fieldNotes
) {
1274 getFieldObservation(true).setFieldNotes(fieldNotes
);
1279 public Integer
getIndividualCount() {
1280 return (hasFieldObservation()?
getFieldObservation(true).getIndividualCount() : null );
1282 public void setIndividualCount(Integer individualCount
) {
1283 getFieldObservation(true).setIndividualCount(individualCount
);
1287 public Stage
getLifeStage() {
1288 return (hasFieldObservation()?
getFieldObservation(true).getLifeStage() : null );
1290 public void setLifeStage(Stage lifeStage
) {
1291 getFieldObservation(true).setLifeStage(lifeStage
);
1295 public Sex
getSex() {
1296 return (hasFieldObservation()?
getFieldObservation(true).getSex() : null );
1298 public void setSex(Sex sex
) {
1299 getFieldObservation(true).setSex(sex
);
1304 public boolean hasFieldObservation(){
1305 return (getFieldObservation(false) != null);
1309 * Returns the field observation as an object.
1313 public FieldObservation
getFieldObservation(){
1314 return getFieldObservation(false);
1318 * Returns the field observation as an object.
1321 public FieldObservation
getFieldObservation(boolean createIfNotExists
){
1322 if (fieldObservation
== null && createIfNotExists
){
1323 fieldObservation
= FieldObservation
.NewInstance();
1324 fieldObservation
.addPropertyChangeListener(getNewEventPropagationListener());
1325 DerivationEvent derivationEvent
= getDerivationEvent(true);
1326 derivationEvent
.addOriginal(fieldObservation
);
1328 return this.fieldObservation
;
1335 //****************** Specimen **************************************************
1338 public void addDerivedUnitDefinition(String text
, Language language
) {
1339 derivedUnit
.addDefinition(text
, language
);
1341 public Map
<Language
, LanguageString
> getDerivedUnitDefinitions(){
1342 return this.derivedUnit
.getDefinition();
1344 public String
getDerivedUnitDefinition(Language language
) {
1345 Map
<Language
,LanguageString
> languageMap
= derivedUnit
.getDefinition();
1346 LanguageString languageString
= languageMap
.get(language
);
1347 if (languageString
!= null){
1348 return languageString
.getText();
1353 public void removeDerivedUnitDefinition(Language lang
) {
1354 derivedUnit
.removeDefinition(lang
);
1358 public void addDetermination(DeterminationEvent determination
) {
1359 derivedUnit
.addDetermination(determination
);
1361 public Set
<DeterminationEvent
> getDeterminations() {
1362 return derivedUnit
.getDeterminations();
1364 public void removeDetermination(DeterminationEvent determination
) {
1365 derivedUnit
.removeDetermination(determination
);
1369 public boolean addDerivedUnitMedia(Media media
) {
1371 return addMedia(media
, derivedUnit
);
1372 } catch (DerivedUnitFacadeNotSupportedException e
) {
1373 throw new IllegalStateException(notSupportMessage
, e
);
1377 * Returns true, if an image gallery exists for the specimen.<BR>
1378 * Returns also <code>true</code> if the image gallery is empty.
1380 public boolean hasDerivedUnitImageGallery(){
1381 return (getImageGallery(derivedUnit
, false) != null);
1384 public SpecimenDescription
getDerivedUnitImageGallery(boolean createIfNotExists
){
1387 textData
= inititialzeTextDataWithSupportTest(Feature
.IMAGE(), derivedUnit
, createIfNotExists
, true);
1388 } catch (DerivedUnitFacadeNotSupportedException e
) {
1389 throw new IllegalStateException(notSupportMessage
, e
);
1391 if (textData
!= null){
1392 return CdmBase
.deproxy(textData
.getInDescription(), SpecimenDescription
.class);
1399 * Returns the media for the specimen.<BR>
1402 public List
<Media
> getDerivedUnitMedia() {
1404 List
<Media
> result
= getMedia(derivedUnit
, false);
1405 return result
== null ?
new ArrayList
<Media
>() : result
;
1406 } catch (DerivedUnitFacadeNotSupportedException e
) {
1407 throw new IllegalStateException(notSupportMessage
, e
);
1410 public boolean removeDerivedUnitMedia(Media media
) {
1412 return removeMedia(media
, derivedUnit
);
1413 } catch (DerivedUnitFacadeNotSupportedException e
) {
1414 throw new IllegalStateException(notSupportMessage
, e
);
1420 public String
getAccessionNumber() {
1421 return derivedUnit
.getAccessionNumber();
1423 public void setAccessionNumber(String accessionNumber
) {
1424 derivedUnit
.setAccessionNumber(accessionNumber
);
1428 public String
getCatalogNumber() {
1429 return derivedUnit
.getCatalogNumber();
1431 public void setCatalogNumber(String catalogNumber
) {
1432 derivedUnit
.setCatalogNumber(catalogNumber
);
1435 //Preservation Method
1438 * Only supported by specimen and fossils
1439 * @see #DerivedUnitType
1442 public PreservationMethod
getPreservationMethod() throws MethodNotSupportedByDerivedUnitTypeException
{
1443 if (derivedUnit
.isInstanceOf(Specimen
.class)){
1444 return CdmBase
.deproxy(derivedUnit
, Specimen
.class).getPreservation();
1446 if (this.config
.isThrowExceptionForNonSpecimenPreservationMethodRequest()){
1447 throw new MethodNotSupportedByDerivedUnitTypeException("A preservation method is only available in derived units of type 'Specimen' or 'Fossil'");
1454 * Only supported by specimen and fossils
1455 * @see #DerivedUnitType
1458 public void setPreservationMethod(PreservationMethod preservation
)throws MethodNotSupportedByDerivedUnitTypeException
{
1459 if (derivedUnit
.isInstanceOf(Specimen
.class)){
1460 CdmBase
.deproxy(derivedUnit
, Specimen
.class).setPreservation(preservation
);
1462 if (this.config
.isThrowExceptionForNonSpecimenPreservationMethodRequest()){
1463 throw new MethodNotSupportedByDerivedUnitTypeException("A preservation method is only available in derived units of type 'Specimen' or 'Fossil'");
1471 public TaxonNameBase
getStoredUnder() {
1472 return derivedUnit
.getStoredUnder();
1474 public void setStoredUnder(TaxonNameBase storedUnder
) {
1475 derivedUnit
.setStoredUnder(storedUnder
);
1479 public String
getCollectorsNumber() {
1480 return derivedUnit
.getCollectorsNumber();
1482 public void setCollectorsNumber(String collectorsNumber
) {
1483 this.derivedUnit
.setCollectorsNumber(collectorsNumber
);
1487 public String
getTitleCache() {
1488 if (! derivedUnit
.isProtectedTitleCache()){
1489 //always compute title cache anew as long as there are no property change listeners on
1490 //field observation, gathering event etc
1491 derivedUnit
.setTitleCache(null, false);
1493 return this.derivedUnit
.getTitleCache();
1495 public void setTitleCache(String titleCache
, boolean isProtected
) {
1496 this.derivedUnit
.setTitleCache(titleCache
, isProtected
);
1501 * Returns the derived unit itself.
1502 * @return the derived unit
1505 public DerivedUnitBase
getDerivedUnit() {
1506 return this.derivedUnit
;
1509 private boolean hasDerivationEvent(){
1510 return getDerivationEvent() == null ?
false : true;
1512 private DerivationEvent
getDerivationEvent(){
1513 return getDerivationEvent(false);
1515 private DerivationEvent
getDerivationEvent(boolean createIfNotExists
){
1516 DerivationEvent result
= derivedUnit
.getDerivedFrom();
1517 if (result
== null){
1518 result
= DerivationEvent
.NewInstance();
1519 derivedUnit
.setDerivedFrom(result
);
1524 public String
getExsiccatum() {
1525 logger
.warn("Exsiccatum method not yet supported. Needs model change");
1529 public String
setExsiccatum() throws MethodNotSupportedException
{
1530 throw new MethodNotSupportedException("Exsiccatum method not yet supported. Needs model change");
1535 public void addSource(IdentifiableSource source
){
1536 this.derivedUnit
.addSource(source
);
1539 * Creates an orignal source, adds it to the specimen and returns it.
1541 * @param microReference
1542 * @param originalNameString
1545 public IdentifiableSource
addSource(ReferenceBase reference
, String microReference
, String originalNameString
){
1546 IdentifiableSource source
= IdentifiableSource
.NewInstance(reference
, microReference
);
1547 source
.setOriginalNameString(originalNameString
);
1548 derivedUnit
.addSource(source
);
1552 public Set
<IdentifiableSource
> getSources(){
1553 return derivedUnit
.getSources();
1556 public void removeSource(IdentifiableSource source
){
1557 this.derivedUnit
.removeSource(source
);
1562 * @return the collection
1564 public Collection
getCollection() {
1565 return derivedUnit
.getCollection();
1570 * @param collection the collection to set
1572 public void setCollection(Collection collection
) {
1573 derivedUnit
.setCollection(collection
);
1577 public void addAnnotation(Annotation annotation
){
1578 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
);