solving lazy loading exception
[cdmlib.git] / cdmlib-services / src / main / java / eu / etaxonomy / cdm / api / service / TaxonServiceImpl.java
index 5adae4ca08a9d39afa5492124289528bfa50ba18..c36c1b6b19fda7d0bb50773ef9caecc4ebc5f26b 100644 (file)
@@ -15,19 +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.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
@@ -37,32 +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.DescriptionElementSource;\r
-import eu.etaxonomy.cdm.model.common.IOriginalSource;\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.Rank;\r
 import eu.etaxonomy.cdm.model.name.TaxonNameBase;\r
 import eu.etaxonomy.cdm.model.name.ZoologicalName;\r
-import eu.etaxonomy.cdm.model.reference.IDatabase;\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
@@ -73,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
@@ -93,44 +112,48 @@ import eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy;
 @Service\r
 @Transactional(propagation = Propagation.SUPPORTS, readOnly = true)\r
 public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDao> implements ITaxonService{\r
-       private static final Logger logger = Logger.getLogger(TaxonServiceImpl.class);\r
+    private static final Logger logger = Logger.getLogger(TaxonServiceImpl.class);\r
 \r
-       public static final String POTENTIAL_COMBINATION_NAMESPACE = "Potential combination";\r
+    public static final String POTENTIAL_COMBINATION_NAMESPACE = "Potential combination";\r
 \r
-       public static final String INFERRED_EPITHET_NAMESPACE = "Inferred epithet";\r
+    public static final String INFERRED_EPITHET_NAMESPACE = "Inferred epithet";\r
 \r
-       public static final String INFERRED_GENUS_NAMESPACE = "Inferred genus";\r
+    public static final String INFERRED_GENUS_NAMESPACE = "Inferred genus";\r
 \r
 \r
     @Autowired\r
     private ITaxonNameDao nameDao;\r
 \r
     @Autowired\r
-    private ISearchResultBuilder searchResultBuilder;\r
+    private INameService nameService;\r
 \r
-       @Autowired\r
-       private INameService nameService;\r
-\r
-       @Autowired\r
-       private ICdmGenericDao genericDao;\r
+    @Autowired\r
+    private ICdmGenericDao genericDao;\r
 \r
-       @Autowired\r
-       private IDescriptionService descriptionService;\r
+    @Autowired\r
+    private IDescriptionService descriptionService;\r
 \r
     @Autowired\r
     private IOrderedTermVocabularyDao orderedVocabularyDao;\r
-       \r
-       /**\r
-        * Constructor\r
-        */\r
-       public TaxonServiceImpl(){\r
-               if (logger.isDebugEnabled()) { logger.debug("Load TaxonService Bean"); }\r
-       }\r
+\r
+    @Autowired\r
+    private IOccurrenceDao occurrenceDao;\r
+\r
+    @Autowired\r
+    private AbstractBeanInitializer beanInitializer;\r
+\r
+    /**\r
+     * Constructor\r
+     */\r
+    public TaxonServiceImpl(){\r
+        if (logger.isDebugEnabled()) { logger.debug("Load TaxonService Bean"); }\r
+    }\r
 \r
     /**\r
      * 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
@@ -141,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
@@ -151,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
@@ -161,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
@@ -172,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
@@ -179,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
@@ -187,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
@@ -203,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
@@ -269,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
@@ -359,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
@@ -366,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
@@ -374,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
@@ -388,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
@@ -402,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
@@ -415,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
@@ -428,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
@@ -441,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
@@ -451,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
@@ -468,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
@@ -482,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
@@ -490,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
@@ -500,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
@@ -524,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
@@ -616,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
@@ -634,126 +756,248 @@ 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
 \r
     /* (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
 \r
-   \r
 \r
-    \r
+\r
+\r
     /* (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
 \r
-    \r
-       /* (non-Javadoc)\r
+\r
+    /* (non-Javadoc)\r
      * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteTaxon(eu.etaxonomy.cdm.model.taxon.Taxon, eu.etaxonomy.cdm.api.service.config.TaxonDeletionConfigurator)\r
      */\r
     @Override\r
     public void deleteTaxon(Taxon taxon, TaxonDeletionConfigurator config) throws ReferencedObjectUndeletableException {\r
-       if (config == null){\r
-               config = new TaxonDeletionConfigurator();\r
-       }\r
-       \r
-                       //      TaxonNode\r
-                       if (! config.isDeleteTaxonNodes()){\r
-                               if (taxon.getTaxonNodes().size() > 0){\r
-                                       String message = "Taxon can't be deleted as it is used in a classification node. Remove taxon from all classifications prior to deletion.";\r
-                                       throw new ReferencedObjectUndeletableException(message);\r
-                               }\r
-                       }\r
-       \r
-                       \r
-                       //      SynonymRelationShip\r
-                       if (config.isDeleteSynonymRelations()){\r
-                               boolean removeSynonymNameFromHomotypicalGroup = false;\r
-                               for (SynonymRelationship synRel : taxon.getSynonymRelations()){\r
-                                       Synonym synonym = synRel.getSynonym();\r
-                                       taxon.removeSynonymRelation(synRel, removeSynonymNameFromHomotypicalGroup);\r
-                                       if (config.isDeleteSynonymsIfPossible()){\r
-                                               //TODO which value\r
-                                               boolean newHomotypicGroupIfNeeded = true;\r
-                                               deleteSynonym(synonym, taxon, config.isDeleteNameIfPossible(), newHomotypicGroupIfNeeded);\r
-                                       }else{\r
-                                               deleteSynonymRelationships(synonym, taxon);\r
-                                       }\r
-                               }\r
-                       }\r
-       \r
-                       //      TaxonRelationship       \r
-                       if (! config.isDeleteTaxonRelationships()){\r
-                               if (taxon.getTaxonRelations().size() > 0){\r
-                                       String message = "Taxon can't be deleted as it is related to another taxon. Remove taxon from all relations to other taxa prior to deletion.";\r
-                                       throw new ReferencedObjectUndeletableException(message);\r
-                               }\r
-                       }\r
-       \r
-                       \r
-                       //      TaxonDescription\r
-                               Set<TaxonDescription> descriptions = taxon.getDescriptions();\r
-                               \r
-                               for (TaxonDescription desc: descriptions){\r
-                                       if (config.isDeleteDescriptions()){\r
-                                               //TODO use description delete configurator ?\r
-                                               //FIXME check if description is ALWAYS deletable\r
-                                               descriptionService.delete(desc); \r
-                                       }else{\r
-                                               if (desc.getDescribedSpecimenOrObservations().size()>0){\r
-                                                       String message = "Taxon can't be deleted as it is used in a TaxonDescription" +\r
-                                                                       " which also describes specimens or abservations";\r
-                                                       throw new ReferencedObjectUndeletableException(message);\r
-                                               }\r
-                                       }\r
-                               }\r
-        \r
-                       \r
-                       //check references with only reverse mapping\r
-                       Set<CdmBase> referencingObjects = genericDao.getReferencingObjects(taxon);\r
-                       for (CdmBase referencingObject : referencingObjects){\r
-                               //IIdentificationKeys (Media, Polytomous, MultiAccess)\r
-                               if (HibernateProxyHelper.isInstanceOf(referencingObject, IIdentificationKey.class)){\r
-                                       String message = "Taxon can't be deleted as it is used in an identification key. Remove from identification key prior to deleting this name";\r
-                                       message = String.format(message, CdmBase.deproxy(referencingObject, DerivedUnitBase.class).getTitleCache());\r
-                                       throw new ReferencedObjectUndeletableException(message);\r
-                               }\r
-       \r
-                               \r
-                               //PolytomousKeyNode\r
-                               if (referencingObject.isInstanceOf(PolytomousKeyNode.class)){\r
-                                       String message = "Taxon can't be deleted as it is used in polytomous key node";\r
-                                       throw new ReferencedObjectUndeletableException(message);\r
-                               }\r
-                               \r
-                               //TaxonInteraction\r
-                               if (referencingObject.isInstanceOf(TaxonInteraction.class)){\r
-                                       String message = "Taxon can't be deleted as it is used in taxonInteraction#taxon2";\r
-                                       throw new ReferencedObjectUndeletableException(message);\r
-                               }\r
-                       }\r
-                       \r
-                       \r
-                       //TaxonNameBase\r
-                       if (config.isDeleteNameIfPossible()){\r
-                       try {\r
-                                       nameService.delete(taxon.getName(), config.getNameDeletionConfig());\r
-                               } catch (ReferencedObjectUndeletableException e) {\r
-                                       //do nothing\r
-                                       if (logger.isDebugEnabled()){logger.debug("Name could not be deleted");}\r
-                               }\r
-                       }\r
+        if (config == null){\r
+            config = new TaxonDeletionConfigurator();\r
+        }\r
+\r
+            //         TaxonNode\r
+            if (! config.isDeleteTaxonNodes()){\r
+                if (taxon.getTaxonNodes().size() > 0){\r
+                    String message = "Taxon can't be deleted as it is used in a classification node. Remove taxon from all classifications prior to deletion.";\r
+                    throw new ReferencedObjectUndeletableException(message);\r
+                }\r
+            }\r
+\r
+\r
+            //         SynonymRelationShip\r
+            if (config.isDeleteSynonymRelations()){\r
+                boolean removeSynonymNameFromHomotypicalGroup = false;\r
+                for (SynonymRelationship synRel : taxon.getSynonymRelations()){\r
+                    Synonym synonym = synRel.getSynonym();\r
+                    taxon.removeSynonymRelation(synRel, removeSynonymNameFromHomotypicalGroup);\r
+                    if (config.isDeleteSynonymsIfPossible()){\r
+                        //TODO which value\r
+                        boolean newHomotypicGroupIfNeeded = true;\r
+                        deleteSynonym(synonym, taxon, config.isDeleteNameIfPossible(), newHomotypicGroupIfNeeded);\r
+                    }else{\r
+                        deleteSynonymRelationships(synonym, taxon);\r
+                    }\r
+                }\r
+            }\r
+\r
+            //         TaxonRelationship\r
+            if (! config.isDeleteTaxonRelationships()){\r
+                if (taxon.getTaxonRelations().size() > 0){\r
+                    String message = "Taxon can't be deleted as it is related to another taxon. Remove taxon from all relations to other taxa prior to deletion.";\r
+                    throw new ReferencedObjectUndeletableException(message);\r
+                }\r
+            }\r
+\r
+\r
+            //         TaxonDescription\r
+                    Set<TaxonDescription> descriptions = taxon.getDescriptions();\r
+\r
+                    for (TaxonDescription desc: descriptions){\r
+                        if (config.isDeleteDescriptions()){\r
+                            //TODO use description delete configurator ?\r
+                            //FIXME check if description is ALWAYS deletable\r
+                            descriptionService.delete(desc);\r
+                        }else{\r
+                            if (desc.getDescribedSpecimenOrObservations().size()>0){\r
+                                String message = "Taxon can't be deleted as it is used in a TaxonDescription" +\r
+                                        " which also describes specimens or abservations";\r
+                                    throw new ReferencedObjectUndeletableException(message);\r
+                                }\r
+                            }\r
+                        }\r
+\r
+\r
+                //check references with only reverse mapping\r
+            Set<CdmBase> referencingObjects = genericDao.getReferencingObjects(taxon);\r
+            for (CdmBase referencingObject : referencingObjects){\r
+                //IIdentificationKeys (Media, Polytomous, MultiAccess)\r
+                if (HibernateProxyHelper.isInstanceOf(referencingObject, IIdentificationKey.class)){\r
+                    String message = "Taxon can't be deleted as it is used in an identification key. Remove from identification key prior to deleting this name";\r
+                    message = String.format(message, CdmBase.deproxy(referencingObject, DerivedUnitBase.class).getTitleCache());\r
+                    throw new ReferencedObjectUndeletableException(message);\r
+                }\r
+\r
+\r
+                //PolytomousKeyNode\r
+                if (referencingObject.isInstanceOf(PolytomousKeyNode.class)){\r
+                    String message = "Taxon can't be deleted as it is used in polytomous key node";\r
+                    throw new ReferencedObjectUndeletableException(message);\r
+                }\r
+\r
+                //TaxonInteraction\r
+                if (referencingObject.isInstanceOf(TaxonInteraction.class)){\r
+                    String message = "Taxon can't be deleted as it is used in taxonInteraction#taxon2";\r
+                    throw new ReferencedObjectUndeletableException(message);\r
+                }\r
+            }\r
+\r
+\r
+            //TaxonNameBase\r
+            if (config.isDeleteNameIfPossible()){\r
+                try {\r
+                    nameService.delete(taxon.getName(), config.getNameDeletionConfig());\r
+                } catch (ReferencedObjectUndeletableException e) {\r
+                    //do nothing\r
+                    if (logger.isDebugEnabled()){logger.debug("Name could not be deleted");}\r
+                }\r
+            }\r
 \r
     }\r
 \r
@@ -794,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
@@ -804,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
@@ -812,20 +1059,23 @@ 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
 \r
-       /* (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
-       public long deleteSynonymRelationships(Synonym syn, Taxon taxon) {\r
-               return dao.deleteSynonymRelationships(syn, taxon);\r
-       }\r
+    /* (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
 \r
 /* (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
@@ -834,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
@@ -1080,38 +1331,259 @@ 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
+    /**\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
+        finalQuery.add(textQuery, Occur.MUST);\r
+\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
-        String luceneQueryTemplate = "titleCache:%1$s OR multilanguageText.text:%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 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
-        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
+        // --- TermBase fields - by representation ----\r
+        // state field from CategoricalData\r
+        textQuery.add(queryFactory.newDefinedTermQuery("states.state", queryString, languages), Occur.SHOULD);\r
 \r
-        return new DefaultPagerImpl<SearchResult<TaxonBase>>(pageNumber, searchResults.size(), pageSize, searchResults);\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
-    public List<Synonym> createInferredSynonyms(Taxon taxon, Classification classification, SynonymRelationshipType type){\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
 \r
         HashMap <UUID, ZoologicalName> zooHashMap = new HashMap<UUID, ZoologicalName>();\r
-        \r
+\r
+\r
         UUID uuid= taxon.getName().getUuid();\r
         ZoologicalName taxonName = getZoologicalName(uuid, zooHashMap);\r
         String epithetOfTaxon = null;\r
         String infragenericEpithetOfTaxon = null;\r
         String infraspecificEpithetOfTaxon = null;\r
         if (taxonName.isSpecies()){\r
-                epithetOfTaxon= taxonName.getSpecificEpithet();\r
+             epithetOfTaxon= taxonName.getSpecificEpithet();\r
         } else if (taxonName.isInfraGeneric()){\r
-               infragenericEpithetOfTaxon = taxonName.getInfraGenericEpithet();\r
+            infragenericEpithetOfTaxon = taxonName.getInfraGenericEpithet();\r
         } else if (taxonName.isInfraSpecific()){\r
-               infraspecificEpithetOfTaxon = taxonName.getInfraSpecificEpithet();\r
+            infraspecificEpithetOfTaxon = taxonName.getInfraSpecificEpithet();\r
         }\r
         String genusOfTaxon = taxonName.getGenusOrUninomial();\r
         Set<TaxonNode> nodes = taxon.getTaxonNodes();\r
@@ -1123,132 +1595,93 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
 \r
             if (node.getClassification().equals(classification)){\r
                 if (!node.isTopmostNode()){\r
-                       TaxonNode parent = (TaxonNode)node.getParent();\r
-                       parent = (TaxonNode)HibernateProxyHelper.deproxy(parent);\r
-                       TaxonNameBase parentName =  parent.getTaxon().getName();\r
-                       ZoologicalName zooParentName = HibernateProxyHelper.deproxy(parentName, ZoologicalName.class);\r
-                       Taxon parentTaxon = (Taxon)HibernateProxyHelper.deproxy(parent.getTaxon());\r
-                       Rank rankOfTaxon = taxonName.getRank();\r
-                       \r
-       \r
-                       //create inferred synonyms for species, subspecies or subgenus\r
-                       if (parentName.isGenus() || parentName.isSpecies() || parentName.getRank().equals(Rank.SUBGENUS())){\r
-       \r
-                           Synonym inferredEpithet;\r
-                           Synonym inferredGenus = null;\r
-                           Synonym potentialCombination;\r
-       \r
-                           List<String> propertyPaths = new ArrayList<String>();\r
-                           propertyPaths.add("synonym");\r
-                           propertyPaths.add("synonym.name");\r
-                           List<OrderHint> orderHints = new ArrayList<OrderHint>();\r
-                           orderHints.add(new OrderHint("relatedFrom.titleCache", SortOrder.ASCENDING));\r
-       \r
-                           List<SynonymRelationship> synonymRelationshipsOfGenus = dao.getSynonyms(parentTaxon, SynonymRelationshipType.HETEROTYPIC_SYNONYM_OF(), null, null,orderHints,propertyPaths);\r
-                           List<SynonymRelationship> synonymRelationshipsOfTaxon= dao.getSynonyms(taxon, SynonymRelationshipType.HETEROTYPIC_SYNONYM_OF(), null, null,orderHints,propertyPaths);\r
-       \r
-                           if (type.equals(SynonymRelationshipType.INFERRED_EPITHET_OF())){\r
-       \r
-                               for (SynonymRelationship synonymRelationOfGenus:synonymRelationshipsOfGenus){\r
-                                   TaxonNameBase synName;\r
-                                   ZoologicalName inferredSynName;\r
-                                   Synonym syn = synonymRelationOfGenus.getSynonym();\r
-                                   HibernateProxyHelper.deproxy(syn);\r
-       \r
-                                   // Determine the idInSource\r
-                                   String idInSourceSyn = getIdInSource(syn);\r
-                                   String idInSourceTaxon =  getIdInSource(taxon);\r
-                                   // Determine the sourceReference\r
-                                   Reference sourceReference = syn.getSec();\r
-       \r
-                                   synName = syn.getName();\r
-                                   ZoologicalName zooName = getZoologicalName(synName.getUuid(), zooHashMap);\r
-                                   String synGenusName = zooName.getGenusOrUninomial();\r
-                                   String synInfraGenericEpithet = null;\r
-                                   String synSpecificEpithet = null;\r
-                                   if (zooName.isInfraGeneric()){\r
-                                       synInfraGenericEpithet = zooName.getInfraGenericEpithet();\r
-                                   } else if (zooName.isSpecies()){\r
-                                       synSpecificEpithet = zooName.getSpecificEpithet();\r
-                                   }\r
-                                   \r
-                                  /* if (synGenusName != null && !synonymsGenus.containsKey(synGenusName)){\r
-                                       synonymsGenus.put(synGenusName, idInSource);\r
-                                   }*/\r
-                                   \r
-                                   inferredSynName = ZoologicalName.NewInstance(rankOfTaxon);\r
-       \r
-                                   // DEBUG TODO: for subgenus or subspecies the infrageneric or infraspecific epithet should be used!!!\r
-                                   if (epithetOfTaxon == null && infragenericEpithetOfTaxon == null && infraspecificEpithetOfTaxon == null) {\r
-                                       logger.error("This specificEpithet is NULL" + taxon.getTitleCache());\r
-                                   }\r
-                                   inferredSynName.setGenusOrUninomial(synGenusName);\r
-                                   if (inferredSynName.isSpecies()){\r
-                                       if (parentName.isInfraGeneric()){\r
-                                               inferredSynName.setInfraGenericEpithet(synInfraGenericEpithet);\r
-                                       }\r
-                                       inferredSynName.setSpecificEpithet(epithetOfTaxon);\r
-                                   } else if (inferredSynName.isInfraGeneric()) {\r
-                                       inferredSynName.setInfraGenericEpithet(infragenericEpithetOfTaxon);\r
-                                   } else if (inferredSynName.isInfraSpecific()){\r
-                                       inferredSynName.setSpecificEpithet(synSpecificEpithet);\r
-                                       inferredSynName.setInfraSpecificEpithet(infraspecificEpithetOfTaxon);\r
-                                   }\r
-                                   \r
-                                   inferredEpithet = Synonym.NewInstance(inferredSynName, null);\r
-                                   \r
-                                   // Set the sourceReference\r
-                                   inferredEpithet.setSec(sourceReference);\r
-       \r
-                                   /* Add the original source\r
-                                   if (idInSource != null) {\r
-                                       IdentifiableSource originalSource = IdentifiableSource.NewInstance(idInSource, "InferredEpithetOf", syn.getSec(), null);\r
-       \r
-                                       // Add the citation\r
-                                       Reference citation = getCitation(syn);\r
-                                       if (citation != null) {\r
-                                           originalSource.setCitation(citation);\r
-                                           inferredEpithet.addSource(originalSource);\r
-                                       }\r
-                                   }*/\r
-                                   String taxonId = idInSourceTaxon+ "; " + idInSourceSyn;\r
-                                  \r
-                                   IdentifiableSource originalSource;\r
-                                       originalSource = IdentifiableSource.NewInstance(taxonId, INFERRED_EPITHET_NAMESPACE, sourceReference, null);\r
-                                       \r
-                                       inferredEpithet.addSource(originalSource);\r
-                                   \r
-                                       originalSource = IdentifiableSource.NewInstance(taxonId, INFERRED_EPITHET_NAMESPACE, sourceReference, null);\r
-                                       \r
-                                       inferredSynName.addSource(originalSource);\r
-                                   \r
-                                                       \r
-                                   \r
-                                   taxon.addSynonym(inferredEpithet, SynonymRelationshipType.INFERRED_EPITHET_OF());\r
-                                   inferredSynonyms.add(inferredEpithet);\r
-                                   inferredSynName.generateTitle();\r
-                                   zooHashMap.put(inferredSynName.getUuid(), inferredSynName);\r
-                                   taxonNames.add(inferredSynName.getNameCache());\r
-                               }\r
-       \r
-                               if (!taxonNames.isEmpty()){\r
-                               List<String> synNotInCDM = dao.taxaByNameNotInDB(taxonNames);\r
-                               ZoologicalName name;\r
-                               if (!synNotInCDM.isEmpty()){\r
-                                   inferredSynonymsToBeRemoved.clear();\r
-       \r
-                                   for (Synonym syn :inferredSynonyms){\r
-                                       name = getZoologicalName(syn.getName().getUuid(), zooHashMap);\r
-                                       if (!synNotInCDM.contains(name.getNameCache())){\r
-                                           inferredSynonymsToBeRemoved.add(syn);\r
-                                       }\r
-                                   }\r
-       \r
-                                   // Remove identified Synonyms from inferredSynonyms\r
-                                   for (Synonym synonym : inferredSynonymsToBeRemoved) {\r
-                                       inferredSynonyms.remove(synonym);\r
-                                   }\r
-                               }\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
+                    Taxon parentTaxon = (Taxon)HibernateProxyHelper.deproxy(parent.getTaxon());\r
+                    Rank rankOfTaxon = taxonName.getRank();\r
+\r
+\r
+                    //create inferred synonyms for species, subspecies\r
+                    if ((parentName.isGenus() || parentName.isSpecies() || parentName.getRank().equals(Rank.SUBGENUS())) ){\r
+\r
+                        Synonym inferredEpithet = null;\r
+                        Synonym inferredGenus = null;\r
+                        Synonym potentialCombination = null;\r
+\r
+                        List<String> propertyPaths = new ArrayList<String>();\r
+                        propertyPaths.add("synonym");\r
+                        propertyPaths.add("synonym.name");\r
+                        List<OrderHint> orderHints = new ArrayList<OrderHint>();\r
+                        orderHints.add(new OrderHint("relatedFrom.titleCache", SortOrder.ASCENDING));\r
+\r
+                        List<SynonymRelationship> synonymRelationshipsOfParent = dao.getSynonyms(parentTaxon, SynonymRelationshipType.HETEROTYPIC_SYNONYM_OF(), null, null,orderHints,propertyPaths);\r
+                        List<SynonymRelationship> synonymRelationshipsOfTaxon= dao.getSynonyms(taxon, SynonymRelationshipType.HETEROTYPIC_SYNONYM_OF(), null, null,orderHints,propertyPaths);\r
+\r
+                        List<TaxonRelationship> taxonRelListParent = null;\r
+                        List<TaxonRelationship> taxonRelListTaxon = null;\r
+                        if (doWithMisappliedNames){\r
+                            taxonRelListParent = dao.getTaxonRelationships(parentTaxon, TaxonRelationshipType.MISAPPLIED_NAME_FOR(), null, null, orderHints, propertyPaths, Direction.relatedTo);\r
+                            taxonRelListTaxon = dao.getTaxonRelationships(taxon, TaxonRelationshipType.MISAPPLIED_NAME_FOR(), null, null, orderHints, propertyPaths, Direction.relatedTo);\r
+                        }\r
+\r
+\r
+                        if (type.equals(SynonymRelationshipType.INFERRED_EPITHET_OF())){\r
+                            Set<String> genusNames = new HashSet<String>();\r
+\r
+                            for (SynonymRelationship synonymRelationOfParent:synonymRelationshipsOfParent){\r
+                                Synonym syn = synonymRelationOfParent.getSynonym();\r
+\r
+                                inferredEpithet = createInferredEpithets(taxon,\r
+                                        zooHashMap, taxonName, epithetOfTaxon,\r
+                                        infragenericEpithetOfTaxon,\r
+                                        infraspecificEpithetOfTaxon,\r
+                                        taxonNames, parentName,\r
+                                        syn);\r
+\r
+\r
+                                inferredSynonyms.add(inferredEpithet);\r
+                                zooHashMap.put(inferredEpithet.getName().getUuid(), (ZoologicalName)inferredEpithet.getName());\r
+                                taxonNames.add(((ZoologicalName)inferredEpithet.getName()).getNameCache());\r
+                            }\r
+\r
+                            if (doWithMisappliedNames){\r
+\r
+                                for (TaxonRelationship taxonRelationship: taxonRelListParent){\r
+                                     Taxon misappliedName = taxonRelationship.getFromTaxon();\r
+\r
+                                     inferredEpithet = createInferredEpithets(taxon,\r
+                                             zooHashMap, taxonName, epithetOfTaxon,\r
+                                             infragenericEpithetOfTaxon,\r
+                                             infraspecificEpithetOfTaxon,\r
+                                             taxonNames, parentName,\r
+                                             misappliedName);\r
+\r
+                                    inferredSynonyms.add(inferredEpithet);\r
+                                    zooHashMap.put(inferredEpithet.getName().getUuid(), (ZoologicalName)inferredEpithet.getName());\r
+                                     taxonNames.add(((ZoologicalName)inferredEpithet.getName()).getNameCache());\r
+                                }\r
+                            }\r
+\r
+                            if (!taxonNames.isEmpty()){\r
+                            List<String> synNotInCDM = dao.taxaByNameNotInDB(taxonNames);\r
+                            ZoologicalName name;\r
+                            if (!synNotInCDM.isEmpty()){\r
+                                inferredSynonymsToBeRemoved.clear();\r
+\r
+                                for (Synonym syn :inferredSynonyms){\r
+                                    name = getZoologicalName(syn.getName().getUuid(), zooHashMap);\r
+                                    if (!synNotInCDM.contains(name.getNameCache())){\r
+                                        inferredSynonymsToBeRemoved.add(syn);\r
+                                    }\r
+                                }\r
+\r
+                                // Remove identified Synonyms from inferredSynonyms\r
+                                for (Synonym synonym : inferredSynonymsToBeRemoved) {\r
+                                    inferredSynonyms.remove(synonym);\r
+                                }\r
+                            }\r
                         }\r
 \r
                     }else if (type.equals(SynonymRelationshipType.INFERRED_GENUS_OF())){\r
@@ -1259,64 +1692,30 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
                             ZoologicalName inferredSynName;\r
 \r
                             Synonym syn = synonymRelationOfTaxon.getSynonym();\r
-                            synName =syn.getName();\r
-                            HibernateProxyHelper.deproxy(syn);\r
+                            inferredGenus = createInferredGenus(taxon,\r
+                                    zooHashMap, taxonName, epithetOfTaxon,\r
+                                    genusOfTaxon, taxonNames, zooParentName, syn);\r
 \r
-                            // Determine the idInSource\r
-                            String idInSourceSyn = getIdInSource(syn);\r
-                            String idInSourceTaxon = getIdInSource(taxon);\r
-                            // Determine the sourceReference\r
-                            Reference sourceReference = syn.getSec();\r
-\r
-                            synName = syn.getName();\r
-                            ZoologicalName synZooName = getZoologicalName(synName.getUuid(), zooHashMap);\r
-                            String synSpeciesEpithetName = synZooName.getSpecificEpithet();\r
-                           /* if (synonymsEpithet != null && !synonymsEpithet.contains(synSpeciesEpithetName)){\r
-                                synonymsEpithet.add(synSpeciesEpithetName);\r
-                            }*/\r
-                           \r
-                            inferredSynName = ZoologicalName.NewInstance(rankOfTaxon);\r
-                            //TODO:differ between parent is genus and taxon is species, parent is subgenus and taxon is species, parent is species and taxon is subspecies and parent is genus and taxon is subgenus...\r
-\r
-\r
-                            inferredSynName.setGenusOrUninomial(genusOfTaxon);\r
-                            \r
-                            if (taxonName.isSpecies()){\r
-                               inferredSynName.setSpecificEpithet(synSpeciesEpithetName);\r
-                               if (zooParentName.isInfraGeneric()){\r
-                                       inferredSynName.setInfraGenericEpithet(zooParentName.getInfraGenericEpithet());\r
-                               }\r
-                            }\r
-                            if (taxonName.isInfraSpecific()){\r
-                               inferredSynName.setSpecificEpithet(epithetOfTaxon);\r
-                               inferredSynName.setInfraSpecificEpithet(synZooName.getInfraGenericEpithet());\r
-                            }\r
-                            if (taxonName.isInfraGeneric()){\r
-                               inferredSynName.setInfraGenericEpithet(synZooName.getInfraGenericEpithet());\r
-                            }\r
-                         \r
-                            inferredGenus = Synonym.NewInstance(inferredSynName, null);\r
+                            inferredSynonyms.add(inferredGenus);\r
+                            zooHashMap.put(inferredGenus.getName().getUuid(), (ZoologicalName)inferredGenus.getName());\r
+                            taxonNames.add(( (ZoologicalName)inferredGenus.getName()).getNameCache());\r
 \r
-                            // Set the sourceReference\r
-                            inferredGenus.setSec(sourceReference);\r
-\r
-                            // Add the original source\r
-                            if (idInSourceSyn != null && idInSourceTaxon != null) {\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
-                                \r
-                            }\r
 \r
-                            taxon.addSynonym(inferredGenus, SynonymRelationshipType.INFERRED_GENUS_OF());\r
-                            inferredSynonyms.add(inferredGenus);\r
-                            inferredSynName.generateTitle();\r
-                            zooHashMap.put(inferredSynName.getUuid(), inferredSynName);\r
-                            taxonNames.add(inferredSynName.getNameCache());\r
                         }\r
 \r
+                        if (doWithMisappliedNames){\r
+\r
+                            for (TaxonRelationship taxonRelationship: taxonRelListTaxon){\r
+                                Taxon misappliedName = taxonRelationship.getFromTaxon();\r
+                                inferredGenus = createInferredGenus(taxon, zooHashMap, taxonName, infraspecificEpithetOfTaxon, genusOfTaxon, taxonNames, zooParentName,  misappliedName);\r
+\r
+                                inferredSynonyms.add(inferredGenus);\r
+                                zooHashMap.put(inferredGenus.getName().getUuid(), (ZoologicalName)inferredGenus.getName());\r
+                                 taxonNames.add(( (ZoologicalName)inferredGenus.getName()).getNameCache());\r
+                            }\r
+                        }\r
+\r
+\r
                         if (!taxonNames.isEmpty()){\r
                             List<String> synNotInCDM = dao.taxaByNameNotInDB(taxonNames);\r
                             ZoologicalName name;\r
@@ -1342,9 +1741,9 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
                         Reference sourceReference = null; // TODO: Determination of sourceReference is redundant\r
                         ZoologicalName inferredSynName;\r
                         //for all synonyms of the parent...\r
-                        for (SynonymRelationship synonymRelationOfGenus:synonymRelationshipsOfGenus){\r
+                        for (SynonymRelationship synonymRelationOfParent:synonymRelationshipsOfParent){\r
                             TaxonNameBase synName;\r
-                            Synonym synParent = synonymRelationOfGenus.getSynonym();\r
+                            Synonym synParent = synonymRelationOfParent.getSynonym();\r
                             synName = synParent.getName();\r
 \r
                             HibernateProxyHelper.deproxy(synParent);\r
@@ -1355,130 +1754,109 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
                             // Determine the idInSource\r
                             String idInSourceParent = getIdInSource(synParent);\r
 \r
-                            ZoologicalName parentZooName = getZoologicalName(synName.getUuid(), zooHashMap);\r
-                            String synParentGenus = parentZooName.getGenusOrUninomial();\r
+                            ZoologicalName parentSynZooName = getZoologicalName(synName.getUuid(), zooHashMap);\r
+                            String synParentGenus = parentSynZooName.getGenusOrUninomial();\r
                             String synParentInfragenericName = null;\r
                             String synParentSpecificEpithet = null;\r
-                            \r
-                            if (parentZooName.isInfraGeneric()){\r
-                               synParentInfragenericName = parentZooName.getInfraGenericEpithet();\r
+\r
+                            if (parentSynZooName.isInfraGeneric()){\r
+                                synParentInfragenericName = parentSynZooName.getInfraGenericEpithet();\r
                             }\r
-                            if (parentZooName.isSpecies()){\r
-                               synParentSpecificEpithet = parentZooName.getSpecificEpithet();\r
+                            if (parentSynZooName.isSpecies()){\r
+                                synParentSpecificEpithet = parentSynZooName.getSpecificEpithet();\r
                             }\r
-                            \r
+\r
                            /* if (synGenusName != null && !synonymsGenus.containsKey(synGenusName)){\r
                                 synonymsGenus.put(synGenusName, idInSource);\r
                             }*/\r
-                            \r
+\r
                             //for all synonyms of the taxon\r
-                            \r
+\r
                             for (SynonymRelationship synonymRelationOfTaxon:synonymRelationshipsOfTaxon){\r
 \r
                                 Synonym syn = synonymRelationOfTaxon.getSynonym();\r
-                                HibernateProxyHelper.deproxy(syn);\r
-\r
-                                // Set sourceReference\r
-                                sourceReference = syn.getSec();\r
-\r
-                                ZoologicalName zooName = getZoologicalName(syn.getName().getUuid(), zooHashMap);\r
-                                String synTaxonSpecificEpithet = zooName.getSpecificEpithet();\r
-                                String synTaxonInfragenericName = null;\r
-                                String synTaxonInfraSpecificName= null;\r
-                                \r
-                                if (parentZooName.isSpecies()){\r
-                                       synTaxonInfraSpecificName = zooName.getInfraSpecificEpithet();\r
-                                }\r
-                                if (zooName.isInfraGeneric()){\r
-                                       synTaxonInfragenericName = zooName.getInfraGenericEpithet();\r
-                                }\r
-                                \r
-                                /*if (epithetName != null && !synonymsEpithet.contains(epithetName)){\r
-                                    synonymsEpithet.add(epithetName);\r
-                                }*/\r
-                                \r
-                                //create potential combinations...\r
-                                inferredSynName = ZoologicalName.NewInstance(rankOfTaxon);\r
-                                \r
-                                inferredSynName.setGenusOrUninomial(synParentGenus);\r
-                                if (taxonName.isSpecies()){\r
-                                         inferredSynName.setSpecificEpithet(synTaxonSpecificEpithet);\r
-                                         if (parentName.isInfraGeneric()){\r
-                                                 inferredSynName.setInfraGenericEpithet(synTaxonInfragenericName);\r
-                                         }\r
-                                }\r
-                                if (taxonName.isInfraSpecific()){\r
-                                       inferredSynName.setSpecificEpithet(synParentSpecificEpithet);\r
-                                       inferredSynName.setInfraSpecificEpithet(synTaxonInfraSpecificName);\r
-                                }\r
-                                if (taxonName.isInfraGeneric()){\r
-                                       inferredSynName.setInfraGenericEpithet(synTaxonInfragenericName);\r
-                                }\r
-                                \r
-                               \r
-                                potentialCombination = Synonym.NewInstance(inferredSynName, null);\r
+                                ZoologicalName zooSynName = getZoologicalName(syn.getName().getUuid(), zooHashMap);\r
+                                potentialCombination = createPotentialCombination(idInSourceParent, parentSynZooName, zooSynName,\r
+                                        synParentGenus,\r
+                                        synParentInfragenericName,\r
+                                        synParentSpecificEpithet, syn, zooHashMap);\r
+\r
+                                taxon.addSynonym(potentialCombination, SynonymRelationshipType.POTENTIAL_COMBINATION_OF());\r
+                                inferredSynonyms.add(potentialCombination);\r
+                                zooHashMap.put(potentialCombination.getName().getUuid(), (ZoologicalName)potentialCombination.getName());\r
+                                 taxonNames.add(( (ZoologicalName)potentialCombination.getName()).getNameCache());\r
+\r
+                            }\r
+\r
+\r
+                        }\r
+\r
+                        if (doWithMisappliedNames){\r
+\r
+                            for (TaxonRelationship parentRelationship: taxonRelListParent){\r
+\r
+                                TaxonNameBase misappliedParentName;\r
+\r
+                                Taxon misappliedParent = parentRelationship.getFromTaxon();\r
+                                misappliedParentName = misappliedParent.getName();\r
+\r
+                                HibernateProxyHelper.deproxy(misappliedParent);\r
 \r
                                 // Set the sourceReference\r
-                                potentialCombination.setSec(sourceReference);\r
+                                sourceReference = misappliedParent.getSec();\r
 \r
-                               \r
                                 // Determine the idInSource\r
-                                String idInSourceSyn= getIdInSource(syn);\r
-                                \r
-                                if (idInSourceParent != null && idInSourceSyn != null) {\r
-//                                    IdentifiableSource originalSourceGenus = IdentifiableSource.NewInstance(idInSourceSyn + "; " + idInSourceParent, POTENTIAL_COMBINATION_NAMESPACE, sourceReference, null);\r
-//                                    inferredGenus.addSource(originalSourceGenus);\r
-                                    \r
-                                    IdentifiableSource originalSource = IdentifiableSource.NewInstance(idInSourceSyn + "; " + idInSourceParent, POTENTIAL_COMBINATION_NAMESPACE, sourceReference, null);\r
-                                    inferredSynName.addSource(originalSource);\r
-                                    \r
+                                String idInSourceParent = getIdInSource(misappliedParent);\r
+\r
+                                ZoologicalName parentSynZooName = getZoologicalName(misappliedParentName.getUuid(), zooHashMap);\r
+                                String synParentGenus = parentSynZooName.getGenusOrUninomial();\r
+                                String synParentInfragenericName = null;\r
+                                String synParentSpecificEpithet = null;\r
+\r
+                                if (parentSynZooName.isInfraGeneric()){\r
+                                    synParentInfragenericName = parentSynZooName.getInfraGenericEpithet();\r
+                                }\r
+                                if (parentSynZooName.isSpecies()){\r
+                                    synParentSpecificEpithet = parentSynZooName.getSpecificEpithet();\r
                                 }\r
-                                \r
-//                                if (idInSourceTaxon != null) {\r
-//                                    IdentifiableSource originalSourceTaxon = IdentifiableSource.NewInstance(idInSourceTaxon, "PotentialCombinationOf", sourceReference, null);\r
-//                                    if (sourceReference != null) {\r
-//                                        originalSourceTaxon.setCitation(sourceReference);\r
-//                                        potentialCombination.addSource(originalSourceTaxon);\r
-//                                    }\r
-//                                }\r
-//                                if (idInSourceParent != null){\r
-//                                     IdentifiableSource originalSourceParent = IdentifiableSource.NewInstance(idInSourceParent, "PotentialCombinationOf", sourceReference, null);\r
-//                                     if (sourceReference != null) {\r
-//                                         originalSourceParent.setCitation(sourceReference);\r
-//                                         potentialCombination.addSource(originalSourceParent);\r
-//                                     }\r
-//                             }\r
-                            \r
-                                    // Add the citation\r
-                                    \r
-                                \r
 \r
-                                inferredSynonyms.add(potentialCombination);\r
-                                inferredSynName.generateTitle();\r
-                                zooHashMap.put(inferredSynName.getUuid(), inferredSynName);\r
-                                taxonNames.add(inferredSynName.getNameCache());\r
-                                \r
+\r
+                                for (TaxonRelationship taxonRelationship: taxonRelListTaxon){\r
+                                    Taxon misappliedName = taxonRelationship.getFromTaxon();\r
+                                    ZoologicalName zooMisappliedName = getZoologicalName(misappliedName.getName().getUuid(), zooHashMap);\r
+                                    potentialCombination = createPotentialCombination(\r
+                                            idInSourceParent, parentSynZooName, zooMisappliedName,\r
+                                            synParentGenus,\r
+                                            synParentInfragenericName,\r
+                                            synParentSpecificEpithet, misappliedName, zooHashMap);\r
+\r
+\r
+                                    taxon.addSynonym(potentialCombination, SynonymRelationshipType.POTENTIAL_COMBINATION_OF());\r
+                                    inferredSynonyms.add(potentialCombination);\r
+                                    zooHashMap.put(potentialCombination.getName().getUuid(), (ZoologicalName)potentialCombination.getName());\r
+                                     taxonNames.add(( (ZoologicalName)potentialCombination.getName()).getNameCache());\r
+                                }\r
                             }\r
-                            \r
                         }\r
+\r
                         if (!taxonNames.isEmpty()){\r
-                               List<String> synNotInCDM = dao.taxaByNameNotInDB(taxonNames);\r
+                            List<String> synNotInCDM = dao.taxaByNameNotInDB(taxonNames);\r
                             ZoologicalName name;\r
                             if (!synNotInCDM.isEmpty()){\r
-                               inferredSynonymsToBeRemoved.clear();\r
-                               for (Synonym syn :inferredSynonyms){\r
-                                       try{\r
-                                               name = (ZoologicalName) syn.getName();\r
+                                inferredSynonymsToBeRemoved.clear();\r
+                                for (Synonym syn :inferredSynonyms){\r
+                                    try{\r
+                                        name = (ZoologicalName) syn.getName();\r
                                     }catch (ClassCastException e){\r
-                                       name = getZoologicalName(syn.getName().getUuid(), zooHashMap);\r
+                                        name = getZoologicalName(syn.getName().getUuid(), zooHashMap);\r
                                     }\r
                                     if (!synNotInCDM.contains(name.getNameCache())){\r
-                                       inferredSynonymsToBeRemoved.add(syn);\r
+                                        inferredSynonymsToBeRemoved.add(syn);\r
                                     }\r
                                  }\r
-                               // Remove identified Synonyms from inferredSynonyms\r
+                                // Remove identified Synonyms from inferredSynonyms\r
                                 for (Synonym synonym : inferredSynonymsToBeRemoved) {\r
-                                       inferredSynonyms.remove(synonym);\r
+                                    inferredSynonyms.remove(synonym);\r
                                 }\r
                             }\r
                          }\r
@@ -1489,12 +1867,256 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
                     }\r
                 }\r
             }\r
-          \r
+\r
         }\r
 \r
         return inferredSynonyms;\r
     }\r
 \r
+    private Synonym createPotentialCombination(String idInSourceParent,\r
+            ZoologicalName parentSynZooName,   ZoologicalName zooSynName, String synParentGenus,\r
+            String synParentInfragenericName, String synParentSpecificEpithet,\r
+            TaxonBase syn, HashMap<UUID, ZoologicalName> zooHashMap) {\r
+        Synonym potentialCombination;\r
+        Reference sourceReference;\r
+        ZoologicalName inferredSynName;\r
+        HibernateProxyHelper.deproxy(syn);\r
+\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
+                sourceReference = taxon.getSec();\r
+            }\r
+        }\r
+        String synTaxonSpecificEpithet = zooSynName.getSpecificEpithet();\r
+\r
+        String synTaxonInfraSpecificName= null;\r
+\r
+        if (parentSynZooName.isSpecies()){\r
+            synTaxonInfraSpecificName = zooSynName.getInfraSpecificEpithet();\r
+        }\r
+\r
+        /*if (epithetName != null && !synonymsEpithet.contains(epithetName)){\r
+            synonymsEpithet.add(epithetName);\r
+        }*/\r
+\r
+        //create potential combinations...\r
+        inferredSynName = ZoologicalName.NewInstance(syn.getName().getRank());\r
+\r
+        inferredSynName.setGenusOrUninomial(synParentGenus);\r
+        if (zooSynName.isSpecies()){\r
+              inferredSynName.setSpecificEpithet(synTaxonSpecificEpithet);\r
+              if (parentSynZooName.isInfraGeneric()){\r
+                  inferredSynName.setInfraGenericEpithet(synParentInfragenericName);\r
+              }\r
+        }\r
+        if (zooSynName.isInfraSpecific()){\r
+            inferredSynName.setSpecificEpithet(synParentSpecificEpithet);\r
+            inferredSynName.setInfraSpecificEpithet(synTaxonInfraSpecificName);\r
+        }\r
+        if (parentSynZooName.isInfraGeneric()){\r
+            inferredSynName.setInfraGenericEpithet(synParentInfragenericName);\r
+        }\r
+\r
+\r
+        potentialCombination = Synonym.NewInstance(inferredSynName, null);\r
+\r
+        // Set the sourceReference\r
+        potentialCombination.setSec(sourceReference);\r
+\r
+\r
+        // Determine the idInSource\r
+        String idInSourceSyn= getIdInSource(syn);\r
+\r
+        if (idInSourceParent != null && idInSourceSyn != null) {\r
+            IdentifiableSource originalSource = IdentifiableSource.NewInstance(idInSourceSyn + "; " + idInSourceParent, POTENTIAL_COMBINATION_NAMESPACE, sourceReference, null);\r
+            inferredSynName.addSource(originalSource);\r
+            originalSource = IdentifiableSource.NewInstance(idInSourceSyn + "; " + idInSourceParent, POTENTIAL_COMBINATION_NAMESPACE, sourceReference, null);\r
+            potentialCombination.addSource(originalSource);\r
+        }\r
+\r
+        inferredSynName.generateTitle();\r
+\r
+        return potentialCombination;\r
+    }\r
+\r
+    private Synonym createInferredGenus(Taxon taxon,\r
+            HashMap<UUID, ZoologicalName> zooHashMap, ZoologicalName taxonName,\r
+            String epithetOfTaxon, String genusOfTaxon,\r
+            List<String> taxonNames, ZoologicalName zooParentName,\r
+            TaxonBase syn) {\r
+\r
+        Synonym inferredGenus;\r
+        TaxonNameBase synName;\r
+        ZoologicalName inferredSynName;\r
+        synName =syn.getName();\r
+        HibernateProxyHelper.deproxy(syn);\r
+\r
+        // Determine the idInSource\r
+        String idInSourceSyn = getIdInSource(syn);\r
+        String idInSourceTaxon = getIdInSource(taxon);\r
+        // 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
+                     /* if (synonymsEpithet != null && !synonymsEpithet.contains(synSpeciesEpithetName)){\r
+            synonymsEpithet.add(synSpeciesEpithetName);\r
+        }*/\r
+\r
+        inferredSynName = ZoologicalName.NewInstance(taxon.getName().getRank());\r
+        //TODO:differ between parent is genus and taxon is species, parent is subgenus and taxon is species, parent is species and taxon is subspecies and parent is genus and taxon is subgenus...\r
+\r
+\r
+        inferredSynName.setGenusOrUninomial(genusOfTaxon);\r
+        if (zooParentName.isInfraGeneric()){\r
+            inferredSynName.setInfraGenericEpithet(zooParentName.getInfraGenericEpithet());\r
+        }\r
+\r
+        if (taxonName.isSpecies()){\r
+            inferredSynName.setSpecificEpithet(synSpeciesEpithetName);\r
+        }\r
+        if (taxonName.isInfraSpecific()){\r
+            inferredSynName.setSpecificEpithet(epithetOfTaxon);\r
+            inferredSynName.setInfraSpecificEpithet(synZooName.getInfraGenericEpithet());\r
+        }\r
+\r
+\r
+        inferredGenus = Synonym.NewInstance(inferredSynName, null);\r
+\r
+        // Set the sourceReference\r
+        inferredGenus.setSec(sourceReference);\r
+\r
+        // Add the original source\r
+        if (idInSourceSyn != null && idInSourceTaxon != null) {\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
+        }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
+\r
+        inferredSynName.generateTitle();\r
+\r
+\r
+        return inferredGenus;\r
+    }\r
+\r
+    private Synonym createInferredEpithets(Taxon taxon,\r
+            HashMap<UUID, ZoologicalName> zooHashMap, ZoologicalName taxonName,\r
+            String epithetOfTaxon, String infragenericEpithetOfTaxon,\r
+            String infraspecificEpithetOfTaxon, List<String> taxonNames,\r
+            TaxonNameBase parentName, TaxonBase syn) {\r
+\r
+        Synonym inferredEpithet;\r
+        TaxonNameBase synName;\r
+        ZoologicalName inferredSynName;\r
+        HibernateProxyHelper.deproxy(syn);\r
+\r
+        // Determine the idInSource\r
+        String idInSourceSyn = getIdInSource(syn);\r
+        String idInSourceTaxon =  getIdInSource(taxon);\r
+        // 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
+        String synInfraGenericEpithet = null;\r
+        String synSpecificEpithet = null;\r
+\r
+        if (zooSynName.getInfraGenericEpithet() != null){\r
+            synInfraGenericEpithet = zooSynName.getInfraGenericEpithet();\r
+        }\r
+\r
+        if (zooSynName.isInfraSpecific()){\r
+            synSpecificEpithet = zooSynName.getSpecificEpithet();\r
+        }\r
+\r
+                     /* if (synGenusName != null && !synonymsGenus.containsKey(synGenusName)){\r
+            synonymsGenus.put(synGenusName, idInSource);\r
+        }*/\r
+\r
+        inferredSynName = ZoologicalName.NewInstance(taxon.getName().getRank());\r
+\r
+        // DEBUG TODO: for subgenus or subspecies the infrageneric or infraspecific epithet should be used!!!\r
+        if (epithetOfTaxon == null && infragenericEpithetOfTaxon == null && infraspecificEpithetOfTaxon == null) {\r
+            logger.error("This specificEpithet is NULL" + taxon.getTitleCache());\r
+        }\r
+        inferredSynName.setGenusOrUninomial(synGenusName);\r
+\r
+        if (parentName.isInfraGeneric()){\r
+            inferredSynName.setInfraGenericEpithet(synInfraGenericEpithet);\r
+        }\r
+        if (taxonName.isSpecies()){\r
+            inferredSynName.setSpecificEpithet(epithetOfTaxon);\r
+        }else if (taxonName.isInfraSpecific()){\r
+            inferredSynName.setSpecificEpithet(synSpecificEpithet);\r
+            inferredSynName.setInfraSpecificEpithet(infraspecificEpithetOfTaxon);\r
+        }\r
+\r
+        inferredEpithet = Synonym.NewInstance(inferredSynName, null);\r
+\r
+        // Set the sourceReference\r
+        inferredEpithet.setSec(sourceReference);\r
+\r
+        /* Add the original source\r
+        if (idInSource != null) {\r
+            IdentifiableSource originalSource = IdentifiableSource.NewInstance(idInSource, "InferredEpithetOf", syn.getSec(), null);\r
+\r
+            // Add the citation\r
+            Reference citation = getCitation(syn);\r
+            if (citation != null) {\r
+                originalSource.setCitation(citation);\r
+                inferredEpithet.addSource(originalSource);\r
+            }\r
+        }*/\r
+        String taxonId = idInSourceTaxon+ "; " + idInSourceSyn;\r
+\r
+        IdentifiableSource originalSource;\r
+        originalSource = IdentifiableSource.NewInstance(taxonId, INFERRED_EPITHET_NAMESPACE, sourceReference, null);\r
+\r
+        inferredEpithet.addSource(originalSource);\r
+\r
+        originalSource = IdentifiableSource.NewInstance(taxonId, INFERRED_EPITHET_NAMESPACE, sourceReference, null);\r
+\r
+        inferredSynName.addSource(originalSource);\r
+\r
+\r
+\r
+        taxon.addSynonym(inferredEpithet, SynonymRelationshipType.INFERRED_EPITHET_OF());\r
+\r
+        inferredSynName.generateTitle();\r
+        return inferredEpithet;\r
+    }\r
+\r
     /**\r
      * Returns an existing ZoologicalName or extends an internal hashmap if it does not exist.\r
      * Very likely only useful for createInferredSynonyms().\r
@@ -1509,7 +2131,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
         }\r
         return taxonName;\r
     }\r
-    \r
+\r
     /**\r
      * Returns the idInSource for a given Synonym.\r
      * @param syn\r
@@ -1532,11 +2154,14 @@ 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
+\r
 \r
     /**\r
      * Returns the citation for a given Synonym.\r
@@ -1556,17 +2181,52 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
 \r
         return citation;\r
     }\r
-    \r
-    public List<Synonym>  createAllInferredSynonyms(Taxon taxon, Classification tree){\r
+\r
+    @Override\r
+    public List<Synonym>  createAllInferredSynonyms(Taxon taxon, Classification tree, boolean doWithMisappliedNames){\r
         List <Synonym> inferredSynonyms = new ArrayList<Synonym>();\r
 \r
-        inferredSynonyms.addAll(createInferredSynonyms(taxon, tree, SynonymRelationshipType.INFERRED_EPITHET_OF()));\r
-        inferredSynonyms.addAll(createInferredSynonyms(taxon, tree, SynonymRelationshipType.INFERRED_GENUS_OF()));\r
-        inferredSynonyms.addAll(createInferredSynonyms(taxon, tree, SynonymRelationshipType.POTENTIAL_COMBINATION_OF()));\r
+        inferredSynonyms.addAll(createInferredSynonyms(taxon, tree, SynonymRelationshipType.INFERRED_EPITHET_OF(), doWithMisappliedNames));\r
+        inferredSynonyms.addAll(createInferredSynonyms(taxon, tree, SynonymRelationshipType.INFERRED_GENUS_OF(), doWithMisappliedNames));\r
+        inferredSynonyms.addAll(createInferredSynonyms(taxon, tree, SynonymRelationshipType.POTENTIAL_COMBINATION_OF(), doWithMisappliedNames));\r
 \r
         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
 }\r