fix #825 rename method that searches by representation label in term dao
[cdmlib.git] / cdmlib-persistence / src / main / java / eu / etaxonomy / cdm / persistence / dao / hibernate / term / DefinedTermDaoImpl.java
index 4d15c64612c415a908a0850593dc635d5460926a..aed1a1d23f88f696ffbd1d541d6a020ba4ad44c7 100644 (file)
@@ -6,16 +6,16 @@
 * The contents of this file are subject to the Mozilla Public License Version 1.1
 * See LICENSE.TXT at the top of this package for the full license terms.
 */
-
 package eu.etaxonomy.cdm.persistence.dao.hibernate.term;
 
-import java.net.URI;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Enumeration;
+import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Locale;
+import java.util.Map;
 import java.util.Set;
 import java.util.UUID;
 
@@ -33,6 +33,7 @@ import org.hibernate.envers.query.AuditEntity;
 import org.hibernate.envers.query.AuditQuery;
 import org.springframework.stereotype.Repository;
 
+import eu.etaxonomy.cdm.common.URI;
 import eu.etaxonomy.cdm.model.common.AnnotationType;
 import eu.etaxonomy.cdm.model.common.CdmBase;
 import eu.etaxonomy.cdm.model.common.ExtensionType;
@@ -50,6 +51,7 @@ import eu.etaxonomy.cdm.model.location.NamedAreaType;
 import eu.etaxonomy.cdm.model.location.ReferenceSystem;
 import eu.etaxonomy.cdm.model.media.Media;
 import eu.etaxonomy.cdm.model.media.RightsType;
+import eu.etaxonomy.cdm.model.metadata.TermSearchField;
 import eu.etaxonomy.cdm.model.name.HybridRelationshipType;
 import eu.etaxonomy.cdm.model.name.NameRelationshipType;
 import eu.etaxonomy.cdm.model.name.NameTypeDesignationStatus;
@@ -66,21 +68,24 @@ import eu.etaxonomy.cdm.model.term.TermVocabulary;
 import eu.etaxonomy.cdm.model.view.AuditEvent;
 import eu.etaxonomy.cdm.persistence.dao.hibernate.common.IdentifiableDaoBase;
 import eu.etaxonomy.cdm.persistence.dao.term.IDefinedTermDao;
+import eu.etaxonomy.cdm.persistence.dto.FeatureDto;
 import eu.etaxonomy.cdm.persistence.dto.TermDto;
 import eu.etaxonomy.cdm.persistence.query.MatchMode;
 import eu.etaxonomy.cdm.persistence.query.OrderHint;
 
-
 /**
  * @author a.kohlbecker
  * @since 29.05.2008
- * @version 1.0
  */
 @Repository
-public class DefinedTermDaoImpl extends IdentifiableDaoBase<DefinedTermBase> implements IDefinedTermDao{
-       private static final Logger logger = Logger.getLogger(DefinedTermDaoImpl.class);
+public class DefinedTermDaoImpl
+        extends IdentifiableDaoBase<DefinedTermBase>
+        implements IDefinedTermDao{
+
+    private static final Logger logger = Logger.getLogger(DefinedTermDaoImpl.class);
 
-       public DefinedTermDaoImpl() {
+       @SuppressWarnings("unchecked")
+    public DefinedTermDaoImpl() {
                super(DefinedTermBase.class);
                indexedClasses = new Class[25];
                indexedClasses[0] = Rank.class;
@@ -112,39 +117,29 @@ public class DefinedTermDaoImpl extends IdentifiableDaoBase<DefinedTermBase> imp
 
        /**
         * Searches by Label
-        * @see eu.etaxonomy.cdm.persistence.dao.common.ITitledDao#findByTitle(java.lang.String)
         */
        @Override
-    public List<DefinedTermBase> findByTitle(String queryString) {
-               return findByTitle(queryString, null);
+    public List<DefinedTermBase> findByLabel(String queryString) {
+               return findByLabel(queryString, null);
        }
 
-
        /**
         * Searches by Label
-        * @see eu.etaxonomy.cdm.persistence.dao.common.ITitledDao#findByTitle(java.lang.String, eu.etaxonomy.cdm.model.common.CdmBase)
         */
        @Override
-    public List<DefinedTermBase> findByTitle(String queryString, CdmBase sessionObject) {
+    public List<DefinedTermBase> findByLabel(String queryString, CdmBase sessionObject) {
                checkNotInPriorView("DefinedTermDaoImpl.findByTitle(String queryString, CdmBase sessionObject)");
                Session session = getSession();
                if ( sessionObject != null ) {//attache the object to the session, TODO needed?
                        session.update(sessionObject);
                }
-               Query query = session.createQuery("select term from DefinedTermBase term join fetch term.representations representation where representation.label = :label");
+               Query query = session.createQuery("SELECT term "
+                       + " FROM DefinedTermBase term JOIN FETCH term.representations representation "
+                       + " WHERE representation.label = :label");
                query.setParameter("label", queryString);
-               return query.list();
-
-       }
-
-       @Override
-    public List<DefinedTermBase> findByTitleAndClass(String queryString, Class<DefinedTermBase> clazz) {
-               checkNotInPriorView("DefinedTermDaoImpl.findByTitleAndClass(String queryString, Class<DefinedTermBase> clazz)");
-               Session session = getSession();
-               Criteria crit = session.createCriteria(clazz);
-               crit.add(Restrictions.ilike("persistentTitleCache", queryString));
-               List<DefinedTermBase> results = crit.list();
-               return results;
+               @SuppressWarnings({ "unchecked", "rawtypes" })
+               List<DefinedTermBase> result = deduplicateResult(query.list());
+               return result;
        }
 
        @Override
@@ -156,11 +151,11 @@ public class DefinedTermDaoImpl extends IdentifiableDaoBase<DefinedTermBase> imp
                crit.setMaxResults(pagesize);
                int firstItem = (page - 1) * pagesize + 1;
                crit.setFirstResult(firstItem);
-               List<DefinedTermBase> results = crit.list();
+               @SuppressWarnings("unchecked")
+        List<DefinedTermBase> results = deduplicateResult(crit.list());
                return results;
        }
 
-
        @Override
     public Country getCountryByIso(String iso3166) {
                // If iso639 = "" query returns non-unique result. We prevent this here:
@@ -194,7 +189,7 @@ public class DefinedTermDaoImpl extends IdentifiableDaoBase<DefinedTermBase> imp
                addPageSizeAndNumber(criteria, pageSize, pageNumber);
 
                @SuppressWarnings("unchecked")
-        List<T> result = criteria.list();
+        List<T> result = deduplicateResult(criteria.list());
                return result;
        }
 
@@ -223,7 +218,7 @@ public class DefinedTermDaoImpl extends IdentifiableDaoBase<DefinedTermBase> imp
                addPageSizeAndNumber(criteria, pageSize, pageNumber);
 
                @SuppressWarnings("unchecked")
-        List<T> result = criteria.list();
+        List<T> result = deduplicateResult(criteria.list());
                return result;
        }
 
@@ -238,7 +233,7 @@ public class DefinedTermDaoImpl extends IdentifiableDaoBase<DefinedTermBase> imp
                addPageSizeAndNumber(criteria, pageSize, pageNumber);
 
                @SuppressWarnings("unchecked")
-               List<T> result = criteria.list();
+               List<T> result = deduplicateResult(criteria.list());
                return result;
        }
 
@@ -263,9 +258,9 @@ public class DefinedTermDaoImpl extends IdentifiableDaoBase<DefinedTermBase> imp
 
                String queryStr;
                if (isIso639_1){
-                       queryStr = "from Language where iso639_1 = :isoCode";
+                       queryStr = "FROM Language WHERE iso639_1 = :isoCode";
                }else{
-                       queryStr = "from Language where idInVocabulary = :isoCode and vocabulary.uuid = :vocUuid";
+                       queryStr = "FROM Language WHERE idInVocabulary = :isoCode AND vocabulary.uuid = :vocUuid";
                }
                AuditEvent auditEvent = getAuditEventFromContext();
                if(auditEvent.equals(AuditEvent.CURRENT_VIEW)) {
@@ -294,7 +289,7 @@ public class DefinedTermDaoImpl extends IdentifiableDaoBase<DefinedTermBase> imp
         */
        @Override
     public List<Language> getLanguagesByIso(List<String> iso639List) {
-               List<Language> languages = new ArrayList<Language>(iso639List.size());
+               List<Language> languages = new ArrayList<>(iso639List.size());
                for (String iso639 : iso639List) {
                        languages.add(getLanguageByIso(iso639));
                }
@@ -303,7 +298,7 @@ public class DefinedTermDaoImpl extends IdentifiableDaoBase<DefinedTermBase> imp
 
        @Override
     public List<Language> getLanguagesByLocale(Enumeration<Locale> locales) {
-               List<Language> languages = new ArrayList<Language>();
+               List<Language> languages = new ArrayList<>();
                while(locales.hasMoreElements()) {
                        Locale locale = locales.nextElement();
                        languages.add(getLanguageByIso(locale.getLanguage()));
@@ -355,7 +350,11 @@ public class DefinedTermDaoImpl extends IdentifiableDaoBase<DefinedTermBase> imp
        @Override
     public List<Media> getMedia(DefinedTermBase definedTerm, Integer pageSize, Integer pageNumber) {
                checkNotInPriorView("DefinedTermDaoImpl.getMedia(DefinedTermBase definedTerm, Integer pageSize, Integer pageNumber)");
-               Query query = getSession().createQuery("select media from DefinedTermBase definedTerm join definedTerm.media media where definedTerm = :definedTerm");
+               Query query = getSession().createQuery(
+                          "SELECT media "
+                       + " FROM DefinedTermBase definedTerm "
+                       + " JOIN definedTerm.media media "
+                       + " WHERE definedTerm = :definedTerm");
                query.setParameter("definedTerm", definedTerm);
 
                addPageSizeAndNumber(query, pageSize, pageNumber);
@@ -382,7 +381,7 @@ public class DefinedTermDaoImpl extends IdentifiableDaoBase<DefinedTermBase> imp
                    addPageSizeAndNumber(criteria, pageSize, pageNumber);
 
                @SuppressWarnings("unchecked")
-               List<NamedArea> result = criteria.list();
+               List<NamedArea> result = deduplicateResult(criteria.list());
                return result;
                } else {
             AuditQuery query = makeAuditQuery(NamedArea.class, auditEvent);
@@ -396,7 +395,7 @@ public class DefinedTermDaoImpl extends IdentifiableDaoBase<DefinedTermBase> imp
                    }
 
                    @SuppressWarnings("unchecked")
-            List<NamedArea> result = query.getResultList();
+            List<NamedArea> result = deduplicateResult(query.getResultList());
                    return result;
                }
        }
@@ -420,7 +419,7 @@ public class DefinedTermDaoImpl extends IdentifiableDaoBase<DefinedTermBase> imp
                        addOrder(criteria,orderHints);
                        addPageSizeAndNumber(criteria, pageSize, pageNumber);
 
-                       result = criteria.list();
+                       result = deduplicateResult(criteria.list());
 
                } else {
                        AuditQuery query = getAuditReader().createQuery().forEntitiesAtRevision(NamedArea.class,
@@ -431,7 +430,7 @@ public class DefinedTermDaoImpl extends IdentifiableDaoBase<DefinedTermBase> imp
                        if (type != null) {
                                query.add(AuditEntity.relatedId("type").eq(type.getId()));
                        }
-                       result = query.getResultList();
+                       result = deduplicateResult(query.getResultList());
                }
 
                defaultBeanInitializer.initializeAll(result, propertyPaths);
@@ -487,7 +486,7 @@ public class DefinedTermDaoImpl extends IdentifiableDaoBase<DefinedTermBase> imp
                    addPageSizeAndNumber(query, pageSize, pageNumber);
 
                    @SuppressWarnings("unchecked")
-            List<T> result = query.list();
+            List<T> result = deduplicateResult(query.list());
                    return result;
                } else {
                         AuditQuery query = makeAuditQuery(DefinedTermBase.class, auditEvent);
@@ -496,7 +495,7 @@ public class DefinedTermDaoImpl extends IdentifiableDaoBase<DefinedTermBase> imp
                         addPageSizeAndNumber(query, pageSize, pageNumber);
 
              @SuppressWarnings("unchecked")
-             List<T> result = query.getResultList();
+             List<T> result = deduplicateResult(query.getResultList());
              return result;
                }
        }
@@ -514,17 +513,17 @@ public class DefinedTermDaoImpl extends IdentifiableDaoBase<DefinedTermBase> imp
                addPageSizeAndNumber(query, pageSize, pageNumber);
 
                    @SuppressWarnings("unchecked")
-            List<T> results = query.list();
+            List<T> results = deduplicateResult(query.list());
                    defaultBeanInitializer.initializeAll(results, propertyPaths);
                    return results;
                } else {
-                       List<T> result = new ArrayList<T>();
+                       List<T> result = new ArrayList<>();
                        for(T t : partOf) {
                                AuditQuery query = makeAuditQuery(DefinedTermBase.class, auditEvent);
                                query.add(AuditEntity.relatedId("partOf").eq(t.getId()));
                                addPageSizeAndNumber(query, pageSize, pageNumber);
 
-                           result.addAll(query.getResultList());
+                           result.addAll(deduplicateResult(query.getResultList()));
                        }
                        defaultBeanInitializer.initializeAll(result, propertyPaths);
                        return result;
@@ -589,7 +588,7 @@ public class DefinedTermDaoImpl extends IdentifiableDaoBase<DefinedTermBase> imp
            query.setParameter("termType", termType);
 
            @SuppressWarnings("unchecked")
-        List<T> result = query.list();
+        List<T> result = deduplicateResult(query.list());
 
            defaultBeanInitializer.initializeAll(result, propertyPaths);
         return result;
@@ -602,7 +601,7 @@ public class DefinedTermDaoImpl extends IdentifiableDaoBase<DefinedTermBase> imp
                Query query = getSession().createQuery("FROM " + clazz.getSimpleName());
 
            @SuppressWarnings("unchecked")
-        List<TERM> result = query.list();
+        List<TERM> result = deduplicateResult(query.list());
 
            defaultBeanInitializer.initializeAll(result, propertyPaths);
 
@@ -617,7 +616,7 @@ public class DefinedTermDaoImpl extends IdentifiableDaoBase<DefinedTermBase> imp
     }
 
     /**
-     * Workaround for http://dev.e-taxonomy.eu/trac/ticket/5871 and #5945
+     * Workaround for https://dev.e-taxonomy.eu/redmine/issues/5871 and #5945
      * Terms with multiple representations return identical duplicates
      * due to eager representation loading. We expect these duplicates to appear
      * in line wo we only compare one term with its predecessor. If it already
@@ -625,7 +624,7 @@ public class DefinedTermDaoImpl extends IdentifiableDaoBase<DefinedTermBase> imp
      * @param orginals
      * @return
      */
-    private <S extends DefinedTermBase<?>> List<S> deduplicateResult(List<S> orginals) {
+    protected static <S extends CdmBase> List<S> deduplicateResult(List<S> orginals) {
         List<S> result = new ArrayList<>();
         Iterator<S> it = orginals.iterator();
         S last = null;
@@ -641,48 +640,39 @@ public class DefinedTermDaoImpl extends IdentifiableDaoBase<DefinedTermBase> imp
         return result;
     }
 
+    @Override
+    public <S extends DefinedTermBase> List<S> list(Class<S> clazz, List<TermVocabulary> vocs, Integer limit, String pattern) {
+        return list(clazz, vocs, 0, limit, pattern, MatchMode.BEGINNING);
+    }
 
     @Override
-    public List<NamedArea> listNamedArea(List<TermVocabulary> vocs, Integer pageNumber, Integer limit, String pattern, MatchMode matchmode){
+    public <S extends DefinedTermBase> List<S> list(Class<S> clazz, List<TermVocabulary> vocs, Integer pageNumber, Integer limit, String pattern, MatchMode matchmode){
         Session session = getSession();
-//        Query query = null;
-//        if (pattern != null){
-//            if (vocs != null && !vocs.isEmpty()){
-//                query = session.createQuery("from NamedArea where titleCache like :pattern and vocabulary in :vocs ORDER BY titleCache");
-//                query.setParameterList("vocs", vocs);
-//            }else{
-//                query = session.createQuery("from NamedArea where titleCache like :pattern ORDER BY titleCache");
-//            }
-//            pattern = pattern.replace("*", "%");
-//            pattern = pattern.replace("?", "_");
-//            pattern = pattern + "%";
-//            query.setParameter("pattern", pattern);
-//
-//        } else {
-//            query = session.createQuery("FROM NamedArea WHERE vocabulary IN :vocs ORDER BY titleCache");
-//            query.setParameterList("vocs", vocs);
-//        }
-//        if (limit != null && limit > 0){
-//           query.setMaxResults(limit);
-//        }
-
-        Criteria crit = getSession().createCriteria(type, "namedArea");
+        if (clazz == null){
+            clazz = (Class)type;
+        }
+        Criteria crit = getSession().createCriteria(clazz, "term");
         if (!StringUtils.isBlank(pattern)){
+            crit.createAlias("term.representations", "reps");
+            Disjunction or = Restrictions.disjunction();
             if (matchmode == MatchMode.EXACT) {
-                crit.add(Restrictions.eq("titleCache", matchmode.queryStringFrom(pattern)));
+                or.add(Restrictions.eq("titleCache", matchmode.queryStringFrom(pattern)));
+                or.add(Restrictions.eq("reps.label", matchmode.queryStringFrom(pattern)));
             } else {
-    //          crit.add(Restrictions.ilike("titleCache", matchmode.queryStringFrom(queryString)));
-                crit.add(Restrictions.like("titleCache", matchmode.queryStringFrom(pattern)));
+                or.add(Restrictions.like("titleCache", matchmode.queryStringFrom(pattern)));
+                or.add(Restrictions.like("reps.label", matchmode.queryStringFrom(pattern)));
             }
+            crit.add(or);
         }
+
         if (limit != null && limit >= 0) {
             crit.setMaxResults(limit);
         }
 
         if (vocs != null &&!vocs.isEmpty()){
-            crit.createAlias("namedArea.vocabulary", "voc");
+            crit.createAlias("term.vocabulary", "voc");
             Disjunction or = Restrictions.disjunction();
-            for (TermVocabulary voc: vocs){
+            for (TermVocabulary<?> voc: vocs){
                 Criterion criterion = Restrictions.eq("voc.id", voc.getId());
                 or.add(criterion);
             }
@@ -693,45 +683,68 @@ public class DefinedTermDaoImpl extends IdentifiableDaoBase<DefinedTermBase> imp
         if (limit == null){
             limit = 1;
         }
-        int firstItem = (pageNumber - 1) * limit;
-
         crit.setFirstResult(0);
         @SuppressWarnings("unchecked")
-        List<NamedArea> results = crit.list();
+        List<S> results = deduplicateResult(crit.list());
         return results;
     }
 
     @Override
-    public long count(List<TermVocabulary> vocs, String pattern){
-        Session session = getSession();
-        Query query = null;
-        if (pattern != null){
-            if (vocs != null && !vocs.isEmpty()){
-                query = session.createQuery("SELECT COUNT(*) FROM NamedArea WHERE titleCache LIKE :pattern AND vocabulary IN :vocs");
-                query.setParameterList("vocs", vocs);
-            }else{
-                query = session.createQuery("SELECT COUNT(*) FROM NamedArea WHERE titleCache LIKE :pattern ");
+    public <S extends DefinedTermBase> List<S> listByAbbrev(Class<S> clazz, List<TermVocabulary> vocs, Integer limit, String pattern, TermSearchField type) {
+        return listByAbbrev(clazz, vocs, 0, limit, pattern, MatchMode.BEGINNING, type);
+    }
+
+    @Override
+    public <S extends DefinedTermBase> List<S> listByAbbrev(Class<S> clazz, List<TermVocabulary> vocs, Integer pageNumber, Integer limit, String pattern, MatchMode matchmode, TermSearchField abbrevType){
+
+        if (clazz == null){
+            clazz = (Class)type;
+        }
+        Criteria crit = getSession().createCriteria(clazz, "type");
+        if (!StringUtils.isBlank(pattern)){
+            if (matchmode == MatchMode.EXACT) {
+                crit.add(Restrictions.eq(abbrevType.getKey(), matchmode.queryStringFrom(pattern)));
+            } else {
+                crit.add(Restrictions.like(abbrevType.getKey(), matchmode.queryStringFrom(pattern)));
+            }
+        }
+        if (limit != null && limit >= 0) {
+            crit.setMaxResults(limit);
+        }
+
+        if (vocs != null &&!vocs.isEmpty()){
+            crit.createAlias("type.vocabulary", "voc");
+            Disjunction or = Restrictions.disjunction();
+            for (TermVocabulary<?> voc: vocs){
+                Criterion criterion = Restrictions.eq("voc.id", voc.getId());
+                or.add(criterion);
             }
-            pattern = pattern.replace("*", "%");
-            pattern = pattern.replace("?", "_");
-            pattern = pattern + "%";
-            query.setParameter("pattern", pattern);
-
-        } else {
-            query = session.createQuery("SELECT COUNT(*) FROM NamedArea WHERE vocabulary IN :vocs");
-            query.setParameterList("vocs", vocs);
+            crit.add(or);
         }
 
+        crit.addOrder(Order.asc(abbrevType.getKey()));
+        if (limit == null){
+            limit = 1;
+        }
+//        int firstItem = (pageNumber - 1) * limit;
 
+        crit.setFirstResult(0);
         @SuppressWarnings("unchecked")
-        Long result = (Long) query.uniqueResult();
-        return result;
+        List<S> results = deduplicateResult(crit.list());
+        return results;
     }
 
+
     @Override
     public Collection<TermDto> getIncludesAsDto(
             TermDto parentTerm) {
-        String queryString = TermDto.getTermDtoSelect()
+        String queryString;
+        if (parentTerm.getTermType().equals(TermType.NamedArea)){
+            queryString = TermDto.getTermDtoSelectNamedArea();
+        }else{
+            queryString = TermDto.getTermDtoSelect();
+        }
+        queryString = queryString
                 + "where a.partOf.uuid = :parentUuid";
         Query query =  getSession().createQuery(queryString);
         query.setParameter("parentUuid", parentTerm.getUuid());
@@ -744,10 +757,15 @@ public class DefinedTermDaoImpl extends IdentifiableDaoBase<DefinedTermBase> imp
     }
 
     @Override
-    public Collection<TermDto> getKindOfsAsDto(
-            TermDto parentTerm) {
-        String queryString = TermDto.getTermDtoSelect()
-                + "where a.kindOf.uuid = :parentUuid";
+    public Collection<TermDto> getKindOfsAsDto(TermDto parentTerm) {
+
+        String queryString;
+        if (parentTerm.getTermType().equals(TermType.NamedArea)){
+            queryString = TermDto.getTermDtoSelectNamedArea();
+        }else{
+            queryString = TermDto.getTermDtoSelect();
+        }
+        queryString = queryString + "where a.kindOf.uuid = :parentUuid";
         Query query =  getSession().createQuery(queryString);
         query.setParameter("parentUuid", parentTerm.getUuid());
 
@@ -758,12 +776,13 @@ public class DefinedTermDaoImpl extends IdentifiableDaoBase<DefinedTermBase> imp
         return list;
     }
 
-
     @Override
     public Collection<TermDto> findByTitleAsDto(String title, TermType termType) {
         String queryString = TermDto.getTermDtoSelect()
                 + " where a.titleCache like :title "
                 + (termType!=null?" and a.termType = :termType ":"");
+
+        title = title.replace("*", "%");
         Query query =  getSession().createQuery(queryString);
         query.setParameter("title", "%"+title+"%");
         if(termType!=null){
@@ -777,6 +796,47 @@ public class DefinedTermDaoImpl extends IdentifiableDaoBase<DefinedTermBase> imp
         return list;
     }
 
+    @Override
+    public TermDto findByUUIDAsDto(UUID uuid) {
+        String queryString = TermDto.getTermDtoSelect()
+                + " where a.uuid like :uuid ";
+
+
+        Query query =  getSession().createQuery(queryString);
+        query.setParameter("uuid", uuid);
+
+
+        @SuppressWarnings("unchecked")
+        List<Object[]> result = query.list();
+
+        List<TermDto> list = TermDto.termDtoListFrom(result);
+        if (list.size()== 1){
+            return list.get(0);
+        }else{
+            return null;
+        }
+
+    }
+
+
+    @Override
+    public Collection<TermDto> findByTypeAsDto(TermType termType) {
+        if (termType == null){
+            return null;
+        }
+        String queryString = TermDto.getTermDtoSelect()
+                + " where a.termType = :termType ";
+        Query query =  getSession().createQuery(queryString);
+
+        query.setParameter("termType", termType);
+
+        @SuppressWarnings("unchecked")
+        List<Object[]> result = query.list();
+
+        List<TermDto> list = TermDto.termDtoListFrom(result);
+        return list;
+    }
+
     @Override
     public Collection<TermDto> findByUriAsDto(URI uri, String termLabel, TermType termType) {
         String queryString = TermDto.getTermDtoSelect()
@@ -800,14 +860,116 @@ public class DefinedTermDaoImpl extends IdentifiableDaoBase<DefinedTermBase> imp
         return list;
     }
 
-    /**
-     * {@inheritDoc}
-     */
     @Override
-    public List<NamedArea> listNamedArea(List<TermVocabulary> vocs, Integer limit, String pattern) {
+    public  Map<UUID, List<TermDto>> getSupportedStatesForFeature(Set<UUID> featureUuids){
+        Map<UUID, List<TermDto>> map = new HashMap<>();
+        for (UUID featureUuid: featureUuids){
+            List<TermDto> list = new ArrayList<>();
+            String supportedCategoriesQueryString = "SELECT cat.uuid "
+                    + "from DefinedTermBase t "
+                    + "join t.supportedCategoricalEnumerations as cat "
+                    + "where t.uuid = :featureUuid";
+            Query supportedCategoriesQuery =  getSession().createQuery(supportedCategoriesQueryString);
+            supportedCategoriesQuery.setParameter("featureUuid", featureUuid);
+            @SuppressWarnings("unchecked")
+               List<UUID> supportedCategories = supportedCategoriesQuery.list();
+            if(supportedCategories.isEmpty()){
+                map.put(featureUuid, list);
+                continue;
+            }
+
+            String queryString = TermDto.getTermDtoSelect()
+                    + "where v.uuid in (:supportedCategories) "
+                    + "order by a.titleCache";
+            Query query =  getSession().createQuery(queryString);
+            query.setParameterList("supportedCategories", supportedCategories);
+
+            @SuppressWarnings("unchecked")
+            List<Object[]> result = query.list();
+
+            list = TermDto.termDtoListFrom(result);
+            map.put(featureUuid, list);
+        }
+        return map;
+    }
+
+    @Override
+    public Collection<TermDto> findByUUIDsAsDto(List<UUID> uuidList) {
+        List<TermDto> list = new ArrayList<>();
+        if (uuidList == null || uuidList.isEmpty()){
+            return null;
+        }
+
+        String queryString = TermDto.getTermDtoSelect()
+                + "where a.uuid in :uuidList "
+                + "order by a.titleCache";
+        Query query =  getSession().createQuery(queryString);
+        query.setParameterList("uuidList", uuidList);
+
+        @SuppressWarnings("unchecked")
+        List<Object[]> result = query.list();
+
+        list = TermDto.termDtoListFrom(result);
+        return list;
+    }
+
+    @Override
+    public Collection<TermDto> findFeatureByUUIDsAsDto(List<UUID> uuidList) {
+        List<TermDto> list = new ArrayList<>();
+        if (uuidList == null || uuidList.isEmpty()){
+            return null;
+        }
+
+        String queryString = FeatureDto.getTermDtoSelect()
+                + "where a.uuid in :uuidList "
+                + "order by a.titleCache";
+        Query query =  getSession().createQuery(queryString);
+        query.setParameterList("uuidList", uuidList);
+
+        @SuppressWarnings("unchecked")
+        List<Object[]> result = query.list();
+
+        list = FeatureDto.termDtoListFrom(result);
+        return list;
+    }
+
+    @Override
+    public Collection<TermDto> findFeatureByTitleAsDto(String pattern) {
+        String queryString = FeatureDto.getTermDtoSelect()
+                + " where a.titleCache like :title "
+                +  " and a.termType = :termType ";
+
+        pattern = pattern.replace("*", "%");
+        Query query =  getSession().createQuery(queryString);
+        query.setParameter("title", "%"+pattern+"%");
+        query.setParameter("termType", TermType.Feature);
 
-        return listNamedArea(vocs, 0, limit, pattern, MatchMode.BEGINNING);
 
+        @SuppressWarnings("unchecked")
+        List<Object[]> result = query.list();
+
+        List<TermDto> list = FeatureDto.termDtoListFrom(result);
+        return list;
     }
 
-}
+    @Override
+    public TermDto getTermDto(UUID uuid) {
+        String queryString = TermDto.getTermDtoSelect()
+                + " where a.uuid = :uuid ";
+
+
+        Query query =  getSession().createQuery(queryString);
+        query.setParameter("uuid", uuid);
+
+
+
+        @SuppressWarnings("unchecked")
+        List<Object[]> result = query.list();
+        TermDto dto = null;
+        List<TermDto> dtoList = TermDto.termDtoListFrom(result);
+        if (dtoList != null && !dtoList.isEmpty()){
+            dto = dtoList.get(0);
+        }
+        return dto;
+    }
+}
\ No newline at end of file