import java.util.HashSet;
import java.util.List;
import java.util.Set;
+import java.util.UUID;
import javax.persistence.Column;
import javax.persistence.Embedded;
import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.CascadeType;
import org.hibernate.annotations.IndexColumn;
+import org.hibernate.envers.Audited;
+import org.hibernate.search.annotations.Analyze;
import org.hibernate.search.annotations.Field;
import org.hibernate.search.annotations.FieldBridge;
-import org.hibernate.search.annotations.IndexedEmbedded;
+import org.hibernate.search.annotations.Fields;
+import org.hibernate.search.annotations.Store;
import org.hibernate.validator.constraints.NotEmpty;
import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
-import eu.etaxonomy.cdm.hibernate.StripHtmlBridge;
+import eu.etaxonomy.cdm.hibernate.search.StripHtmlBridge;
import eu.etaxonomy.cdm.jaxb.FormattedTextAdapter;
import eu.etaxonomy.cdm.jaxb.LSIDAdapter;
import eu.etaxonomy.cdm.model.media.Rights;
+import eu.etaxonomy.cdm.model.name.BotanicalName;
import eu.etaxonomy.cdm.model.name.NonViralName;
import eu.etaxonomy.cdm.model.name.TaxonNameBase;
import eu.etaxonomy.cdm.model.reference.Reference;
"credits",
"sources"
})
+@Audited
@MappedSuperclass
public abstract class IdentifiableEntity<S extends IIdentifiableEntityCacheStrategy> extends AnnotatableEntity
implements IIdentifiableEntity /*, ISourceable<IdentifiableSource> */ {
@XmlElement(name = "TitleCache", required = true)
@XmlJavaTypeAdapter(FormattedTextAdapter.class)
- @Column(length=255, name="titleCache")
-
- @FieldBridge(impl=StripHtmlBridge.class)
+ @Column(name="titleCache")
@Match(value=MatchMode.CACHE, cacheReplaceMode=ReplaceMode.ALL)
@NotEmpty(groups = Level2.class) // implictly NotNull
- @Size(max = 255)
- @Field
+ @Size(max = 800) //see #1592
+ @Fields({
+ @Field(store=Store.YES),
+ @Field(name = "titleCache__sort", analyze = Analyze.NO, store=Store.YES)
+ })
+ @FieldBridge(impl=StripHtmlBridge.class)
protected String titleCache;
//if true titleCache will not be automatically generated/updated
@XmlElementWrapper(name = "Rights", nillable = true)
@XmlElement(name = "Rights")
- @OneToMany(fetch = FetchType.LAZY)
- @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE, CascadeType.DELETE_ORPHAN})
+ @OneToMany(fetch = FetchType.LAZY, orphanRemoval=true)
+ @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE})
//TODO
@Merge(MergeMode.ADD_CLONE)
@NotNull
@XmlElementWrapper(name = "Credits", nillable = true)
@XmlElement(name = "Credit")
@IndexColumn(name="sortIndex", base = 0)
- @OneToMany(fetch = FetchType.LAZY)
- @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE, CascadeType.DELETE_ORPHAN})
+ @OneToMany(fetch = FetchType.LAZY, orphanRemoval=true)
+ @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE})
//TODO
@Merge(MergeMode.ADD_CLONE)
@NotNull
@XmlElementWrapper(name = "Extensions", nillable = true)
@XmlElement(name = "Extension")
- @OneToMany(fetch = FetchType.LAZY)
- @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE, CascadeType.DELETE_ORPHAN})
+ @OneToMany(fetch = FetchType.LAZY, orphanRemoval=true)
+ @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE})
@Merge(MergeMode.ADD_CLONE)
@NotNull
private Set<Extension> extensions = new HashSet<Extension>();
+ @XmlElementWrapper(name = "Identifiers", nillable = true)
+ @XmlElement(name = "Identifier")
+ @OneToMany(fetch = FetchType.LAZY, orphanRemoval=true)
+ @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE})
+ @Merge(MergeMode.ADD_CLONE)
+ @NotNull
+ private Set<Identifier> identifiers = new HashSet<Identifier>();
+
@XmlElementWrapper(name = "Sources", nillable = true)
@XmlElement(name = "IdentifiableSource")
- @OneToMany(fetch = FetchType.LAZY)
- @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE, CascadeType.DELETE_ORPHAN})
+ @OneToMany(fetch = FetchType.LAZY, orphanRemoval=true)
+ @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE})
@Merge(MergeMode.ADD_CLONE)
@NotNull
private Set<IdentifiableSource> sources = new HashSet<IdentifiableSource>();
protected void initListener(){
PropertyChangeListener listener = new PropertyChangeListener() {
- public void propertyChange(PropertyChangeEvent e) {
- if (!e.getPropertyName().equals("titleCache") && !e.getPropertyName().equals("cacheStrategy") && ! isProtectedTitleCache()){
+ @Override
+ public void propertyChange(PropertyChangeEvent ev) {
+ if (!ev.getPropertyName().equals("titleCache") && !ev.getPropertyName().equals("cacheStrategy") && ! isProtectedTitleCache()){
titleCache = null;
}
}
*
* Specific subclasses (e.g. Sequence) can override if necessary.
*/
+ @Override
public byte[] getData() {
return null;
}
//******************************** CACHE *****************************************************/
-
- /* (non-Javadoc)
- * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#getTitleCache()
- */
// @Transient - must not be transient, since this property needs to to be included in all serializations produced by the remote layer
+ @Override
public String getTitleCache(){
if (protectedTitleCache){
return this.titleCache;
}
return titleCache;
}
- /* (non-Javadoc)
- * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#setTitleCache(java.lang.String)
+
+ /**
+ * The titleCache will be regenerated from scratch if not protected
+ * @return <code>true</code> if title cache was regenerated, <code>false</code> otherwise
*/
+ protected boolean regenerateTitleCache() {
+ if (!protectedTitleCache) {
+ this.titleCache = null;
+ getTitleCache();
+ }
+ return protectedTitleCache;
+ }
+
+ @Deprecated
+ @Override
public void setTitleCache(String titleCache){
- this.titleCache = titleCache;
+ //TODO shouldn't we call setTitleCache(String, boolean),but is this conformant with Java Bean Specification?
+ this.titleCache = getTruncatedCache(titleCache);
}
- /* (non-Javadoc)
- * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#setTitleCache(java.lang.String, boolean)
- */
+ @Override
public void setTitleCache(String titleCache, boolean protectCache){
titleCache = getTruncatedCache(titleCache);
this.titleCache = titleCache;
*/
@Transient
protected String getTruncatedCache(String cache) {
- if (cache != null && cache.length() > 255){
+ int maxLength = 800;
+ if (cache != null && cache.length() > maxLength){
logger.warn("Truncation of cache: " + this.toString() + "/" + cache);
- cache = cache.substring(0, 252) + "...";
+ cache = cache.substring(0, maxLength - 4) + "..."; //TODO do we need -4 or is -3 enough
}
return cache;
}
//**************************************************************************************
- /* (non-Javadoc)
- * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#getLsid()
- */
+ @Override
public LSID getLsid(){
return this.lsid;
}
- /* (non-Javadoc)
- * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#setLsid(java.lang.String)
- */
+ @Override
public void setLsid(LSID lsid){
this.lsid = lsid;
}
- /* (non-Javadoc)
- * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#getRights()
- */
+ @Override
public Set<Rights> getRights() {
if(rights == null) {
this.rights = new HashSet<Rights>();
return this.rights;
}
- /* (non-Javadoc)
- * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#addRights(eu.etaxonomy.cdm.model.media.Rights)
- */
+ @Override
public void addRights(Rights right){
getRights().add(right);
}
- /* (non-Javadoc)
- * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#removeRights(eu.etaxonomy.cdm.model.media.Rights)
- */
+ @Override
public void removeRights(Rights right){
getRights().remove(right);
}
+ @Override
public List<Credit> getCredits() {
if(credits == null) {
this.credits = new ArrayList<Credit>();
return this.credits;
}
- /* (non-Javadoc)
- * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#getCredits(int)
- */
+ @Override
public Credit getCredits(Integer index){
return getCredits().get(index);
}
- /* (non-Javadoc)
- * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#addCredit(eu.etaxonomy.cdm.model.common.Credit)
- */
+ @Override
public void addCredit(Credit credit){
getCredits().add(credit);
}
- /* (non-Javadoc)
- * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#addCredit(eu.etaxonomy.cdm.model.common.Credit, int)
- */
+ @Override
public void addCredit(Credit credit, int index){
getCredits().add(index, credit);
}
- /* (non-Javadoc)
- * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#removeCredit(eu.etaxonomy.cdm.model.common.Credit)
- */
+ @Override
public void removeCredit(Credit credit){
getCredits().remove(credit);
}
- /* (non-Javadoc)
- * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#removeCredit(int)
- */
+ @Override
public void removeCredit(int index){
getCredits().remove(index);
}
-
- /* (non-Javadoc)
- * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#getExtensions()
+ @Override
+ public Set<Identifier> getIdentifiers(){
+ if(this.identifiers == null) {
+ this.identifiers = new HashSet<Identifier>();
+ }
+ return this.identifiers;
+ }
+ /**
+ * @param type
+ * @return a Set of extension value strings
+ */
+ public Set<String> getIdentifiers(DefinedTerm type){
+ return getIdentifiers(type.getUuid());
+ }
+ /**
+ * @param extensionTypeUuid
+ * @return a Set of extension value strings
*/
+ public Set<String> getIdentifiers(UUID identifierTypeUuid){
+ Set<String> result = new HashSet<String>();
+ for (Identifier identifier : getIdentifiers()){
+ if (identifier.getType().getUuid().equals(identifierTypeUuid)){
+ result.add(identifier.getIdentifier());
+ }
+ }
+ return result;
+ }
+
+ public Identifier addIdentifier(String identifier, DefinedTerm identifierType){
+ Identifier result = Identifier.NewInstance(this, identifier, identifierType);
+ return result;
+ }
+
+ @Override
+ public void addIdentifier(Identifier identifier){
+ if (identifier != null){
+ identifier.setIdentifiedObj(this);
+ getIdentifiers().add(identifier);
+ }
+ }
+ @Override
+ public void removeIdentifier(Identifier identifier){
+ if (identifier != null){
+ logger.warn("TODO");
+// identifier.setExtendedObj(null);
+ getIdentifiers().remove(identifier);
+ }
+ }
+
+ @Override
public Set<Extension> getExtensions(){
if(extensions == null) {
this.extensions = new HashSet<Extension>();
}
return this.extensions;
}
+ /**
+ * @param type
+ * @return a Set of extension value strings
+ */
+ public Set<String> getExtensions(ExtensionType type){
+ return getExtensions(type.getUuid());
+ }
+ /**
+ * @param extensionTypeUuid
+ * @return a Set of extension value strings
+ */
+ public Set<String> getExtensions(UUID extensionTypeUuid){
+ Set<String> result = new HashSet<String>();
+ for (Extension extension : getExtensions()){
+ if (extension.getType().getUuid().equals(extensionTypeUuid)){
+ result.add(extension.getValue());
+ }
+ }
+ return result;
+ }
public void addExtension(String value, ExtensionType extensionType){
Extension.NewInstance(this, value, extensionType);
}
- /* (non-Javadoc)
- * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#addExtension(eu.etaxonomy.cdm.model.common.Extension)
- */
+ @Override
public void addExtension(Extension extension){
if (extension != null){
extension.setExtendedObj(this);
getExtensions().add(extension);
}
}
- /* (non-Javadoc)
- * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#removeExtension(eu.etaxonomy.cdm.model.common.Extension)
- */
+ @Override
public void removeExtension(Extension extension){
if (extension != null){
extension.setExtendedObj(null);
}
}
-
- /* (non-Javadoc)
- * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#isProtectedTitleCache()
- */
+ @Override
public boolean isProtectedTitleCache() {
return protectedTitleCache;
}
- /* (non-Javadoc)
- * @see eu.etaxonomy.cdm.model.common.IIdentifiableEntity#setProtectedTitleCache(boolean)
- */
+ @Override
public void setProtectedTitleCache(boolean protectedTitleCache) {
this.protectedTitleCache = protectedTitleCache;
}
- /* (non-Javadoc)
- * @see eu.etaxonomy.cdm.model.common.ISourceable#getSources()
- */
+ @Override
public Set<IdentifiableSource> getSources() {
if(sources == null) {
this.sources = new HashSet<IdentifiableSource>();
return this.sources;
}
- /* (non-Javadoc)
- * @see eu.etaxonomy.cdm.model.common.ISourceable#addSource(eu.etaxonomy.cdm.model.common.OriginalSourceBase)
- */
+ @Override
public void addSource(IdentifiableSource source) {
if (source != null){
- IdentifiableEntity oldSourcedObj = source.getSourcedObj();
+ IdentifiableEntity<?> oldSourcedObj = source.getSourcedObj();
if (oldSourcedObj != null && oldSourcedObj != this){
oldSourcedObj.getSources().remove(source);
}
}
}
- /* (non-Javadoc)
- * @see eu.etaxonomy.cdm.model.common.ISourceable#addSource(java.lang.String, java.lang.String, eu.etaxonomy.cdm.model.reference.Reference, java.lang.String)
- */
- public IdentifiableSource addSource(String id, String idNamespace, Reference citation, String microCitation) {
+ @Override
+ public void addSources(Set<IdentifiableSource> sources) {
+ if (sources != null){
+ for (IdentifiableSource source: sources){
+ IdentifiableEntity<?> oldSourcedObj = source.getSourcedObj();
+ if (oldSourcedObj != null && oldSourcedObj != this){
+ oldSourcedObj.getSources().remove(source);
+ }
+ getSources().add(source);
+ source.setSourcedObj(this);
+ }
+ }
+ }
+
+ @Override
+ public void removeSources() {
+ this.sources.clear();
+ }
+
+ @Override
+ public IdentifiableSource addSource(OriginalSourceType type, String id, String idNamespace, Reference citation, String microCitation) {
if (id == null && idNamespace == null && citation == null && microCitation == null){
return null;
}
- IdentifiableSource source = IdentifiableSource.NewInstance(id, idNamespace, citation, microCitation);
+ IdentifiableSource source = IdentifiableSource.NewInstance(type, id, idNamespace, citation, microCitation);
addSource(source);
return source;
}
- /* (non-Javadoc)
- * @see eu.etaxonomy.cdm.model.common.ISourceable#removeSource(eu.etaxonomy.cdm.model.common.IOriginalSource)
- */
+
+ @Override
+ public IdentifiableSource addImportSource(String id, String idNamespace, Reference<?> citation, String microCitation) {
+ if (id == null && idNamespace == null && citation == null && microCitation == null){
+ return null;
+ }
+ IdentifiableSource source = IdentifiableSource.NewInstance(OriginalSourceType.Import, id, idNamespace, citation, microCitation);
+ addSource(source);
+ return source;
+ }
+
+
+ @Override
public void removeSource(IdentifiableSource source) {
getSources().remove(source);
}
String specifiedGenusString = "";
int thisrank_order = 0;
+ //TODO we can remove all the deproxies here except for the first one
+ identifiableEntity = HibernateProxyHelper.deproxy(identifiableEntity, IdentifiableEntity.class);
if(identifiableEntity instanceof NonViralName) {
specifiedNameCache = HibernateProxyHelper.deproxy(identifiableEntity, NonViralName.class).getNameCache();
specifiedTitleCache = identifiableEntity.getTitleCache();
+ if (identifiableEntity instanceof BotanicalName){
+ if (((BotanicalName)identifiableEntity).isAutonym()){
+ boolean isProtected = false;
+ String oldNameCache = ((BotanicalName) identifiableEntity).getNameCache();
+ if ( ((BotanicalName)identifiableEntity).isProtectedNameCache()){
+ isProtected = true;
+ }
+ ((BotanicalName)identifiableEntity).setProtectedNameCache(false);
+ ((BotanicalName)identifiableEntity).setNameCache(null, false);
+ specifiedNameCache = ((BotanicalName) identifiableEntity).getNameCache();
+ ((BotanicalName)identifiableEntity).setNameCache(oldNameCache, isProtected);
+
+ }
+ }
} else if(identifiableEntity instanceof TaxonBase) {
TaxonBase taxonBase = HibernateProxyHelper.deproxy(identifiableEntity, TaxonBase.class);
}
}
- if(this instanceof NonViralName) {
+ if(this.isInstanceOf(NonViralName.class)) {
thisNameCache = HibernateProxyHelper.deproxy(this, NonViralName.class).getNameCache();
thisTitleCache = getTitleCache();
- } else if(this instanceof TaxonBase) {
+
+ if (this instanceof BotanicalName){
+ if (((BotanicalName)this).isAutonym()){
+ boolean isProtected = false;
+ String oldNameCache = ((BotanicalName) this).getNameCache();
+ if ( ((BotanicalName)this).isProtectedNameCache()){
+ isProtected = true;
+ }
+ ((BotanicalName)this).setProtectedNameCache(false);
+ ((BotanicalName)this).setNameCache(null, false);
+ thisNameCache = ((BotanicalName) this).getNameCache();
+ ((BotanicalName)this).setNameCache(oldNameCache, isProtected);
+ }
+ }
+ } else if(this.isInstanceOf(TaxonBase.class)) {
TaxonNameBase<?,?> taxonNameBase= HibernateProxyHelper.deproxy(this, TaxonBase.class).getName();
NonViralName nonViralName = HibernateProxyHelper.deproxy(taxonNameBase, NonViralName.class);
thisNameCache = nonViralName.getNameCache();
thisTitleCache = taxonNameBase.getTitleCache();
- thisReferenceTitleCache = getTitleCache();
+ thisReferenceTitleCache = ((TaxonBase)this).getSec().getTitleCache();
thisGenusString = nonViralName.getGenusOrUninomial();
}
// Compare name cache of taxon names
+
+
if (!specifiedNameCache.equals("") && !thisNameCache.equals("")) {
result = thisNameCache.compareTo(specifiedNameCache);
}
this.cacheStrategy = cacheStrategy;
}
+ @Override
public String generateTitle() {
- if (cacheStrategy == null){
+ if (getCacheStrategy() == null){
//logger.warn("No CacheStrategy defined for "+ this.getClass() + ": " + this.getUuid());
return this.getClass() + ": " + this.getUuid();
}else{
- return cacheStrategy.getTitleCache(this);
+ return getCacheStrategy().getTitleCache(this);
}
}