+\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
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>/{datasource-name}/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>/{datasource-name}/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>/{datasource-name}/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>/{datasource-name}/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>/{datasource-name}/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>/{datasource-name}/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>/{datasource-name}/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>/{datasource-name}/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>/{datasource-name}/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>/{datasource-name}/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>/{datasource-name}/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