X-Git-Url: https://dev.e-taxonomy.eu/gitweb/cdmlib.git/blobdiff_plain/ea2896bab7f30a32a7ab4533262d27fe517f156d..d94ae8ac05e2bf2dbad253b965223e9ce8383e57:/cdmlib-model/src/main/java/eu/etaxonomy/cdm/model/occurrence/SpecimenOrObservationBase.java diff --git a/cdmlib-model/src/main/java/eu/etaxonomy/cdm/model/occurrence/SpecimenOrObservationBase.java b/cdmlib-model/src/main/java/eu/etaxonomy/cdm/model/occurrence/SpecimenOrObservationBase.java index cd05214260..572e5e5088 100644 --- a/cdmlib-model/src/main/java/eu/etaxonomy/cdm/model/occurrence/SpecimenOrObservationBase.java +++ b/cdmlib-model/src/main/java/eu/etaxonomy/cdm/model/occurrence/SpecimenOrObservationBase.java @@ -9,19 +9,51 @@ package eu.etaxonomy.cdm.model.occurrence; -import eu.etaxonomy.cdm.model.common.IdentifyableMediaEntity; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.Inheritance; +import javax.persistence.InheritanceType; +import javax.persistence.ManyToMany; +import javax.persistence.ManyToOne; +import javax.persistence.OneToMany; +import javax.persistence.Transient; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlElementWrapper; +import javax.xml.bind.annotation.XmlIDREF; +import javax.xml.bind.annotation.XmlRootElement; +import javax.xml.bind.annotation.XmlSchemaType; +import javax.xml.bind.annotation.XmlType; +import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; + +import org.apache.log4j.Logger; +import org.hibernate.annotations.Cascade; +import org.hibernate.annotations.CascadeType; +import org.hibernate.annotations.Index; +import org.hibernate.annotations.Table; +import org.hibernate.envers.Audited; +import org.hibernate.search.annotations.Field; +import org.hibernate.search.annotations.IndexedEmbedded; + +import eu.etaxonomy.cdm.jaxb.MultilanguageTextAdapter; import eu.etaxonomy.cdm.model.common.Language; import eu.etaxonomy.cdm.model.common.LanguageString; -import eu.etaxonomy.cdm.model.common.MultilanguageSet; import eu.etaxonomy.cdm.model.description.DescriptionBase; import eu.etaxonomy.cdm.model.description.Sex; import eu.etaxonomy.cdm.model.description.SpecimenDescription; import eu.etaxonomy.cdm.model.description.Stage; -import org.apache.log4j.Logger; -import org.hibernate.annotations.Cascade; -import org.hibernate.annotations.CascadeType; -import java.util.*; -import javax.persistence.*; +import eu.etaxonomy.cdm.model.description.TaxonDescription; +import eu.etaxonomy.cdm.model.description.TaxonNameDescription; +import eu.etaxonomy.cdm.model.media.IdentifiableMediaEntity; +import eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy; /** * type figures are observations with at least a figure object in media @@ -29,21 +61,76 @@ import javax.persistence.*; * @version 1.0 * @created 08-Nov-2007 13:06:41 */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "SpecimenOrObservationBase", propOrder = { + "sex", + "individualCount", + "lifeStage", + "description", + "descriptions", + "determinations", + "derivationEvents" +}) +@XmlRootElement(name = "SpecimenOrObservationBase") @Entity +@Audited @Inheritance(strategy=InheritanceType.SINGLE_TABLE) -public abstract class SpecimenOrObservationBase extends IdentifyableMediaEntity{ +@Table(appliesTo="SpecimenOrObservationBase", indexes = { @Index(name = "specimenOrObservationBaseTitleCacheIndex", columnNames = { "titleCache" }) }) +public abstract class SpecimenOrObservationBase extends IdentifiableMediaEntity { + private static final Logger logger = Logger.getLogger(SpecimenOrObservationBase.class); + @XmlElementWrapper(name = "Descriptions") + @XmlElement(name = "Description") + @ManyToMany(fetch = FetchType.LAZY,mappedBy="describedSpecimenOrObservations",targetEntity=DescriptionBase.class) + @Cascade(CascadeType.SAVE_UPDATE) + @NotNull private Set descriptions = new HashSet(); + + @XmlElementWrapper(name = "Determinations") + @XmlElement(name = "Determination") + @OneToMany(mappedBy="identifiedUnit") + @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE, CascadeType.DELETE_ORPHAN}) + @IndexedEmbedded(depth = 2) + @NotNull private Set determinations = new HashSet(); + + @XmlElement(name = "Sex") + @XmlIDREF + @XmlSchemaType(name = "IDREF") + @ManyToOne(fetch = FetchType.LAZY) private Sex sex; + + @XmlElement(name = "LifeStage") + @XmlIDREF + @XmlSchemaType(name = "IDREF") + @ManyToOne(fetch = FetchType.LAZY) private Stage lifeStage; + + @XmlElement(name = "IndividualCount") + @Field(index=org.hibernate.search.annotations.Index.UN_TOKENIZED) + @Min(0) private Integer individualCount; + // the verbatim description of this occurrence. Free text usable when no atomised data is available. // in conjunction with titleCache which serves as the "citation" string for this object - private MultilanguageSet description; + @XmlElement(name = "Description") + @XmlJavaTypeAdapter(MultilanguageTextAdapter.class) + @OneToMany(fetch = FetchType.LAZY) + @Cascade({CascadeType.SAVE_UPDATE, CascadeType.DELETE, CascadeType.DELETE_ORPHAN}) + @IndexedEmbedded + @NotNull + protected Map description = new HashMap(); + // events that created derivedUnits from this unit - private Set derivationEvents = new HashSet(); + @XmlElementWrapper(name = "DerivationEvents") + @XmlElement(name = "DerivationEvent") + @XmlIDREF + @XmlSchemaType(name = "IDREF") + @ManyToMany(fetch=FetchType.LAZY) + @Cascade({CascadeType.SAVE_UPDATE, CascadeType.DELETE, CascadeType.DELETE_ORPHAN}) + @NotNull + protected Set derivationEvents = new HashSet(); /** * Constructor @@ -52,57 +139,130 @@ public abstract class SpecimenOrObservationBase extends IdentifyableMediaEntity{ super(); } - @ManyToMany - @Cascade( { CascadeType.SAVE_UPDATE }) + /** + * The descriptions this specimen or observation is part of.
+ * A specimen can not only have it's own {@link SpecimenDescription specimen description } + * but can also be part of a {@link TaxonDescription taxon description} or a + * {@link TaxonNameDescription taxon name description}.
+ * @see #getSpecimenDescriptions() + * @return + */ public Set getDescriptions() { + if(descriptions == null) { + this.descriptions = new HashSet(); + } return this.descriptions; } - protected void setDescriptions(Set descriptions) { - this.descriptions = descriptions; + + /** + * Returns the {@link SpecimenDescription specimen descriptions} this specimen is part of. + * @see #getDescriptions() + * @return + */ + @Transient + public Set getSpecimenDescriptions() { + return getSpecimenDescriptions(true); + } + + /** + * Returns the {@link SpecimenDescription specimen descriptions} this specimen is part of. + * @see #getDescriptions() + * @return + */ + @Transient + public Set getSpecimenDescriptions(boolean includeImageGallery) { + Set specimenDescriptions = new HashSet(); + for (DescriptionBase descriptionBase : getDescriptions()){ + if (descriptionBase.isInstanceOf(SpecimenDescription.class)){ + if (includeImageGallery || descriptionBase.isImageGallery() == false){ + specimenDescriptions.add(descriptionBase.deproxy(descriptionBase, SpecimenDescription.class)); + } + + } + } + return specimenDescriptions; + } + /** + * Returns the {@link SpecimenDescription specimen descriptions} this specimen is part of. + * @see #getDescriptions() + * @return + */ + @Transient + public Set getSpecimenDescriptionImageGallery() { + Set specimenDescriptions = new HashSet(); + for (DescriptionBase descriptionBase : getDescriptions()){ + if (descriptionBase.isInstanceOf(SpecimenDescription.class)){ + if (descriptionBase.isImageGallery() == true){ + specimenDescriptions.add(descriptionBase.deproxy(descriptionBase, SpecimenDescription.class)); + } + } + } + return specimenDescriptions; } + + /** + * Adds a new description to this specimen or observation + * @param description + */ public void addDescription(DescriptionBase description) { this.descriptions.add(description); + if (! description.getDescribedSpecimenOrObservations().contains(this)){ + description.addDescribedSpecimenOrObservation(this); + } +// Method method = ReflectionUtils.findMethod(SpecimenDescription.class, "addDescribedSpecimenOrObservation", new Class[] {SpecimenOrObservationBase.class}); +// ReflectionUtils.makeAccessible(method); +// ReflectionUtils.invokeMethod(method, description, new Object[] {this}); } + + /** + * Removes a specimen from a description (removes a description from this specimen) + * @param description + */ public void removeDescription(DescriptionBase description) { this.descriptions.remove(description); + if (description.getDescribedSpecimenOrObservations().contains(this)){ + description.removeDescribedSpecimenOrObservation(this); + } +// Method method = ReflectionUtils.findMethod(SpecimenDescription.class, "removeDescribedSpecimenOrObservations", new Class[] {SpecimenOrObservationBase.class}); +// ReflectionUtils.makeAccessible(method); +// ReflectionUtils.invokeMethod(method, description, new Object[] {this}); } - @ManyToMany - @Cascade( { CascadeType.SAVE_UPDATE }) public Set getDerivationEvents() { + if(derivationEvents == null) { + this.derivationEvents = new HashSet(); + } return this.derivationEvents; } - protected void setDerivationEvents(Set derivationEvents) { - this.derivationEvents = derivationEvents; - } - public void addDerivationEvent(DerivationEvent event) { - this.derivationEvents.add(event); + + public void addDerivationEvent(DerivationEvent derivationEvent) { + if (! this.derivationEvents.contains(derivationEvent)){ + this.derivationEvents.add(derivationEvent); + derivationEvent.addOriginal(this); + } } - public void removeDerivationEvent(DerivationEvent event) { - this.derivationEvents.remove(event); + + public void removeDerivationEvent(DerivationEvent derivationEvent) { + this.derivationEvents.remove(derivationEvent); } - - - @OneToMany(mappedBy="identifiedUnit") - @Cascade({CascadeType.SAVE_UPDATE}) public Set getDeterminations() { + if(determinations == null) { + this.determinations = new HashSet(); + } return this.determinations; } - protected void setDeterminations(Set determinations) { - this.determinations = determinations; - } + public void addDetermination(DeterminationEvent determination) { // FIXME bidirectional integrity. Use protected Determination setter this.determinations.add(determination); } + public void removeDetermination(DeterminationEvent determination) { // FIXME bidirectional integrity. Use protected Determination setter this.determinations.remove(determination); } - - @ManyToOne public Sex getSex() { return sex; } @@ -111,7 +271,6 @@ public abstract class SpecimenOrObservationBase extends IdentifyableMediaEntity{ this.sex = sex; } - @ManyToOne public Stage getLifeStage() { return lifeStage; } @@ -120,12 +279,11 @@ public abstract class SpecimenOrObservationBase extends IdentifyableMediaEntity{ this.lifeStage = lifeStage; } - + @Override public String generateTitle(){ - return ""; + return getCacheStrategy().getTitleCache(this); } - - + public Integer getIndividualCount() { return individualCount; } @@ -134,24 +292,21 @@ public abstract class SpecimenOrObservationBase extends IdentifyableMediaEntity{ this.individualCount = individualCount; } - - public MultilanguageSet getDefinition(){ + public Map getDefinition(){ return this.description; } - private void setDefinition(MultilanguageSet description){ - this.description = description; - } + public void addDefinition(LanguageString description){ - this.description.put(description); + this.description.put(description.getLanguage(),description); } - public void addDefinition(String text, Language lang){ - this.description.put(text, lang); + + public void addDefinition(String text, Language language){ + this.description.put(language, LanguageString.NewInstance(text, language)); } public void removeDefinition(Language lang){ this.description.remove(lang); } - /** * for derived units get the single next higher parental/original unit. * If multiple original units exist throw error @@ -159,10 +314,52 @@ public abstract class SpecimenOrObservationBase extends IdentifyableMediaEntity{ */ @Transient public SpecimenOrObservationBase getOriginalUnit(){ + logger.warn("GetOriginalUnit not yet implemented"); return null; } - @Transient - public abstract GatheringEvent getGatheringEvent(); +//******************** CLONE **********************************************/ + + /* (non-Javadoc) + * @see eu.etaxonomy.cdm.model.media.IdentifiableMediaEntity#clone() + * @see eu.etaxonomy.cdm.model.common.IdentifiableEntity#clone() + * @see java.lang.Object#clone() + */ + @Override + public Object clone() throws CloneNotSupportedException { + SpecimenOrObservationBase result = null; + result = (SpecimenOrObservationBase)super.clone(); + + //defininion (description, languageString) + result.description = new HashMap(); + for(LanguageString languageString : this.description.values()) { + LanguageString newLanguageString = (LanguageString)languageString.clone(); + result.addDefinition(newLanguageString); + } + + //sex + result.setSex(this.sex); + //life stage + result.setLifeStage(this.lifeStage); + + //Descriptions + for(DescriptionBase description : this.descriptions) { + result.addDescription((SpecimenDescription)description); + } + + //DeterminationEvent FIXME should clone() the determination + // as the relationship is OneToMany + for(DeterminationEvent determination : this.determinations) { + result.addDetermination(determination); + } + + //DerivationEvent + for(DerivationEvent derivationEvent : this.derivationEvents) { + result.addDerivationEvent(derivationEvent); + } + + //no changes to: individualCount + return result; + } } \ No newline at end of file