* The contents of this file are subject to the Mozilla Public License Version 1.1
* See LICENSE.TXT at the top of this package for the full license terms.
*/
-
package eu.etaxonomy.cdm.model.taxon;
import java.util.ArrayList;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
-import javax.persistence.ManyToOne;
import javax.persistence.MapKeyJoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.xml.bind.annotation.XmlType;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
-import org.apache.log4j.Logger;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.CascadeType;
import org.hibernate.envers.Audited;
import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
import eu.etaxonomy.cdm.jaxb.MultilanguageTextAdapter;
-import eu.etaxonomy.cdm.model.common.IReferencedEntity;
import eu.etaxonomy.cdm.model.common.IdentifiableEntity;
import eu.etaxonomy.cdm.model.common.Language;
import eu.etaxonomy.cdm.model.common.LanguageString;
import eu.etaxonomy.cdm.model.common.MultilanguageText;
import eu.etaxonomy.cdm.model.common.TimePeriod;
import eu.etaxonomy.cdm.model.location.NamedArea;
+import eu.etaxonomy.cdm.model.reference.NamedSource;
+import eu.etaxonomy.cdm.model.reference.OriginalSourceType;
import eu.etaxonomy.cdm.model.reference.Reference;
import eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy;
+import eu.etaxonomy.cdm.strategy.cache.taxon.ClassificationDefaultCacheStrategy;
/**
* @author a.mueller
- * @created 31.03.2009
+ * @since 31.03.2009
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "Classification", propOrder = {
"name",
"description",
"rootNode",
- "reference",
- "microReference",
+ "source",
"timeperiod",
"geoScopes"
})
@Entity
@Audited
@Indexed(index = "eu.etaxonomy.cdm.model.taxon.Classification")
-public class Classification extends IdentifiableEntity<IIdentifiableEntityCacheStrategy<Classification>> implements IReferencedEntity, ITaxonTreeNode, Cloneable{
+public class Classification
+ extends IdentifiableEntity<IIdentifiableEntityCacheStrategy<Classification>>
+ implements ITaxonTreeNode{
+
private static final long serialVersionUID = -753804821474209635L;
- private static final Logger logger = Logger.getLogger(Classification.class);
+ private static final Logger logger = LogManager.getLogger();
@XmlElement(name = "Name")
@OneToOne(fetch = FetchType.LAZY)
@IndexedEmbedded
private LanguageString name;
-
@XmlElement(name = "rootNode")
@XmlIDREF
@XmlSchemaType(name = "IDREF")
@Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE})
private TaxonNode rootNode;
- @XmlElement(name = "reference")
- @XmlIDREF
- @XmlSchemaType(name = "IDREF")
- @ManyToOne(fetch = FetchType.LAZY)
- @Cascade({CascadeType.SAVE_UPDATE,CascadeType.MERGE})
- private Reference reference;
-
- @XmlElement(name = "microReference")
- private String microReference;
-
@XmlElement(name = "TimePeriod")
private TimePeriod timeperiod = TimePeriod.NewInstance();
@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(name="Classification_GeoScope")
// @Cascade({CascadeType.SAVE_UPDATE,CascadeType.MERGE}) remove cascade #5755
- private Set<NamedArea> geoScopes = new HashSet<NamedArea>();
+ private Set<NamedArea> geoScopes = new HashSet<>();
@XmlElement(name = "Description")
@XmlJavaTypeAdapter(MultilanguageTextAdapter.class)
// @FieldBridge(impl=MultilanguageTextFieldBridge.class)
private Map<Language,LanguageString> description = new HashMap<>();
-
-
-// /**
-// * If this classification is an alternative classification for a subclassification in
-// * an other classification(parent view),
-// * the alternativeViewRoot is the connection node from this classification to the parent classification.
-// * It replaces another node in the parent view.
-// */
-// private AlternativeViewRoot alternativeViewRoot;
+ //TODO remove, due to #9211
+ //the source for this single classification
+ @XmlElement(name = "source")
+ @XmlIDREF
+ @XmlSchemaType(name = "IDREF")
+ @OneToOne(fetch = FetchType.LAZY, orphanRemoval=true)
+ @Cascade({CascadeType.SAVE_UPDATE,CascadeType.MERGE, CascadeType.DELETE})
+ private NamedSource source;
// ********************** FACTORY METHODS *********************************************/
// **************************** CONSTRUCTOR *********************************/
- //for hibernate use only, protected required by Javassist
- protected Classification(){super();}
+ //for hibernate use only, *packet* private required by bytebuddy
+ @Deprecated
+ Classification(){}
protected Classification(String name, Reference reference, Language language){
this();
rootNode.setClassification(this);
}
+ @Override
+ protected void initDefaultCacheStrategy() {
+ this.cacheStrategy = ClassificationDefaultCacheStrategy.NewInstance();
+ }
+
//********************** xxxxxxxxxxxxx ******************************************/
+
/**
* Returns the topmost {@link TaxonNode taxon node} (root node) of <i>this</i>
* classification. The root node does not have any parent and no taxon. Since taxon nodes
childNode.setParentTreeNode(this.rootNode, index);
- childNode.setReference(citation);
- childNode.setMicroReference(microCitation);
+ childNode.setCitation(citation);
+ childNode.setCitationMicroReference(microCitation);
// childNode.setSynonymToBeUsed(synonymToBeUsed);
return childNode;
@Override
public TaxonNode addChildTaxon(Taxon taxon, int index, Reference citation, String microCitation) {
- return addChildNode(new TaxonNode(taxon), index, citation, microCitation);
+ return addChildNode(new TaxonNode(taxon), index, NamedSource.NewPrimarySourceInstance(citation, microCitation));
+ }
+
+ @Override
+ public TaxonNode addChildTaxon(Taxon taxon, NamedSource source) {
+ return addChildTaxon(taxon, rootNode.getCountChildren(), source);
+ }
+
+ @Override
+ public TaxonNode addChildTaxon(Taxon taxon, int index, NamedSource source) {
+ return addChildNode(new TaxonNode(taxon), index, source);
+ }
+
+ @Override
+ public TaxonNode addChildNode(TaxonNode childNode, int index, NamedSource source) {
+ childNode.setParentTreeNode(this.rootNode, index);
+ childNode.setSource(source);
+
+ return childNode;
}
@Override
node.setTaxon(null);
}
- ArrayList<TaxonNode> childNodes = new ArrayList<TaxonNode>(node.getChildNodes());
+ ArrayList<TaxonNode> childNodes = new ArrayList<>(node.getChildNodes());
for (TaxonNode childNode : childNodes){
if (childNode != null){
node.deleteChildNode(childNode);
public boolean deleteChildNode(TaxonNode node, boolean deleteChildren) {
boolean result = removeChildNode(node);
+ if (node.hasTaxon()){
+ node.getTaxon().removeTaxonNode(node);
+ node.setTaxon(null);
+ }
- node.getTaxon().removeTaxonNode(node);
- //node.setTaxon(null);
if (deleteChildren){
ArrayList<TaxonNode> childNodes = new ArrayList<TaxonNode>(node.getChildNodes());
for (TaxonNode childNode : childNodes){
return result;
}
- /**
- *
- * @param node
- * @return
- */
protected boolean removeChildNode(TaxonNode node){
boolean result = false;
+ rootNode = HibernateProxyHelper.deproxy(rootNode, TaxonNode.class);
if(!rootNode.getChildNodes().contains(node)){
throw new IllegalArgumentException("TaxonNode is a not a root node of this classification");
}
- rootNode = HibernateProxyHelper.deproxy(rootNode, TaxonNode.class);
+// rootNode = HibernateProxyHelper.deproxy(rootNode, TaxonNode.class);
result = rootNode.removeChildNode(node);
node.setParent(null);
result = true;
}
return result;
-
}
/**
otherNode.addChildNode(topmostNode, ref, microReference);
}
-
/**
* Checks if the given taxon is part of <b>this</b> tree.
* @param taxon
/**
* Checks if the given taxon is part of <b>this</b> tree. If so the according TaxonNode is returned.
- * Otherwise null is returned.
+ * Otherwise <code>null</code> is returned.
* @param taxon
* @return
*/
}
for (TaxonNode taxonNode: taxon.getTaxonNodes()){
- Classification classification = HibernateProxyHelper.deproxy(taxonNode.getClassification(), Classification.class);
+ Classification classification = deproxy(taxonNode.getClassification());
if (classification.equals(this)){
return taxonNode;
}
return (getTopmostNode(taxon) != null);
}
-
/**
- * Checks if the taxon is a direct child of <b>this</b> tree and returns the according node if true.
- * Returns null otherwise.
+ * Checks if the taxon is a direct child of the root of <b>this</b> tree and returns the according node if true.
+ * Returns <code>null</code> otherwise.
* @param taxon
* @return
*/
private boolean handleCitationOverwrite(TaxonNode childNode, Reference citation, String microCitation){
if (citation != null){
if (childNode.getReference() != null && ! childNode.getReference().equals(citation)){
- logger.warn("ReferenceForParentChildRelation will be overwritten");
+ logger.warn("TaxonNode source will be overwritten");
}
- childNode.setReference(citation);
+ childNode.setCitation(citation);
}
if (microCitation != null){
if (childNode.getMicroReference() != null && ! childNode.getMicroReference().equals(microCitation)){
- logger.warn("MicroReferenceForParentChildRelation will be overwritten");
+ logger.warn("TaxonNode source detail will be overwritten");
}
- childNode.setMicroReference(microCitation);
+ childNode.setCitationMicroReference(microCitation);
}
return true;
}
}
}
+ @Override
+ @Transient
+ public String getMicroReference() {
+ return source == null ? null : this.source.getCitationMicroReference();
+ }
+ public void setMicroReference(String microReference) {
+ this.getSource(true).setCitationMicroReference(isBlank(microReference)? null : microReference);
+ checkNullSource();
+ }
@Override
@Transient
- public Reference getCitation() {
- return reference;
+ public Reference getReference() {
+ return (this.source == null) ? null : source.getCitation();
+ }
+ public void setReference(Reference reference) {
+ getSource(true).setCitation(reference);
+ checkNullSource();
+ }
+
+ public NamedSource getSource() {
+ return source;
+ }
+ public void setSource(NamedSource source) {
+ this.source = source;
+ }
+
+ private void checkNullSource() {
+ if (this.source != null && this.source.checkEmpty(true)){
+ this.source = null;
+ }
+ }
+
+ private NamedSource getSource(boolean createIfNotExist){
+ if (this.source == null && createIfNotExist){
+ this.source = NamedSource.NewInstance(OriginalSourceType.PrimaryTaxonomicSource);
+ }
+ return source;
}
public LanguageString getName() {
return name;
}
-
public void setName(LanguageString name) {
this.name = name;
}
*/
@Transient
public Set<TaxonNode> getAllNodes() {
- Set<TaxonNode> allNodes = new HashSet<TaxonNode>();
+ Set<TaxonNode> allNodes = new HashSet<>();
for(TaxonNode rootNode : getChildNodes()){
allNodes.addAll(rootNode.getDescendants());
return rootNode.getChildNodes();
}
- @Override
- public Reference getReference() {
- return reference;
- }
-
- public void setReference(Reference reference) {
- this.reference = reference;
- }
-
-
- @Override
- public String getMicroReference() {
- return microReference;
- }
-
- /**
- * @param microReference the microReference to set
- */
- public void setMicroReference(String microReference) {
- this.microReference = microReference;
- }
-
-
/**
* The point in time, the time period or the season for which this description element
* is valid. A season may be expressed by not filling the year part(s) of the time period.
public TimePeriod getTimeperiod() {
return timeperiod;
}
-
/**
* @see #getTimeperiod()
*/
this.timeperiod = timeperiod;
}
-
/**
* Returns the set of {@link NamedArea named areas} indicating the geospatial
* data where <i>this</i> {@link Classification} is valid.
this.geoScopes.remove(geoScope);
}
-
/**
* Returns the i18n description used to describe
* <i>this</i> {@link Classification}. The different {@link LanguageString language strings}
this.description.remove(language);
}
-
- @Override
- public String generateTitle() {
- //TODO implement as cache strategy
- if (protectedTitleCache){
- return this.titleCache;
- }else if (name != null){
- return name.getText();
- }else if (reference != null){
- return this.reference.getTitleCache();
- }else{
- return this.toString();
- }
- }
-
public int compareTo(Object o) {
//TODO needs to be implemented
return 0;
}
-
@Override
public boolean hasChildNodes() {
return getChildNodes().size() > 0;
}
//*********************** CLONE ********************************************************/
+
/**
* Clones <i>this</i> classification. This is a shortcut that enables to create
* a new instance that differs only slightly from <i>this</i> classification by
* modifying only some of the attributes.<BR><BR>
- * @see eu.etaxonomy.cdm.model.media.IdentifiableEntity#clone()
* @see java.lang.Object#clone()
*/
@Override
- public Object clone() {
+ public Classification clone() {
Classification result;
try{
result = (Classification)super.clone();
List<TaxonNode> rootNodes = new ArrayList<>();
TaxonNode rootNodeClone;
-
rootNodes.addAll(rootNode.getChildNodes());
TaxonNode rootNode;
Iterator<TaxonNode> iterator = rootNodes.iterator();
rootNodeClone.setSynonymToBeUsed(rootNode.getSynonymToBeUsed());
}
+ if (this.source != null){
+ result.source = source.clone();
+ }
+
//geo-scopes
result.geoScopes = new HashSet<>();
for (NamedArea namedArea : getGeoScopes()){
e.printStackTrace();
return null;
}
-
}
-
}