solving lazy loading exception
[cdmlib.git] / cdmlib-services / src / main / java / eu / etaxonomy / cdm / api / service / TaxonServiceImpl.java
index 2f5bc272cec3ab44e0dff34fb970e868d1d98fef..c36c1b6b19fda7d0bb50773ef9caecc4ebc5f26b 100644 (file)
@@ -15,20 +15,23 @@ import java.util.ArrayList;
 import java.util.HashMap;\r
 import java.util.HashSet;\r
 import java.util.List;\r
+import java.util.Map;\r
 import java.util.Set;\r
 import java.util.UUID;\r
 \r
 import org.apache.log4j.Logger;\r
 import org.apache.lucene.index.CorruptIndexException;\r
 import org.apache.lucene.queryParser.ParseException;\r
-import org.apache.lucene.search.TopDocs;\r
-import org.hibernate.criterion.Criterion;\r
+import org.apache.lucene.search.BooleanClause.Occur;\r
+import org.apache.lucene.search.BooleanQuery;\r
+import org.apache.lucene.search.Query;\r
+import org.apache.lucene.search.SortField;\r
 import org.springframework.beans.factory.annotation.Autowired;\r
 import org.springframework.stereotype.Service;\r
 import org.springframework.transaction.annotation.Propagation;\r
 import org.springframework.transaction.annotation.Transactional;\r
 \r
-import eu.etaxonomy.cdm.api.service.config.ITaxonServiceConfigurator;\r
+import eu.etaxonomy.cdm.api.service.config.IFindTaxaAndNamesConfigurator;\r
 import eu.etaxonomy.cdm.api.service.config.MatchingTaxonConfigurator;\r
 import eu.etaxonomy.cdm.api.service.config.NameDeletionConfigurator;\r
 import eu.etaxonomy.cdm.api.service.config.TaxonDeletionConfigurator;\r
@@ -38,30 +41,46 @@ import eu.etaxonomy.cdm.api.service.exception.ReferencedObjectUndeletableExcepti
 import eu.etaxonomy.cdm.api.service.pager.Pager;\r
 import eu.etaxonomy.cdm.api.service.pager.impl.DefaultPagerImpl;\r
 import eu.etaxonomy.cdm.api.service.search.ISearchResultBuilder;\r
+import eu.etaxonomy.cdm.api.service.search.LuceneMultiSearch;\r
+import eu.etaxonomy.cdm.api.service.search.LuceneSearch;\r
+import eu.etaxonomy.cdm.api.service.search.LuceneSearch.TopGroupsWithMaxScore;\r
+import eu.etaxonomy.cdm.api.service.search.QueryFactory;\r
 import eu.etaxonomy.cdm.api.service.search.SearchResult;\r
+import eu.etaxonomy.cdm.api.service.search.SearchResultBuilder;\r
+import eu.etaxonomy.cdm.api.service.util.TaxonRelationshipEdge;\r
 import eu.etaxonomy.cdm.common.monitor.IProgressMonitor;\r
 import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;\r
+import eu.etaxonomy.cdm.hibernate.search.DefinedTermBaseClassBridge;\r
+import eu.etaxonomy.cdm.hibernate.search.MultilanguageTextFieldBridge;\r
+import eu.etaxonomy.cdm.model.CdmBaseType;\r
 import eu.etaxonomy.cdm.model.common.CdmBase;\r
 import eu.etaxonomy.cdm.model.common.IdentifiableEntity;\r
 import eu.etaxonomy.cdm.model.common.IdentifiableSource;\r
+import eu.etaxonomy.cdm.model.common.Language;\r
 import eu.etaxonomy.cdm.model.common.OrderedTermVocabulary;\r
 import eu.etaxonomy.cdm.model.common.RelationshipBase;\r
 import eu.etaxonomy.cdm.model.common.RelationshipBase.Direction;\r
 import eu.etaxonomy.cdm.model.common.UuidAndTitleCache;\r
+import eu.etaxonomy.cdm.model.description.DescriptionBase;\r
 import eu.etaxonomy.cdm.model.description.DescriptionElementBase;\r
+import eu.etaxonomy.cdm.model.description.Feature;\r
 import eu.etaxonomy.cdm.model.description.IIdentificationKey;\r
 import eu.etaxonomy.cdm.model.description.PolytomousKeyNode;\r
+import eu.etaxonomy.cdm.model.description.SpecimenDescription;\r
 import eu.etaxonomy.cdm.model.description.TaxonDescription;\r
 import eu.etaxonomy.cdm.model.description.TaxonInteraction;\r
+import eu.etaxonomy.cdm.model.description.TaxonNameDescription;\r
 import eu.etaxonomy.cdm.model.media.Media;\r
 import eu.etaxonomy.cdm.model.media.MediaRepresentation;\r
 import eu.etaxonomy.cdm.model.media.MediaUtils;\r
+import eu.etaxonomy.cdm.model.molecular.DnaSample;\r
+import eu.etaxonomy.cdm.model.molecular.Sequence;\r
 import eu.etaxonomy.cdm.model.name.HomotypicalGroup;\r
-import eu.etaxonomy.cdm.model.name.NonViralName;\r
 import eu.etaxonomy.cdm.model.name.Rank;\r
 import eu.etaxonomy.cdm.model.name.TaxonNameBase;\r
 import eu.etaxonomy.cdm.model.name.ZoologicalName;\r
 import eu.etaxonomy.cdm.model.occurrence.DerivedUnitBase;\r
+import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase;\r
 import eu.etaxonomy.cdm.model.reference.Reference;\r
 import eu.etaxonomy.cdm.model.taxon.Classification;\r
 import eu.etaxonomy.cdm.model.taxon.Synonym;\r
@@ -72,15 +91,16 @@ import eu.etaxonomy.cdm.model.taxon.TaxonBase;
 import eu.etaxonomy.cdm.model.taxon.TaxonNode;\r
 import eu.etaxonomy.cdm.model.taxon.TaxonRelationship;\r
 import eu.etaxonomy.cdm.model.taxon.TaxonRelationshipType;\r
+import eu.etaxonomy.cdm.persistence.dao.AbstractBeanInitializer;\r
 import eu.etaxonomy.cdm.persistence.dao.common.ICdmGenericDao;\r
 import eu.etaxonomy.cdm.persistence.dao.common.IOrderedTermVocabularyDao;\r
 import eu.etaxonomy.cdm.persistence.dao.name.ITaxonNameDao;\r
+import eu.etaxonomy.cdm.persistence.dao.occurrence.IOccurrenceDao;\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
 import eu.etaxonomy.cdm.persistence.query.OrderHint.SortOrder;\r
-import eu.etaxonomy.cdm.search.LuceneSearch;\r
 import eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy;\r
 \r
 \r
@@ -104,9 +124,6 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
     @Autowired\r
     private ITaxonNameDao nameDao;\r
 \r
-    @Autowired\r
-    private ISearchResultBuilder searchResultBuilder;\r
-\r
     @Autowired\r
     private INameService nameService;\r
 \r
@@ -119,6 +136,12 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
     @Autowired\r
     private IOrderedTermVocabularyDao orderedVocabularyDao;\r
 \r
+    @Autowired\r
+    private IOccurrenceDao occurrenceDao;\r
+\r
+    @Autowired\r
+    private AbstractBeanInitializer beanInitializer;\r
+\r
     /**\r
      * Constructor\r
      */\r
@@ -130,6 +153,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
      * FIXME Candidate for harmonization\r
      * rename searchByName ?\r
      */\r
+    @Override\r
     public List<TaxonBase> searchTaxaByName(String name, Reference sec) {\r
         return dao.getTaxaByName(name, sec);\r
     }\r
@@ -140,6 +164,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
      *  (non-Javadoc)\r
      * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllSynonyms(int, int)\r
      */\r
+    @Override\r
     public List<Synonym> getAllSynonyms(int limit, int start) {\r
         return dao.getAllSynonyms(limit, start);\r
     }\r
@@ -150,6 +175,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
      *  (non-Javadoc)\r
      * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllTaxa(int, int)\r
      */\r
+    @Override\r
     public List<Taxon> getAllTaxa(int limit, int start) {\r
         return dao.getAllTaxa(limit, start);\r
     }\r
@@ -160,6 +186,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
      *  (non-Javadoc)\r
      * @see eu.etaxonomy.cdm.api.service.ITaxonService#getRootTaxa(eu.etaxonomy.cdm.model.reference.Reference, boolean)\r
      */\r
+    @Override\r
     public List<Taxon> getRootTaxa(Reference sec, CdmFetch cdmFetch, boolean onlyWithChildren) {\r
         if (cdmFetch == null){\r
             cdmFetch = CdmFetch.NO_FETCH();\r
@@ -171,6 +198,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
     /* (non-Javadoc)\r
      * @see eu.etaxonomy.cdm.api.service.ITaxonService#getRootTaxa(eu.etaxonomy.cdm.model.name.Rank, eu.etaxonomy.cdm.model.reference.Reference, boolean, boolean)\r
      */\r
+    @Override\r
     public List<Taxon> getRootTaxa(Rank rank, Reference sec, boolean onlyWithChildren,boolean withMisapplications, List<String> propertyPaths) {\r
         return dao.getRootTaxa(rank, sec, null, onlyWithChildren, withMisapplications, propertyPaths);\r
     }\r
@@ -178,6 +206,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
     /* (non-Javadoc)\r
      * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllRelationships(int, int)\r
      */\r
+    @Override\r
     public List<RelationshipBase> getAllRelationships(int limit, int start){\r
         return dao.getAllRelationships(limit, start);\r
     }\r
@@ -186,6 +215,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
      * FIXME Candidate for harmonization\r
      * is this the same as termService.getVocabulary(VocabularyEnum.TaxonRelationshipType) ?\r
      */\r
+    @Override\r
     @Deprecated\r
     public OrderedTermVocabulary<TaxonRelationshipType> getTaxonRelationshipTypeVocabulary() {\r
 \r
@@ -202,6 +232,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
      * (non-Javadoc)\r
      * @see eu.etaxonomy.cdm.api.service.ITaxonService#swapSynonymWithAcceptedTaxon(eu.etaxonomy.cdm.model.taxon.Synonym)\r
      */\r
+    @Override\r
     @Transactional(readOnly = false)\r
     public void swapSynonymAndAcceptedTaxon(Synonym synonym, Taxon acceptedTaxon){\r
 \r
@@ -268,6 +299,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
     }\r
 \r
 \r
+    @Override\r
     public Taxon changeSynonymToRelatedTaxon(Synonym synonym, Taxon toTaxon, TaxonRelationshipType taxonRelationshipType, Reference citation, String microcitation){\r
 \r
         // Get name from synonym\r
@@ -358,6 +390,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
      * @see eu.etaxonomy.cdm.api.service.IIdentifiableEntityService#updateTitleCache(java.lang.Integer, eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy)\r
      */\r
     @Override\r
+    @Transactional(readOnly = false)\r
     public void updateTitleCache(Class<? extends TaxonBase> clazz, Integer stepSize, IIdentifiableEntityCacheStrategy<TaxonBase> cacheStrategy, IProgressMonitor monitor) {\r
         if (clazz == null){\r
             clazz = TaxonBase.class;\r
@@ -365,6 +398,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
         super.updateTitleCacheImpl(clazz, stepSize, cacheStrategy, monitor);\r
     }\r
 \r
+    @Override\r
     @Autowired\r
     protected void setDao(ITaxonDao dao) {\r
         this.dao = dao;\r
@@ -373,6 +407,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
     /* (non-Javadoc)\r
      * @see eu.etaxonomy.cdm.api.service.ITaxonService#findTaxaByName(java.lang.Class, java.lang.String, java.lang.String, java.lang.String, java.lang.String, eu.etaxonomy.cdm.model.name.Rank, java.lang.Integer, java.lang.Integer)\r
      */\r
+    @Override\r
     public Pager<TaxonBase> findTaxaByName(Class<? extends TaxonBase> clazz, String uninomial, String infragenericEpithet, String specificEpithet,     String infraspecificEpithet, Rank rank, Integer pageSize,Integer pageNumber) {\r
         Integer numberOfResults = dao.countTaxaByName(clazz, uninomial, infragenericEpithet, specificEpithet, infraspecificEpithet, rank);\r
 \r
@@ -387,6 +422,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
     /* (non-Javadoc)\r
      * @see eu.etaxonomy.cdm.api.service.ITaxonService#listTaxaByName(java.lang.Class, java.lang.String, java.lang.String, java.lang.String, java.lang.String, eu.etaxonomy.cdm.model.name.Rank, java.lang.Integer, java.lang.Integer)\r
      */\r
+    @Override\r
     public List<TaxonBase> listTaxaByName(Class<? extends TaxonBase> clazz, String uninomial,  String infragenericEpithet, String specificEpithet,     String infraspecificEpithet, Rank rank, Integer pageSize,Integer pageNumber) {\r
         Integer numberOfResults = dao.countTaxaByName(clazz, uninomial, infragenericEpithet, specificEpithet, infraspecificEpithet, rank);\r
 \r
@@ -401,6 +437,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
     /* (non-Javadoc)\r
      * @see eu.etaxonomy.cdm.api.service.ITaxonService#listToTaxonRelationships(eu.etaxonomy.cdm.model.taxon.Taxon, eu.etaxonomy.cdm.model.taxon.TaxonRelationshipType, java.lang.Integer, java.lang.Integer, java.util.List, java.util.List)\r
      */\r
+    @Override\r
     public List<TaxonRelationship> listToTaxonRelationships(Taxon taxon, TaxonRelationshipType type, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths){\r
         Integer numberOfResults = dao.countTaxonRelationships(taxon, type, TaxonRelationship.Direction.relatedTo);\r
 \r
@@ -414,6 +451,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
     /* (non-Javadoc)\r
      * @see eu.etaxonomy.cdm.api.service.ITaxonService#pageToTaxonRelationships(eu.etaxonomy.cdm.model.taxon.Taxon, eu.etaxonomy.cdm.model.taxon.TaxonRelationshipType, java.lang.Integer, java.lang.Integer, java.util.List, java.util.List)\r
      */\r
+    @Override\r
     public Pager<TaxonRelationship> pageToTaxonRelationships(Taxon taxon, TaxonRelationshipType type, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {\r
         Integer numberOfResults = dao.countTaxonRelationships(taxon, type, TaxonRelationship.Direction.relatedTo);\r
 \r
@@ -427,6 +465,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
     /* (non-Javadoc)\r
      * @see eu.etaxonomy.cdm.api.service.ITaxonService#listFromTaxonRelationships(eu.etaxonomy.cdm.model.taxon.Taxon, eu.etaxonomy.cdm.model.taxon.TaxonRelationshipType, java.lang.Integer, java.lang.Integer, java.util.List, java.util.List)\r
      */\r
+    @Override\r
     public List<TaxonRelationship> listFromTaxonRelationships(Taxon taxon, TaxonRelationshipType type, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths){\r
         Integer numberOfResults = dao.countTaxonRelationships(taxon, type, TaxonRelationship.Direction.relatedFrom);\r
 \r
@@ -440,6 +479,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
     /* (non-Javadoc)\r
      * @see eu.etaxonomy.cdm.api.service.ITaxonService#pageFromTaxonRelationships(eu.etaxonomy.cdm.model.taxon.Taxon, eu.etaxonomy.cdm.model.taxon.TaxonRelationshipType, java.lang.Integer, java.lang.Integer, java.util.List, java.util.List)\r
      */\r
+    @Override\r
     public Pager<TaxonRelationship> pageFromTaxonRelationships(Taxon taxon, TaxonRelationshipType type, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {\r
         Integer numberOfResults = dao.countTaxonRelationships(taxon, type, TaxonRelationship.Direction.relatedFrom);\r
 \r
@@ -450,9 +490,86 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
         return new DefaultPagerImpl<TaxonRelationship>(pageNumber, numberOfResults, pageSize, results);\r
     }\r
 \r
+    /**\r
+     * @param taxon\r
+     * @param includeRelationships\r
+     * @param maxDepth\r
+     * @param limit\r
+     * @param starts\r
+     * @param propertyPaths\r
+     * @return an List which is not specifically ordered\r
+     */\r
+    @Override\r
+    public Set<Taxon> listRelatedTaxa(Taxon taxon, Set<TaxonRelationshipEdge> includeRelationships, Integer maxDepth,\r
+            Integer limit, Integer start, List<String> propertyPaths) {\r
+\r
+        Set<Taxon> relatedTaxa = collectRelatedTaxa(taxon, includeRelationships, new HashSet<Taxon>(), maxDepth);\r
+        relatedTaxa.remove(taxon);\r
+        beanInitializer.initializeAll(relatedTaxa, propertyPaths);\r
+        return relatedTaxa;\r
+    }\r
+\r
+\r
+    /**\r
+     * recursively collect related taxa for the given <code>taxon</code> . The returned list will also include the\r
+     *  <code>taxon</code> supplied as parameter.\r
+     *\r
+     * @param taxon\r
+     * @param includeRelationships\r
+     * @param taxa\r
+     * @param maxDepth can be <code>null</code> for infinite depth\r
+     * @return\r
+     */\r
+    private Set<Taxon> collectRelatedTaxa(Taxon taxon, Set<TaxonRelationshipEdge> includeRelationships, Set<Taxon> taxa, Integer maxDepth) {\r
+\r
+        if(taxa.isEmpty()) {\r
+            taxa.add(taxon);\r
+        }\r
+\r
+        if(maxDepth != null) {\r
+            maxDepth--;\r
+        }\r
+        if(logger.isDebugEnabled()){\r
+            logger.debug("collecting related taxa for " + taxon + " with maxDepth=" + maxDepth);\r
+        }\r
+        List<TaxonRelationship> taxonRelationships = dao.getTaxonRelationships(taxon, null, null, null, null, null, null);\r
+        for (TaxonRelationship taxRel : taxonRelationships) {\r
+\r
+            // skip invalid data\r
+            if (taxRel.getToTaxon() == null || taxRel.getFromTaxon() == null || taxRel.getType() == null) {\r
+                continue;\r
+            }\r
+            // filter by includeRelationships\r
+            for (TaxonRelationshipEdge relationshipEdgeFilter : includeRelationships) {\r
+                if ( relationshipEdgeFilter.getTaxonRelationshipType().equals(taxRel.getType()) ) {\r
+                    if (relationshipEdgeFilter.getDirections().contains(Direction.relatedTo) && !taxa.contains(taxRel.getToTaxon())) {\r
+                        if(logger.isDebugEnabled()){\r
+                            logger.debug(maxDepth + ": " + taxon.getTitleCache() + " --[" + taxRel.getType().getLabel() + "]--> " + taxRel.getToTaxon().getTitleCache());\r
+                        }\r
+                        taxa.add(taxRel.getToTaxon());\r
+                        if(maxDepth == null || maxDepth > 0) {\r
+                            taxa.addAll(collectRelatedTaxa(taxRel.getToTaxon(), includeRelationships, taxa, maxDepth));\r
+                        }\r
+                    }\r
+                    if(relationshipEdgeFilter.getDirections().contains(Direction.relatedFrom) && !taxa.contains(taxRel.getFromTaxon())) {\r
+                        taxa.add(taxRel.getFromTaxon());\r
+                        if(logger.isDebugEnabled()){\r
+                            logger.debug(maxDepth + ": " +taxRel.getFromTaxon().getTitleCache() + " --[" + taxRel.getType().getLabel() + "]--> " + taxon.getTitleCache() );\r
+                        }\r
+                        if(maxDepth == null || maxDepth > 0) {\r
+                            taxa.addAll(collectRelatedTaxa(taxRel.getFromTaxon(), includeRelationships, taxa, maxDepth));\r
+                        }\r
+                    }\r
+                }\r
+            }\r
+        }\r
+        return taxa;\r
+    }\r
+\r
     /* (non-Javadoc)\r
      * @see eu.etaxonomy.cdm.api.service.ITaxonService#getSynonyms(eu.etaxonomy.cdm.model.taxon.Taxon, eu.etaxonomy.cdm.model.taxon.SynonymRelationshipType, java.lang.Integer, java.lang.Integer, java.util.List, java.util.List)\r
      */\r
+    @Override\r
     public Pager<SynonymRelationship> getSynonyms(Taxon taxon, SynonymRelationshipType type, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {\r
         Integer numberOfResults = dao.countSynonyms(taxon, type);\r
 \r
@@ -467,6 +584,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
     /* (non-Javadoc)\r
      * @see eu.etaxonomy.cdm.api.service.ITaxonService#getSynonyms(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.SynonymRelationshipType, java.lang.Integer, java.lang.Integer, java.util.List, java.util.List)\r
      */\r
+    @Override\r
     public Pager<SynonymRelationship> getSynonyms(Synonym synonym,     SynonymRelationshipType type, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {\r
         Integer numberOfResults = dao.countSynonyms(synonym, type);\r
 \r
@@ -481,6 +599,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
     /* (non-Javadoc)\r
      * @see eu.etaxonomy.cdm.api.service.ITaxonService#getHomotypicSynonymsByHomotypicGroup(eu.etaxonomy.cdm.model.taxon.Taxon, java.util.List)\r
      */\r
+    @Override\r
     public List<Synonym> getHomotypicSynonymsByHomotypicGroup(Taxon taxon, List<String> propertyPaths){\r
         Taxon t = (Taxon)dao.load(taxon.getUuid(), propertyPaths);\r
         return t.getHomotypicSynonymsByHomotypicGroup();\r
@@ -489,6 +608,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
     /* (non-Javadoc)\r
      * @see eu.etaxonomy.cdm.api.service.ITaxonService#getHeterotypicSynonymyGroups(eu.etaxonomy.cdm.model.taxon.Taxon, java.util.List)\r
      */\r
+    @Override\r
     public List<List<Synonym>> getHeterotypicSynonymyGroups(Taxon taxon, List<String> propertyPaths){\r
         Taxon t = (Taxon)dao.load(taxon.getUuid(), propertyPaths);\r
         List<HomotypicalGroup> homotypicalGroups = t.getHeterotypicSynonymyGroups();\r
@@ -499,7 +619,8 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
         return heterotypicSynonymyGroups;\r
     }\r
 \r
-    public List<UuidAndTitleCache<TaxonBase>> findTaxaAndNamesForEditor(ITaxonServiceConfigurator configurator){\r
+    @Override\r
+    public List<UuidAndTitleCache<TaxonBase>> findTaxaAndNamesForEditor(IFindTaxaAndNamesConfigurator configurator){\r
 \r
         List<UuidAndTitleCache<TaxonBase>> result = new ArrayList<UuidAndTitleCache<TaxonBase>>();\r
 //        Class<? extends TaxonBase> clazz = null;\r
@@ -523,7 +644,8 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
     /* (non-Javadoc)\r
      * @see eu.etaxonomy.cdm.api.service.ITaxonService#findTaxaAndNames(eu.etaxonomy.cdm.api.service.config.ITaxonServiceConfigurator)\r
      */\r
-    public Pager<IdentifiableEntity> findTaxaAndNames(ITaxonServiceConfigurator configurator) {\r
+    @Override\r
+    public Pager<IdentifiableEntity> findTaxaAndNames(IFindTaxaAndNamesConfigurator configurator) {\r
 \r
         List<IdentifiableEntity> results = new ArrayList<IdentifiableEntity>();\r
         int numberOfResults = 0; // overall number of results (as opposed to number of results per page)\r
@@ -615,6 +737,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
     /* (non-Javadoc)\r
      * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllMedia(eu.etaxonomy.cdm.model.taxon.Taxon, int, int, int, java.lang.String[])\r
      */\r
+    @Override\r
     public List<MediaRepresentation> getAllMedia(Taxon taxon, int size, int height, int widthOrDuration, String[] mimeTypes){\r
         List<MediaRepresentation> medRep = new ArrayList<MediaRepresentation>();\r
         taxon = (Taxon)dao.load(taxon.getUuid());\r
@@ -633,16 +756,129 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
         return medRep;\r
     }\r
 \r
+    /* (non-Javadoc)\r
+     * @see eu.etaxonomy.cdm.api.service.ITaxonService#listTaxonDescriptionMedia(eu.etaxonomy.cdm.model.taxon.Taxon, boolean)\r
+     */\r
+    @Override\r
+    public List<Media> listTaxonDescriptionMedia(Taxon taxon, Set<TaxonRelationshipEdge> includeRelationships, boolean limitToGalleries, List<String> propertyPath){\r
+        return listMedia(taxon, includeRelationships, limitToGalleries, true, false, false, propertyPath);\r
+    }\r
+\r
+\r
+    /* (non-Javadoc)\r
+     * @see eu.etaxonomy.cdm.api.service.ITaxonService#listMedia(eu.etaxonomy.cdm.model.taxon.Taxon, java.util.Set, boolean, java.util.List)\r
+     */\r
+    @Override\r
+    public List<Media> listMedia(Taxon taxon, Set<TaxonRelationshipEdge> includeRelationships,\r
+            Boolean limitToGalleries, Boolean includeTaxonDescriptions, Boolean includeOccurrences,\r
+            Boolean includeTaxonNameDescriptions, List<String> propertyPath) {\r
+\r
+        Set<Taxon> taxa = new HashSet<Taxon>();\r
+        List<Media> taxonMedia = new ArrayList<Media>();\r
+\r
+        if (limitToGalleries == null) {\r
+            limitToGalleries = false;\r
+        }\r
+\r
+        // --- resolve related taxa\r
+        if (includeRelationships != null) {\r
+            taxa = listRelatedTaxa(taxon, includeRelationships, null, null, null, null);\r
+        }\r
+\r
+        taxa.add((Taxon) dao.load(taxon.getUuid()));\r
+\r
+        if(includeTaxonDescriptions != null && includeTaxonDescriptions){\r
+            List<TaxonDescription> taxonDescriptions = new ArrayList<TaxonDescription>();\r
+            // --- TaxonDescriptions\r
+            for (Taxon t : taxa) {\r
+                taxonDescriptions.addAll(descriptionService.listTaxonDescriptions(t, null, null, null, null, propertyPath));\r
+            }\r
+            for (TaxonDescription taxonDescription : taxonDescriptions) {\r
+                if (!limitToGalleries || taxonDescription.isImageGallery()) {\r
+                    for (DescriptionElementBase element : taxonDescription.getElements()) {\r
+                        for (Media media : element.getMedia()) {\r
+                            taxonMedia.add(media);\r
+                        }\r
+                    }\r
+                }\r
+            }\r
+        }\r
+\r
+        if(includeOccurrences != null && includeOccurrences) {\r
+            Set<SpecimenOrObservationBase> specimensOrObservations = new HashSet<SpecimenOrObservationBase>();\r
+            // --- Specimens\r
+            for (Taxon t : taxa) {\r
+                specimensOrObservations.addAll(occurrenceDao.listByAssociatedTaxon(null, t, null, null, null, null));\r
+            }\r
+            for (SpecimenOrObservationBase occurrence : specimensOrObservations) {\r
+\r
+                taxonMedia.addAll(occurrence.getMedia());\r
+\r
+                // SpecimenDescriptions\r
+                Set<SpecimenDescription> specimenDescriptions = occurrence.getSpecimenDescriptions();\r
+                for (DescriptionBase specimenDescription : specimenDescriptions) {\r
+                    if (!limitToGalleries || specimenDescription.isImageGallery()) {\r
+                        Set<DescriptionElementBase> elements = specimenDescription.getElements();\r
+                        for (DescriptionElementBase element : elements) {\r
+                            for (Media media : element.getMedia()) {\r
+                                taxonMedia.add(media);\r
+                            }\r
+                        }\r
+                    }\r
+                }\r
+\r
+                // Collection\r
+                if (occurrence instanceof DerivedUnitBase) {\r
+                    if (((DerivedUnitBase) occurrence).getCollection() != null){\r
+                        taxonMedia.addAll(((DerivedUnitBase) occurrence).getCollection().getMedia());\r
+                    }\r
+                }\r
+\r
+                // Chromatograms\r
+                if (occurrence instanceof DnaSample) {\r
+                    Set<Sequence> sequences = ((DnaSample) occurrence).getSequences();\r
+                    for (Sequence sequence : sequences) {\r
+                        taxonMedia.addAll(sequence.getChromatograms());\r
+                    }\r
+                }\r
+\r
+            }\r
+        }\r
+\r
+        if(includeTaxonNameDescriptions != null && includeTaxonNameDescriptions) {\r
+            // --- TaxonNameDescription\r
+            Set<TaxonNameDescription> nameDescriptions = new HashSet<TaxonNameDescription>();\r
+            for (Taxon t : taxa) {\r
+                nameDescriptions .addAll(t.getName().getDescriptions());\r
+            }\r
+            for(TaxonNameDescription nameDescription: nameDescriptions){\r
+                if (!limitToGalleries || nameDescription.isImageGallery()) {\r
+                    Set<DescriptionElementBase> elements = nameDescription.getElements();\r
+                    for (DescriptionElementBase element : elements) {\r
+                        for (Media media : element.getMedia()) {\r
+                            taxonMedia.add(media);\r
+                        }\r
+                    }\r
+                }\r
+            }\r
+        }\r
+\r
+        beanInitializer.initializeAll(taxonMedia, propertyPath);\r
+        return taxonMedia;\r
+    }\r
+\r
     /* (non-Javadoc)\r
      * @see eu.etaxonomy.cdm.api.service.ITaxonService#findTaxaByID(java.util.Set)\r
      */\r
+    @Override\r
     public List<TaxonBase> findTaxaByID(Set<Integer> listOfIDs) {\r
-        return this.dao.findById(listOfIDs);\r
+        return this.dao.listByIds(listOfIDs, null, null, null, null);\r
     }\r
 \r
     /* (non-Javadoc)\r
      * @see eu.etaxonomy.cdm.api.service.ITaxonService#findTaxonByUuid(UUID uuid, List<String> propertyPaths)\r
      */\r
+    @Override\r
     public TaxonBase findTaxonByUuid(UUID uuid, List<String> propertyPaths){\r
         return this.dao.findByUuid(uuid, null ,propertyPaths);\r
     }\r
@@ -650,6 +886,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
     /* (non-Javadoc)\r
      * @see eu.etaxonomy.cdm.api.service.ITaxonService#countAllRelationships()\r
      */\r
+    @Override\r
     public int countAllRelationships() {\r
         return this.dao.countAllRelationships();\r
     }\r
@@ -660,6 +897,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
     /* (non-Javadoc)\r
      * @see eu.etaxonomy.cdm.api.service.ITaxonService#findIdenticalTaxonNames(java.util.List)\r
      */\r
+    @Override\r
     public List<TaxonNameBase> findIdenticalTaxonNames(List<String> propertyPath) {\r
         return this.dao.findIdenticalTaxonNames(propertyPath);\r
     }\r
@@ -800,7 +1038,9 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
                 try{\r
                     nameService.delete(name, new NameDeletionConfigurator());\r
                 }catch (DataChangeNoRollbackException ex){\r
-                    if (logger.isDebugEnabled())logger.debug("Name wasn't deleted as it is referenced");\r
+                    if (logger.isDebugEnabled()) {\r
+                        logger.debug("Name wasn't deleted as it is referenced");\r
+                    }\r
                 }\r
             }\r
         }\r
@@ -810,6 +1050,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
     /* (non-Javadoc)\r
      * @see eu.etaxonomy.cdm.api.service.ITaxonService#findIdenticalTaxonNameIds(java.util.List)\r
      */\r
+    @Override\r
     public List<TaxonNameBase> findIdenticalTaxonNameIds(List<String> propertyPath) {\r
 \r
         return this.dao.findIdenticalNamesNew(propertyPath);\r
@@ -818,6 +1059,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
     /* (non-Javadoc)\r
      * @see eu.etaxonomy.cdm.api.service.ITaxonService#getPhylumName(eu.etaxonomy.cdm.model.name.TaxonNameBase)\r
      */\r
+    @Override\r
     public String getPhylumName(TaxonNameBase name){\r
         return this.dao.getPhylumName(name);\r
     }\r
@@ -825,6 +1067,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
     /* (non-Javadoc)\r
      * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteSynonymRelationships(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.Taxon)\r
      */\r
+    @Override\r
     public long deleteSynonymRelationships(Synonym syn, Taxon taxon) {\r
         return dao.deleteSynonymRelationships(syn, taxon);\r
     }\r
@@ -832,6 +1075,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
 /* (non-Javadoc)\r
      * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteSynonymRelationships(eu.etaxonomy.cdm.model.taxon.Synonym)\r
      */\r
+    @Override\r
     public long deleteSynonymRelationships(Synonym syn) {\r
         return dao.deleteSynonymRelationships(syn, null);\r
     }\r
@@ -840,6 +1084,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
     /* (non-Javadoc)\r
      * @see eu.etaxonomy.cdm.api.service.ITaxonService#listSynonymRelationships(eu.etaxonomy.cdm.model.taxon.TaxonBase, eu.etaxonomy.cdm.model.taxon.SynonymRelationshipType, java.lang.Integer, java.lang.Integer, java.util.List, java.util.List, eu.etaxonomy.cdm.model.common.RelationshipBase.Direction)\r
      */\r
+    @Override\r
     public List<SynonymRelationship> listSynonymRelationships(\r
             TaxonBase taxonBase, SynonymRelationshipType type, Integer pageSize, Integer pageNumber,\r
             List<OrderHint> orderHints, List<String> propertyPaths, Direction direction) {\r
@@ -1086,21 +1331,241 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
         return dao.getUuidAndTitleCacheSynonym();\r
     }\r
 \r
+    /* (non-Javadoc)\r
+     * @see eu.etaxonomy.cdm.api.service.ITaxonService#findByFullText(java.lang.Class, java.lang.String, eu.etaxonomy.cdm.model.taxon.Classification, java.util.List, boolean, java.lang.Integer, java.lang.Integer, java.util.List, java.util.List)\r
+     */\r
     @Override\r
-    public Pager<SearchResult<TaxonBase>> findByDescriptionElementFullText(Class<? extends DescriptionElementBase> clazz, String queryString, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints,\r
-            List<String> propertyPaths) throws CorruptIndexException, IOException, ParseException {\r
+    public Pager<SearchResult<TaxonBase>> findByFullText(\r
+            Class<? extends TaxonBase> clazz, String queryString,\r
+            Classification classification, List<Language> languages,\r
+            boolean highlightFragments, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) throws CorruptIndexException, IOException, ParseException {\r
+\r
+\r
+        LuceneSearch luceneSearch = prepareFindByFullTextSearch(clazz, queryString, classification, languages, highlightFragments);\r
+\r
+        // --- execute search\r
+        TopGroupsWithMaxScore topDocsResultSet = luceneSearch.executeSearch(pageSize, pageNumber);\r
+\r
+        Map<CdmBaseType, String> idFieldMap = new HashMap<CdmBaseType, String>();\r
+        idFieldMap.put(CdmBaseType.TAXON, "id");\r
+\r
+        // ---  initialize taxa, thighlight matches ....\r
+        ISearchResultBuilder searchResultBuilder = new SearchResultBuilder(luceneSearch, luceneSearch.getQuery());\r
+        List<SearchResult<TaxonBase>> searchResults = searchResultBuilder.createResultSet(\r
+                topDocsResultSet, luceneSearch.getHighlightFields(), dao, idFieldMap, propertyPaths);\r
+\r
+        int totalHits = topDocsResultSet != null ? topDocsResultSet.topGroups.totalGroupedHitCount : 0;\r
+        return new DefaultPagerImpl<SearchResult<TaxonBase>>(pageNumber, totalHits, pageSize, searchResults);\r
+    }\r
 \r
-        String luceneQueryTemplate = "titleCache:%1$s OR text.ALL:%1$s OR name:%1$s";\r
-        String luceneQuery = String.format(luceneQueryTemplate, queryString);\r
+    /**\r
+     * @param clazz\r
+     * @param queryString\r
+     * @param classification\r
+     * @param languages\r
+     * @param highlightFragments\r
+     * @param directorySelectClass\r
+     * @return\r
+     */\r
+    protected LuceneSearch prepareFindByFullTextSearch(Class<? extends CdmBase> clazz, String queryString, Classification classification, List<Language> languages,\r
+            boolean highlightFragments) {\r
+        BooleanQuery finalQuery = new BooleanQuery();\r
+        BooleanQuery textQuery = new BooleanQuery();\r
+\r
+        LuceneSearch luceneSearch = new LuceneSearch(getSession(), TaxonBase.class);\r
+        QueryFactory queryFactory = new QueryFactory(luceneSearch);\r
+\r
+        SortField[] sortFields = new  SortField[]{SortField.FIELD_SCORE, new SortField("titleCache__sort", false)};\r
+        luceneSearch.setSortFields(sortFields);\r
+\r
+        // ---- search criteria\r
+        luceneSearch.setClazz(clazz);\r
+\r
+        textQuery.add(queryFactory.newTermQuery("titleCache", queryString), Occur.SHOULD);\r
+        textQuery.add(queryFactory.newDefinedTermQuery("name.rank", queryString, languages), Occur.SHOULD);\r
 \r
-        LuceneSearch luceneSearch = new LuceneSearch(getSession(), clazz);\r
-        TopDocs topDocsResultSet = luceneSearch.executeSearch(luceneQuery);\r
-        List<SearchResult<TaxonBase>> searchResults = searchResultBuilder.createResultSetFromIds(luceneSearch, topDocsResultSet, dao, "inDescription.taxon.id");\r
+        finalQuery.add(textQuery, Occur.MUST);\r
 \r
-        return new DefaultPagerImpl<SearchResult<TaxonBase>>(pageNumber, searchResults.size(), pageSize, searchResults);\r
+        if(classification != null){\r
+            finalQuery.add(queryFactory.newEntityIdQuery("taxonNodes.classification.id", classification), Occur.MUST);\r
+        }\r
+        luceneSearch.setQuery(finalQuery);\r
 \r
+        if(highlightFragments){\r
+            luceneSearch.setHighlightFields(queryFactory.getTextFieldNamesAsArray());\r
+        }\r
+        return luceneSearch;\r
     }\r
 \r
+\r
+    /* (non-Javadoc)\r
+     * @see eu.etaxonomy.cdm.api.service.ITaxonService#findByDescriptionElementFullText(java.lang.Class, java.lang.String, eu.etaxonomy.cdm.model.taxon.Classification, java.util.List, java.util.List, boolean, java.lang.Integer, java.lang.Integer, java.util.List, java.util.List)\r
+     */\r
+    @Override\r
+    public Pager<SearchResult<TaxonBase>> findByDescriptionElementFullText(\r
+            Class<? extends DescriptionElementBase> clazz, String queryString,\r
+            Classification classification, List<Feature> features, List<Language> languages,\r
+            boolean highlightFragments, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) throws CorruptIndexException, IOException, ParseException {\r
+\r
+\r
+        LuceneSearch luceneSearch = prepareByDescriptionElementFullTextSearch(clazz, queryString, classification, features, languages, highlightFragments);\r
+\r
+        // --- execute search\r
+        TopGroupsWithMaxScore topDocsResultSet = luceneSearch.executeSearch(pageSize, pageNumber);\r
+\r
+        Map<CdmBaseType, String> idFieldMap = new HashMap<CdmBaseType, String>();\r
+        idFieldMap.put(CdmBaseType.DESCRIPTION_ELEMENT, "inDescription.taxon.id");\r
+\r
+        // --- initialize taxa, highlight matches ....\r
+        ISearchResultBuilder searchResultBuilder = new SearchResultBuilder(luceneSearch, luceneSearch.getQuery());\r
+        @SuppressWarnings("rawtypes")\r
+        List<SearchResult<TaxonBase>> searchResults = searchResultBuilder.createResultSet(\r
+                topDocsResultSet, luceneSearch.getHighlightFields(), dao, idFieldMap, propertyPaths);\r
+\r
+        int totalHits = topDocsResultSet != null ? topDocsResultSet.topGroups.totalGroupCount : 0;\r
+        return new DefaultPagerImpl<SearchResult<TaxonBase>>(pageNumber, totalHits, pageSize, searchResults);\r
+\r
+    }\r
+\r
+\r
+    @Override\r
+    public Pager<SearchResult<TaxonBase>> findByEverythingFullText(String queryString,\r
+            Classification classification, List<Language> languages, boolean highlightFragments,\r
+            Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) throws CorruptIndexException, IOException, ParseException {\r
+\r
+        LuceneSearch luceneSearchByDescriptionElement = prepareByDescriptionElementFullTextSearch(null, queryString, classification, null, languages, highlightFragments);\r
+        LuceneSearch luceneSearchByTaxonBase = prepareFindByFullTextSearch(null, queryString, classification, languages, highlightFragments);\r
+\r
+        LuceneMultiSearch multiSearch = new LuceneMultiSearch(luceneSearchByDescriptionElement, luceneSearchByTaxonBase);\r
+\r
+        // --- execute search\r
+        TopGroupsWithMaxScore topDocsResultSet = multiSearch.executeSearch(pageSize, pageNumber);\r
+\r
+        // --- initialize taxa, highlight matches ....\r
+        ISearchResultBuilder searchResultBuilder = new SearchResultBuilder(multiSearch, multiSearch.getQuery());\r
+\r
+        Map<CdmBaseType, String> idFieldMap = new HashMap<CdmBaseType, String>();\r
+        idFieldMap.put(CdmBaseType.TAXON, "id");\r
+        idFieldMap.put(CdmBaseType.DESCRIPTION_ELEMENT, "inDescription.taxon.id");\r
+\r
+        List<SearchResult<TaxonBase>> searchResults = searchResultBuilder.createResultSet(\r
+                topDocsResultSet, multiSearch.getHighlightFields(), dao, idFieldMap, propertyPaths);\r
+\r
+        int totalHits = topDocsResultSet != null ? topDocsResultSet.topGroups.totalGroupedHitCount : 0;\r
+        return new DefaultPagerImpl<SearchResult<TaxonBase>>(pageNumber, totalHits, pageSize, searchResults);\r
+\r
+    }\r
+\r
+\r
+    /**\r
+     * @param clazz\r
+     * @param queryString\r
+     * @param classification\r
+     * @param features\r
+     * @param languages\r
+     * @param highlightFragments\r
+     * @param directorySelectClass\r
+     * @return\r
+     */\r
+    protected LuceneSearch prepareByDescriptionElementFullTextSearch(Class<? extends CdmBase> clazz, String queryString, Classification classification, List<Feature> features,\r
+            List<Language> languages, boolean highlightFragments) {\r
+        BooleanQuery finalQuery = new BooleanQuery();\r
+        BooleanQuery textQuery = new BooleanQuery();\r
+\r
+        LuceneSearch luceneSearch = new LuceneSearch(getSession(), DescriptionElementBase.class);\r
+        QueryFactory queryFactory = new QueryFactory(luceneSearch);\r
+\r
+        SortField[] sortFields = new  SortField[]{SortField.FIELD_SCORE, new SortField("inDescription.taxon.titleCache__sort", false)};\r
+        luceneSearch.setSortFields(sortFields);\r
+\r
+        // ---- search criteria\r
+        luceneSearch.setClazz(clazz);\r
+        textQuery.add(queryFactory.newTermQuery("titleCache", queryString), Occur.SHOULD);\r
+\r
+        // common name\r
+        Query nameQuery;\r
+        if(languages == null || languages.size() == 0){\r
+            nameQuery = queryFactory.newTermQuery("name", queryString);\r
+        } else {\r
+            nameQuery = new BooleanQuery();\r
+            BooleanQuery languageSubQuery = new BooleanQuery();\r
+            for(Language lang : languages){\r
+                languageSubQuery.add(queryFactory.newTermQuery("language.uuid",  lang.getUuid().toString()), Occur.SHOULD);\r
+            }\r
+            ((BooleanQuery) nameQuery).add(queryFactory.newTermQuery("name", queryString), Occur.MUST);\r
+            ((BooleanQuery) nameQuery).add(languageSubQuery, Occur.MUST);\r
+        }\r
+        textQuery.add(nameQuery, Occur.SHOULD);\r
+\r
+\r
+        // text field from TextData\r
+        textQuery.add(queryFactory.newMultilanguageTextQuery("text", queryString, languages), Occur.SHOULD);\r
+\r
+        // --- TermBase fields - by representation ----\r
+        // state field from CategoricalData\r
+        textQuery.add(queryFactory.newDefinedTermQuery("states.state", queryString, languages), Occur.SHOULD);\r
+\r
+        // state field from CategoricalData\r
+        textQuery.add(queryFactory.newDefinedTermQuery("states.modifyingText", queryString, languages), Occur.SHOULD);\r
+\r
+        // area field from Distribution\r
+        textQuery.add(queryFactory.newDefinedTermQuery("area", queryString, languages), Occur.SHOULD);\r
+\r
+        // status field from Distribution\r
+        textQuery.add(queryFactory.newDefinedTermQuery("status", queryString, languages), Occur.SHOULD);\r
+\r
+        finalQuery.add(textQuery, Occur.MUST);\r
+        // --- classification ----\r
+\r
+        if(classification != null){\r
+            finalQuery.add(queryFactory.newEntityIdQuery("inDescription.taxon.taxonNodes.classification.id", classification), Occur.MUST);\r
+        }\r
+\r
+        // --- IdentifieableEntity fields - by uuid\r
+        if(features != null && features.size() > 0 ){\r
+            finalQuery.add(queryFactory.newEntityUuidQuery("feature.uuid", features), Occur.MUST);\r
+        }\r
+\r
+        // the description must be associated with a taxon\r
+        finalQuery.add(queryFactory.newIsNotNullQuery("inDescription.taxon.id"), Occur.MUST);\r
+\r
+        luceneSearch.setQuery(finalQuery);\r
+\r
+        if(highlightFragments){\r
+            luceneSearch.setHighlightFields(queryFactory.getTextFieldNamesAsArray());\r
+        }\r
+        return luceneSearch;\r
+    }\r
+\r
+    /**\r
+     * DefinedTerm representations and MultilanguageString maps are stored in the Lucene index by the {@link DefinedTermBaseClassBridge}\r
+     * and {@link MultilanguageTextFieldBridge } in a consistent way. One field per language and also in one additional field for all languages.\r
+     * This method is a convenient means to retrieve a Lucene query string for such the fields.\r
+     *\r
+     * @param name name of the term field as in the Lucene index. Must be field created by {@link DefinedTermBaseClassBridge}\r
+     * or {@link MultilanguageTextFieldBridge }\r
+     * @param languages the languages to search for exclusively. Can be <code>null</code> to search in all languages\r
+     * @param stringBuilder a StringBuilder to be reused, if <code>null</code> a new StringBuilder will be instantiated and is returned\r
+     * @return the StringBuilder given a parameter or a new one if the stringBuilder parameter was null.\r
+     *\r
+     * TODO move to utiliy class !!!!!!!!\r
+     */\r
+    private StringBuilder appendLocalizedFieldQuery(String name, List<Language> languages, StringBuilder stringBuilder) {\r
+\r
+        if(stringBuilder == null){\r
+            stringBuilder = new StringBuilder();\r
+        }\r
+        if(languages == null || languages.size() == 0){\r
+            stringBuilder.append(name + ".ALL:(%1$s) ");\r
+        } else {\r
+            for(Language lang : languages){\r
+                stringBuilder.append(name + "." + lang.getUuid().toString() + ":(%1$s) ");\r
+            }\r
+        }\r
+        return stringBuilder;\r
+    }\r
+\r
+    @Override\r
     public List<Synonym> createInferredSynonyms(Taxon taxon, Classification classification, SynonymRelationshipType type, boolean doWithMisappliedNames){\r
         List <Synonym> inferredSynonyms = new ArrayList<Synonym>();\r
         List<Synonym> inferredSynonymsToBeRemoved = new ArrayList<Synonym>();\r
@@ -1130,7 +1595,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
 \r
             if (node.getClassification().equals(classification)){\r
                 if (!node.isTopmostNode()){\r
-                    TaxonNode parent = (TaxonNode)node.getParent();\r
+                    TaxonNode parent = node.getParent();\r
                     parent = (TaxonNode)HibernateProxyHelper.deproxy(parent);\r
                     TaxonNameBase parentName =  parent.getTaxon().getName();\r
                     ZoologicalName zooParentName = HibernateProxyHelper.deproxy(parentName, ZoologicalName.class);\r
@@ -1419,8 +1884,15 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
 \r
         // Set sourceReference\r
         sourceReference = syn.getSec();\r
+        if (sourceReference == null){\r
+            logger.warn("The synonym has no sec reference because it is a misapplied name! Take the sec reference of taxon");\r
+            //TODO:Remove\r
+            if (!parentSynZooName.getTaxa().isEmpty()){\r
+                TaxonBase taxon = parentSynZooName.getTaxa().iterator().next();\r
 \r
-\r
+                sourceReference = taxon.getSec();\r
+            }\r
+        }\r
         String synTaxonSpecificEpithet = zooSynName.getSpecificEpithet();\r
 \r
         String synTaxonInfraSpecificName= null;\r
@@ -1491,6 +1963,8 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
         // Determine the sourceReference\r
         Reference sourceReference = syn.getSec();\r
 \r
+        //logger.warn(sourceReference.getTitleCache());\r
+\r
         synName = syn.getName();\r
         ZoologicalName synZooName = getZoologicalName(synName.getUuid(), zooHashMap);\r
         String synSpeciesEpithetName = synZooName.getSpecificEpithet();\r
@@ -1528,7 +2002,16 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
 \r
             originalSource = IdentifiableSource.NewInstance(idInSourceSyn + "; " + idInSourceTaxon, INFERRED_GENUS_NAMESPACE, sourceReference, null);\r
             inferredSynName.addSource(originalSource);\r
+            originalSource = null;\r
 \r
+        }else{\r
+            logger.error("There is an idInSource missing: " + idInSourceSyn + " of Synonym or " + idInSourceTaxon + " of Taxon");\r
+            IdentifiableSource originalSource = IdentifiableSource.NewInstance(idInSourceSyn + "; " + idInSourceTaxon, INFERRED_GENUS_NAMESPACE, sourceReference, null);\r
+            inferredGenus.addSource(originalSource);\r
+\r
+            originalSource = IdentifiableSource.NewInstance(idInSourceSyn + "; " + idInSourceTaxon, INFERRED_GENUS_NAMESPACE, sourceReference, null);\r
+            inferredSynName.addSource(originalSource);\r
+            originalSource = null;\r
         }\r
 \r
         taxon.addSynonym(inferredGenus, SynonymRelationshipType.INFERRED_GENUS_OF());\r
@@ -1556,6 +2039,13 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
         // Determine the sourceReference\r
         Reference sourceReference = syn.getSec();\r
 \r
+        if (sourceReference == null){\r
+            logger.warn("The synonym has no sec reference because it is a misapplied name! Take the sec reference of taxon");\r
+            //TODO:Remove\r
+            System.out.println("The synonym has no sec reference because it is a misapplied name! Take the sec reference of taxon" + taxon.getSec());\r
+            sourceReference = taxon.getSec();\r
+        }\r
+\r
         synName = syn.getName();\r
         ZoologicalName zooSynName = getZoologicalName(synName.getUuid(), zooHashMap);\r
         String synGenusName = zooSynName.getGenusOrUninomial();\r
@@ -1664,8 +2154,11 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
                 }\r
                 count++;\r
             }\r
+        } else if (sources.size() == 0){\r
+            logger.warn("No idInSource for TaxonBase " + taxonBase.getUuid() + " - " + taxonBase.getTitleCache());\r
         }\r
 \r
+\r
         return idInSource;\r
     }\r
 \r
@@ -1689,6 +2182,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
         return citation;\r
     }\r
 \r
+    @Override\r
     public List<Synonym>  createAllInferredSynonyms(Taxon taxon, Classification tree, boolean doWithMisappliedNames){\r
         List <Synonym> inferredSynonyms = new ArrayList<Synonym>();\r
 \r
@@ -1699,6 +2193,39 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
         return inferredSynonyms;\r
     }\r
 \r
+    /* (non-Javadoc)\r
+     * @see eu.etaxonomy.cdm.api.service.ITaxonService#listClassifications(eu.etaxonomy.cdm.model.taxon.TaxonBase, java.lang.Integer, java.lang.Integer, java.util.List)\r
+     */\r
+    @Override\r
+    public List<Classification> listClassifications(TaxonBase taxonBase, Integer limit, Integer start, List<String> propertyPaths) {\r
+\r
+        // TODO quickly implemented, create according dao !!!!\r
+        Set<TaxonNode> nodes = new HashSet<TaxonNode>();\r
+        Set<Classification> classifications = new HashSet<Classification>();\r
+        List<Classification> list = new ArrayList<Classification>();\r
+\r
+        if (taxonBase == null) {\r
+            return list;\r
+        }\r
+\r
+        taxonBase = load(taxonBase.getUuid());\r
+\r
+        if (taxonBase instanceof Taxon) {\r
+            nodes.addAll(((Taxon)taxonBase).getTaxonNodes());\r
+        } else {\r
+            for (Taxon taxon : ((Synonym)taxonBase).getAcceptedTaxa() ) {\r
+                nodes.addAll(taxon.getTaxonNodes());\r
+            }\r
+        }\r
+        for (TaxonNode node : nodes) {\r
+            classifications.add(node.getClassification());\r
+        }\r
+        list.addAll(classifications);\r
+        return list;\r
+    }\r
+\r
+\r
+\r
 \r
 \r
 \r