a bit more cleaning up
[cdmlib.git] / cdmlib-services / src / main / java / eu / etaxonomy / cdm / api / service / TaxonServiceImpl.java
index 6681697647b8989f1a1b3b42e5619164f5472ce9..beb58134b1fb3c581363cba49f01a47b690821bf 100644 (file)
@@ -21,14 +21,17 @@ import java.util.UUID;
 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.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.apache.lucene.search.TopDocs;\r
-import org.hibernate.criterion.Criterion;\r
 import org.springframework.beans.factory.annotation.Autowired;\r
 import org.springframework.stereotype.Service;\r
 import org.springframework.transaction.annotation.Propagation;\r
 import org.springframework.transaction.annotation.Transactional;\r
 \r
-import eu.etaxonomy.cdm.api.service.config.ITaxonServiceConfigurator;\r
+import eu.etaxonomy.cdm.api.service.config.IFindTaxaAndNamesConfigurator;\r
 import eu.etaxonomy.cdm.api.service.config.MatchingTaxonConfigurator;\r
 import eu.etaxonomy.cdm.api.service.config.NameDeletionConfigurator;\r
 import eu.etaxonomy.cdm.api.service.config.TaxonDeletionConfigurator;\r
@@ -38,10 +41,14 @@ 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.LuceneSearch;\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.common.monitor.IProgressMonitor;\r
 import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;\r
-import eu.etaxonomy.cdm.hibernate.search.DefinedTermBaseFieldBridge;\r
+import eu.etaxonomy.cdm.hibernate.search.DefinedTermBaseClassBridge;\r
+import eu.etaxonomy.cdm.hibernate.search.MultilanguageTextFieldBridge;\r
 import eu.etaxonomy.cdm.model.common.CdmBase;\r
 import eu.etaxonomy.cdm.model.common.IdentifiableEntity;\r
 import eu.etaxonomy.cdm.model.common.IdentifiableSource;\r
@@ -51,6 +58,7 @@ import eu.etaxonomy.cdm.model.common.RelationshipBase;
 import eu.etaxonomy.cdm.model.common.RelationshipBase.Direction;\r
 import eu.etaxonomy.cdm.model.common.UuidAndTitleCache;\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.TaxonDescription;\r
@@ -59,7 +67,6 @@ import eu.etaxonomy.cdm.model.media.Media;
 import eu.etaxonomy.cdm.model.media.MediaRepresentation;\r
 import eu.etaxonomy.cdm.model.media.MediaUtils;\r
 import eu.etaxonomy.cdm.model.name.HomotypicalGroup;\r
-import eu.etaxonomy.cdm.model.name.NonViralName;\r
 import eu.etaxonomy.cdm.model.name.Rank;\r
 import eu.etaxonomy.cdm.model.name.TaxonNameBase;\r
 import eu.etaxonomy.cdm.model.name.ZoologicalName;\r
@@ -82,7 +89,6 @@ import eu.etaxonomy.cdm.persistence.fetch.CdmFetch;
 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
@@ -106,9 +112,6 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
     @Autowired\r
     private ITaxonNameDao nameDao;\r
 \r
-    @Autowired\r
-    private ISearchResultBuilder searchResultBuilder;\r
-\r
     @Autowired\r
     private INameService nameService;\r
 \r
@@ -502,7 +505,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
         return heterotypicSynonymyGroups;\r
     }\r
 \r
-    public List<UuidAndTitleCache<TaxonBase>> findTaxaAndNamesForEditor(ITaxonServiceConfigurator configurator){\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
@@ -526,7 +529,7 @@ 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
+    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
@@ -636,6 +639,42 @@ 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
+    public List<Media> listTaxonDescriptionMedia(Taxon taxon, boolean limitToGalleries, List<String> propertyPath){\r
+\r
+        Pager<TaxonDescription> p =\r
+                    descriptionService.getTaxonDescriptions(taxon, null, null, null, null, propertyPath);\r
+\r
+        // pars the media and quality parameters\r
+\r
+\r
+        // collect all media of the given taxon\r
+        List<Media> taxonMedia = new ArrayList<Media>();\r
+        List<Media> taxonGalleryMedia = new ArrayList<Media>();\r
+        for(TaxonDescription desc : p.getRecords()){\r
+\r
+            if(desc.isImageGallery()){\r
+                for(DescriptionElementBase element : desc.getElements()){\r
+                    for(Media media : element.getMedia()){\r
+                        taxonGalleryMedia.add(media);\r
+                    }\r
+                }\r
+            } else if(!limitToGalleries){\r
+                for(DescriptionElementBase element : desc.getElements()){\r
+                    for(Media media : element.getMedia()){\r
+                        taxonMedia.add(media);\r
+                    }\r
+                }\r
+            }\r
+\r
+        }\r
+\r
+        taxonGalleryMedia.addAll(taxonMedia);\r
+        return taxonGalleryMedia;\r
+    }\r
+\r
     /* (non-Javadoc)\r
      * @see eu.etaxonomy.cdm.api.service.ITaxonService#findTaxaByID(java.util.Set)\r
      */\r
@@ -1090,58 +1129,107 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
     }\r
 \r
     @Override\r
-    public Pager<SearchResult<TaxonBase>> findByDescriptionElementFullText(\r
-            Class<? extends DescriptionElementBase> clazz, String queryString,\r
-            List<Language> languages, Integer pageSize, Integer pageNumber,\r
-            List<OrderHint> orderHints, 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
-//        // type selection\r
-//        String typeSelect = "";\r
+//        // -- set defaults\r
+//        Class<? extends TaxonBase> directorySelectClass = TaxonBase.class;\r
 //        if(clazz != null){\r
-//            typeSelect = "_hibernate_class:\"" + clazz.getName() + "\" AND ";\r
+//            directorySelectClass = clazz;\r
 //        }\r
+        return null;\r
+\r
+    }\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
+        // -- set defaults\r
         Class<? extends DescriptionElementBase> directorySelectClass = DescriptionElementBase.class;\r
         if(clazz != null){\r
             directorySelectClass = clazz;\r
         }\r
 \r
-        StringBuilder luceneQueryTemplate = new StringBuilder();\r
 \r
-        luceneQueryTemplate.append("titleCache:%1$s ");\r
+        BooleanQuery finalQuery = new BooleanQuery();\r
+        BooleanQuery textQuery = new BooleanQuery();\r
+\r
+        LuceneSearch luceneSearch = new LuceneSearch(getSession(), directorySelectClass);\r
+        QueryFactory queryFactory = new QueryFactory(luceneSearch);\r
+\r
+        // ---- search criteria\r
+        textQuery.add(queryFactory.newTermQuery("titleCache", queryString), Occur.SHOULD);\r
+\r
         // common name\r
+        Query nameQuery;\r
         if(languages == null || languages.size() == 0){\r
-            luceneQueryTemplate.append("name:%1$s ");\r
+            nameQuery = queryFactory.newTermQuery("name", queryString);\r
         } else {\r
-            luceneQueryTemplate.append("(name:%1$s AND (");\r
+            nameQuery = new BooleanQuery();\r
+            BooleanQuery languageSubQuery = new BooleanQuery();\r
             for(Language lang : languages){\r
-                luceneQueryTemplate.append(" language.label:" + lang.getLabel());\r
+                languageSubQuery.add(queryFactory.newTermQuery("language.uuid",  lang.getUuid().toString()), Occur.SHOULD);\r
             }\r
-            luceneQueryTemplate.append("))");\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
-        appendLocalizedFieldQuery("text", languages, luceneQueryTemplate).append(" ");\r
+        textQuery.add(queryFactory.newLocalizedTermQuery("text", queryString, languages), Occur.SHOULD);\r
+\r
+        // --- TermBase fields - by representation ----\r
         // state field from CategoricalData\r
-        appendLocalizedFieldQuery("states.state.representation", languages, luceneQueryTemplate).append(" ");\r
+        textQuery.add(queryFactory.newLocalizedTermQuery("states.state.representation", queryString, languages), Occur.SHOULD);\r
+\r
         // state field from CategoricalData\r
-        appendLocalizedFieldQuery("states.modifyingText", languages, luceneQueryTemplate).append(" ");\r
+        textQuery.add(queryFactory.newLocalizedTermQuery("states.modifyingText", queryString, languages), Occur.SHOULD);\r
 \r
-//        String luceneQueryTemplate = typeSelect + "( titleCache:%1$s OR " + languageSelection + "OR name:%1$s )";\r
-        String luceneQuery = String.format(luceneQueryTemplate.toString(), queryString);\r
+        finalQuery.add(textQuery, Occur.MUST);\r
+        // --- classification ----\r
 \r
-        LuceneSearch luceneSearch = new LuceneSearch(getSession(), directorySelectClass);\r
-        TopDocs topDocsResultSet = luceneSearch.executeSearch(luceneQuery, clazz);\r
-        List<SearchResult<TaxonBase>> searchResults = searchResultBuilder.createResultSetFromIds(luceneSearch, topDocsResultSet, dao, "inDescription.taxon.id");\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.newIdNotNullQuery("inDescription.taxon.id"), Occur.MUST);\r
+\r
+        SortField[] sortFields = new  SortField[]{SortField.FIELD_SCORE, new SortField("inDescription.taxon.titleCache__sort", false)};\r
+\r
+        TopDocs topDocsResultSet = luceneSearch.executeSearch(finalQuery, clazz, pageSize, pageNumber, sortFields);\r
+\r
+        String[] highlightFields = null;\r
+        if(highlightFragments){\r
+            highlightFields = queryFactory.getTextFieldNames().toArray(new String[queryFactory.getTextFieldNames().size()]);\r
+        }\r
+\r
+        // initialize taxa, thighlight matches ....\r
+        ISearchResultBuilder searchResultBuilder = new SearchResultBuilder(luceneSearch, finalQuery);\r
+        List<SearchResult<TaxonBase>> searchResults = searchResultBuilder.createResultSet(\r
+                topDocsResultSet, highlightFields, dao, "inDescription.taxon.id", propertyPaths);\r
 \r
         return new DefaultPagerImpl<SearchResult<TaxonBase>>(pageNumber, searchResults.size(), pageSize, searchResults);\r
 \r
     }\r
 \r
     /**\r
-     * DefinedTerm representations and MultilanguageString maps are stored in the Lucene index by the {@link DefinedTermBaseFieldBridge}\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 DefinedTermBaseFieldBridge}\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
@@ -1155,10 +1243,10 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
             stringBuilder = new StringBuilder();\r
         }\r
         if(languages == null || languages.size() == 0){\r
-            stringBuilder.append(name + ".ALL:%1$s ");\r
+            stringBuilder.append(name + ".ALL:(%1$s) ");\r
         } else {\r
             for(Language lang : languages){\r
-                stringBuilder.append(name + "." + lang.getLabel() + ":%1$s ");\r
+                stringBuilder.append(name + "." + lang.getUuid().toString() + ":(%1$s) ");\r
             }\r
         }\r
         return stringBuilder;\r
@@ -1482,8 +1570,15 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
 \r
         // Set sourceReference\r
         sourceReference = syn.getSec();\r
+        if (sourceReference == null){\r
+            logger.warn("The synonym has no sec reference because it is a misapplied name! Take the sec reference of taxon");\r
+            //TODO:Remove\r
+            if (!parentSynZooName.getTaxa().isEmpty()){\r
+                TaxonBase taxon = parentSynZooName.getTaxa().iterator().next();\r
 \r
-\r
+                sourceReference = taxon.getSec();\r
+            }\r
+        }\r
         String synTaxonSpecificEpithet = zooSynName.getSpecificEpithet();\r
 \r
         String synTaxonInfraSpecificName= null;\r
@@ -1554,6 +1649,8 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
         // Determine the sourceReference\r
         Reference sourceReference = syn.getSec();\r
 \r
+        //logger.warn(sourceReference.getTitleCache());\r
+\r
         synName = syn.getName();\r
         ZoologicalName synZooName = getZoologicalName(synName.getUuid(), zooHashMap);\r
         String synSpeciesEpithetName = synZooName.getSpecificEpithet();\r
@@ -1591,7 +1688,16 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
 \r
             originalSource = IdentifiableSource.NewInstance(idInSourceSyn + "; " + idInSourceTaxon, INFERRED_GENUS_NAMESPACE, sourceReference, null);\r
             inferredSynName.addSource(originalSource);\r
+            originalSource = null;\r
 \r
+        }else{\r
+            logger.error("There is an idInSource missing: " + idInSourceSyn + " of Synonym or " + idInSourceTaxon + " of Taxon");\r
+            IdentifiableSource originalSource = IdentifiableSource.NewInstance(idInSourceSyn + "; " + idInSourceTaxon, INFERRED_GENUS_NAMESPACE, sourceReference, null);\r
+            inferredGenus.addSource(originalSource);\r
+\r
+            originalSource = IdentifiableSource.NewInstance(idInSourceSyn + "; " + idInSourceTaxon, INFERRED_GENUS_NAMESPACE, sourceReference, null);\r
+            inferredSynName.addSource(originalSource);\r
+            originalSource = null;\r
         }\r
 \r
         taxon.addSynonym(inferredGenus, SynonymRelationshipType.INFERRED_GENUS_OF());\r
@@ -1619,6 +1725,13 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
         // Determine the sourceReference\r
         Reference sourceReference = syn.getSec();\r
 \r
+        if (sourceReference == null){\r
+            logger.warn("The synonym has no sec reference because it is a misapplied name! Take the sec reference of taxon");\r
+            //TODO:Remove\r
+            System.out.println("The synonym has no sec reference because it is a misapplied name! Take the sec reference of taxon" + taxon.getSec());\r
+            sourceReference = taxon.getSec();\r
+        }\r
+\r
         synName = syn.getName();\r
         ZoologicalName zooSynName = getZoologicalName(synName.getUuid(), zooHashMap);\r
         String synGenusName = zooSynName.getGenusOrUninomial();\r
@@ -1727,8 +1840,11 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
                 }\r
                 count++;\r
             }\r
+        } else if (sources.size() == 0){\r
+            logger.warn("No idInSource for TaxonBase " + taxonBase.getUuid() + " - " + taxonBase.getTitleCache());\r
         }\r
 \r
+\r
         return idInSource;\r
     }\r
 \r