\r
package eu.etaxonomy.cdm.api.facade;\r
\r
+import java.beans.PropertyChangeEvent;\r
+import java.beans.PropertyChangeListener;\r
import java.text.ParseException;\r
+import java.util.ArrayList;\r
import java.util.HashMap;\r
import java.util.HashSet;\r
import java.util.List;\r
import java.util.Map;\r
import java.util.Set;\r
\r
-import javax.mail.MethodNotSupportedException;\r
+import javax.persistence.Transient;\r
\r
import org.apache.log4j.Logger;\r
\r
+import eu.etaxonomy.cdm.api.service.IOccurrenceService;\r
import eu.etaxonomy.cdm.model.agent.AgentBase;\r
+import eu.etaxonomy.cdm.model.agent.Person;\r
+import eu.etaxonomy.cdm.model.common.Annotation;\r
import eu.etaxonomy.cdm.model.common.CdmBase;\r
import eu.etaxonomy.cdm.model.common.IdentifiableSource;\r
import eu.etaxonomy.cdm.model.common.Language;\r
import eu.etaxonomy.cdm.model.occurrence.PreservationMethod;\r
import eu.etaxonomy.cdm.model.occurrence.Specimen;\r
import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase;\r
-import eu.etaxonomy.cdm.model.reference.ReferenceBase;\r
+import eu.etaxonomy.cdm.model.reference.Reference;\r
\r
/**\r
* This class is a facade to the eu.etaxonomy.cdm.model.occurrence package from\r
\r
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 ";\r
\r
- \r
/**\r
* Enum that defines the class the "Specimen" belongs to.\r
* Some methods of the facade are not available for certain classes\r
private FieldObservation fieldObservation;\r
\r
private DerivedUnitBase derivedUnit;\r
- private List<Media> specimenMedia;\r
- private List<Media> fieldObservationMedia;\r
+\r
+ //media - the text data holding the media\r
+ private TextData derivedUnitMediaTextData;\r
+ private TextData fieldObjectMediaTextData;\r
+ \r
\r
private TextData ecology;\r
private TextData plantDescription;\r
\r
+ \r
+ /**\r
+ * Creates a derived unit facade for a new derived unit of type <code>type</code>.\r
+ * @param type\r
+ * @return\r
+ */\r
public static DerivedUnitFacade NewInstance(DerivedUnitType type){\r
return new DerivedUnitFacade(type);\r
}\r
\r
+ /**\r
+ * Creates a derived unit facade for a given derived unit using the default configuration.\r
+ * @param derivedUnit\r
+ * @return\r
+ * @throws DerivedUnitFacadeNotSupportedException\r
+ */\r
public static DerivedUnitFacade NewInstance(DerivedUnitBase derivedUnit) throws DerivedUnitFacadeNotSupportedException{\r
- return new DerivedUnitFacade(derivedUnit, null, DerivedUnitType.Specimen);\r
+ return new DerivedUnitFacade(derivedUnit, null);\r
}\r
\r
public static DerivedUnitFacade NewInstance(DerivedUnitBase derivedUnit, DerivedUnitFacadeConfigurator config) throws DerivedUnitFacadeNotSupportedException{\r
- return new DerivedUnitFacade(derivedUnit, config, DerivedUnitType.Specimen);\r
+ return new DerivedUnitFacade(derivedUnit, config);\r
}\r
\r
+\r
+ \r
// ****************** CONSTRUCTOR ****************************************************\r
\r
private DerivedUnitFacade(DerivedUnitType type){\r
setCacheStrategy();\r
}\r
\r
- private DerivedUnitFacade(DerivedUnitBase derivedUnit, DerivedUnitFacadeConfigurator config, DerivedUnitType type) throws DerivedUnitFacadeNotSupportedException{\r
- //this.type = type; ??\r
+ private DerivedUnitFacade(DerivedUnitBase derivedUnit, DerivedUnitFacadeConfigurator config) throws DerivedUnitFacadeNotSupportedException{\r
\r
if (config == null){\r
config = DerivedUnitFacadeConfigurator.NewInstance();\r
//fieldObservation = FieldObservation.NewInstance();\r
}else if (fieldOriginals.size() == 1){\r
fieldObservation = fieldOriginals.iterator().next();\r
+ //###fieldObservation = getInitializedFieldObservation(fieldObservation);\r
+ fieldObservation.addPropertyChangeListener(getNewEventPropagationListener());\r
}else{\r
throw new IllegalStateException("Illegal state");\r
} \r
}\r
+ // #### derivedUnit = getInitializedDerivedUnit(derivedUnit);\r
\r
//test if unsupported\r
+ \r
+ //media\r
//specimen\r
- String objectTypeExceptionText = "Specimen";\r
- SpecimenDescription imageGallery = getImageGalleryWithSupportTest(derivedUnit, objectTypeExceptionText, false);\r
- getImageTextDataWithSupportTest(imageGallery, objectTypeExceptionText);\r
+// String objectTypeExceptionText = "Specimen";\r
+// SpecimenDescription imageGallery = getImageGalleryWithSupportTest(derivedUnit, objectTypeExceptionText, false);\r
+// getImageTextDataWithSupportTest(imageGallery, objectTypeExceptionText);\r
+ this.derivedUnitMediaTextData = inititializeTextDataWithSupportTest(Feature.IMAGE(), this.derivedUnit, false, true);\r
\r
//field observation\r
- objectTypeExceptionText = "Field observation";\r
- imageGallery = getImageGalleryWithSupportTest(fieldObservation, objectTypeExceptionText, false);\r
- getImageTextDataWithSupportTest(imageGallery, objectTypeExceptionText);\r
+// objectTypeExceptionText = "Field observation";\r
+// imageGallery = getImageGalleryWithSupportTest(fieldObservation, objectTypeExceptionText, false);\r
+// getImageTextDataWithSupportTest(imageGallery, objectTypeExceptionText);\r
+ fieldObjectMediaTextData = initializeFieldObjectTextDataWithSupportTest(Feature.IMAGE(), false, true);\r
\r
- //direct media of derived unit\r
+ //handle derivedUnit.getMedia()\r
if (derivedUnit.getMedia().size() > 0){\r
//TODO better changed model here to allow only one place for images\r
if (this.config.isMoveDerivedUnitMediaToGallery()){\r
}\r
}\r
\r
- //direct media of field observation\r
+ //handle fieldObservation.getMedia()\r
if (fieldObservation != null && fieldObservation.getMedia() != null && fieldObservation.getMedia().size() > 0){\r
//TODO better changed model here to allow only one place for images\r
if (this.config.isMoveFieldObjectMediaToGallery()){\r
}\r
\r
//test if descriptions are supported\r
- ecology = initializeFieldObjectTextDataWithSupportTest(Feature.ECOLOGY(), false);\r
- plantDescription = initializeFieldObjectTextDataWithSupportTest(Feature.DESCRIPTION(), false);\r
+ ecology = initializeFieldObjectTextDataWithSupportTest(Feature.ECOLOGY(), false, false);\r
+ plantDescription = initializeFieldObjectTextDataWithSupportTest(Feature.DESCRIPTION(), false, false);\r
}\r
\r
\r
+ private DerivedUnitBase getInitializedDerivedUnit(DerivedUnitBase derivedUnit) {\r
+ IOccurrenceService occurrenceService = this.config.getOccurrenceService();\r
+ if (occurrenceService == null){\r
+ return derivedUnit;\r
+ }\r
+ List<String> propertyPaths = this.config.getPropertyPaths();\r
+ if (propertyPaths == null){\r
+ return derivedUnit;\r
+ }\r
+ propertyPaths = getDerivedUnitPropertyPaths(propertyPaths);\r
+ DerivedUnitBase result = (DerivedUnitBase)occurrenceService.load(derivedUnit.getUuid(), propertyPaths);\r
+ return result;\r
+ }\r
+\r
+ /**\r
+ * Initializes the derived unit according to the configuartions property path.\r
+ * If the property path is <code>null</code> or no occurrence service is given the\r
+ * returned object is the same as the input parameter.\r
+ * @param fieldObservation2\r
+ * @return\r
+ */\r
+ private FieldObservation getInitializedFieldObservation(FieldObservation fieldObservation) {\r
+ IOccurrenceService occurrenceService = this.config.getOccurrenceService();\r
+ if (occurrenceService == null){\r
+ return fieldObservation;\r
+ }\r
+ List<String> propertyPaths = this.config.getPropertyPaths();\r
+ if (propertyPaths == null){\r
+ return fieldObservation;\r
+ }\r
+ propertyPaths = getFieldObjectPropertyPaths(propertyPaths);\r
+ FieldObservation result = (FieldObservation)occurrenceService.load(fieldObservation.getUuid(), propertyPaths);\r
+ return result;\r
+ }\r
+\r
+ /**\r
+ * Transforms the property paths in a way that the facade is handled just like an \r
+ * ordinary CdmBase object.<BR>\r
+ * E.g. a property path "collectinAreas" will be translated into gatheringEvent.collectingAreas\r
+ * @param propertyPaths\r
+ * @return\r
+ */\r
+ private List<String> getFieldObjectPropertyPaths(List<String> propertyPaths) {\r
+ List<String> result = new ArrayList<String>();\r
+ for (String facadePath : propertyPaths){\r
+ // collecting areas (named area)\r
+ if (facadePath.startsWith("collectingAreas")){\r
+ facadePath = "gatheringEvent." + facadePath;\r
+ result.add(facadePath);\r
+ }\r
+ // collector (agentBase)\r
+ else if (facadePath.startsWith("collector")){\r
+ facadePath = facadePath.replace("collector", "gatheringEvent.actor");\r
+ result.add(facadePath);\r
+ }\r
+ // exactLocation (agentBase)\r
+ else if (facadePath.startsWith("exactLocation")){\r
+ facadePath = "gatheringEvent." + facadePath;\r
+ result.add(facadePath);\r
+ }\r
+ // gatheringPeriod (TimePeriod)\r
+ else if (facadePath.startsWith("gatheringPeriod")){\r
+ facadePath = facadePath.replace("gatheringPeriod", "gatheringEvent.timeperiod");\r
+ result.add(facadePath);\r
+ }\r
+ // (locality/ localityLanguage , LanguageString)\r
+ else if (facadePath.startsWith("locality")){\r
+ facadePath = "gatheringEvent." + facadePath;\r
+ result.add(facadePath);\r
+ }\r
+ \r
+ //*********** FIELD OBJECT ************\r
+ // fieldObjectDefinitions (Map<language, languageString)\r
+ else if (facadePath.startsWith("fieldObjectDefinitions")){\r
+ // TODO or definition ???\r
+ facadePath = facadePath.replace("fieldObjectDefinitions", "description");\r
+ result.add(facadePath);\r
+ }\r
+ // fieldObjectMedia (Media)\r
+ else if (facadePath.startsWith("fieldObjectMedia")){\r
+ // TODO ??? \r
+ facadePath = facadePath.replace("fieldObjectMedia", "descriptions.elements.media");\r
+ result.add(facadePath);\r
+ }\r
+ \r
+ //Gathering Event will always be added\r
+ result.add("gatheringEvent");\r
+ \r
+ }\r
+ \r
+/*\r
+ Gathering Event\r
+ ====================\r
+ - gatheringEvent (GatheringEvent)\r
+\r
+ Field Object\r
+ =================\r
+ - ecology/ ecologyAll (String) ???\r
+ - plant description (like ecology)\r
+ \r
+ - fieldObjectImageGallery (SpecimenDescription) - is automatically initialized via fieldObjectMedia\r
+\r
+*/\r
+ \r
+ return result;\r
+ }\r
+ \r
+ /**\r
+ * Transforms the property paths in a way that the facade is handled just like an \r
+ * ordinary CdmBase object.<BR>\r
+ * E.g. a property path "collectinAreas" will be translated into gatheringEvent.collectingAreas\r
+ * \r
+ * Not needed (?) as the facade works with REST service property paths without using this method.\r
+ * @param propertyPaths\r
+ * @return\r
+ */\r
+ private List<String> getDerivedUnitPropertyPaths(List<String> propertyPaths) {\r
+ List<String> result = new ArrayList<String>();\r
+ for (String facadePath : propertyPaths){\r
+ // determinations (DeterminationEvent)\r
+ if (facadePath.startsWith("determinations")){\r
+ facadePath = "" + facadePath; //no change\r
+ result.add(facadePath);\r
+ }\r
+ // storedUnder (TaxonNameBase)\r
+ else if (facadePath.startsWith("storedUnder")){\r
+ facadePath = "" + facadePath; //no change\r
+ result.add(facadePath);\r
+ }\r
+ // sources (IdentifiableSource)\r
+ else if (facadePath.startsWith("sources")){\r
+ facadePath = "" + facadePath; //no change\r
+ result.add(facadePath);\r
+ }\r
+ // collection (Collection)\r
+ else if (facadePath.startsWith("collection")){\r
+ facadePath = "" + facadePath; //no change\r
+ result.add(facadePath);\r
+ }\r
+ // (locality/ localityLanguage , LanguageString)\r
+ else if (facadePath.startsWith("locality")){\r
+ facadePath = "gatheringEvent." + facadePath;\r
+ result.add(facadePath);\r
+ }\r
+ \r
+ //*********** FIELD OBJECT ************\r
+ // derivedUnitDefinitions (Map<language, languageString)\r
+ else if (facadePath.startsWith("derivedUnitDefinitions")){\r
+ // TODO or definition ???\r
+ facadePath = facadePath.replace("derivedUnitDefinitions", "description");\r
+ result.add(facadePath);\r
+ }\r
+ \r
+ // derivedUnitMedia (Media)\r
+ else if (facadePath.startsWith("derivedUnitMedia")){\r
+ // TODO ??? \r
+ facadePath = facadePath.replace("derivedUnitMedia", "descriptions.elements.media");\r
+ result.add(facadePath);\r
+ }\r
+ \r
+ }\r
+ \r
+/*\r
+ //TODO\r
+ Derived Unit\r
+ =====================\r
+ \r
+ - derivedUnitImageGallery (SpecimenDescription) - is automatically initialized via derivedUnitMedia\r
+ \r
+ - derivationEvent (DerivationEvent) - will always be initialized\r
+ - duplicates (??? Specimen???) ???\r
+*/\r
+ \r
+ return result;\r
+ }\r
+\r
/**\r
* \r
*/\r
private void setCacheStrategy() {\r
+ if (derivedUnit == null){\r
+ throw new NullPointerException("Facade's derviedUnit must not be null to set cache strategy");\r
+ }\r
derivedUnit.setCacheStrategy(new DerivedUnitFacadeCacheStrategy());\r
}\r
\r
-/**\r
- * @param b\r
- * @throws DerivedUnitFacadeNotSupportedException \r
+\r
+ /**\r
+ * @param feature\r
+ * @param createIfNotExists\r
+ * @param isImageGallery\r
+ * @return\r
+ * @throws DerivedUnitFacadeNotSupportedException\r
+ */\r
+ private TextData initializeFieldObjectTextDataWithSupportTest(Feature feature, boolean createIfNotExists, boolean isImageGallery) throws DerivedUnitFacadeNotSupportedException {\r
+ //field object\r
+ FieldObservation fieldObject = getFieldObservation(createIfNotExists) ;\r
+ if (fieldObject == null){\r
+ return null;\r
+ }\r
+ return inititializeTextDataWithSupportTest(feature, fieldObject, createIfNotExists, isImageGallery);\r
+ }\r
+\r
+\r
+ /**\r
+ * @param feature\r
+ * @param specimen\r
+ * @param createIfNotExists\r
+ * @param isImageGallery\r
+ * @return\r
+ * @throws DerivedUnitFacadeNotSupportedException\r
*/\r
- private TextData initializeFieldObjectTextDataWithSupportTest(Feature feature, boolean createIfNotExists) throws DerivedUnitFacadeNotSupportedException {\r
- if (feature == null){\r
+ private TextData inititializeTextDataWithSupportTest(Feature feature, SpecimenOrObservationBase specimen, boolean createIfNotExists, \r
+ boolean isImageGallery) throws DerivedUnitFacadeNotSupportedException {\r
+ if (feature == null ){\r
return null;\r
}\r
TextData textData = null;\r
textData = TextData.NewInstance(feature);\r
}\r
\r
- //field object\r
- FieldObservation fieldObject = getFieldObservation(createIfNotExists) ;\r
- if (fieldObject == null){\r
- return null;\r
+ Set<SpecimenDescription> descriptions;\r
+ if (isImageGallery){\r
+ descriptions = specimen.getSpecimenDescriptionImageGallery();\r
+ }else{\r
+ descriptions = specimen.getSpecimenDescriptions(false);\r
}\r
- Set<SpecimenDescription> descriptions = fieldObject.getSpecimenDescriptions(false);\r
if (descriptions.size() == 0){\r
if (createIfNotExists){\r
- SpecimenDescription newSpecimenDescription = SpecimenDescription.NewInstance(fieldObject);\r
+ SpecimenDescription newSpecimenDescription = SpecimenDescription.NewInstance(specimen);\r
newSpecimenDescription.addElement(textData);\r
return textData;\r
}else{\r
Set<DescriptionElementBase> existingTextData = new HashSet<DescriptionElementBase>();\r
for (SpecimenDescription description : descriptions){\r
for (DescriptionElementBase element: description.getElements()){\r
- if (element.isInstanceOf(TextData.class) && feature.equals(element.getFeature()) ){\r
+ if (element.isInstanceOf(TextData.class) && ( feature.equals(element.getFeature() )|| isImageGallery ) ){\r
existingTextData.add(element);\r
}\r
}\r
return textData;\r
}\r
}\r
+ \r
+\r
+ /**\r
+ * Tests if a given image gallery is supported by the derived unit facade.\r
+ * It returns the only text data attached to the given image gallery.\r
+ * If the given image gallery does not have text data attached, it is created and attached.\r
+ * @param imageGallery\r
+ * @return\r
+ * @throws DerivedUnitFacadeNotSupportedException\r
+ */\r
+ private TextData testImageGallery(SpecimenDescription imageGallery) throws DerivedUnitFacadeNotSupportedException {\r
+ if (imageGallery.isImageGallery() == false){\r
+ throw new DerivedUnitFacadeNotSupportedException("Image gallery needs to have image gallery flag set");\r
+ }\r
+ if (imageGallery.getElements().size() > 1){\r
+ throw new DerivedUnitFacadeNotSupportedException("Image gallery must not have more then one description element");\r
+ }\r
+ TextData textData;\r
+ if (imageGallery.getElements().size() == 0){\r
+ textData = TextData.NewInstance(Feature.IMAGE());\r
+ imageGallery.addElement(textData);\r
+ }else{\r
+ if (! imageGallery.getElements().iterator().next().isInstanceOf(TextData.class)){\r
+ throw new DerivedUnitFacadeNotSupportedException("Image gallery must only have TextData as element");\r
+ }else{\r
+ textData = CdmBase.deproxy(imageGallery.getElements().iterator().next(), TextData.class);\r
+ }\r
+ }\r
+ return textData;\r
+ }\r
\r
//************************** METHODS ***************************************** \r
\r
- private List<Media> setDerivedUnitImageGalleryMedia() throws DerivedUnitFacadeNotSupportedException{\r
- if (specimenMedia == null){\r
- specimenMedia = getImageGalleryMedia(derivedUnit, "Specimen");\r
+ private TextData getDerivedUnitImageGalleryTextData(boolean createIfNotExists) throws DerivedUnitFacadeNotSupportedException{\r
+ if (this.derivedUnitMediaTextData == null && createIfNotExists){\r
+ this.derivedUnitMediaTextData = getImageGalleryTextData(derivedUnit, "Specimen");\r
}\r
- return specimenMedia;\r
+ return this.derivedUnitMediaTextData;\r
}\r
-\r
- private List<Media> setObservationImageGalleryMedia() throws DerivedUnitFacadeNotSupportedException{\r
- if (fieldObservationMedia == null){\r
- fieldObservationMedia = getImageGalleryMedia(fieldObservation, "Field observation");\r
+ \r
+ private TextData getObservationImageGalleryTextData(boolean createIfNotExists) throws DerivedUnitFacadeNotSupportedException{\r
+ if (this.fieldObjectMediaTextData == null && createIfNotExists){\r
+ this.fieldObjectMediaTextData = getImageGalleryTextData(fieldObservation, "Field observation");\r
}\r
- return fieldObservationMedia;\r
+ return this.fieldObjectMediaTextData;\r
}\r
\r
\r
\r
//*********** MEDIA METHODS ******************************\r
\r
+// /**\r
+// * Returns the media list for a specimen. Throws an exception if the existing specimen descriptions\r
+// * are not supported by this facade.\r
+// * @param specimen the specimen the media belongs to\r
+// * @param specimenExceptionText text describing the specimen for exception messages\r
+// * @return\r
+// * @throws DerivedUnitFacadeNotSupportedException\r
+// */\r
+// private List<Media> getImageGalleryMedia(SpecimenOrObservationBase specimen, String specimenExceptionText) throws DerivedUnitFacadeNotSupportedException{\r
+// List<Media> result;\r
+// SpecimenDescription imageGallery = getImageGalleryWithSupportTest(specimen, specimenExceptionText, true);\r
+// TextData textData = getImageTextDataWithSupportTest(imageGallery, specimenExceptionText);\r
+// result = textData.getMedia();\r
+// return result;\r
+// }\r
+ \r
/**\r
* Returns the media list for a specimen. Throws an exception if the existing specimen descriptions\r
* are not supported by this facade.\r
* @return\r
* @throws DerivedUnitFacadeNotSupportedException\r
*/\r
- private List<Media> getImageGalleryMedia(SpecimenOrObservationBase specimen, String specimenExceptionText) throws DerivedUnitFacadeNotSupportedException{\r
- List<Media> result;\r
+ private TextData getImageGalleryTextData(SpecimenOrObservationBase specimen, String specimenExceptionText) throws DerivedUnitFacadeNotSupportedException{\r
+ TextData result;\r
SpecimenDescription imageGallery = getImageGalleryWithSupportTest(specimen, specimenExceptionText, true);\r
- TextData textData = getImageTextDataWithSupportTest(imageGallery, specimenExceptionText);\r
- result = textData.getMedia();\r
+ result = getImageTextDataWithSupportTest(imageGallery, specimenExceptionText);\r
return result;\r
}\r
\r
* Returns the image gallery for a specimen. If there are multiple specimen descriptions\r
* marked as image galleries an arbitrary one is chosen.\r
* If no image gallery exists, a new one is created if <code>createNewIfNotExists</code>\r
- * is <code>true</code>.\r
+ * is <code>true</code>.<Br>\r
+ * If specimen is <code>null</code> a null pointer exception is thrown.\r
* @param createNewIfNotExists\r
* @return\r
*/\r
- private SpecimenDescription getImageGallery(SpecimenOrObservationBase<?> specimen, boolean createNewIfNotExists) {\r
+ private SpecimenDescription getImageGallery(SpecimenOrObservationBase<?> specimen, boolean createIfNotExists) {\r
SpecimenDescription result = null;\r
Set<SpecimenDescription> descriptions= specimen.getSpecimenDescriptions();\r
for (SpecimenDescription description : descriptions){\r
break;\r
}\r
}\r
- if (result == null && createNewIfNotExists){\r
+ if (result == null && createIfNotExists){\r
result = SpecimenDescription.NewInstance(specimen);\r
result.setImageGallery(true);\r
}\r
*/\r
private boolean addMedia(Media media, SpecimenOrObservationBase<?> specimen) throws DerivedUnitFacadeNotSupportedException {\r
if (media != null){\r
- List<Media> mediaList = getMedia(specimen);\r
+ List<Media> mediaList = getMedia(specimen, true);\r
return mediaList.add(media);\r
}else{\r
return false;\r
* @throws DerivedUnitFacadeNotSupportedException\r
*/\r
private boolean removeMedia(Media media, SpecimenOrObservationBase<?> specimen) throws DerivedUnitFacadeNotSupportedException {\r
- List<Media> mediaList = getMedia(specimen);\r
+ List<Media> mediaList = getMedia(specimen, true);\r
return mediaList == null ? null : mediaList.remove(media);\r
}\r
\r
+ private List<Media> getMedia(SpecimenOrObservationBase<?> specimen, boolean createIfNotExists) throws DerivedUnitFacadeNotSupportedException {\r
+ TextData textData = getMediaTextData(specimen, createIfNotExists);\r
+ return textData == null ? null : textData.getMedia();\r
+ }\r
+ \r
/**\r
* Returns the one media list of a specimen which is part of the only image gallery that \r
* this specimen is part of.<BR>\r
* @return\r
* @throws DerivedUnitFacadeNotSupportedException\r
*/\r
- private List<Media> getMedia(SpecimenOrObservationBase<?> specimen) throws DerivedUnitFacadeNotSupportedException {\r
+// private List<Media> getMedia(SpecimenOrObservationBase<?> specimen) throws DerivedUnitFacadeNotSupportedException {\r
+// if (specimen == null){\r
+// return null;\r
+// }\r
+// if (specimen == this.derivedUnit){\r
+// return getDerivedUnitImageGalleryMedia();\r
+// }else if (specimen == this.fieldObservation){\r
+// return getObservationImageGalleryTextData();\r
+// }else{\r
+// return getImageGalleryMedia(specimen, "Undefined specimen ");\r
+// }\r
+// }\r
+ \r
+ /**\r
+ * Returns the one media list of a specimen which is part of the only image gallery that \r
+ * this specimen is part of.<BR>\r
+ * If these conditions are not hold an exception is thrwon.\r
+ * @param specimen\r
+ * @return\r
+ * @throws DerivedUnitFacadeNotSupportedException\r
+ */\r
+ private TextData getMediaTextData(SpecimenOrObservationBase<?> specimen, boolean createIfNotExists) throws DerivedUnitFacadeNotSupportedException {\r
if (specimen == null){\r
return null;\r
}\r
if (specimen == this.derivedUnit){\r
- return setDerivedUnitImageGalleryMedia();\r
+ return getDerivedUnitImageGalleryTextData(createIfNotExists);\r
}else if (specimen == this.fieldObservation){\r
- return setObservationImageGalleryMedia();\r
+ return getObservationImageGalleryTextData(createIfNotExists);\r
}else{\r
- return getImageGalleryMedia(specimen, "Undefined specimen ");\r
+ return getImageGalleryTextData(specimen, "Undefined specimen ");\r
}\r
}\r
\r
\r
// ****************** Gathering Event *********************************/\r
\r
+ //country\r
+ @Transient\r
+ public NamedArea getCountry(){\r
+ return (hasGatheringEvent() ? getGatheringEvent(true).getCountry() : null);\r
+ }\r
+ \r
+ public void setCountry(NamedArea country){\r
+ getGatheringEvent(true).setCountry(country);\r
+ }\r
+ \r
+ \r
//Collecting area\r
public void addCollectingArea(NamedArea area) {\r
getGatheringEvent(true).addCollectingArea(area);\r
getGatheringEvent(true).addCollectingArea(area);\r
}\r
}\r
+ @Transient\r
public Set<NamedArea> getCollectingAreas() {\r
return (hasGatheringEvent() ? getGatheringEvent(true).getCollectingAreas() : null);\r
}\r
* @see #getAbsoluteElevationError()\r
* @see #getAbsoluteElevationRange()\r
**/\r
+ @Transient\r
public Integer getAbsoluteElevation() {\r
return (hasGatheringEvent() ? getGatheringEvent(true).getAbsoluteElevation() : null);\r
}\r
}\r
\r
//absolute elevation error\r
+ @Transient\r
public Integer getAbsoluteElevationError() {\r
return (hasGatheringEvent() ? getGatheringEvent(true).getAbsoluteElevationError() : null);\r
}\r
* @see #setAbsoluteElevationRange(Integer, Integer)\r
* @see #getAbsoluteElevationMaximum()\r
*/\r
+ @Transient\r
public Integer getAbsoluteElevationMinimum(){\r
if ( ! hasGatheringEvent() ){\r
return null;\r
* @see #setAbsoluteElevationRange(Integer, Integer)\r
* @see #getAbsoluteElevationMinimum()\r
*/\r
+ @Transient\r
public Integer getAbsoluteElevationMaximum(){\r
if ( ! hasGatheringEvent() ){\r
return null;\r
}\r
\r
//collector\r
+ @Transient\r
public AgentBase getCollector() {\r
return (hasGatheringEvent() ? getGatheringEvent(true).getCollector() : null);\r
}\r
}\r
\r
//collecting method\r
+ @Transient\r
public String getCollectingMethod() {\r
return (hasGatheringEvent() ? getGatheringEvent(true).getCollectingMethod() : null);\r
}\r
}\r
\r
//distance to ground\r
+ @Transient\r
public Integer getDistanceToGround() {\r
return (hasGatheringEvent() ? getGatheringEvent(true).getDistanceToGround() : null);\r
}\r
}\r
\r
//distance to water surface\r
+ @Transient\r
public Integer getDistanceToWaterSurface() {\r
return (hasGatheringEvent() ? getGatheringEvent(true).getDistanceToWaterSurface() : null);\r
}\r
}\r
\r
//exact location\r
+ @Transient\r
public Point getExactLocation() {\r
return (hasGatheringEvent() ? getGatheringEvent(true).getExactLocation() : null );\r
}\r
\r
/**\r
- * Returns a sexagesimal representation of the exact location (e.g. 12°59'N, 35°23E).\r
+ * Returns a sexagesimal representation of the exact location (e.g. 12°59'N, 35°23E).\r
* If the exact location is <code>null</code> the empty string is returned.\r
* @param includeEmptySeconds\r
* @param includeReferenceSystem\r
}\r
\r
//gathering event description\r
+ @Transient\r
public String getGatheringEventDescription() {\r
return (hasGatheringEvent() ? getGatheringEvent(true).getDescription() : null);\r
}\r
}\r
\r
//gatering period\r
+ @Transient\r
public TimePeriod getGatheringPeriod() {\r
return (hasGatheringEvent() ? getGatheringEvent(true).getTimeperiod() : null);\r
}\r
}\r
\r
//locality\r
+ @Transient\r
public LanguageString getLocality(){\r
return (hasGatheringEvent() ? getGatheringEvent(true).getLocality() : null);\r
}\r
+ /**\r
+ * convienience method for {@link #getLocality()}.{@link LanguageString#getText() getText()}\r
+ * @return\r
+ */\r
+ @Transient\r
public String getLocalityText(){\r
LanguageString locality = getLocality();\r
if(locality != null){\r
}\r
return null;\r
}\r
+ /**\r
+ * convienience method for {@link #getLocality()}.{@link LanguageString#getLanguage() getLanguage()}\r
+ * @return\r
+ */\r
+ @Transient\r
public Language getLocalityLanguage(){\r
LanguageString locality = getLocality();\r
if(locality != null){\r
public boolean hasGatheringEvent(){\r
return (getGatheringEvent(false) != null);\r
}\r
- public GatheringEvent getGatheringEvent() {\r
+ \r
+ public GatheringEvent innerGatheringEvent() {\r
return getGatheringEvent(false);\r
}\r
\r
}\r
\r
//ecology\r
+ @Transient\r
public String getEcology(){\r
return getEcology(Language.DEFAULT());\r
}\r
// LanguageString languageString = getEcologyAll().getPreferredLanguageString(languages);\r
// return languageString.getText();\r
// }\r
+ /**\r
+ * Returns a copy of the multilanguage text holding the ecology data.\r
+ * @see {@link TextData#getMultilanguageText()}\r
+ * @return\r
+ */\r
+ @Transient\r
public Map<Language, LanguageString> getEcologyAll(){\r
if (ecology == null){\r
try {\r
- ecology = initializeFieldObjectTextDataWithSupportTest(Feature.ECOLOGY(), true);\r
+ ecology = initializeFieldObjectTextDataWithSupportTest(Feature.ECOLOGY(), false, false);\r
} catch (DerivedUnitFacadeNotSupportedException e) {\r
throw new IllegalStateException(notSupportMessage, e);\r
}\r
+ if (ecology == null){\r
+ return new HashMap<Language, LanguageString>();\r
+ }\r
}\r
return ecology.getMultilanguageText();\r
}\r
}\r
if (ecology == null){\r
try {\r
- ecology = initializeFieldObjectTextDataWithSupportTest(Feature.ECOLOGY(), true);\r
+ ecology = initializeFieldObjectTextDataWithSupportTest(Feature.ECOLOGY(), true, false);\r
} catch (DerivedUnitFacadeNotSupportedException e) {\r
throw new IllegalStateException(notSupportMessage, e);\r
}\r
if (ecologyText == null){\r
ecology.removeText(language);\r
}else{\r
- ecology.putText(ecologyText, language);\r
+ ecology.putText(language, ecologyText);\r
}\r
}\r
public void removeEcology(Language language){\r
\r
\r
//plant description\r
+ @Transient\r
public String getPlantDescription(){\r
return getPlantDescription(null);\r
}\r
// LanguageString languageString = getPlantDescriptionAll().getPreferredLanguageString(languages);\r
// return languageString.getText();\r
// }\r
+ /**\r
+ * Returns a copy of the multilanguage text holding the description data.\r
+ * @see {@link TextData#getMultilanguageText()}\r
+ * @return\r
+ */\r
+ @Transient\r
public Map<Language, LanguageString> getPlantDescriptionAll(){\r
if (plantDescription == null){\r
try {\r
- plantDescription = initializeFieldObjectTextDataWithSupportTest(Feature.DESCRIPTION(), true);\r
+ plantDescription = initializeFieldObjectTextDataWithSupportTest(Feature.DESCRIPTION(), false, false);\r
} catch (DerivedUnitFacadeNotSupportedException e) {\r
throw new IllegalStateException(notSupportMessage, e);\r
}\r
+ if (plantDescription == null){\r
+ return new HashMap<Language, LanguageString>();\r
+ }\r
}\r
return plantDescription.getMultilanguageText();\r
}\r
}\r
if (plantDescription == null){\r
try {\r
- plantDescription = initializeFieldObjectTextDataWithSupportTest(Feature.DESCRIPTION(), true);\r
+ plantDescription = initializeFieldObjectTextDataWithSupportTest(Feature.DESCRIPTION(), true, false);\r
} catch (DerivedUnitFacadeNotSupportedException e) {\r
throw new IllegalStateException(notSupportMessage, e);\r
}\r
if (plantDescriptionText == null){\r
plantDescription.removeText(language);\r
}else{\r
- plantDescription.putText(plantDescriptionText, language);\r
+ plantDescription.putText(language, plantDescriptionText);\r
}\r
}\r
public void removePlantDescription(Language language){\r
setPlantDescription(null, language);\r
}\r
\r
-\r
- \r
//field object definition\r
public void addFieldObjectDefinition(String text, Language language) {\r
getFieldObservation(true).addDefinition(text, language);\r
}\r
+ @Transient\r
public Map<Language, LanguageString> getFieldObjectDefinition() {\r
if (! hasFieldObservation()){\r
return new HashMap<Language, LanguageString>();\r
return (getImageGallery(fieldObservation, false) != null);\r
}\r
}\r
+ \r
+ public void setFieldObjectImageGallery(SpecimenDescription imageGallery) throws DerivedUnitFacadeNotSupportedException{\r
+ SpecimenDescription existingGallery = getFieldObjectImageGallery(false);\r
+ \r
+ //test attached specimens contain this.derivedUnit\r
+ SpecimenOrObservationBase<?> facadeFieldObservation = innerFieldObservation();\r
+ testSpecimenInImageGallery(imageGallery, facadeFieldObservation);\r
+ \r
+ if (existingGallery != null){\r
+ if (existingGallery != imageGallery){\r
+ throw new DerivedUnitFacadeNotSupportedException("DerivedUnitFacade does not allow more than one image gallery");\r
+ }else{\r
+ //do nothing\r
+ }\r
+ }else {\r
+ TextData textData = testImageGallery(imageGallery);\r
+ this.fieldObjectMediaTextData = textData;\r
+ }\r
+ }\r
+\r
+ \r
+ /**\r
+ * Returns the field object image gallery. If no such image gallery exists and\r
+ * createIfNotExists is true an new one is created. Otherwise null is returned.\r
+ * @param createIfNotExists\r
+ * @return\r
+ */\r
+ public SpecimenDescription getFieldObjectImageGallery(boolean createIfNotExists){\r
+ TextData textData;\r
+ try {\r
+ textData = initializeFieldObjectTextDataWithSupportTest(Feature.IMAGE(), createIfNotExists, true);\r
+ } catch (DerivedUnitFacadeNotSupportedException e) {\r
+ throw new IllegalStateException(notSupportMessage, e);\r
+ }\r
+ if (textData != null){\r
+ return CdmBase.deproxy(textData.getInDescription(), SpecimenDescription.class);\r
+ }else{\r
+ return null;\r
+ }\r
+ }\r
/**\r
* Returns the media for the field object.<BR>\r
- * Please handle with care as <B>this method will create an empty image gallery</B>\r
- * if it does not yet exist. Use {@link #hasFieldObjectImageGallery()} first\r
- * to test if an image gallery exists at all to avoid creating an empty gallery.\r
* @return\r
*/\r
+ @Transient\r
public List<Media> getFieldObjectMedia() {\r
try {\r
- return getMedia(getFieldObservation(false));\r
+ List<Media> result = getMedia(getFieldObservation(false), false);\r
+ return result == null ? new ArrayList<Media>() : result;\r
} catch (DerivedUnitFacadeNotSupportedException e) {\r
throw new IllegalStateException(notSupportMessage, e);\r
}\r
}\r
\r
//field number\r
+ @Transient\r
public String getFieldNumber() {\r
if (! hasFieldObservation()){\r
return null;\r
getFieldObservation(true).setFieldNumber(fieldNumber);\r
}\r
\r
+ //primary collector\r
+ @Transient\r
+ public Person getPrimaryCollector() {\r
+ if (! hasFieldObservation()){\r
+ return null;\r
+ }else{\r
+ return getFieldObservation(true).getPrimaryCollector();\r
+ }\r
+ }\r
+ public void setPrimaryCollector(Person primaryCollector) {\r
+ getFieldObservation(true).setPrimaryCollector(primaryCollector);\r
+ }\r
+ \r
+ \r
\r
//field notes\r
+ @Transient\r
public String getFieldNotes() {\r
if (! hasFieldObservation()){\r
return null;\r
\r
\r
//individual counts\r
+ @Transient\r
public Integer getIndividualCount() {\r
return (hasFieldObservation()? getFieldObservation(true).getIndividualCount() : null );\r
}\r
}\r
\r
//life stage\r
+ @Transient\r
public Stage getLifeStage() {\r
return (hasFieldObservation()? getFieldObservation(true).getLifeStage() : null );\r
}\r
}\r
\r
//sex\r
+ @Transient\r
public Sex getSex() {\r
return (hasFieldObservation()? getFieldObservation(true).getSex() : null );\r
}\r
* Returns the field observation as an object.\r
* @return\r
*/\r
- public FieldObservation getFieldObservation(){\r
+ public FieldObservation innerFieldObservation(){\r
return getFieldObservation(false);\r
}\r
\r
public FieldObservation getFieldObservation(boolean createIfNotExists){\r
if (fieldObservation == null && createIfNotExists){\r
fieldObservation = FieldObservation.NewInstance();\r
+ fieldObservation.addPropertyChangeListener(getNewEventPropagationListener());\r
DerivationEvent derivationEvent = getDerivationEvent(true);\r
derivationEvent.addOriginal(fieldObservation);\r
}\r
\r
\r
\r
+\r
+ \r
//****************** Specimen ************************************************** \r
\r
//Definition\r
public void addDerivedUnitDefinition(String text, Language language) {\r
derivedUnit.addDefinition(text, language);\r
}\r
+ @Transient\r
public Map<Language, LanguageString> getDerivedUnitDefinitions(){\r
return this.derivedUnit.getDefinition();\r
}\r
public void addDetermination(DeterminationEvent determination) {\r
derivedUnit.addDetermination(determination);\r
}\r
+ @Transient\r
public Set<DeterminationEvent> getDeterminations() {\r
return derivedUnit.getDeterminations();\r
}\r
* Returns true, if an image gallery exists for the specimen.<BR>\r
* Returns also <code>true</code> if the image gallery is empty. \r
*/\r
- public boolean hasSpecimenImageGallery(){\r
+ public boolean hasDerivedUnitImageGallery(){\r
return (getImageGallery(derivedUnit, false) != null);\r
- } \r
+ }\r
+ \r
+ public SpecimenDescription getDerivedUnitImageGallery(boolean createIfNotExists){\r
+ TextData textData;\r
+ try {\r
+ textData = inititializeTextDataWithSupportTest(Feature.IMAGE(), derivedUnit, createIfNotExists, true);\r
+ } catch (DerivedUnitFacadeNotSupportedException e) {\r
+ throw new IllegalStateException(notSupportMessage, e);\r
+ }\r
+ if (textData != null){\r
+ return CdmBase.deproxy(textData.getInDescription(), SpecimenDescription.class);\r
+ }else{\r
+ return null;\r
+ }\r
+ }\r
+ public void setDerivedUnitImageGallery(SpecimenDescription imageGallery) throws DerivedUnitFacadeNotSupportedException{\r
+ SpecimenDescription existingGallery = getDerivedUnitImageGallery(false);\r
+ \r
+ //test attached specimens contain this.derivedUnit\r
+ SpecimenOrObservationBase facadeDerivedUnit = innerDerivedUnit();\r
+ testSpecimenInImageGallery(imageGallery, facadeDerivedUnit);\r
+ \r
+ if (existingGallery != null){\r
+ if (existingGallery != imageGallery){\r
+ throw new DerivedUnitFacadeNotSupportedException("DerivedUnitFacade does not allow more than one image gallery");\r
+ }else{\r
+ //do nothing\r
+ }\r
+ }else {\r
+ TextData textData = testImageGallery(imageGallery);\r
+ this.derivedUnitMediaTextData = textData;\r
+ }\r
+ }\r
+\r
+ /**\r
+ * @param imageGallery\r
+ * @throws DerivedUnitFacadeNotSupportedException\r
+ */\r
+ private void testSpecimenInImageGallery(SpecimenDescription imageGallery, SpecimenOrObservationBase specimen) throws DerivedUnitFacadeNotSupportedException {\r
+ Set<SpecimenOrObservationBase> imageGallerySpecimens = imageGallery.getDescribedSpecimenOrObservations();\r
+ if (imageGallerySpecimens.size() < 1){\r
+ throw new DerivedUnitFacadeNotSupportedException("Image Gallery has no Specimen attached. Please attache according specimen or field observation.");\r
+ }\r
+ if (! imageGallerySpecimens.contains(specimen)){\r
+ throw new DerivedUnitFacadeNotSupportedException("Image Gallery has not the facade's field object attached. Please add field object first to image gallery specimenOrObservation list.");\r
+ }\r
+ }\r
+ \r
/**\r
* Returns the media for the specimen.<BR>\r
- * Please handle with care as <B>this method will create an empty image gallery</B>\r
- * if it does not yet exist. Use {@link #hasFieldObjectImageGallery()} first\r
- * to test if an image gallery exists at all to avoid creating an empty gallery.\r
* @return\r
*/\r
+ @Transient\r
public List<Media> getDerivedUnitMedia() {\r
try {\r
- return getMedia(derivedUnit);\r
+ List<Media> result = getMedia(derivedUnit, false);\r
+ return result == null ? new ArrayList<Media>() : result;\r
} catch (DerivedUnitFacadeNotSupportedException e) {\r
throw new IllegalStateException(notSupportMessage, e);\r
}\r
\r
\r
//Accession Number\r
+ @Transient\r
public String getAccessionNumber() {\r
return derivedUnit.getAccessionNumber();\r
}\r
derivedUnit.setAccessionNumber(accessionNumber);\r
}\r
\r
- //Catalog Number\r
+ @Transient\r
public String getCatalogNumber() {\r
return derivedUnit.getCatalogNumber();\r
}\r
derivedUnit.setCatalogNumber(catalogNumber);\r
}\r
\r
+ @Transient\r
+ public String getBarcode() {\r
+ return derivedUnit.getBarcode();\r
+ }\r
+ public void setBarcode(String barcode) {\r
+ derivedUnit.setBarcode(barcode);\r
+ }\r
+\r
+ \r
//Preservation Method\r
\r
/**\r
* @see #DerivedUnitType\r
* @return\r
*/\r
+ @Transient\r
public PreservationMethod getPreservationMethod() throws MethodNotSupportedByDerivedUnitTypeException {\r
if (derivedUnit.isInstanceOf(Specimen.class)){\r
return CdmBase.deproxy(derivedUnit, Specimen.class).getPreservation();\r
}else{\r
- throw new MethodNotSupportedByDerivedUnitTypeException("A preservation method is only available in derived units of type 'Specimen' or 'Fossil'");\r
+ if (this.config.isThrowExceptionForNonSpecimenPreservationMethodRequest()){\r
+ throw new MethodNotSupportedByDerivedUnitTypeException("A preservation method is only available in derived units of type 'Specimen' or 'Fossil'");\r
+ }else{\r
+ return null;\r
+ }\r
}\r
}\r
/**\r
if (derivedUnit.isInstanceOf(Specimen.class)){\r
CdmBase.deproxy(derivedUnit, Specimen.class).setPreservation(preservation);\r
}else{\r
- throw new MethodNotSupportedByDerivedUnitTypeException("A preservation method is only available in derived units of type 'Specimen' or 'Fossil'");\r
- \r
+ if (this.config.isThrowExceptionForNonSpecimenPreservationMethodRequest()){\r
+ throw new MethodNotSupportedByDerivedUnitTypeException("A preservation method is only available in derived units of type 'Specimen' or 'Fossil'");\r
+ }else{\r
+ return;\r
+ }\r
}\r
}\r
\r
//Stored under name\r
+ @Transient\r
public TaxonNameBase getStoredUnder() {\r
return derivedUnit.getStoredUnder();\r
}\r
}\r
\r
//colletors number\r
+ @Transient\r
public String getCollectorsNumber() {\r
return derivedUnit.getCollectorsNumber();\r
}\r
}\r
return this.derivedUnit.getTitleCache();\r
}\r
+ public boolean isProtectedTitleCache(){\r
+ return derivedUnit.isProtectedTitleCache();\r
+ }\r
public void setTitleCache(String titleCache, boolean isProtected) {\r
this.derivedUnit.setTitleCache(titleCache, isProtected);\r
}\r
* Returns the derived unit itself.\r
* @return the derived unit\r
*/\r
- public DerivedUnitBase getDerivedUnit() {\r
+ public DerivedUnitBase innerDerivedUnit() {\r
return this.derivedUnit;\r
}\r
\r
}\r
return result;\r
}\r
- \r
- public String getExsiccatum() {\r
- logger.warn("Exsiccatum method not yet supported. Needs model change");\r
- return null;\r
+ @Transient\r
+ public String getExsiccatum() throws MethodNotSupportedByDerivedUnitTypeException {\r
+ if (derivedUnit.isInstanceOf(Specimen.class)){\r
+ return CdmBase.deproxy(derivedUnit, Specimen.class).getExsiccatum();\r
+ }else{\r
+ if (this.config.isThrowExceptionForNonSpecimenPreservationMethodRequest()){\r
+ throw new MethodNotSupportedByDerivedUnitTypeException("An exsiccatum is only available in derived units of type 'Specimen' or 'Fossil'");\r
+ }else{\r
+ return null;\r
+ }\r
+ }\r
}\r
\r
- public String setExsiccatum() throws MethodNotSupportedException{\r
- throw new MethodNotSupportedException("Exsiccatum method not yet supported. Needs model change");\r
+ public void setExsiccatum(String exsiccatum) throws Exception{\r
+ if (derivedUnit.isInstanceOf(Specimen.class)){\r
+ CdmBase.deproxy(derivedUnit, Specimen.class).setExsiccatum(exsiccatum);\r
+ }else{\r
+ if (this.config.isThrowExceptionForNonSpecimenPreservationMethodRequest()){\r
+ throw new MethodNotSupportedByDerivedUnitTypeException("An exsiccatum is only available in derived units of type 'Specimen' or 'Fossil'");\r
+ }else{\r
+ return;\r
+ }\r
+ }\r
}\r
\r
\r
* @param originalNameString\r
* @return\r
*/\r
- public IdentifiableSource addSource(ReferenceBase reference, String microReference, String originalNameString){\r
+ public IdentifiableSource addSource(Reference reference, String microReference, String originalNameString){\r
IdentifiableSource source = IdentifiableSource.NewInstance(reference, microReference);\r
source.setOriginalNameString(originalNameString);\r
derivedUnit.addSource(source);\r
return source;\r
}\r
- \r
+\r
+ @Transient\r
public Set<IdentifiableSource> getSources(){\r
return derivedUnit.getSources();\r
}\r
/**\r
* @return the collection\r
*/\r
+ @Transient\r
public Collection getCollection() {\r
return derivedUnit.getCollection();\r
}\r
derivedUnit.setCollection(collection);\r
}\r
\r
+ //annotation \r
+ public void addAnnotation(Annotation annotation){\r
+ this.derivedUnit.addAnnotation(annotation);\r
+ }\r
+\r
+ @Transient\r
+ public void getAnnotations(){\r
+ this.derivedUnit.getAnnotations();\r
+ }\r
+ \r
+ public void removeAnnotation(Annotation annotation){\r
+ this.derivedUnit.removeAnnotation(annotation);\r
+ }\r
+ \r
\r
+// ******************************* Events *********************************************\r
+ \r
+ /**\r
+ * @return\r
+ */\r
+ private PropertyChangeListener getNewEventPropagationListener() {\r
+ PropertyChangeListener listener = new PropertyChangeListener(){\r
+ @Override\r
+ public void propertyChange(PropertyChangeEvent event) {\r
+ derivedUnit.firePropertyChange(event);\r
+ }\r
+ \r
+ };\r
+ return listener;\r
+ }\r
\r
+ \r
\r
\r
//**************** Other Collections *************************************************** \r
//TODO check derivedUnitType\r
getDerivationEvent(true).addDerivative(duplicateSpecimen); \r
}\r
+ \r
+ @Transient\r
public Set<Specimen> getDuplicates(){\r
Set<Specimen> result = new HashSet<Specimen>();\r
if (hasDerivationEvent()){\r