(no commit message)
[cdmlib.git] / cdmlib-persistence / src / main / java / eu / etaxonomy / cdm / persistence / dao / hibernate / taxon / TaxonDaoHibernateImpl.java
index deaca8f691b3ebd19693688330117e0d7db95c68..27ce8a1a2c6828cbdddfce3ca7fecaf0c63b30c6 100644 (file)
@@ -9,12 +9,17 @@
 package eu.etaxonomy.cdm.persistence.dao.hibernate.taxon;\r
 \r
 import java.lang.reflect.Field;\r
+import java.lang.reflect.InvocationTargetException;\r
+import java.lang.reflect.Method;\r
 import java.util.ArrayList;\r
 import java.util.Collections;\r
+import java.util.Comparator;\r
 import java.util.HashSet;\r
 import java.util.Iterator;\r
 import java.util.List;\r
 import java.util.Set;\r
+import java.util.SortedSet;\r
+import java.util.TreeSet;\r
 import java.util.UUID;\r
 \r
 import org.apache.log4j.Logger;\r
@@ -66,24 +71,19 @@ import eu.etaxonomy.cdm.model.taxon.TaxonBase;
 import eu.etaxonomy.cdm.model.taxon.TaxonRelationship;\r
 import eu.etaxonomy.cdm.model.taxon.TaxonRelationshipType;\r
 import eu.etaxonomy.cdm.model.view.AuditEvent;\r
+import eu.etaxonomy.cdm.persistence.dao.BeanInitializer;\r
 import eu.etaxonomy.cdm.persistence.dao.QueryParseException;\r
 import eu.etaxonomy.cdm.persistence.dao.common.ISearchableDao;\r
 import eu.etaxonomy.cdm.persistence.dao.common.ITitledDao;\r
 import eu.etaxonomy.cdm.persistence.dao.hibernate.AlternativeSpellingSuggestionParser;\r
+import eu.etaxonomy.cdm.persistence.dao.hibernate.HibernateBeanInitializer;\r
 import eu.etaxonomy.cdm.persistence.dao.hibernate.common.IdentifiableDaoBase;\r
 import eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonDao;\r
 import eu.etaxonomy.cdm.persistence.fetch.CdmFetch;\r
 import eu.etaxonomy.cdm.persistence.query.MatchMode;\r
+import eu.etaxonomy.cdm.persistence.query.OrderHint;\r
+\r
 \r
-/**\r
- * @author a.mueller\r
- *\r
- */\r
-/**\r
- * @author a.mueller\r
- * @created 24.11.2008\r
- * @version 1.0\r
- */\r
 /**\r
  * @author a.mueller\r
  * @created 24.11.2008\r
@@ -97,7 +97,7 @@ public class TaxonDaoHibernateImpl extends IdentifiableDaoBase<TaxonBase> implem
        \r
        @SuppressWarnings("unused")\r
        private static final Logger logger = Logger.getLogger(TaxonDaoHibernateImpl.class);\r
-       \r
+               \r
        private String defaultField = "name.titleCache";\r
        private String defaultSort = "name.titleCache_forSort";\r
        private Class<? extends TaxonBase> indexedClasses[]; \r
@@ -120,23 +120,11 @@ public class TaxonDaoHibernateImpl extends IdentifiableDaoBase<TaxonBase> implem
        public List<Taxon> getRootTaxa(ReferenceBase sec) {\r
                return getRootTaxa(sec, CdmFetch.FETCH_CHILDTAXA(), true, false);\r
        }\r
-       \r
-       @Override\r
-       public TaxonBase findByUuid(UUID uuid) {\r
-               TaxonBase taxonBase = super.findByUuid(uuid);\r
-               if(taxonBase == null) \r
-                       return taxonBase;\r
                \r
-               Hibernate.initialize(taxonBase.getName());\r
-               Hibernate.initialize(taxonBase.getSec());\r
-\r
-               return taxonBase; \r
-       }\r
-       \r
        /* (non-Javadoc)\r
         * @see eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonDao#getRootTaxa(eu.etaxonomy.cdm.model.name.Rank, eu.etaxonomy.cdm.model.reference.ReferenceBase, eu.etaxonomy.cdm.persistence.fetch.CdmFetch, java.lang.Boolean, java.lang.Boolean)\r
         */\r
-       public List<Taxon> getRootTaxa(Rank rank, ReferenceBase sec, CdmFetch cdmFetch, Boolean onlyWithChildren, Boolean withMisapplications) {\r
+       public List<Taxon> getRootTaxa(Rank rank, ReferenceBase sec, CdmFetch cdmFetch, Boolean onlyWithChildren, Boolean withMisapplications, List<String> propertyPaths) {\r
                checkNotInPriorView("TaxonDaoHibernateImpl.getRootTaxa(Rank rank, ReferenceBase sec, CdmFetch cdmFetch, Boolean onlyWithChildren, Boolean withMisapplications)");\r
                if (onlyWithChildren == null){\r
                        onlyWithChildren = true;\r
@@ -149,13 +137,14 @@ public class TaxonDaoHibernateImpl extends IdentifiableDaoBase<TaxonBase> implem
                }\r
 \r
                Criteria crit = getSession().createCriteria(Taxon.class);\r
-               //crit.add(Restrictions.isNull("taxonomicParentCache"));\r
                \r
                crit.setFetchMode("name", FetchMode.JOIN);\r
                crit.createAlias("name", "name");\r
                \r
                if (rank != null) {\r
                        crit.add(Restrictions.eq("name.rank", rank));\r
+               }else{\r
+                       crit.add(Restrictions.isNull("taxonomicParentCache"));\r
                }\r
 \r
                if (sec != null){\r
@@ -163,7 +152,7 @@ public class TaxonDaoHibernateImpl extends IdentifiableDaoBase<TaxonBase> implem
                }\r
 \r
                if (! cdmFetch.includes(CdmFetch.FETCH_CHILDTAXA())){\r
-                       logger.warn("no child taxa fetch");\r
+                       logger.info("Not fetching child taxa");\r
                        //TODO overwrite LAZY (SELECT) does not work (bug in hibernate?)\r
                        crit.setFetchMode("relationsToThisTaxon.fromTaxon", FetchMode.LAZY);\r
                }\r
@@ -171,21 +160,22 @@ public class TaxonDaoHibernateImpl extends IdentifiableDaoBase<TaxonBase> implem
                List<Taxon> results = new ArrayList<Taxon>();\r
                List<Taxon> taxa = crit.list();\r
                for(Taxon taxon : taxa){\r
+                       \r
+                       \r
                        //childTaxa\r
                        //TODO create restriction instead\r
-                       //Hibernate.initialize(taxon.getName());\r
-                       Hibernate.initialize(taxon.getSec());\r
-                       \r
                        // (a) not using cache fields\r
                        /*Hibernate.initialize(taxon.getRelationsFromThisTaxon());\r
                        if (onlyWithChildren == false || taxon.getRelationsFromThisTaxon().size() > 0){\r
                                if (withMisapplications == true || ! taxon.isMisappliedName()){\r
+                                       defaultBeanInitializer.initialize(taxon, propertyPaths);\r
                                        results.add(taxon);\r
                                }\r
                        }*/\r
                        // (b) using cache fields\r
                        if (onlyWithChildren == false || taxon.hasTaxonomicChildren()){\r
                                if (withMisapplications == true || ! taxon.isMisappliedName()){\r
+                                       defaultBeanInitializer.initialize(taxon, propertyPaths);\r
                                        results.add(taxon);\r
                                }\r
                        }\r
@@ -197,7 +187,7 @@ public class TaxonDaoHibernateImpl extends IdentifiableDaoBase<TaxonBase> implem
         * @see eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonDao#getRootTaxa(eu.etaxonomy.cdm.model.reference.ReferenceBase, eu.etaxonomy.cdm.persistence.fetch.CdmFetch, java.lang.Boolean, java.lang.Boolean)\r
         */\r
        public List<Taxon> getRootTaxa(ReferenceBase sec, CdmFetch cdmFetch, Boolean onlyWithChildren, Boolean withMisapplications) {\r
-               return getRootTaxa(null, sec, cdmFetch, onlyWithChildren, withMisapplications);\r
+               return getRootTaxa(null, sec, cdmFetch, onlyWithChildren, withMisapplications, null);\r
        }\r
        \r
 \r
@@ -219,13 +209,12 @@ public class TaxonDaoHibernateImpl extends IdentifiableDaoBase<TaxonBase> implem
                criteria.setFetchMode( "name", FetchMode.JOIN );\r
                criteria.createAlias("name", "name");\r
                \r
+               if (sec != null && sec.getId() != 0) {\r
+                       criteria.add(Restrictions.eq("sec", sec ) );\r
+               }\r
+\r
                // FIXME: sec restriction caused problems in cich image import: results was empty\r
-//             if (sec != null){\r
-//                     if(sec.getId() == 0){\r
-//                             getSession().save(sec);\r
-//                     }\r
-//                     criteria.add(Restrictions.eq("sec", sec ) );\r
-//             }\r
+               \r
                if (queryString != null) {\r
                        criteria.add(Restrictions.ilike("name.nameCache", queryString));\r
                }\r
@@ -246,17 +235,13 @@ public class TaxonDaoHibernateImpl extends IdentifiableDaoBase<TaxonBase> implem
                criteria.setFetchMode( "name", FetchMode.JOIN );\r
                criteria.createAlias("name", "name");\r
                \r
+               String hqlQueryString = matchMode.queryStringFrom(queryString);\r
                if (matchMode == MatchMode.EXACT) {\r
-                       criteria.add(Restrictions.eq("name.nameCache", matchMode.queryStringFrom(queryString)));\r
+                       criteria.add(Restrictions.eq("name.nameCache", hqlQueryString));\r
                } else {\r
-                       criteria.add(Restrictions.ilike("name.nameCache", matchMode.queryStringFrom(queryString)));\r
+                       criteria.add(Restrictions.ilike("name.nameCache", hqlQueryString));\r
                }\r
-               \r
-\r
-//             if (queryString != null) {\r
-//                     criteria.add(Restrictions.ilike("name.nameCache", queryString));\r
-//             }\r
-//             \r
+                               \r
                if(pageSize != null) {\r
                        criteria.setMaxResults(pageSize);\r
                        if(pageNumber != null) {\r
@@ -267,6 +252,14 @@ public class TaxonDaoHibernateImpl extends IdentifiableDaoBase<TaxonBase> implem
                List<TaxonBase> results = criteria.list();\r
                return results;\r
        }\r
+       \r
+       public Integer countTaxaByName(String queryString, MatchMode matchMode, \r
+                       Boolean accepted) {\r
+               //TODO improve performance\r
+               List<TaxonBase> restultSet = getTaxaByName(queryString, matchMode, accepted, null, null);\r
+               return restultSet.size();\r
+       }\r
+       \r
 \r
        public List<TaxonBase> getAllTaxonBases(Integer pagesize, Integer page) {\r
                return super.list(pagesize, page);\r
@@ -290,7 +283,29 @@ public class TaxonDaoHibernateImpl extends IdentifiableDaoBase<TaxonBase> implem
                        return (List<RelationshipBase>)query.getResultList();\r
                }\r
        }\r
-\r
+       \r
+       /** Sets the taxonomic parent to null. Does not handle taxonomic relationships. */\r
+//     private boolean nullifyTaxonomicParent(Taxon taxon) {\r
+//\r
+//             try {\r
+//                     Method nullifyTaxonomicParent = taxon.getClass().getMethod("nullifyTaxonomicParent");\r
+//                     nullifyTaxonomicParent.invoke(taxon);\r
+//             } catch (NoSuchMethodException ex) {\r
+//                     logger.error("NoSuchMethod: " + ex.getMessage());\r
+//                     return false;\r
+//             } catch (IllegalArgumentException ex) {\r
+//                     logger.error("IllegalArgumentException: " + ex.getMessage());\r
+//                     return false;\r
+//             } catch (IllegalAccessException ex) {\r
+//                     logger.error("IllegalAccessException: " + ex.getMessage());\r
+//                     return false;\r
+//             } catch (InvocationTargetException ex) {\r
+//                     logger.error("IllegalAccessException: " + ex.getMessage());\r
+//                     return false;\r
+//             }\r
+//             return true;\r
+//     }\r
+       \r
        @Override\r
        public UUID delete(TaxonBase taxonBase) throws DataAccessException{\r
                if (taxonBase == null){\r
@@ -344,21 +359,37 @@ public class TaxonDaoHibernateImpl extends IdentifiableDaoBase<TaxonBase> implem
                        Taxon taxon = (Taxon)taxonBase;\r
                                                \r
                        for (Iterator<TaxonRelationship> iterator = taxon.getRelationsFromThisTaxon().iterator(); iterator.hasNext();){\r
-                               TaxonRelationship relationToThisTaxon = iterator.next();\r
-                               iterator.remove();\r
-                               relationToThisTaxon.setFromTaxon(null);\r
-                               relationToThisTaxon.setToTaxon(null);\r
-                               getSession().delete(relationToThisTaxon);\r
-                       }\r
-                       \r
-                       for (Iterator<TaxonRelationship> iterator = taxon.getRelationsToThisTaxon().iterator(); iterator.hasNext();){\r
                                TaxonRelationship relationFromThisTaxon = iterator.next();\r
                                iterator.remove();\r
+                               \r
+                               // decrease children count of taxonomic parent by one\r
+                               if (relationFromThisTaxon.getType().equals(TaxonRelationshipType.TAXONOMICALLY_INCLUDED_IN())) {\r
+                                       Taxon toTaxon = relationFromThisTaxon.getToTaxon(); // parent\r
+                                       if (toTaxon != null) {\r
+                                               toTaxon.setTaxonomicChildrenCount(toTaxon.getTaxonomicChildrenCount() - 1);     \r
+                                       }\r
+                               }\r
                                relationFromThisTaxon.setToTaxon(null);\r
                                relationFromThisTaxon.setFromTaxon(null);\r
                                getSession().delete(relationFromThisTaxon);\r
                        }\r
                        \r
+                       for (Iterator<TaxonRelationship> iterator = taxon.getRelationsToThisTaxon().iterator(); iterator.hasNext();){\r
+                               TaxonRelationship relationToThisTaxon = iterator.next();\r
+                               iterator.remove();\r
+                               \r
+                // set parent cache of child to null\r
+                               if (relationToThisTaxon.getType().equals(TaxonRelationshipType.TAXONOMICALLY_INCLUDED_IN())) {\r
+                                       Taxon fromTaxon = relationToThisTaxon.getFromTaxon(); // child\r
+                                       if (fromTaxon != null) {\r
+                                               fromTaxon.nullifyTaxonomicParent();\r
+                                       }\r
+                               }\r
+                               relationToThisTaxon.setFromTaxon(null);\r
+                               relationToThisTaxon.setToTaxon(null);\r
+                               getSession().delete(relationToThisTaxon);\r
+                       }\r
+                       \r
                        //SynonymRelationships\r
                        for (Iterator<SynonymRelationship> iterator = taxon.getSynonymRelations().iterator(); iterator.hasNext();){\r
                                SynonymRelationship synonymRelation = iterator.next();\r
@@ -385,6 +416,8 @@ public class TaxonDaoHibernateImpl extends IdentifiableDaoBase<TaxonBase> implem
                                getSession().delete(taxonDescription);\r
                        }\r
                        \r
+                       taxon.nullifyTaxonomicParent();\r
+\r
                } else { //is Synonym\r
                        Synonym synonym = (Synonym)taxonBase;\r
                        for (Iterator<SynonymRelationship> iterator = synonym.getSynonymRelations().iterator(); iterator.hasNext();){\r
@@ -600,21 +633,28 @@ public class TaxonDaoHibernateImpl extends IdentifiableDaoBase<TaxonBase> implem
                criteria.setFetchMode( "name", FetchMode.JOIN );\r
                criteria.createAlias("name", "name");\r
                \r
-               if(genusOrUninomial != null) {\r
+               if(genusOrUninomial == null) {\r
+                       criteria.add(Restrictions.isNull("name.genusOrUninomial"));\r
+               } else if(!genusOrUninomial.equals("*")) {\r
                        criteria.add(Restrictions.eq("name.genusOrUninomial", genusOrUninomial));\r
                }\r
                \r
-               if(infraGenericEpithet != null) {\r
-                       criteria.add(Restrictions.eq("name.infraGenericEpithet", infraGenericEpithet));\r
-               } else {\r
+               if(infraGenericEpithet == null) {\r
                        criteria.add(Restrictions.isNull("name.infraGenericEpithet"));\r
-               }\r
+               } else if(!infraGenericEpithet.equals("*")) {\r
+                       criteria.add(Restrictions.eq("name.infraGenericEpithet", infraGenericEpithet));\r
+               } \r
                \r
-               if(specificEpithet != null) {\r
+               if(specificEpithet == null) {\r
+                       criteria.add(Restrictions.isNull("name.specificEpithet"));\r
+               } else if(!specificEpithet.equals("*")) {\r
                        criteria.add(Restrictions.eq("name.specificEpithet", specificEpithet));\r
+                       \r
                }\r
                \r
-               if(infraSpecificEpithet != null) {\r
+               if(infraSpecificEpithet == null) {\r
+                       criteria.add(Restrictions.isNull("name.infraSpecificEpithet"));\r
+               } else if(!infraSpecificEpithet.equals("*")) {\r
                        criteria.add(Restrictions.eq("name.infraSpecificEpithet", infraSpecificEpithet));\r
                }\r
                \r
@@ -634,30 +674,31 @@ public class TaxonDaoHibernateImpl extends IdentifiableDaoBase<TaxonBase> implem
                return (List<TaxonBase>)criteria.list();\r
        }\r
 \r
-       public List<TaxonRelationship> getRelatedTaxa(Taxon taxon,      TaxonRelationshipType type, Integer pageSize, Integer pageNumber) {\r
+       public List<TaxonRelationship> getRelatedTaxa(Taxon taxon,      TaxonRelationshipType type, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {\r
                AuditEvent auditEvent = getAuditEventFromContext();\r
                if(auditEvent.equals(AuditEvent.CURRENT_VIEW)) {\r
-            Query query = null;\r
+                       Criteria criteria = getSession().createCriteria(TaxonRelationship.class);\r
             \r
-                   if(type == null) {\r
-                           query = getSession().createQuery("select taxonRelationship from TaxonRelationship taxonRelationship join fetch taxonRelationship.relatedFrom where taxonRelationship.relatedTo = :relatedTo");\r
-                   } else {\r
-                           query = getSession().createQuery("select taxonRelationship from TaxonRelationship taxonRelationship join fetch taxonRelationship.relatedFrom where taxonRelationship.relatedTo = :relatedTo and taxonRelationship.type = :type");\r
-                           query.setParameter("type",type);\r
-                   }\r
+                       criteria.add(Restrictions.eq("relatedTo", taxon));\r
+                   if(type != null) {\r
+                       criteria.add(Restrictions.eq("type", type));\r
+                   } \r
                \r
-                   query.setParameter("relatedTo", taxon);\r
+            addOrder(criteria,orderHints);\r
                \r
                    if(pageSize != null) {\r
-                       query.setMaxResults(pageSize);\r
+                       criteria.setMaxResults(pageSize);\r
                        if(pageNumber != null) {\r
-                           query.setFirstResult(pageNumber * pageSize);\r
+                               criteria.setFirstResult(pageNumber * pageSize);\r
                        } else {\r
-                           query.setFirstResult(0);\r
+                               criteria.setFirstResult(0);\r
                        }\r
                    }\r
                \r
-                   return (List<TaxonRelationship>)query.list();\r
+                   List<TaxonRelationship> result = (List<TaxonRelationship>)criteria.list();\r
+                   defaultBeanInitializer.initializeAll(result, propertyPaths);\r
+                   \r
+                   return result;\r
                } else {\r
                        AuditQuery query = getAuditReader().createQuery().forEntitiesAtRevision(TaxonRelationship.class,auditEvent.getRevisionNumber());\r
                        query.add(AuditEntity.relatedId("relatedTo").eq(taxon.getId()));\r
@@ -676,38 +717,54 @@ public class TaxonDaoHibernateImpl extends IdentifiableDaoBase<TaxonBase> implem
                    }\r
                        \r
                        List<TaxonRelationship> result = (List<TaxonRelationship>)query.getResultList();\r
-                       for(TaxonRelationship relationship : result) {\r
-                               Hibernate.initialize(relationship.getFromTaxon());\r
+                       defaultBeanInitializer.initializeAll(result, propertyPaths);\r
+                       \r
+                       // Ugly, but for now, there is no way to sort on a related entity property in Envers,\r
+                       // and we can't live without this functionality in CATE as it screws up the whole \r
+                       // taxon tree thing\r
+                       if(orderHints != null && !orderHints.isEmpty()) {\r
+                           SortedSet<TaxonRelationship> sortedList = new TreeSet<TaxonRelationship>(new TaxonRelationshipFromTaxonComparator());\r
+                           sortedList.addAll(result);\r
+                           return new ArrayList<TaxonRelationship>(sortedList);\r
                        }\r
                        \r
                        return result;\r
                }\r
        }\r
+       \r
+       class TaxonRelationshipFromTaxonComparator implements Comparator<TaxonRelationship> {\r
+\r
+               public int compare(TaxonRelationship o1, TaxonRelationship o2) {\r
+                       return o1.getFromTaxon().getTitleCache().compareTo(o2.getFromTaxon().getTitleCache());\r
+               }\r
+               \r
+       }\r
 \r
-       public List<SynonymRelationship> getSynonyms(Taxon taxon, SynonymRelationshipType type, Integer pageSize, Integer pageNumber) {\r
+       public List<SynonymRelationship> getSynonyms(Taxon taxon, SynonymRelationshipType type, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {\r
                AuditEvent auditEvent = getAuditEventFromContext();\r
                if(auditEvent.equals(AuditEvent.CURRENT_VIEW)) {\r
-                       Query query = null;\r
-\r
-                       if(type == null) {\r
-                               query = getSession().createQuery("select synonymRelationship from SynonymRelationship synonymRelationship join fetch synonymRelationship.relatedFrom where synonymRelationship.relatedTo = :relatedTo");\r
-                       } else {\r
-                               query = getSession().createQuery("select synonymRelationship from SynonymRelationship synonymRelationship join fetch synonymRelationship.relatedFrom where synonymRelationship.relatedTo = :relatedTo and synonymRelationship.type = :type");\r
-                               query.setParameter("type",type);\r
-                       }\r
-\r
-                       query.setParameter("relatedTo", taxon);\r
-\r
-                       if(pageSize != null) {\r
-                               query.setMaxResults(pageSize);\r
-                               if(pageNumber != null) {\r
-                                       query.setFirstResult(pageNumber * pageSize);\r
-                               } else {\r
-                                       query.setFirstResult(0);\r
-                               }\r
-                       }\r
-\r
-                       return (List<SynonymRelationship>)query.list();\r
+            Criteria criteria = getSession().createCriteria(SynonymRelationship.class);\r
+            \r
+                       criteria.add(Restrictions.eq("relatedTo", taxon));\r
+                   if(type != null) {\r
+                       criteria.add(Restrictions.eq("type", type));\r
+                   } \r
+               \r
+            addOrder(criteria,orderHints);\r
+               \r
+                   if(pageSize != null) {\r
+                       criteria.setMaxResults(pageSize);\r
+                       if(pageNumber != null) {\r
+                               criteria.setFirstResult(pageNumber * pageSize);\r
+                       } else {\r
+                               criteria.setFirstResult(0);\r
+                       }\r
+                   }\r
+               \r
+                   List<SynonymRelationship> result = (List<SynonymRelationship>)criteria.list();\r
+                   defaultBeanInitializer.initializeAll(result, propertyPaths);\r
+                   \r
+                   return result;\r
                } else {\r
                        AuditQuery query = getAuditReader().createQuery().forEntitiesAtRevision(SynonymRelationship.class,auditEvent.getRevisionNumber());\r
                        query.add(AuditEntity.relatedId("relatedTo").eq(taxon.getId()));\r
@@ -726,9 +783,7 @@ public class TaxonDaoHibernateImpl extends IdentifiableDaoBase<TaxonBase> implem
                    }\r
                        \r
                        List<SynonymRelationship> result = (List<SynonymRelationship>)query.getResultList();\r
-                       for(SynonymRelationship relationship : result) {\r
-                               Hibernate.initialize(relationship.getSynonym());\r
-                       }\r
+                       defaultBeanInitializer.initializeAll(result, propertyPaths);\r
                        \r
                        return result;\r
                }\r