package org.gmod.schema.mapped;
import static javax.persistence.GenerationType.SEQUENCE;
import org.genedb.db.dao.CvDao;
import org.gmod.schema.utils.Rankable;
import org.gmod.schema.utils.propinterface.PropertyI;
import org.apache.log4j.Logger;
import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.Filter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Configurable;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.OrderBy;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.persistence.Transient;
@Configurable
@Entity
@Table(name = "feature_cvterm")
/*
* This filter definition depends on the name-mangling algorithm used by
* Hbernate, but it is more than an order of magnitude faster than the
* corresponding nested subquery. It also assumes that the feature is
* being fetched in the same query, of course, which is usually the case
* anyway in our examples but is forced to be universally true by marking
* the feature with <code>FetchType.EAGER</code>
*/
@Filter(name="excludeObsoleteFeatures", condition="not feature2_.is_obsolete")
public class FeatureCvTerm implements Serializable, Rankable, PropertyI, HasPubsAndDbXRefs {
private static final Logger logger = Logger.getLogger(FeatureCvTerm.class);
// Fields
@Autowired
private transient CvDao cvDao;
@SequenceGenerator(name = "generator", sequenceName = "feature_cvterm_feature_cvterm_id_seq", allocationSize=1)
@Id @GeneratedValue(strategy=SEQUENCE, generator="generator")
@Column(name = "feature_cvterm_id", unique = false, nullable = false, insertable = true, updatable = true)
private int featureCvTermId;
/*
* We are rarely if ever interested in a FeatureCvTerm without also being
* interested in the corresponding Feature and CvTerm, so it makes sense
* to fetch these eagerly. Besides, the filter definition above relies on
* the feature being fetched eagerly.
*/
@ManyToOne(cascade = {CascadeType.ALL}, fetch = FetchType.EAGER)
@JoinColumn(name = "cvterm_id", unique = false, nullable = false, insertable = true, updatable = true)
private CvTerm cvTerm;
@ManyToOne(cascade = {CascadeType.ALL}, fetch = FetchType.EAGER)
@JoinColumn(name = "feature_id", unique = false, nullable = false, insertable = true, updatable = true)
private Feature feature;
@ManyToOne(cascade = {CascadeType.ALL}, fetch = FetchType.LAZY)
@JoinColumn(name = "pub_id", unique = false, nullable = false, insertable = true, updatable = true)
private Pub pub;
@Column(name = "is_not", unique = false, nullable = false, insertable = true, updatable = true)
private boolean not;
@Column(name = "rank", unique = false, nullable = false, insertable = true, updatable = true)
private int rank;
@OneToMany(cascade = {CascadeType.PERSIST}, fetch = FetchType.LAZY, mappedBy = "featureCvTerm")
@Cascade({org.hibernate.annotations.CascadeType.ALL, org.hibernate.annotations.CascadeType.DELETE_ORPHAN})
@OrderBy("rank")
private List<FeatureCvTermProp> featureCvTermProps = new ArrayList<FeatureCvTermProp>();
@OneToMany(cascade = {CascadeType.PERSIST}, fetch = FetchType.LAZY, mappedBy = "featureCvTerm")
@Cascade({org.hibernate.annotations.CascadeType.ALL, org.hibernate.annotations.CascadeType.DELETE_ORPHAN})
private Collection<FeatureCvTermPub> featureCvTermPubs = new HashSet<FeatureCvTermPub>();
@OneToMany(cascade = {CascadeType.PERSIST}, fetch = FetchType.LAZY, mappedBy = "featureCvTerm")
@Cascade({org.hibernate.annotations.CascadeType.ALL, org.hibernate.annotations.CascadeType.DELETE_ORPHAN})
private Collection<FeatureCvTermDbXRef> featureCvTermDbXRefs = new HashSet<FeatureCvTermDbXRef>();
// Constructors
/** default constructor */
FeatureCvTerm() {
// Deliberately empty default constructor
}
/** minimal constructor */
public FeatureCvTerm(CvTerm cvTerm, Feature feature, Pub pub, boolean not, int rank) {
this.cvTerm = cvTerm;
this.feature = feature;
this.pub = pub;
this.not = not;
this.rank = rank;
}
// Property accessors
public int getFeatureCvTermId() {
return this.featureCvTermId;
}
/**
* An alias for {@link #getCvTerm}, which exists
* so that the generic interface <code>PropertyI</code>
* can be used.
*/
public CvTerm getType() {
return getCvTerm();
}
public CvTerm getCvTerm() {
return this.cvTerm;
}
public void setCvTerm(CvTerm cvTerm) {
this.cvTerm = cvTerm;
}
public Feature getFeature() {
return this.feature;
}
void setFeature(Feature feature) {
this.feature = feature;
}
/**
* Get the details of the principal publication associated with this FeatureCvTerm, if any.
* @return a Pub object containing the details of the principal publication associated with
* this FeatureCvTerm, or <code>null</code> if there isn't one.
*/
public Pub getPub() {
return this.pub;
}
void setPub(Pub pub) {
this.pub = pub;
}
public boolean isNot() {
return this.not;
}
/**
* Get the <code>FeatureCvTermProp</code> objects that describe properties of this FeatureCvTerm.
* @return an unmodifiable collection of <code>FeatureCvTermProp</code> objects
*/
public List<FeatureCvTermProp> getFeatureCvTermProps() {
return Collections.unmodifiableList(this.featureCvTermProps);
}
public FeatureCvTermProp addProp(String cvName, String cvTermName, String value) {
CvTerm propType = cvDao.getCvTermByNameAndCvName(cvTermName, cvName);
if (propType == null) {
throw new RuntimeException(String.format("Could not find CV term '%s' in CV '%s'",
cvTermName, cvName));
}
return addProp(propType, value);
}
public FeatureCvTermProp addProp(CvTerm type, String value) {
FeatureCvTermProp featureCvTermProp = new FeatureCvTermProp(type, this, value, 0);
this.featureCvTermProps.add(featureCvTermProp);
return featureCvTermProp;
}
public FeatureCvTermProp addPropIfNotNull(String cvName, String cvTermName, String value) {
if (value != null) {
return addProp(cvName, cvTermName, value);
} else {
return null;
}
}
@Transient
private Object featureCvTermPubsLock = new Object();
/**
* Get the <code>FeatureCvTermPub</code> objects that describe publications related to this FeatureCvTerm.
* It is usually easier to use the method {@link #getPubs()} instead.
*
* @return an unmodifiable collection of <code>FeatureCvTermPub</code> objects
*/
public Collection<FeatureCvTermPub> getFeatureCvTermPubs() {
synchronized(featureCvTermPubsLock) {
return Collections.unmodifiableCollection(this.featureCvTermPubs);
}
}
public void addFeatureCvTermPub(FeatureCvTermPub featureCvTermPub) {
logger.trace(String.format("Adding FeatureCvTermPub (%s) to FeatureCvTerm",
featureCvTermPub, this));
synchronized(featureCvTermPubsLock) {
featureCvTermPub.setFeatureCvTerm(this);
this.featureCvTermPubs.add(featureCvTermPub);
}
}
public FeatureCvTermPub addPub(Pub pub) {
FeatureCvTermPub featureCvTermPub = new FeatureCvTermPub(this, pub);
addFeatureCvTermPub(featureCvTermPub);
return featureCvTermPub;
}
/**
* Get all the publications associated with this FeatureCvTerm.
*
* @return an unmodifiable collection of <code>Pub</code> objects
*/
@Transient
public Collection<Pub> getPubs() {
Collection<Pub> pubs = new HashSet<Pub>();
for (FeatureCvTermPub featureCvTermPub: this.featureCvTermPubs) {
pubs.add(featureCvTermPub.getPub());
}
return Collections.unmodifiableCollection(pubs);
}
@Transient
private Object featureCvTermDbXRefsLock = new Object();
/**
* Get the <code>FeatureCvTermDbXRef</code> objects that describe the database cross-references
* for this FeatureCvTerm.
*
* @return an unmodifiable collection of <code>FeatureCvTermDbXRef</code> objects
*/
public Collection<FeatureCvTermDbXRef> getFeatureCvTermDbXRefs() {
synchronized(featureCvTermDbXRefsLock) {
return Collections.unmodifiableCollection(this.featureCvTermDbXRefs);
}
}
public void addFeatureCvTermDbXRef(FeatureCvTermDbXRef featureCvTermDbXRef) {
synchronized(featureCvTermDbXRefsLock) {
this.featureCvTermDbXRefs.add(featureCvTermDbXRef);
featureCvTermDbXRef.setFeatureCvTerm(this);
}
}
public FeatureCvTermDbXRef addDbXRef(DbXRef dbXRef) {
FeatureCvTermDbXRef featureCvTermDbXRef = new FeatureCvTermDbXRef(this, dbXRef);
addFeatureCvTermDbXRef(featureCvTermDbXRef);
return featureCvTermDbXRef;
}
public int getRank() {
return rank;
}
@Override
public String toString() {
return String.format("FeatureCvTerm(ID=%d, feature=%s, cvTerm=%s, rank=%d, not=%b)",
getFeatureCvTermId(), getFeature(), getCvTerm(), getRank(), isNot());
}
}