a little bit documentation
[cdmlib.git] / cdmlib-remote / src / main / java / eu / etaxonomy / cdm / remote / controller / NameCatalogueController.java
index 9cb5bc78ad5677b09c00e51c4c3036a1f5c7a8d3..15e993588afa53877c7e9d1acfca70e9eb78f21b 100755 (executable)
@@ -1,19 +1,35 @@
+\r
 package eu.etaxonomy.cdm.remote.controller;\r
 \r
+import java.io.File;\r
 import java.io.IOException;\r
+import java.io.InputStream;\r
+import java.io.PrintWriter;\r
 import java.util.ArrayList;\r
 import java.util.Arrays;\r
+import java.util.HashMap;\r
+import java.util.HashSet;\r
+import java.util.Iterator;\r
 import java.util.LinkedHashMap;\r
 import java.util.List;\r
 import java.util.Map;\r
 import java.util.Set;\r
+import java.util.TreeMap;\r
 import java.util.UUID;\r
 \r
 import javax.servlet.http.HttpServletRequest;\r
 import javax.servlet.http.HttpServletResponse;\r
 \r
 import java.util.Hashtable;\r
+\r
+import org.apache.log4j.Level;\r
+import org.joda.time.DateTime;\r
+import org.joda.time.format.DateTimeFormat;\r
+import org.joda.time.format.DateTimeFormatter;\r
 import org.springframework.beans.factory.annotation.Autowired;\r
+import org.springframework.context.ResourceLoaderAware;\r
+import org.springframework.core.io.Resource;\r
+import org.springframework.core.io.ResourceLoader;\r
 import org.springframework.stereotype.Controller;\r
 import org.springframework.web.bind.annotation.RequestMapping;\r
 import org.springframework.web.bind.annotation.RequestMethod;\r
@@ -21,317 +37,982 @@ import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.servlet.ModelAndView;\r
 \r
 import eu.etaxonomy.cdm.api.service.IClassificationService;\r
+import eu.etaxonomy.cdm.api.service.ICommonService;\r
 import eu.etaxonomy.cdm.api.service.INameService;\r
 import eu.etaxonomy.cdm.api.service.ITaxonService;\r
+import eu.etaxonomy.cdm.api.service.ITermService;\r
+import eu.etaxonomy.cdm.common.DocUtils;\r
 \r
 import eu.etaxonomy.cdm.remote.dto.common.ErrorResponse;\r
 import eu.etaxonomy.cdm.remote.dto.common.RemoteResponse;\r
 import eu.etaxonomy.cdm.remote.dto.namecatalogue.NameInformation;\r
 import eu.etaxonomy.cdm.remote.dto.namecatalogue.NameSearch;\r
 import eu.etaxonomy.cdm.remote.dto.namecatalogue.TaxonInformation;\r
+import eu.etaxonomy.cdm.remote.view.HtmlView;\r
+import eu.etaxonomy.cdm.model.common.CdmBase;\r
+import eu.etaxonomy.cdm.model.common.DefinedTermBase;\r
+import eu.etaxonomy.cdm.model.common.IdentifiableSource;\r
+import eu.etaxonomy.cdm.model.common.Language;\r
+import eu.etaxonomy.cdm.model.common.Representation;\r
+import eu.etaxonomy.cdm.model.description.Feature;\r
 import eu.etaxonomy.cdm.model.name.NonViralName;\r
 import eu.etaxonomy.cdm.model.name.TaxonNameBase;\r
-import eu.etaxonomy.cdm.model.name.TypeDesignationBase;\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
+import eu.etaxonomy.cdm.model.taxon.SynonymRelationship;\r
 import eu.etaxonomy.cdm.model.taxon.Taxon;\r
 import eu.etaxonomy.cdm.model.taxon.TaxonBase;\r
 import eu.etaxonomy.cdm.model.taxon.TaxonNode;\r
+import eu.etaxonomy.cdm.model.taxon.TaxonRelationship;\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
 \r
 /**\r
- * The controller class for the namespace 'name_catalogue'.\r
- * This controller provides search mechanisims for searching by taxon name as well as taxon. \r
- * \r
+ * The controller class for the namespace 'name_catalogue'. This web service namespace\r
+ * is an add-on to the already existing CDM REST API and provides information relating\r
+ * to scientific names as well as taxa present in the underlying datasource.\r
+ *\r
  * @author c.mathew\r
- * @version 1.0\r
- * @created 15-Apr-2012 \r
+ * @version 1.1.0\r
+ * @created 15-Apr-2012\r
  */\r
 \r
 @Controller\r
-@RequestMapping(value = {"/name_catalogue"})\r
-public class NameCatalogueController  extends BaseController<TaxonNameBase, INameService> {\r
-\r
-       /** Taxon status strings*/\r
-       public static final String ACCECPTED_NAME_STATUS = "accepted_name";\r
-       public static final String SYNONYM_STATUS = "synonym";\r
-       \r
-       /** Flag strings*/\r
-       public static final String DOUBTFUL_FLAG = "doubtful";\r
-       \r
-       @Autowired\r
-       private ITaxonService taxonService;\r
-\r
-       @Autowired\r
-       private IClassificationService classificationService;\r
-\r
-       private static final List<String> NAME_SEARCH_INIT_STRATEGY = Arrays.asList(new String []{\r
-                       "combinationAuthorTeam.$",\r
-                       "exCombinationAuthorTeam.$",\r
-                       "basionymAuthorTeam.$",\r
-                       "exBasionymAuthorTeam.$",\r
-                       "taxonBases"\r
-       });\r
-\r
-       private static final List<String> NAME_INFORMATION_INIT_STRATEGY = Arrays.asList(new String []{\r
-                       "taxonBases",\r
-                       "status",\r
-                       "nomenclaturalReference.$",\r
-                       "combinationAuthorTeam.$",\r
-                       "exCombinationAuthorTeam.$",\r
-                       "basionymAuthorTeam.$",\r
-                       "exBasionymAuthorTeam.$",\r
-                       "relationsToThisName.$",\r
-                       "relationsFromThisName.$"       \r
-       });\r
-\r
-       private static final List<String> TAXON_INFORMATION_INIT_STRATEGY = Arrays.asList(new String []{\r
-                       "synonymRelations",     \r
-                       "taxonNodes",\r
-                       "taxonNodes.classification"\r
-       });\r
-\r
-       private static final List<String> TAXON_NODE_INIT_STRATEGY = Arrays.asList(new String[]{\r
-                       "taxon.sec", \r
-                       "taxon.name",                   \r
-                       "classification",\r
-                       "classification.reference.$",\r
-                       "classification.reference.authorTeam.$"\r
-       });\r
-\r
-       public NameCatalogueController(){\r
-               super();\r
-               setInitializationStrategy(Arrays.asList(new String[]{"$"})); //TODO still needed????\r
-       }\r
-\r
-       /* (non-Javadoc)\r
-        * @see eu.etaxonomy.cdm.remote.controller.GenericController#setService(eu.etaxonomy.cdm.api.service.IService)\r
-        */\r
-       @Autowired\r
-       @Override\r
-       public void setService(INameService service) {\r
-               this.service = service;\r
-       }\r
-\r
-       /**\r
-        * Returns a list of taxon names matching the <code>{query}</code> string pattern. \r
-        * Each of these taxon names is accompanied by a list of name uuids and\r
-        * a list of taxon uuids.\r
-        * <p>\r
-        * URI: <b>&#x002F;{datasource-name}&#x002F;name_catalogue</b>\r
-        *\r
-        * @param query\r
-        *                      The taxon name pattern(s) to query for. The query can contain wildcard characters ('*'). \r
-        *              The query can be performed with no wildcard or with the wildcard at the begin and / or end \r
-        *              depending on the search pattern.\r
-        * @param request\r
-        * @param response\r
-        * @return a List of {@link NameSearch} objects each corresponding to a single query. These are built from \r
-        *                      {@TaxonNameBase} entities which are in turn initialized using the {@link #NAME_SEARCH_INIT_STRATEGY}\r
-        * @throws IOException\r
-        */\r
-       @RequestMapping(value = {""},\r
-                       method = RequestMethod.GET)\r
-       public ModelAndView doGetNameSearch(@RequestParam(value = "query", required = true) String[] queries,\r
-                       HttpServletRequest request, \r
-                       HttpServletResponse response) throws IOException {\r
-               ModelAndView mv = new ModelAndView();\r
-               List <RemoteResponse> nsList = new ArrayList<RemoteResponse>();\r
-               for(String query : queries ) {\r
-\r
-                       String queryWOWildcards = getQueryWithoutWildCards(query);\r
-                       MatchMode mm = getMatchModeFromQuery(query);\r
-                       logger.info("doGetNameSearch()" + request.getServletPath() + " for query \"" + query + "\" without wild cards : " + queryWOWildcards + " and match mode : " + mm);\r
-                       List<NonViralName> nameList = (List<NonViralName>)service.findNamesByTitleCache(queryWOWildcards, mm, NAME_SEARCH_INIT_STRATEGY);\r
-                       if(nameList == null || !nameList.isEmpty()) {\r
-                               System.out.println("Size : " + nameList.size());\r
-\r
-                               NameSearch ns = new NameSearch();       \r
-                               ns.setRequest(query);           \r
-\r
-                               for (NonViralName nvn : nameList)\r
-                               {\r
-                                       String titleCacheString = nvn.getTitleCache();      \r
-                                       ns.addToResponseList(titleCacheString, nvn.getUuid().toString(), nvn.getTaxonBases());\r
-                               }\r
-                               nsList.add(ns);\r
-\r
-                       } else {\r
-                               ErrorResponse er = new ErrorResponse();\r
-                               er.setErrorMessage("No Taxon Name for given query : " + query);\r
-                               nsList.add(er);\r
-                       }\r
-               }\r
-               mv.addObject(nsList);\r
-               return mv;         \r
-       }\r
-\r
-       /**\r
-        * Returns information related to the taxon name matching the given <code>{nameUuid}</code>. \r
-        * The information includes the name string, relationships, rank, list of related lsids / taxon uuids, etc. \r
-        * <p>\r
-        * URI: <b>&#x002F;{datasource-name}&#x002F;name_catalogue</b>\r
-        *\r
-        * @param query\r
-        *                      The taxon name pattern(s) to query for. The query can contain wildcard characters ('*'). \r
-        *              The query can be performed with no wildcard or with the wildcard at the begin and / or end \r
-        *              depending on the search pattern.\r
-        * @param request\r
-        * @param response\r
-        * @return a List of {@link NameSearch} objects each corresponding to a single query. These are built from \r
-        *                      {@TaxonNameBase} entities which are in turn initialized using the {@link #NAME_SEARCH_INIT_STRATEGY}\r
-        * @throws IOException\r
-        */\r
-       @RequestMapping(value = {"name"},\r
-                       method = RequestMethod.GET)\r
-       public ModelAndView doGetNameInformation(@RequestParam(value = "nameUuid", required = true) String[] nameUuids,\r
-                       HttpServletRequest request, \r
-                       HttpServletResponse response) throws IOException {\r
-               ModelAndView mv = new ModelAndView();\r
-               List <RemoteResponse> niList = new ArrayList<RemoteResponse>();\r
-               for(String nameUuid : nameUuids ) {\r
-                       logger.info("doGetNameInformation()" + request.getServletPath() + " for name uuid \"" + nameUuid);\r
-                       NonViralName nvn = (NonViralName)service.findNameByUuid(UUID.fromString(nameUuid), NAME_INFORMATION_INIT_STRATEGY);\r
-                       if(nvn != null) {                               \r
-                               NameInformation ni = new NameInformation();\r
-                               ni.setRequest(nameUuid);\r
-                               Reference ref = (Reference) nvn.getNomenclaturalReference();\r
-                               String citation = "";\r
-                               String citation_details = "";\r
-                               if(ref != null) {\r
-                                       citation = ref.getTitleCache();\r
-                               }\r
-                               ni.setResponse(nvn.getTitleCache(), \r
-                                               nvn.getRank().getTitleCache(), \r
-                                               nvn.getStatus(), \r
-                                               citation,\r
-                                               nvn.getRelationsFromThisName(),\r
-                                               nvn.getRelationsToThisName(),\r
-                                               nvn.getTaxonBases());\r
-                               niList.add(ni); \r
-                       } else {\r
-                               ErrorResponse re = new ErrorResponse();\r
-                               re.setErrorMessage("No Taxon Name for given UUID : " + nameUuid);\r
-                               niList.add(re);\r
-                       }\r
-               }\r
-               mv.addObject(niList);\r
-               return mv;       \r
-       }\r
-\r
-       @RequestMapping(value = {"taxon"},\r
-                       method = RequestMethod.GET)\r
-       public ModelAndView doGetTaxonInformation(@RequestParam(value = "taxonUuid", required = true) String[] taxonUuids,\r
-                       HttpServletRequest request, \r
-                       HttpServletResponse response) throws IOException {\r
-               ModelAndView mv = new ModelAndView();\r
-               List <RemoteResponse> tiList = new ArrayList<RemoteResponse>();\r
-               for(String taxonUuid : taxonUuids ) {\r
-                       logger.info("doGetTaxonInformation()" + request.getServletPath() + " for taxon uuid \"" + taxonUuid);\r
-                       TaxonBase tb= taxonService.findTaxonByUuid(UUID.fromString(taxonUuid), TAXON_INFORMATION_INIT_STRATEGY);\r
-                       if(tb != null) {\r
-                               System.out.println("Name : " + tb.getTitleCache());\r
-                               TaxonInformation ti = new TaxonInformation();\r
-                               ti.setRequest(taxonUuid);\r
-\r
-                               if(tb.isInstanceOf(Taxon.class)) {\r
-                                       Taxon taxon = (Taxon)tb;\r
-                                       System.out.println("Is a Taxon");\r
-                                       ti.setResponseTaxon(tb.getTitleCache(), \r
-                                                       ACCECPTED_NAME_STATUS, \r
-                                                       buildFlagMap(tb),\r
-                                                       buildClassificationMap(taxon));                                 \r
-                                       Set<Synonym> synonyms = taxon.getSynonyms();\r
-                                       for(Synonym syn: synonyms) {\r
-                                               String uuid = syn.getUuid().toString();\r
-                                               String name = syn.getTitleCache();\r
-                                               String status = SYNONYM_STATUS; \r
-                                               ti.addToResponseRelatedTaxa(taxonUuid, name, status, "");\r
-                                       }\r
-                               } else if(tb instanceof Synonym) {\r
-                                       Synonym synonym = (Synonym)tb;\r
-                                       System.out.println("Is a Synonym");\r
-                                       ti.setResponseTaxon(tb.getTitleCache(), \r
-                                                       SYNONYM_STATUS, \r
-                                                       buildFlagMap(tb),\r
-                                                       null);\r
-                                       Set<Taxon> acceptedTaxa = synonym.getAcceptedTaxa();\r
-                                       for(Taxon taxon : acceptedTaxa) {\r
-                                               String uuid = taxon.getUuid().toString();\r
-                                               String name = taxon.getTitleCache();\r
-                                               String status = ACCECPTED_NAME_STATUS;\r
-                                               ti.addToResponseRelatedTaxa(taxonUuid, name, status, "");\r
-                                       }\r
-                               }                               \r
-                               tiList.add(ti); \r
-                       } else {\r
-                               ErrorResponse re = new ErrorResponse();\r
-                               re.setErrorMessage("No Taxon for given UUID : " + taxonUuid);\r
-                               tiList.add(re);\r
-                       }\r
-               }\r
-               mv.addObject(tiList);\r
-               return mv;       \r
-       }\r
-\r
-       private MatchMode getMatchModeFromQuery(String query) {\r
-               if(query.startsWith("*") && query.endsWith("*")) {\r
-                       return MatchMode.ANYWHERE;\r
-               } else if(query.startsWith("*")) {\r
-                       return MatchMode.END;\r
-               } else if(query.endsWith("*")) {\r
-                       return MatchMode.BEGINNING;\r
-               } else {\r
-                       return MatchMode.EXACT;\r
-               }\r
-       }\r
-\r
-       private String getQueryWithoutWildCards(String query) {\r
-\r
-               String newQuery = query;\r
-               if(query.startsWith("*")) {\r
-                       newQuery = newQuery.substring(1, newQuery.length());\r
-               }\r
-\r
-               if(query.endsWith("*")) {\r
-                       newQuery = newQuery.substring(0, newQuery.length()-1);\r
-               }\r
-               return newQuery;\r
-       }\r
-\r
-       private Map<String, String> buildFlagMap(TaxonBase tb) {\r
-               Map<String, String> flags = new Hashtable<String, String>();            \r
-               flags.put(DOUBTFUL_FLAG, Boolean.toString(tb.isDoubtful()));            \r
-               return flags;\r
-       }\r
-\r
-       private Map<String, Map> buildClassificationMap(Taxon taxon) {\r
-               Map<String, Map> classificationMap = new Hashtable<String, Map>();\r
-               Set<TaxonNode> taxonNodes = taxon.getTaxonNodes();\r
-\r
-               for(TaxonNode tn : taxonNodes) {\r
-                       Map<String, String> classification = new LinkedHashMap<String, String>();\r
-                       List<TaxonNode> tnList = classificationService.loadTreeBranchToTaxon(taxon, tn.getClassification(), null, TAXON_NODE_INIT_STRATEGY);\r
-                       for(TaxonNode classificationtn : tnList) {\r
-\r
-                               classification.put(classificationtn.getTaxon().getName().getRank().getTitleCache(), \r
-                                               classificationtn.getTaxon().getName().getTitleCache());\r
-                               System.out.println("Classification : " + classificationtn.getTaxon().getName().getRank().getTitleCache());\r
-\r
-                       }\r
-                       System.out.println("CTitle : " + tn.getClassification().getTitleCache());\r
-                       String cname = tn.getClassification().getTitleCache();\r
-                       String [] words = cname.split("\\s+");\r
-                       //"\\s+" in regular expression language meaning one or more spaces\r
-                       StringBuilder builder = new StringBuilder();     \r
-                       for (String word : words){\r
-                               builder.append(word);\r
-                       }               \r
-                       cname = builder.toString();             \r
-                       classificationMap.put(cname, classification);\r
-               }\r
-               return classificationMap;\r
-       }\r
-\r
-\r
+@RequestMapping(value = { "/name_catalogue" })\r
+public class NameCatalogueController extends BaseController<TaxonNameBase, INameService> implements ResourceLoaderAware {\r
+\r
+    private ResourceLoader resourceLoader;\r
+\r
+    /** Taxonomic status 'accepted' string */\r
+    public static final String ACCEPTED_NAME_STATUS = "accepted";\r
+\r
+    /** Taxonpmic status 'synonym' string */\r
+    public static final String SYNONYM_STATUS = "synonym";\r
+\r
+    /** Flag 'doubtful' strings */\r
+    public static final String DOUBTFUL_FLAG = "doubtful";\r
+\r
+    /** Base scientific name search type */\r
+    public static final String NAME_SEARCH = "name";\r
+\r
+    /** Complete scientific name search type */\r
+    public static final String TITLE_SEARCH = "title";\r
+\r
+    /** Default name search type */\r
+    public static final String DEFAULT_SEARCH_TYPE = NAME_SEARCH;\r
+\r
+    /** Classifcation 'default' key */\r
+    public static final String CLASSIFICATION_DEFAULT = "default";\r
+\r
+    /** Classifcation 'all' key */\r
+    public static final String CLASSIFICATION_ALL = "all";\r
+    \r
+    private static final String DWC_DATASET_ID = "http://rs.tdwg.org/dwc/terms/datasetID";\r
+\r
+    private static final DateTimeFormatter fmt = DateTimeFormat.forPattern("dd-MM-yyyy");\r
+    @Autowired\r
+    private ITaxonService taxonService;\r
+    \r
+    \r
+    @Autowired\r
+    private IClassificationService classificationService;\r
+    \r
+    @Autowired\r
+    private ICommonService commonService;\r
+    /** Hibernate name search initialisation strategy */\r
+    private static final List<String> NAME_SEARCH_INIT_STRATEGY = Arrays.asList(new String[] {\r
+            "combinationAuthorTeam.$",\r
+            "exCombinationAuthorTeam.$",\r
+            "basionymAuthorTeam.$",\r
+            "exBasionymAuthorTeam.$",\r
+            "nameCache",\r
+            "taxonBases",\r
+            "taxonBases.synonymRelations.type.$"});\r
+\r
+    /** Hibernate name information initialisation strategy */\r
+    private static final List<String> NAME_INFORMATION_INIT_STRATEGY = Arrays.asList(new String[] {\r
+            "taxonBases",\r
+            "status",\r
+            "nomenclaturalReference.$",\r
+            "combinationAuthorTeam.$",\r
+            "exCombinationAuthorTeam.$",\r
+            "basionymAuthorTeam.$",\r
+            "exBasionymAuthorTeam.$",\r
+            "relationsToThisName.fromName.$",\r
+            "relationsToThisName.nomenclaturalReference.$",\r
+            "relationsToThisName.type.$",\r
+            "relationsFromThisName.toName.$",\r
+            "relationsFromThisName.nomenclaturalReference.$",\r
+            "relationsFromThisName.type.$"});\r
+\r
+    /** Hibernate taxon information initialisation strategy */\r
+    private static final List<String> TAXON_INFORMATION_INIT_STRATEGY = Arrays.asList(new String[] {\r
+            "name.titleCache",\r
+            "name.rank.titleCache",    \r
+            \r
+            "sec.updated",\r
+            "sec.titleCache",\r
+            "sources.citation.sources.idNamespace",\r
+            "sources.citation.sources.idInSource",\r
+            \r
+            "synonymRelations.synonym.name.rank.titleCache",\r
+            "synonymRelations.synonym.sec.updated",\r
+            "synonymRelations.synonym.sec.titleCache",            \r
+            "synonymRelations.synonym.sources.citation.sources.idNamespace",\r
+            "synonymRelations.synonym.sources.citation.sources.idInSource",   \r
+            "synonymRelations.acceptedTaxon.name.rank.titleCache",\r
+            "synonymRelations.acceptedTaxon.sec.titleCache",\r
+            "synonymRelations.acceptedTaxon.sources.citation.sources.idNamespace",\r
+            "synonymRelations.acceptedTaxon.sources.citation.sources.idInSource",    \r
+            "synonymRelations.type.$",\r
+            \r
+            "relationsFromThisTaxon.type.$",\r
+            "relationsFromThisTaxon.toTaxon.name.rank.titleCache",\r
+            "relationsFromThisTaxon.toTaxon.sec.updated",\r
+            "relationsFromThisTaxon.toTaxon.sec.titleCache",\r
+            "relationsFromThisTaxon.toTaxon.sources.citation.sources.idNamespace",\r
+            "relationsFromThisTaxon.toTaxon.sources.citation.sources.idInSource",\r
+            \r
+            "relationsToThisTaxon.type.$",\r
+            "relationsToThisTaxon.fromTaxon.name.rank.titleCache",\r
+            "relationsToThisTaxon.fromTaxon.sec.updated",\r
+            "relationsToThisTaxon.fromTaxon.sec.titleCache",\r
+            "relationsToThisTaxon.fromTaxon.sources.citation.sources.idNamespace",\r
+            "relationsToThisTaxon.fromTaxon.sources.citation.sources.idInSource",\r
+            \r
+            "taxonNodes",\r
+            "taxonNodes.classification" });\r
+\r
+    /** Hibernate taxon node initialisation strategy */\r
+    private static final List<String> TAXON_NODE_INIT_STRATEGY = Arrays.asList(new String[] {\r
+            "taxon.sec",\r
+            "taxon.name",\r
+            "classification",\r
+            "classification.reference.$",\r
+            "classification.reference.authorTeam.$" });\r
+\r
+    /** Hibernate classification vocabulary initialisation strategy */\r
+    private static final List<String> VOC_CLASSIFICATION_INIT_STRATEGY = Arrays.asList(new String[] {\r
+            "classification",\r
+            "classification.reference.$",\r
+            "classification.reference.authorTeam.$" });\r
+    \r
+    /** Hibernate classification vocabulary initialisation strategy */\r
+    private static final List<String> COMMON_INIT_STRATEGY = Arrays.asList(new String[] {});\r
+    \r
+    public NameCatalogueController() {\r
+        super();\r
+        setInitializationStrategy(Arrays.asList(new String[] { "$" }));\r
+    }\r
+\r
+    /*\r
+     * (non-Javadoc)\r
+     *\r
+     * @see\r
+     * eu.etaxonomy.cdm.remote.controller.GenericController#setService(eu\r
+     * .etaxonomy.cdm.api.service.IService)\r
+     */\r
+    @Autowired\r
+    @Override\r
+    public void setService(INameService service) {\r
+        this.service = service;\r
+    }\r
+\r
+    /**\r
+     * Returns a documentation page for the Name Search API.\r
+     * <p>\r
+     * URI: <b>&#x002F;{datasource-name}&#x002F;name_catalogue</b>\r
+     *\r
+     * @param request\r
+     * @param response\r
+     * @return Html page describing the Name Search API\r
+     * @throws IOException\r
+     */\r
+    @RequestMapping(value = { "" }, method = RequestMethod.GET, params = {})\r
+    public ModelAndView doGetNameSearchDocumentation(\r
+            HttpServletRequest request, HttpServletResponse response)\r
+            throws IOException {\r
+        ModelAndView mv = new ModelAndView();\r
+        // Read apt documentation file.\r
+        Resource resource = resourceLoader.getResource("classpath:eu/etaxonomy/cdm/doc/remote/apt/name-catalogue-default.apt");\r
+        // using input stream as this works for both files in the classes directory\r
+        // as well as files inside jars\r
+        InputStream aptInputStream = resource.getInputStream();\r
+        // Build Html View\r
+        Map<String, String> modelMap = new HashMap<String, String>();\r
+        // Convert Apt to Html\r
+        modelMap.put("html", DocUtils.convertAptToHtml(aptInputStream));\r
+        mv.addAllObjects(modelMap);\r
+\r
+        HtmlView hv = new HtmlView();\r
+        mv.setView(hv);\r
+        return mv;\r
+    }\r
+\r
+    /**\r
+     * Returns a list of scientific names matching the <code>{query}</code>\r
+     * string pattern. Each of these scientific names is accompanied by a list of\r
+     * name uuids, a list of taxon uuids, a list of accepted taxon uuids, etc.\r
+     * <p>\r
+     * Endpoint documentation can be found <a href="{@docRoot}/../remote/name-catalogue-default.html">here</a>\r
+     * <p>\r
+     * URI: <b>&#x002F;{datasource-name}&#x002F;name_catalogue</b>\r
+     *\r
+     * @param queries\r
+     *                The base scientific name pattern(s) to query for. The query can\r
+     *                contain wildcard characters ('*'). The query can be\r
+     *                performed with no wildcard or with the wildcard at the\r
+     *                begin and / or end depending on the search pattern.\r
+     * @param request Http servlet request.\r
+     * @param response Http servlet response.\r
+     * @return a list of {@link NameSearch} objects each corresponding to a\r
+     *         single query. These are built from {@link TaxonNameBase}\r
+     *         entities which are in turn initialized using\r
+     *         the {@link #NAME_SEARCH_INIT_STRATEGY}\r
+     * @throws IOException\r
+     */\r
+    @RequestMapping(value = { "" }, method = RequestMethod.GET, params = {"query"})\r
+    public ModelAndView doGetNameSearch(@RequestParam(value = "query", required = true) String[] queries,\r
+            HttpServletRequest request, HttpServletResponse response) throws IOException {\r
+    return doGetNameSearch(queries, DEFAULT_SEARCH_TYPE, request, response);\r
+    }\r
+\r
+    /**\r
+     * Returns a list of scientific names matching the <code>{query}</code>\r
+     * string pattern. Each of these scientific names is accompanied by a list of\r
+     * name uuids, a list of taxon uuids and a list of accepted taxon uuids.\r
+     * <p>\r
+     * Endpoint documentation can be found <a href="{@docRoot}/../remote/name-catalogue-default.html">here</a>\r
+     * <p>\r
+     * URI: <b>&#x002F;{datasource-name}&#x002F;name_catalogue</b>\r
+     *\r
+     * @param query\r
+     *                The scientific name pattern(s) to query for. The query can\r
+     *                contain wildcard characters ('*'). The query can be\r
+     *                performed with no wildcard or with the wildcard at the\r
+     *                begin and / or end depending on the search pattern.\r
+     * @param type\r
+     *                The type of name to query. This be either\r
+     *                "name" : scientific name corresponding to 'name cache' in CDM or\r
+     *                "title" : complete name corresponding to 'title cache' in CDM\r
+     * @param request Http servlet request.\r
+     * @param response Http servlet response.\r
+     * @return a List of {@link NameSearch} objects each corresponding to a\r
+     *         single query. These are built from {@link TaxonNameBase} entities\r
+     *         which are in turn initialized using the {@link #NAME_SEARCH_INIT_STRATEGY}\r
+     * @throws IOException\r
+     */\r
+    @RequestMapping(value = { "" }, method = RequestMethod.GET, params = {"query", "type"})\r
+    public ModelAndView doGetNameSearch(@RequestParam(value = "query", required = true) String[] queries,\r
+            @RequestParam(value = "type", required = false, defaultValue = DEFAULT_SEARCH_TYPE) String searchType,\r
+            HttpServletRequest request, HttpServletResponse response) throws IOException {\r
+        ModelAndView mv = new ModelAndView();\r
+        List<RemoteResponse> nsList = new ArrayList<RemoteResponse>();\r
+\r
+        // if search type is not known then return error\r
+        if (!searchType.equals(NAME_SEARCH) && !searchType.equals(TITLE_SEARCH)) {\r
+            ErrorResponse er = new ErrorResponse();\r
+            er.setErrorMessage("searchType parameter can only be set as" + NAME_SEARCH + " or "\r
+                    + TITLE_SEARCH);\r
+            mv.addObject(er);\r
+            return mv;\r
+        }\r
+\r
+        // search through each query\r
+        for (String query : queries) {\r
+\r
+            String queryWOWildcards = getQueryWithoutWildCards(query);\r
+            MatchMode mm = getMatchModeFromQuery(query);\r
+            logger.info("doGetNameSearch()" + request.getServletPath() + " for query \"" + query\r
+                    + "\" without wild cards : " + queryWOWildcards + " and match mode : " + mm);\r
+            List<NonViralName> nameList = new ArrayList<NonViralName>();\r
+\r
+            // if "name" search then find by name cache\r
+            if (searchType.equals(NAME_SEARCH)) {\r
+                nameList = (List<NonViralName>) service.findNamesByNameCache(queryWOWildcards, mm,\r
+                        NAME_SEARCH_INIT_STRATEGY);\r
+            }\r
+\r
+            //if "title" search then find by title cache\r
+            if (searchType.equals(TITLE_SEARCH)) {\r
+                nameList = (List<NonViralName>) service.findNamesByTitleCache(queryWOWildcards, mm,\r
+                        NAME_SEARCH_INIT_STRATEGY);\r
+            }\r
+\r
+            // if search is successful then get related information , else return error\r
+            if (nameList == null || !nameList.isEmpty()) {\r
+                NameSearch ns = new NameSearch();\r
+                ns.setRequest(query);\r
+\r
+                for (NonViralName nvn : nameList) {\r
+                    // we need to retrieve both taxon uuid of name queried and\r
+                    // the corresponding accepted taxa.\r
+                    // reason to return accepted taxa also, is to be able to get from\r
+                    // scientific name to taxon concept in two web service calls.\r
+                    Set<TaxonBase> tbSet = nvn.getTaxonBases();\r
+                    Set<TaxonBase> accTbSet = new HashSet<TaxonBase>();\r
+                    for (TaxonBase tb : tbSet) {\r
+                        // if synonym then get accepted taxa.\r
+                        if (tb instanceof Synonym) {\r
+                            Synonym synonym = (Synonym) tb;\r
+                            Set<SynonymRelationship> synRelationships = synonym.getSynonymRelations();\r
+                            for (SynonymRelationship sr : synRelationships) {\r
+                                Taxon accTaxon = sr.getAcceptedTaxon();\r
+                                accTbSet.add(accTaxon);\r
+                            }\r
+                        } else {\r
+                            accTbSet.add(tb);\r
+                        }\r
+                    }\r
+                    // update name search object\r
+                    ns.addToResponseList(nvn.getTitleCache(), nvn.getNameCache(), nvn.getUuid()\r
+                            .toString(), tbSet, accTbSet);\r
+                }\r
+                nsList.add(ns);\r
+\r
+            } else {\r
+                ErrorResponse er = new ErrorResponse();\r
+                er.setErrorMessage("No Taxon Name for given query : " + query);\r
+                nsList.add(er);\r
+            }\r
+        }        \r
+\r
+        mv.addObject(nsList);\r
+        return mv;\r
+    }\r
+\r
+\r
+    /**\r
+     * Returns a documentation page for the Name Information API.\r
+     * <p>\r
+     * URI: <b>&#x002F;{datasource-name}&#x002F;name_catalogue/name</b>\r
+     *\r
+     * @param request Http servlet request.\r
+     * @param response Http servlet response.\r
+     * @return Html page describing the Name Information API\r
+     * @throws IOException\r
+     */\r
+    @RequestMapping(value = { "name" }, method = RequestMethod.GET, params = {})\r
+    public ModelAndView doGetNameInformationDocumentation(\r
+            HttpServletRequest request, HttpServletResponse response)\r
+            throws IOException {\r
+        ModelAndView mv = new ModelAndView();\r
+        // Read apt documentation file.\r
+        Resource resource = resourceLoader.getResource("classpath:eu/etaxonomy/cdm/doc/remote/apt/name-catalogue-name-info.apt");\r
+        // using input stream as this works for both files in the classes directory\r
+        // as well as files inside jars\r
+        InputStream aptInputStream = resource.getInputStream();\r
+        // Build Html View\r
+        Map<String, String> modelMap = new HashMap<String, String>();\r
+        // Convert Apt to Html\r
+        modelMap.put("html", DocUtils.convertAptToHtml(aptInputStream));\r
+        mv.addAllObjects(modelMap);\r
+\r
+        HtmlView hv = new HtmlView();\r
+        mv.setView(hv);\r
+        return mv;\r
+    }\r
+\r
+    /**\r
+     * Returns information related to the scientific name matching the given\r
+     * <code>{nameUuid}</code>. The information includes the name string,\r
+     * relationships, rank, list of related lsids / taxon uuids, etc.\r
+     * <p>\r
+     * Endpoint documentation can be found <a href="{@docRoot}/../remote/name-catalogue-name-info.html">here</a>\r
+     * <p>\r
+     * URI: <b>&#x002F;{datasource-name}&#x002F;name_catalogue/name</b>\r
+     *\r
+     * @param nameUuids uuid(s) of the scientific name to search for.\r
+     * @param request Http servlet request.\r
+     * @param response Http servlet response.\r
+     * @return a List of {@link NameInformation} objects each corresponding to a\r
+     *         single name uuid. These are built from {@link TaxonNameBase} entities\r
+     *         which are in turn initialized using the {@link #NAME_INFORMATION_INIT_STRATEGY}\r
+     * @throws IOException\r
+     */\r
+    @RequestMapping(value = { "name" }, method = RequestMethod.GET, params = {"nameUuid"})\r
+    public ModelAndView doGetNameInformation(@RequestParam(value = "nameUuid", required = true) String[] nameUuids,\r
+            HttpServletRequest request, HttpServletResponse response) throws IOException {\r
+        ModelAndView mv = new ModelAndView();\r
+        List<RemoteResponse> niList = new ArrayList<RemoteResponse>();\r
+        // loop through each name uuid\r
+        for (String nameUuid : nameUuids) {\r
+            logger.info("doGetNameInformation()" + request.getServletPath() + " for name uuid \""\r
+                    + nameUuid + "\"");\r
+            // find name by uuid\r
+            NonViralName nvn = (NonViralName) service.findNameByUuid(UUID.fromString(nameUuid),\r
+                        NAME_INFORMATION_INIT_STRATEGY);\r
+\r
+            // if search is successful then get related information, else return error\r
+            if (nvn != null) {\r
+                NameInformation ni = new NameInformation();\r
+                ni.setRequest(nameUuid);\r
+                Reference ref = (Reference) nvn.getNomenclaturalReference();\r
+                String citation = "";\r
+                String citation_details = "";\r
+                if (ref != null) {\r
+                    citation = ref.getTitleCache();\r
+                }\r
+                // update name information object\r
+                ni.setResponse(nvn.getTitleCache(), nvn.getNameCache(), nvn.getRank().getTitleCache(),\r
+                        nvn.getStatus(), citation, nvn.getRelationsFromThisName(),\r
+                        nvn.getRelationsToThisName(), nvn.getTaxonBases());\r
+                niList.add(ni);\r
+            } else {\r
+                ErrorResponse re = new ErrorResponse();\r
+\r
+                if(isValid(nameUuid)) {\r
+                    re.setErrorMessage("No Name for given UUID : " + nameUuid);\r
+                } else {\r
+                    re.setErrorMessage(nameUuid + " not a valid UUID");\r
+                }\r
+                niList.add(re);\r
+            }\r
+        }\r
+        mv.addObject(niList);\r
+        return mv;\r
+    }\r
+\r
+    /**\r
+     * Returns a documentation page for the Taxon Information API.\r
+     * <p>\r
+     * URI: <b>&#x002F;{datasource-name}&#x002F;name_catalogue/taxon</b>\r
+     *\r
+     * @param request Http servlet request.\r
+     * @param response Http servlet response.\r
+     * @return Html page describing the Taxon Information API\r
+     * @throws IOException\r
+     */\r
+    @RequestMapping(value = { "taxon" }, method = RequestMethod.GET, params = {})\r
+    public ModelAndView doGetTaxonInformation(\r
+            HttpServletRequest request, HttpServletResponse response)\r
+            throws IOException {\r
+        ModelAndView mv = new ModelAndView();\r
+        // Read apt documentation file.\r
+        Resource resource = resourceLoader.getResource("classpath:eu/etaxonomy/cdm/doc/remote/apt/name-catalogue-taxon-info.apt");\r
+        // using input stream as this works for both files in the classes directory\r
+        // as well as files inside jars\r
+        InputStream aptInputStream = resource.getInputStream();\r
+        // Build Html View\r
+        Map<String, String> modelMap = new HashMap<String, String>();\r
+        // Convert Apt to Html\r
+        modelMap.put("html", DocUtils.convertAptToHtml(aptInputStream));\r
+        mv.addAllObjects(modelMap);\r
+\r
+        HtmlView hv = new HtmlView();\r
+        mv.setView(hv);\r
+        return mv;\r
+    }\r
+\r
+    /**\r
+     * Returns information related to the taxon matching the given\r
+     * <code>{taxonUuid}</code>. The information includes the name cache, title cache\r
+     * relationship type, taxonomic status, information , etc.\r
+     * <p>\r
+     * Endpoint documentation can be found <a href="{@docRoot}/../remote/name-catalogue-taxon-info.html">here</a>\r
+     * <p>\r
+     * URI: <b>&#x002F;{datasource-name}&#x002F;name_catalogue</b>\r
+     *\r
+     * @param taxonUuid\r
+     *                 The taxon uuid to query for. The classification returned corresponds\r
+     *                 to the first in the alphabetically sorted list of classifications\r
+     *                 currently available in the database.\r
+     *\r
+     * @param request Http servlet request.\r
+     * @param response Http servlet response.\r
+     * @return a List of {@link TaxonInformation} objects each corresponding to a\r
+     *         single query. These are built from {@TaxonBase} entities which are\r
+     *         in turn initialized using the {@link #TAXON_INFORMATION_INIT_STRATEGY}\r
+     * @throws IOException\r
+     */\r
+    @RequestMapping(value = { "taxon" }, method = RequestMethod.GET,params = {"taxonUuid"})\r
+    public ModelAndView doGetTaxonInformation(\r
+            @RequestParam(value = "taxonUuid", required = true) String[] taxonUuids,\r
+            HttpServletRequest request, HttpServletResponse response) throws IOException {\r
+        return doGetTaxonInformation(taxonUuids,CLASSIFICATION_DEFAULT, request, response);\r
+    }\r
+\r
+    /**\r
+     * Returns information related to the taxon matching the given\r
+     * <code>{taxonUuid}</code>. The information includes the name cache, title cache\r
+     * relationship type, taxonomic status, information , etc.\r
+     * <p>\r
+     * Endpoint documentation can be found <a href="{@docRoot}/../remote/name-catalogue-taxon-info.html">here</a>\r
+     * <p>\r
+     * URI: <b>&#x002F;{datasource-name}&#x002F;name_catalogue/taxon</b>\r
+     *\r
+     * @param taxonUuid\r
+     *                 The taxon uuid to query for.\r
+     * @param classification\r
+     *                 [Optional] String representing the taxonomic classification to use for\r
+     *                 building the classification tree. Defaults to the first in the alphabetically\r
+     *                 sorted list of classifications currently available in the database.\r
+     *\r
+     * @param request Http servlet request.\r
+     * @param response Http servlet response.\r
+     * @return a List of {@link TaxonInformation} objects each corresponding to a\r
+     *         single query. These are built from {@TaxonBase} entities which are\r
+     *         in turn initialized using the {@link #TAXON_INFORMATION_INIT_STRATEGY}\r
+     * @throws IOException\r
+     */\r
+    @RequestMapping(value = { "taxon" }, method = RequestMethod.GET, params = {"taxonUuid", "classification"})\r
+    public ModelAndView doGetTaxonInformation(\r
+            @RequestParam(value = "taxonUuid", required = true) String[] taxonUuids,\r
+            @RequestParam(value = "classification", required = false, defaultValue = CLASSIFICATION_DEFAULT) String classificationType,\r
+            HttpServletRequest request, HttpServletResponse response) throws IOException {\r
+        ModelAndView mv = new ModelAndView();\r
+        List<RemoteResponse> tiList = new ArrayList<RemoteResponse>();\r
+        // loop through each name uuid\r
+        for (String taxonUuid : taxonUuids) {\r
+            logger.info("doGetTaxonInformation()" + request.getServletPath() + " for taxon uuid \""\r
+                    + taxonUuid);\r
+            // find name by uuid\r
+            TaxonBase tb = taxonService.findTaxonByUuid(UUID.fromString(taxonUuid),\r
+                    TAXON_INFORMATION_INIT_STRATEGY);\r
+            \r
+            // if search is successful then get related information, else return error\r
+            if (tb != null) {\r
+                TaxonInformation ti = new TaxonInformation();\r
+                ti.setRequest(taxonUuid);\r
+                // check if result (taxon base) is a taxon or synonym\r
+                if (tb.isInstanceOf(Taxon.class)) {\r
+                    Taxon taxon = (Taxon) tb;\r
+                    // build classification map\r
+                    Map classificationMap = getClassification(taxon, classificationType);\r
+\r
+                    logger.info("taxon uuid " + taxon.getUuid().toString() + " original hash code : " + System.identityHashCode(taxon) + ", name class " + taxon.getName().getClass().getName());
+                    // update taxon information object with taxon related data\r
+                    NonViralName nvn = (NonViralName) taxon.getName();\r
+\r
+                    String secTitle = "" ;\r
+                    String modified = "";\r
+                    if(taxon.getSec() != null) {\r
+                       secTitle = taxon.getSec().getTitleCache();\r
+                       DateTime dt = taxon.getUpdated();                               \r
+                        modified = fmt.print(dt);\r
+                    }\r
+                    \r
+                    Set<IdentifiableSource> sources = taxon.getSources();\r
+                    String[] didname = getDatasetIdName(sources);                    \r
+\r
+                    ti.setResponseTaxon(tb.getTitleCache(),\r
+                            nvn.getTitleCache(),\r
+                            nvn.getRank().getTitleCache(),\r
+                            ACCEPTED_NAME_STATUS,\r
+                            buildFlagMap(tb),\r
+                            classificationMap,\r
+                            "",\r
+                            didname[0],\r
+                            didname[1],\r
+                            secTitle,\r
+                            modified);\r
+                    \r
+                    \r
+                    Set<SynonymRelationship> synRelationships = taxon.getSynonymRelations();\r
+                    // add synonyms (if exists) to taxon information object\r
+                    for (SynonymRelationship sr : synRelationships) {\r
+                        Synonym syn = sr.getSynonym();\r
+                        String uuid = syn.getUuid().toString();\r
+                        String title = syn.getTitleCache();\r
+                        TaxonNameBase synnvn = (TaxonNameBase) syn.getName();\r
+                        String name = synnvn.getTitleCache();\r
+                        String rank = synnvn.getRank().getTitleCache();\r
+                        String status = SYNONYM_STATUS;\r
+                        String relLabel = sr.getType()\r
+                                .getInverseRepresentation(Language.DEFAULT())\r
+                                .getLabel();\r
+                        \r
+                        secTitle = "" ;\r
+                        modified = "";\r
+                        if(syn.getSec() != null) {\r
+                               secTitle = syn.getSec().getTitleCache();\r
+                               DateTime dt = syn.getUpdated();                               \r
+                            modified = fmt.print(dt);\r
+                        }\r
+                        \r
+                        sources = syn.getSources();\r
+                        didname = getDatasetIdName(sources);\r
+                                                \r
+                        ti.addToResponseRelatedTaxa(uuid, \r
+                                       title, \r
+                                       name, \r
+                                       rank, \r
+                                       status, \r
+                                       relLabel,\r
+                                       "",\r
+                                didname[0],\r
+                                didname[1],\r
+                                       secTitle,\r
+                                modified);\r
+                    }\r
+\r
+                    // build relationship information as,\r
+                    // - relationships from the requested taxon\r
+                    Set<TaxonRelationship> trFromSet = taxon.getRelationsFromThisTaxon();\r
+                    for (TaxonRelationship tr : trFromSet) {                        \r
+                        String titleTo = tr.getToTaxon().getTitleCache();\r
+                        TaxonNameBase tonvn = (TaxonNameBase) tr.getToTaxon().getName();\r
+                        String name = tonvn.getTitleCache();\r
+                        String rank = tonvn.getRank().getTitleCache();\r
+                        String uuid = tr.getToTaxon().getUuid().toString();\r
+                        String status = ACCEPTED_NAME_STATUS;\r
+                        String relLabel = tr.getType().getRepresentation(Language.DEFAULT())\r
+                                .getLabel();\r
+\r
+                        secTitle = "" ;\r
+                        modified = "";\r
+                        if(tr.getToTaxon().getSec() != null) {\r
+                               secTitle = tr.getToTaxon().getSec().getTitleCache();\r
+                               DateTime dt = tr.getToTaxon().getUpdated();                               \r
+                            modified = fmt.print(dt);\r
+                        }\r
+                        \r
+                        sources = tr.getToTaxon().getSources();\r
+                        didname = getDatasetIdName(sources);\r
+                                                \r
+                        ti.addToResponseRelatedTaxa(uuid, \r
+                                       titleTo, \r
+                                       name, \r
+                                       rank, \r
+                                       status, \r
+                                       relLabel,\r
+                                       "",\r
+                                didname[0],\r
+                                didname[1],\r
+                                       secTitle,\r
+                                modified);\r
+                        //logger.info("titleTo : " + titleTo + " , name : " + name);\r
+                    }\r
+\r
+                    // - relationships to the requested taxon\r
+                    Set<TaxonRelationship> trToSet = taxon.getRelationsToThisTaxon();\r
+                    for (TaxonRelationship tr : trToSet) {\r
+                        String titleFrom = tr.getFromTaxon().getTitleCache();\r
+                        TaxonNameBase fromnvn = (TaxonNameBase) tr.getFromTaxon().getName();\r
+                        String name = fromnvn.getTitleCache();\r
+                        String rank = fromnvn.getRank().getTitleCache();\r
+                        String uuid = tr.getFromTaxon().getUuid().toString();\r
+                        String status = ACCEPTED_NAME_STATUS;\r
+                        String relLabel = tr.getType()\r
+                                .getInverseRepresentation(Language.DEFAULT())\r
+                                .getLabel();\r
+\r
+                        if(tr.getFromTaxon().getSec() != null) {\r
+                               secTitle = tr.getFromTaxon().getSec().getTitleCache();\r
+                               DateTime dt = tr.getFromTaxon().getSec().getUpdated();                               \r
+                            modified = fmt.print(dt);\r
+                        }\r
+                        \r
+                        sources = tr.getFromTaxon().getSources();\r
+                        didname = getDatasetIdName(sources);\r
+                        \r
+                        secTitle = (tr.getFromTaxon().getSec() == null) ? "" : tr.getFromTaxon().getSec().getTitleCache();\r
+                        ti.addToResponseRelatedTaxa(uuid, \r
+                                       titleFrom, \r
+                                       name, \r
+                                       rank, \r
+                                       status,\r
+                                       relLabel,\r
+                                       "",\r
+                                didname[0],\r
+                                didname[1],\r
+                                       secTitle,\r
+                                modified);\r
+                        //logger.info("titleFrom : " + titleFrom + " , name : " + name);\r
+                    }\r
+                } else if (tb instanceof Synonym) {\r
+                    Synonym synonym = (Synonym) tb;\r
+                    TaxonNameBase nvn = (TaxonNameBase) synonym.getName();\r
+                 // update taxon information object with synonym related data\r
+                    DateTime dt = synonym.getUpdated();                    \r
+                    String modified = fmt.print(dt);\r
+                    \r
+                    Set<IdentifiableSource> sources = synonym.getSources();\r
+                    String[] didname = getDatasetIdName(sources);\r
+                    \r
+                    String secTitle = (synonym.getSec() == null) ? "" : synonym.getSec().getTitleCache();\r
+                    ti.setResponseTaxon(synonym.getTitleCache(),\r
+                            nvn.getTitleCache(),\r
+                            nvn.getRank().getTitleCache(),\r
+                            SYNONYM_STATUS,\r
+                            buildFlagMap(synonym),\r
+                            new TreeMap<String,Map>(),\r
+                            "",\r
+                            didname[0],\r
+                            didname[1],\r
+                               secTitle,\r
+                            modified);\r
+                    // add accepted taxa (if exists) to taxon information object\r
+                    \r
+                    Set<SynonymRelationship> synRelationships = synonym.getSynonymRelations();\r
+                    for (SynonymRelationship sr : synRelationships) {\r
+                        Taxon accTaxon = sr.getAcceptedTaxon();                        \r
+                        String uuid = accTaxon.getUuid().toString();\r
+                        logger.info("acc taxon uuid " + accTaxon.getUuid().toString() + " original hash code : " + System.identityHashCode(accTaxon) + ", name class " + accTaxon.getName().getClass().getName());\r
+                        String title = accTaxon.getTitleCache();\r
+                        logger.info("taxon title cache : " + accTaxon.getTitleCache());\r
+                                           \r
+                        TaxonNameBase accnvn = (TaxonNameBase)accTaxon.getName();\r
+                        String name = accnvn.getTitleCache();\r
+                        String rank = accnvn.getRank().getTitleCache();\r
+                        String status = ACCEPTED_NAME_STATUS;\r
+                        String relLabel = sr.getType().getRepresentation(Language.DEFAULT())\r
+                                .getLabel();\r
+                        dt = accTaxon.getUpdated();                    \r
+                        modified = fmt.print(dt);\r
+                        \r
+                        sources = accTaxon.getSources();\r
+                        didname = getDatasetIdName(sources);\r
+                        \r
+                        secTitle = (accTaxon.getSec() == null) ? "" : accTaxon.getSec().getTitleCache();\r
+                        ti.addToResponseRelatedTaxa(uuid, \r
+                                       title, \r
+                                       name, \r
+                                       rank, \r
+                                       status, \r
+                                       relLabel,\r
+                                       "",\r
+                                didname[0],\r
+                                didname[1],\r
+                                       secTitle,\r
+                                modified);\r
+                    }\r
+\r
+                }\r
+                tiList.add(ti);\r
+            } else {\r
+                ErrorResponse re = new ErrorResponse();\r
+                if(isValid(taxonUuid)) {\r
+                    re.setErrorMessage("No Taxon for given UUID : " + taxonUuid);\r
+                } else {\r
+                    re.setErrorMessage(taxonUuid + " not a valid UUID");\r
+                }\r
+                tiList.add(re);\r
+            }\r
+        }\r
+        mv.addObject(tiList);\r
+        return mv;\r
+    }\r
+\r
+    /**\r
+     * Returns a list of all available classifications (with associated referenc information) and the default classification.\r
+     * <p>\r
+     * Endpoint documentation can be found <a href="{@docRoot}/../remote/name-catalogue-classification-info.html">here</a>\r
+     * <p>\r
+     * URI: <b>&#x002F;{datasource-name}&#x002F;name_catalogue/voc/classification</b>\r
+     *\r
+     * @param request Http servlet request.\r
+     * @param response Http servlet response.\r
+     * @return a List of {@link Classification} objects represebted as strings.\r
+     *         These are initialized using the {@link #VOC_CLASSIFICATION_INIT_STRATEGY}\r
+     * @throws IOException\r
+     */\r
+    @RequestMapping(value = { "voc/classification" }, method = RequestMethod.GET, params = {})\r
+    public ModelAndView doGetClassificationMap(HttpServletRequest request, HttpServletResponse response) throws IOException {\r
+        List<Map> cmapList = new ArrayList<Map>();\r
+        Map<String, String> classifications = new HashMap<String, String>();\r
+        ModelAndView mv = new ModelAndView();\r
+        List<Classification> clist = getClassificationList(100);\r
+        boolean isFirst = true;\r
+        Iterator itr = clist.iterator();\r
+        // loop through all classifications and populate map with\r
+        // (classificationKey, reference) elements\r
+        while(itr.hasNext()) {\r
+            Classification c = (Classification) itr.next();\r
+            String refTitleCache = "";\r
+            String classificationKey = removeInternalWhitespace(c.getTitleCache());\r
+            if(c.getReference() != null) {\r
+                refTitleCache = c.getReference().getTitleCache();\r
+            }\r
+            // default is the first element of the list\r
+            // always created with the same sorting (DESCENDING)\r
+            if(isFirst) {\r
+                Map<String, String> defaultMap = new HashMap<String, String>();\r
+                defaultMap.put("default", classificationKey);\r
+                cmapList.add(defaultMap);\r
+                isFirst = false;\r
+            }\r
+            classifications.put(classificationKey, refTitleCache);\r
+\r
+        }\r
+        Map<String, Map> cmap = new HashMap<String, Map>();\r
+        cmap.put("classification",classifications);\r
+        cmapList.add(cmap);\r
+        mv.addObject(cmapList);\r
+        return mv;\r
+    }\r
+\r
+    /**\r
+     * Returns the Dataset ID / Name of the given original source.\r
+     * FIXME: Very hacky and needs to be revisited. Mainly for deciding on which objects to use during import.\r
+     * FIXME: dataset id is mapped to a DWC term - is that right?\r
+     * \r
+     * @param sources Set of sources attached to a taxa / synonym\r
+     *             \r
+     *\r
+     * @return String array where [0] is the datsetID and [1] is the datsetName\r
+     */\r
+    private String[] getDatasetIdName(Set<IdentifiableSource> sources) {\r
+       String didname[] = {"",""};\r
+        Iterator<IdentifiableSource> itr = sources.iterator();\r
+        while(itr.hasNext()) {\r
+               IdentifiableSource source = itr.next();         \r
+               Reference ref = source.getCitation();              \r
+            Set<IdentifiableSource> ref_sources = ref.getSources();\r
+            Iterator<IdentifiableSource> ref_itr = ref_sources.iterator();\r
+            while(ref_itr.hasNext()) {\r
+               IdentifiableSource ref_source = ref_itr.next();                 \r
+               if(ref_source.getIdNamespace().equals(DWC_DATASET_ID)) {\r
+                       didname[0] = ref_source.getIdInSource();\r
+                       break;\r
+               }\r
+            }\r
+            if(!didname[0].isEmpty()) {\r
+               didname[1] = ref.getTitleCache();\r
+               break;\r
+            }\r
+        }\r
+       return didname;\r
+    }\r
+    \r
+    /**\r
+     * Returns the match mode by parsing the input string of wildcards.\r
+     *\r
+     * @param query\r
+     *             String to parse.\r
+     *\r
+     * @return {@link MatchMode} depending on the the position of the wildcard (*)\r
+     */\r
+    private MatchMode getMatchModeFromQuery(String query) {\r
+        if (query.startsWith("*") && query.endsWith("*")) {\r
+            return MatchMode.ANYWHERE;\r
+        } else if (query.startsWith("*")) {\r
+            return MatchMode.END;\r
+        } else if (query.endsWith("*")) {\r
+            return MatchMode.BEGINNING;\r
+        } else {\r
+            return MatchMode.EXACT;\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Removes wildcards from the input string.\r
+     *\r
+     * @param query\r
+     *             String to parse.\r
+     *\r
+     * @return input string with wildcards removed\r
+     */\r
+    private String getQueryWithoutWildCards(String query) {\r
+\r
+        String newQuery = query;\r
+\r
+        if (query.startsWith("*")) {\r
+            newQuery = newQuery.substring(1, newQuery.length());\r
+        }\r
+\r
+        if (query.endsWith("*")) {\r
+            newQuery = newQuery.substring(0, newQuery.length() - 1);\r
+        }\r
+\r
+        return newQuery.trim();\r
+    }\r
+\r
+    /**\r
+     * Build map with taxon flag key-value pairs.\r
+     */\r
+    private Map<String, String> buildFlagMap(TaxonBase tb) {\r
+        Map<String, String> flags = new Hashtable<String, String>();\r
+        flags.put(DOUBTFUL_FLAG, Boolean.toString(tb.isDoubtful()));\r
+        return flags;\r
+    }\r
+\r
+    /**\r
+     * Build classification map.\r
+     */
+    private Map<String, Map> getClassification(Taxon taxon, String classificationType) {\r
+        // Using TreeMap is important, because we need the sorting of the classification keys\r
+        // in the map to be stable.\r
+        TreeMap<String, Map> sourceClassificationMap = buildClassificationMap(taxon, classificationType);\r
+\r
+        // if classification key is 'default' then return the default element of the map\r
+        if(classificationType.equals(CLASSIFICATION_DEFAULT) && !sourceClassificationMap.isEmpty()) {\r
+            List<Classification> clist = getClassificationList(1);\r
+            String defaultKey = removeInternalWhitespace(clist.get(0).getTitleCache());\r
+            return sourceClassificationMap.get(defaultKey);\r
+            // if classification key is provided then return the classification corresponding to the key\r
+        } else if(sourceClassificationMap.containsKey(classificationType)) {\r
+            return sourceClassificationMap.get(classificationType);\r
+            // if classification key is 'all' then return the entire map\r
+        } else if(classificationType.equals(CLASSIFICATION_ALL)) {\r
+            return sourceClassificationMap;\r
+        } else {\r
+            return new TreeMap<String,Map>();\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Build classification map.\r
+     */\r
+    private TreeMap<String, Map> buildClassificationMap(Taxon taxon, String classificationType) {\r
+        // Using TreeMap is important, because we need the sorting of the classification keys
+        // in the map to be stable.\r
+        TreeMap<String, Map> sourceClassificationMap = new TreeMap<String, Map>();\r
+        Set<TaxonNode> taxonNodes = taxon.getTaxonNodes();\r
+        //loop through taxon nodes and build classification map for each classification key\r
+        for (TaxonNode tn : taxonNodes) {\r
+            Map<String, String> classificationMap = new LinkedHashMap<String, String>();\r
+            List<TaxonNode> tnList = classificationService.loadTreeBranchToTaxon(taxon,\r
+                    tn.getClassification(), null, TAXON_NODE_INIT_STRATEGY);\r
+            for (TaxonNode classificationtn : tnList) {\r
+                classificationMap.put(classificationtn.getTaxon().getName().getRank().getTitleCache(),\r
+                        classificationtn.getTaxon().getName().getTitleCache());\r
+            }\r
+            String cname = removeInternalWhitespace(tn.getClassification().getTitleCache());\r
+            logger.info("Building classification map " + cname);\r
+            sourceClassificationMap.put(cname, classificationMap);\r
+        }\r
+        return sourceClassificationMap;\r
+    }\r
+\r
+    private String removeInternalWhitespace(String withWSpace) {\r
+        String[] words = withWSpace.split("\\s+");\r
+        // "\\s+" in regular expression language meaning one or\r
+        // more spaces\r
+        StringBuilder builder = new StringBuilder();\r
+        for (String word : words) {\r
+            builder.append(word);\r
+        }\r
+        return builder.toString();\r
+    }\r
+\r
+    private List<Classification> getClassificationList(int limit) {\r
+        List<OrderHint> orderHints = new ArrayList<OrderHint>();\r
+        orderHints.add(new OrderHint("titleCache", SortOrder.DESCENDING));\r
+        List<Classification> clist = classificationService.listClassifications(limit, 0, orderHints, VOC_CLASSIFICATION_INIT_STRATEGY);\r
+        return clist;\r
+    }\r
+\r
+    private boolean isValid(String uuid){\r
+        if( uuid == null) return false;\r
+        try {\r
+            // we have to convert to object and back to string because the built in fromString does not have\r
+            // good validation logic.\r
+\r
+            UUID fromStringUUID = UUID.fromString(uuid);\r
+            String toStringUUID = fromStringUUID.toString();\r
+\r
+            System.out.println("input uuid : " + uuid + " , parsed uuid : " + toStringUUID);\r
+            return toStringUUID.equals(uuid);\r
+        } catch(IllegalArgumentException e) {\r
+            return false;\r
+        }\r
+    }\r
+    @Override\r
+    public void setResourceLoader(ResourceLoader resourceLoader) {\r
+        this.resourceLoader = resourceLoader;\r
+\r
+    }\r
 }\r