1 package eu
.etaxonomy
.cdm
.remote
.controller
;
3 import java
.io
.IOException
;
4 import java
.util
.ArrayList
;
5 import java
.util
.Arrays
;
6 import java
.util
.LinkedHashMap
;
10 import java
.util
.UUID
;
12 import javax
.servlet
.http
.HttpServletRequest
;
13 import javax
.servlet
.http
.HttpServletResponse
;
15 import java
.util
.Hashtable
;
16 import org
.springframework
.beans
.factory
.annotation
.Autowired
;
17 import org
.springframework
.stereotype
.Controller
;
18 import org
.springframework
.web
.bind
.annotation
.RequestMapping
;
19 import org
.springframework
.web
.bind
.annotation
.RequestMethod
;
20 import org
.springframework
.web
.bind
.annotation
.RequestParam
;
21 import org
.springframework
.web
.servlet
.ModelAndView
;
23 import eu
.etaxonomy
.cdm
.api
.service
.IClassificationService
;
24 import eu
.etaxonomy
.cdm
.api
.service
.INameService
;
25 import eu
.etaxonomy
.cdm
.api
.service
.ITaxonService
;
27 import eu
.etaxonomy
.cdm
.remote
.dto
.common
.ErrorResponse
;
28 import eu
.etaxonomy
.cdm
.remote
.dto
.common
.RemoteResponse
;
29 import eu
.etaxonomy
.cdm
.remote
.dto
.namecatalogue
.NameInformation
;
30 import eu
.etaxonomy
.cdm
.remote
.dto
.namecatalogue
.NameSearch
;
31 import eu
.etaxonomy
.cdm
.remote
.dto
.namecatalogue
.TaxonInformation
;
32 import eu
.etaxonomy
.cdm
.model
.common
.Language
;
33 import eu
.etaxonomy
.cdm
.model
.name
.NonViralName
;
34 import eu
.etaxonomy
.cdm
.model
.name
.TaxonNameBase
;
35 import eu
.etaxonomy
.cdm
.model
.name
.TypeDesignationBase
;
36 import eu
.etaxonomy
.cdm
.model
.reference
.Reference
;
37 import eu
.etaxonomy
.cdm
.model
.taxon
.Synonym
;
38 import eu
.etaxonomy
.cdm
.model
.taxon
.SynonymRelationship
;
39 import eu
.etaxonomy
.cdm
.model
.taxon
.Taxon
;
40 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonBase
;
41 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonNode
;
42 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonRelationship
;
43 import eu
.etaxonomy
.cdm
.persistence
.query
.MatchMode
;
46 * The controller class for the namespace 'name_catalogue'.
47 * This controller provides search mechanisims for searching by taxon name as well as taxon.
51 * @created 15-Apr-2012
55 @RequestMapping(value
= {"/name_catalogue"})
56 public class NameCatalogueController
extends BaseController
<TaxonNameBase
, INameService
> {
58 /** Taxon status strings*/
59 public static final String ACCEPTED_NAME_STATUS
= "accepted";
60 public static final String SYNONYM_STATUS
= "synonym";
63 public static final String DOUBTFUL_FLAG
= "doubtful";
66 public static final String NAME_SEARCH
= "name";
67 public static final String TITLE_SEARCH
= "title";
70 private ITaxonService taxonService
;
73 private IClassificationService classificationService
;
75 private static final List
<String
> NAME_SEARCH_INIT_STRATEGY
= Arrays
.asList(new String
[]{
76 "combinationAuthorTeam.$",
77 "exCombinationAuthorTeam.$",
78 "basionymAuthorTeam.$",
79 "exBasionymAuthorTeam.$",
84 private static final List
<String
> NAME_INFORMATION_INIT_STRATEGY
= Arrays
.asList(new String
[]{
87 "nomenclaturalReference.$",
88 "combinationAuthorTeam.$",
89 "exCombinationAuthorTeam.$",
90 "basionymAuthorTeam.$",
91 "exBasionymAuthorTeam.$",
92 "relationsToThisName.$",
93 "relationsFromThisName.$"
96 private static final List
<String
> TAXON_INFORMATION_INIT_STRATEGY
= Arrays
.asList(new String
[]{
97 "synonymRelations.type.$",
98 "relationsFromThisTaxon.type.$",
99 "relationsToThisTaxon.type.$",
101 "taxonNodes.classification"
104 private static final List
<String
> TAXON_NODE_INIT_STRATEGY
= Arrays
.asList(new String
[]{
108 "classification.reference.$",
109 "classification.reference.authorTeam.$"
112 public NameCatalogueController(){
114 setInitializationStrategy(Arrays
.asList(new String
[]{"$"})); //TODO still needed????
118 * @see eu.etaxonomy.cdm.remote.controller.GenericController#setService(eu.etaxonomy.cdm.api.service.IService)
122 public void setService(INameService service
) {
123 this.service
= service
;
127 * Returns a list of taxon names matching the <code>{query}</code> string pattern.
128 * Each of these taxon names is accompanied by a list of name uuids and
129 * a list of taxon uuids.
131 * URI: <b>/{datasource-name}/name_catalogue</b>
134 * The taxon name pattern(s) to query for. The query can contain wildcard characters ('*').
135 * The query can be performed with no wildcard or with the wildcard at the begin and / or end
136 * depending on the search pattern.
138 * The type of name to query. This could any of,
139 * - name : scientific name corresponding to 'name cache' in CDM
140 * - title : complete name corresponding to 'title cache' in CDM
143 * @return a List of {@link NameSearch} objects each corresponding to a single query. These are built from
144 * {@TaxonNameBase} entities which are in turn initialized using the {@link #NAME_SEARCH_INIT_STRATEGY}
145 * @throws IOException
147 @RequestMapping(value
= {""},
148 method
= RequestMethod
.GET
)
149 public ModelAndView
doGetNameSearch(@RequestParam(value
= "query", required
= true) String
[] queries
,
150 @RequestParam(value
= "type", required
= false, defaultValue
=NAME_SEARCH
) String searchType
,
151 HttpServletRequest request
,
152 HttpServletResponse response
) throws IOException
{
153 ModelAndView mv
= new ModelAndView();
154 List
<RemoteResponse
> nsList
= new ArrayList
<RemoteResponse
>();
156 if(!searchType
.equals(NAME_SEARCH
) && !searchType
.equals(TITLE_SEARCH
)) {
157 ErrorResponse er
= new ErrorResponse();
158 er
.setErrorMessage("searchType parameter can only be set as" + NAME_SEARCH
+ " or " + TITLE_SEARCH
);
163 for(String query
: queries
) {
165 String queryWOWildcards
= getQueryWithoutWildCards(query
);
166 MatchMode mm
= getMatchModeFromQuery(query
);
167 logger
.info("doGetNameSearch()" + request
.getServletPath() + " for query \"" + query
+ "\" without wild cards : " + queryWOWildcards
+ " and match mode : " + mm
);
168 List
<NonViralName
> nameList
= new ArrayList
<NonViralName
>();
169 if(searchType
.equals(NAME_SEARCH
)) {
170 nameList
= (List
<NonViralName
>)service
.findNamesByNameCache(queryWOWildcards
, mm
, NAME_SEARCH_INIT_STRATEGY
);
173 if(searchType
.equals(TITLE_SEARCH
)) {
174 nameList
= (List
<NonViralName
>)service
.findNamesByTitleCache(queryWOWildcards
, mm
, NAME_SEARCH_INIT_STRATEGY
);
176 if(nameList
== null || !nameList
.isEmpty()) {
177 NameSearch ns
= new NameSearch();
178 ns
.setRequest(query
);
180 for (NonViralName nvn
: nameList
)
182 ns
.addToResponseList(nvn
.getTitleCache(), nvn
.getNameCache(), nvn
.getUuid().toString(), nvn
.getTaxonBases());
187 ErrorResponse er
= new ErrorResponse();
188 er
.setErrorMessage("No Taxon Name for given query : " + query
);
192 mv
.addObject(nsList
);
197 * Returns information related to the taxon name matching the given <code>{nameUuid}</code>.
198 * The information includes the name string, relationships, rank, list of related lsids / taxon uuids, etc.
200 * URI: <b>/{datasource-name}/name_catalogue</b>
203 * The taxon name pattern(s) to query for. The query can contain wildcard characters ('*').
204 * The query can be performed with no wildcard or with the wildcard at the begin and / or end
205 * depending on the search pattern.
208 * @return a List of {@link NameSearch} objects each corresponding to a single query. These are built from
209 * {@TaxonNameBase} entities which are in turn initialized using the {@link #NAME_SEARCH_INIT_STRATEGY}
210 * @throws IOException
212 @RequestMapping(value
= {"name"},
213 method
= RequestMethod
.GET
)
214 public ModelAndView
doGetNameInformation(@RequestParam(value
= "nameUuid", required
= true) String
[] nameUuids
,
215 HttpServletRequest request
,
216 HttpServletResponse response
) throws IOException
{
217 ModelAndView mv
= new ModelAndView();
218 List
<RemoteResponse
> niList
= new ArrayList
<RemoteResponse
>();
219 for(String nameUuid
: nameUuids
) {
220 logger
.info("doGetNameInformation()" + request
.getServletPath() + " for name uuid \"" + nameUuid
+ "\"");
221 NonViralName nvn
= (NonViralName
)service
.findNameByUuid(UUID
.fromString(nameUuid
), NAME_INFORMATION_INIT_STRATEGY
);
223 NameInformation ni
= new NameInformation();
224 ni
.setRequest(nameUuid
);
225 Reference ref
= (Reference
) nvn
.getNomenclaturalReference();
226 String citation
= "";
227 String citation_details
= "";
229 citation
= ref
.getTitleCache();
231 ni
.setResponse(nvn
.getTitleCache(),
233 nvn
.getRank().getTitleCache(),
236 nvn
.getRelationsFromThisName(),
237 nvn
.getRelationsToThisName(),
238 nvn
.getTaxonBases());
241 ErrorResponse re
= new ErrorResponse();
242 re
.setErrorMessage("No Taxon Name for given UUID : " + nameUuid
);
246 mv
.addObject(niList
);
250 @RequestMapping(value
= {"taxon"},
251 method
= RequestMethod
.GET
)
252 public ModelAndView
doGetTaxonInformation(@RequestParam(value
= "taxonUuid", required
= true) String
[] taxonUuids
,
253 HttpServletRequest request
,
254 HttpServletResponse response
) throws IOException
{
255 ModelAndView mv
= new ModelAndView();
256 List
<RemoteResponse
> tiList
= new ArrayList
<RemoteResponse
>();
257 for(String taxonUuid
: taxonUuids
) {
258 logger
.info("doGetTaxonInformation()" + request
.getServletPath() + " for taxon uuid \"" + taxonUuid
);
259 TaxonBase tb
= taxonService
.findTaxonByUuid(UUID
.fromString(taxonUuid
), TAXON_INFORMATION_INIT_STRATEGY
);
262 TaxonInformation ti
= new TaxonInformation();
263 ti
.setRequest(taxonUuid
);
265 if(tb
.isInstanceOf(Taxon
.class)) {
266 Taxon taxon
= (Taxon
)tb
;
267 ti
.setResponseTaxon(tb
.getTitleCache(),
268 ACCEPTED_NAME_STATUS
,
270 buildClassificationMap(taxon
));
271 Set
<SynonymRelationship
> synRelationships
= taxon
.getSynonymRelations();
272 for(SynonymRelationship sr
: synRelationships
) {
273 Synonym syn
= sr
.getSynonym();
274 String uuid
= syn
.getUuid().toString();
275 String title
= syn
.getTitleCache();
276 String status
= SYNONYM_STATUS
;
277 String relLabel
= sr
.getType().getInverseRepresentation(Language
.DEFAULT()).getLabel();
278 ti
.addToResponseRelatedTaxa(uuid
, title
, status
, "", relLabel
);
281 Set
<TaxonRelationship
> trFromSet
= taxon
.getRelationsFromThisTaxon();
283 for(TaxonRelationship tr
: trFromSet
) {
284 String titleFrom
= tr
.getRelatedFrom().getTitleCache();
286 String titleTo
= tr
.getRelatedTo().getTitleCache();
287 String uuid
= tr
.getRelatedTo().getUuid().toString();
288 String status
= ACCEPTED_NAME_STATUS
;
289 String relLabel
= tr
.getType().getRepresentation(Language
.DEFAULT()).getLabel();
290 //System.out.println("From : " + titleFrom + ", To : " + titleTo + "type " + tr.getType().getTitleCache());
291 ti
.addToResponseRelatedTaxa(uuid
, titleTo
, status
, "", relLabel
);
294 Set
<TaxonRelationship
> trToSet
= taxon
.getRelationsToThisTaxon();
295 for(TaxonRelationship tr
: trToSet
) {
296 String titleTo
= tr
.getRelatedTo().getTitleCache();
298 String titleFrom
= tr
.getRelatedFrom().getTitleCache();
299 String uuid
= tr
.getRelatedFrom().getUuid().toString();
300 String status
= ACCEPTED_NAME_STATUS
;
301 String relLabel
= tr
.getType().getInverseRepresentation(Language
.DEFAULT()).getLabel();
302 //System.out.println("From : " + titleFrom + ", To : " + titleFrom + "type " + tr.getType().getTitleCache());
303 ti
.addToResponseRelatedTaxa(uuid
, titleFrom
, status
, "", relLabel
);
305 } else if(tb
instanceof Synonym
) {
306 Synonym synonym
= (Synonym
)tb
;
307 ti
.setResponseTaxon(synonym
.getTitleCache(),
309 buildFlagMap(synonym
),
311 Set
<SynonymRelationship
> synRelationships
= synonym
.getSynonymRelations();
312 for(SynonymRelationship sr
: synRelationships
) {
313 Taxon accTaxon
= sr
.getAcceptedTaxon();
314 String uuid
= accTaxon
.getUuid().toString();
315 String title
= accTaxon
.getTitleCache();
316 String status
= ACCEPTED_NAME_STATUS
;
317 String relLabel
= sr
.getType().getRepresentation(Language
.DEFAULT()).getLabel();
318 ti
.addToResponseRelatedTaxa(uuid
, title
, status
, "", relLabel
);
323 ErrorResponse re
= new ErrorResponse();
324 re
.setErrorMessage("No Taxon for given UUID : " + taxonUuid
);
328 mv
.addObject(tiList
);
332 private MatchMode
getMatchModeFromQuery(String query
) {
333 if(query
.startsWith("*") && query
.endsWith("*")) {
334 return MatchMode
.ANYWHERE
;
335 } else if(query
.startsWith("*")) {
336 return MatchMode
.END
;
337 } else if(query
.endsWith("*")) {
338 return MatchMode
.BEGINNING
;
340 return MatchMode
.EXACT
;
344 private String
getQueryWithoutWildCards(String query
) {
346 String newQuery
= query
;
348 if(query
.startsWith("*")) {
349 newQuery
= newQuery
.substring(1, newQuery
.length());
352 if(query
.endsWith("*")) {
353 newQuery
= newQuery
.substring(0, newQuery
.length()-1);
356 return newQuery
.trim();
359 private Map
<String
, String
> buildFlagMap(TaxonBase tb
) {
360 Map
<String
, String
> flags
= new Hashtable
<String
, String
>();
361 flags
.put(DOUBTFUL_FLAG
, Boolean
.toString(tb
.isDoubtful()));
365 private Map
<String
, Map
> buildClassificationMap(Taxon taxon
) {
366 Map
<String
, Map
> classificationMap
= new Hashtable
<String
, Map
>();
367 Set
<TaxonNode
> taxonNodes
= taxon
.getTaxonNodes();
369 for(TaxonNode tn
: taxonNodes
) {
370 Map
<String
, String
> classification
= new LinkedHashMap
<String
, String
>();
371 List
<TaxonNode
> tnList
= classificationService
.loadTreeBranchToTaxon(taxon
, tn
.getClassification(), null, TAXON_NODE_INIT_STRATEGY
);
372 for(TaxonNode classificationtn
: tnList
) {
374 classification
.put(classificationtn
.getTaxon().getName().getRank().getTitleCache(),
375 classificationtn
.getTaxon().getName().getTitleCache());
378 String cname
= tn
.getClassification().getTitleCache();
379 String
[] words
= cname
.split("\\s+");
380 //"\\s+" in regular expression language meaning one or more spaces
381 StringBuilder builder
= new StringBuilder();
382 for (String word
: words
){
383 builder
.append(word
);
385 cname
= builder
.toString();
386 classificationMap
.put(cname
, classification
);
388 return classificationMap
;