Merging r13268 through r14040 from trunk/cdmlib into branches/cdmlib-unitils3
[cdmlib.git] / cdmlib-remote / src / main / java / eu / etaxonomy / cdm / remote / controller / TaxonPortalController.java
1 // $Id: TaxonController.java 5473 2009-03-25 13:42:07Z a.kohlbecker $
2 /**
3 * Copyright (C) 2007 EDIT
4 * European Distributed Institute of Taxonomy
5 * http://www.e-taxonomy.eu
6 *
7 * The contents of this file are subject to the Mozilla Public License Version 1.1
8 * See LICENSE.TXT at the top of this package for the full license terms.
9 */
10
11 package eu.etaxonomy.cdm.remote.controller;
12
13 import static java.net.HttpURLConnection.HTTP_BAD_REQUEST;
14
15 import java.io.IOException;
16 import java.util.ArrayList;
17 import java.util.Arrays;
18 import java.util.HashSet;
19 import java.util.Hashtable;
20 import java.util.Iterator;
21 import java.util.List;
22 import java.util.Map;
23 import java.util.Set;
24 import java.util.UUID;
25
26 import javax.servlet.http.HttpServletRequest;
27 import javax.servlet.http.HttpServletResponse;
28
29 import org.apache.commons.lang.ObjectUtils;
30 import org.apache.http.HttpRequest;
31 import org.apache.log4j.Logger;
32 import org.springframework.beans.factory.annotation.Autowired;
33 import org.springframework.stereotype.Controller;
34 import org.springframework.web.bind.WebDataBinder;
35 import org.springframework.web.bind.annotation.InitBinder;
36 import org.springframework.web.bind.annotation.PathVariable;
37 import org.springframework.web.bind.annotation.RequestMapping;
38 import org.springframework.web.bind.annotation.RequestMethod;
39 import org.springframework.web.bind.annotation.RequestParam;
40 import org.springframework.web.servlet.ModelAndView;
41
42 import eu.etaxonomy.cdm.api.service.IDescriptionService;
43 import eu.etaxonomy.cdm.api.service.IFeatureTreeService;
44 import eu.etaxonomy.cdm.api.service.INameService;
45 import eu.etaxonomy.cdm.api.service.IOccurrenceService;
46 import eu.etaxonomy.cdm.api.service.ITaxonService;
47 import eu.etaxonomy.cdm.api.service.IClassificationService;
48 import eu.etaxonomy.cdm.api.service.config.ITaxonServiceConfigurator;
49 import eu.etaxonomy.cdm.api.service.config.TaxonServiceConfiguratorImpl;
50 import eu.etaxonomy.cdm.api.service.pager.Pager;
51 import eu.etaxonomy.cdm.database.UpdatableRoutingDataSource;
52 import eu.etaxonomy.cdm.model.common.IdentifiableEntity;
53 import eu.etaxonomy.cdm.model.common.RelationshipBase.Direction;
54 import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
55 import eu.etaxonomy.cdm.model.description.TaxonDescription;
56 import eu.etaxonomy.cdm.model.location.NamedArea;
57 import eu.etaxonomy.cdm.model.media.Media;
58 import eu.etaxonomy.cdm.model.media.MediaRepresentationPart;
59 import eu.etaxonomy.cdm.model.media.MediaUtils;
60 import eu.etaxonomy.cdm.model.name.NameRelationship;
61 import eu.etaxonomy.cdm.model.name.TypeDesignationBase;
62 import eu.etaxonomy.cdm.model.taxon.Synonym;
63 import eu.etaxonomy.cdm.model.taxon.Taxon;
64 import eu.etaxonomy.cdm.model.taxon.TaxonBase;
65 import eu.etaxonomy.cdm.model.taxon.TaxonNode;
66 import eu.etaxonomy.cdm.model.taxon.TaxonRelationship;
67 import eu.etaxonomy.cdm.model.taxon.TaxonRelationshipType;
68 import eu.etaxonomy.cdm.model.taxon.Classification;
69 import eu.etaxonomy.cdm.persistence.query.MatchMode;
70 import eu.etaxonomy.cdm.remote.controller.util.PagerParameters;
71 import eu.etaxonomy.cdm.remote.editor.CdmTypePropertyEditor;
72 import eu.etaxonomy.cdm.remote.editor.MatchModePropertyEditor;
73 import eu.etaxonomy.cdm.remote.editor.NamedAreaPropertyEditor;
74
75 /**
76 * The TaxonPortalController class is a Spring MVC Controller.
77 * <p>
78 * The syntax of the mapped service URIs contains the the {datasource-name} path element.
79 * The available {datasource-name}s are defined in a configuration file which
80 * is loaded by the {@link UpdatableRoutingDataSource}. If the
81 * UpdatableRoutingDataSource is not being used in the actual application
82 * context any arbitrary {datasource-name} may be used.
83 * <p>
84 * Methods mapped at type level, inherited from super classes ({@link BaseController}):
85 * <blockquote>
86 * URI: <b>&#x002F;{datasource-name}&#x002F;portal&#x002F;taxon&#x002F;{taxon-uuid}</b>
87 *
88 * Get the {@link TaxonBase} instance identified by the <code>{taxon-uuid}</code>.
89 * The returned Taxon is initialized by
90 * the following strategy {@link #TAXON_INIT_STRATEGY}
91 * </blockquote>
92 *
93 * @author a.kohlbecker
94 * @date 20.07.2009
95 *
96 */
97 @Controller
98 @RequestMapping(value = {"/portal/taxon/{uuid}"})
99 public class TaxonPortalController extends BaseController<TaxonBase, ITaxonService>
100 {
101 public static final Logger logger = Logger.getLogger(TaxonPortalController.class);
102
103 @Autowired
104 private INameService nameService;
105
106 @Autowired
107 private IDescriptionService descriptionService;
108
109 @Autowired
110 private IOccurrenceService occurrenceService;
111
112 @Autowired
113 private IClassificationService classificationService;
114
115 @Autowired
116 private ITaxonService taxonService;
117
118 @Autowired
119 private IFeatureTreeService featureTreeService;
120
121 private static final List<String> TAXON_INIT_STRATEGY = Arrays.asList(new String []{
122 "*",
123 // taxon relations
124 "relationsToThisName.fromTaxon.name",
125 // the name
126 "name.$",
127 "name.rank.representations",
128 "name.status.type.representations",
129
130 // taxon descriptions
131 "descriptions.elements.area.$",
132 "descriptions.elements.multilanguageText",
133 "descriptions.elements.media.representations.parts",
134 "descriptions.elements.media.title",
135
136 });
137
138 private static final List<String> TAXON_WITH_NODES_INIT_STRATEGY = Arrays.asList(new String []{
139 "taxonNodes.$",
140 "taxonNodes.classification.$",
141 "taxonNodes.childNodes.$"
142 });
143
144 private static final List<String> SIMPLE_TAXON_INIT_STRATEGY = Arrays.asList(new String []{
145 "*",
146 // taxon relations
147 "relationsToThisName.fromTaxon.name",
148 // the name
149 "name.$",
150 "name.rank.representations",
151 "name.status.type.representations",
152 "name.nomenclaturalReference"
153 });
154
155 private static final List<String> SYNONYMY_INIT_STRATEGY = Arrays.asList(new String []{
156 // initialize homotypical and heterotypical groups; needs synonyms
157 "synonymRelations.$",
158 "synonymRelations.synonym.$",
159 "synonymRelations.synonym.name.status.type.representation",
160 "synonymRelations.synonym.name.nomenclaturalReference.inReference",
161 "synonymRelations.synonym.name.homotypicalGroup.typifiedNames.$",
162 "synonymRelations.synonym.name.homotypicalGroup.typifiedNames.taxonBases.$",
163 "synonymRelations.synonym.name.combinationAuthorTeam.$",
164
165 "name.typeDesignations",
166
167 "name.homotypicalGroup.$",
168 "name.homotypicalGroup.typifiedNames.$",
169 "name.homotypicalGroup.typifiedNames.nomenclaturalReference.authorTeam",
170
171 "name.homotypicalGroup.typifiedNames.taxonBases.$"
172 });
173
174 private static final List<String> SYNONYMY_WITH_NODES_INIT_STRATEGY = Arrays.asList(new String []{
175 // initialize homotypical and heterotypical groups; needs synonyms
176 "synonymRelations.$",
177 "synonymRelations.synonym.$",
178 "synonymRelations.synonym.name.status.type.representation",
179 "synonymRelations.synonym.name.nomenclaturalReference.inReference",
180 "synonymRelations.synonym.name.homotypicalGroup.typifiedNames.$",
181 "synonymRelations.synonym.name.homotypicalGroup.typifiedNames.taxonBases.$",
182 "synonymRelations.synonym.name.combinationAuthorTeam.$",
183
184 "name.homotypicalGroup.$",
185 "name.homotypicalGroup.typifiedNames.$",
186 "name.homotypicalGroup.typifiedNames.nomenclaturalReference.authorTeam",
187
188 "name.homotypicalGroup.typifiedNames.taxonBases.$",
189
190 "taxonNodes.$",
191 "taxonNodes.classification.$",
192 "taxonNodes.childNodes.$"
193 });
194 private static final List<String> SIMPLE_TAXON_WITH_NODES_INIT_STRATEGY = Arrays.asList(new String []{
195 "*",
196 // taxon relations
197 "relationsToThisName.fromTaxon.name",
198 // the name
199 "name.$",
200 "name.rank.representations",
201 "name.status.type.representations",
202 "name.nomenclaturalReference",
203
204 "taxonNodes.$",
205 "taxonNodes.classification.$",
206 "taxonNodes.childNodes.$"
207 });
208
209
210 private static final List<String> TAXONRELATIONSHIP_INIT_STRATEGY = Arrays.asList(new String []{
211 "$",
212 "type.inverseRepresentations",
213 "fromTaxon.sec",
214 "fromTaxon.name",
215 "toTaxon.sec",
216 "toTaxon.name"
217 });
218
219 private static final List<String> NAMERELATIONSHIP_INIT_STRATEGY = Arrays.asList(new String []{
220 "$",
221 "type.inverseRepresentations",
222 "fromName",
223 "toName.$",
224 });
225
226
227 protected static final List<String> TAXONDESCRIPTION_INIT_STRATEGY = Arrays.asList(new String []{
228 "$",
229 "elements.$",
230 "elements.sources.citation.authorTeam",
231 "elements.sources.nameUsedInSource.originalNameString",
232 "elements.multilanguageText",
233 "elements.media.representations.parts",
234 "elements.media.title",
235 });
236
237 protected static final List<String> DESCRIPTION_ELEMENT_INIT_STRATEGY = Arrays.asList(new String []{
238 "$",
239 "sources.citation.authorTeam",
240 "sources.nameUsedInSource.originalNameString",
241 "multilanguageText",
242 "media.representations.parts",
243 "media.title",
244 });
245
246
247 // private static final List<String> NAMEDESCRIPTION_INIT_STRATEGY = Arrays.asList(new String []{
248 // "uuid",
249 // "feature",
250 // "elements.$",
251 // "elements.multilanguageText",
252 // "elements.media.representations.parts",
253 // "elements.media.title",
254 // });
255
256 protected static final List<String> TAXONDESCRIPTION_MEDIA_INIT_STRATEGY = Arrays.asList(new String []{
257 "elements.media.representations.parts",
258 "elements.media.title"
259
260 });
261
262 private static final List<String> TYPEDESIGNATION_INIT_STRATEGY = Arrays.asList(new String []{
263 //"$",
264 "typeSpecimen.$",
265 "citation.authorTeam.$",
266 "typeName",
267 });
268
269 protected static final List<String> TAXONNODE_WITHTAXON_INIT_STRATEGY = Arrays.asList(new String []{
270 "childNodes.taxon",
271 });
272
273 protected static final List<String> TAXONNODE_INIT_STRATEGY = Arrays.asList(new String []{
274 "taxonNodes.classification"
275 });
276
277
278
279 private static final String featureTreeUuidPattern = "^/taxon(?:(?:/)([^/?#&\\.]+))+.*";
280
281 public TaxonPortalController(){
282 super();
283 setInitializationStrategy(TAXON_INIT_STRATEGY);
284 }
285
286 /* (non-Javadoc)
287 * @see eu.etaxonomy.cdm.remote.controller.GenericController#setService(eu.etaxonomy.cdm.api.service.IService)
288 */
289 @Autowired
290 @Override
291 public void setService(ITaxonService service) {
292 this.service = service;
293 }
294
295 @InitBinder
296 @Override
297 public void initBinder(WebDataBinder binder) {
298 super.initBinder(binder);
299 binder.registerCustomEditor(NamedArea.class, new NamedAreaPropertyEditor());
300 binder.registerCustomEditor(MatchMode.class, new MatchModePropertyEditor());
301 binder.registerCustomEditor(Class.class, new CdmTypePropertyEditor());
302 }
303
304
305 /* (non-Javadoc)
306 * @see eu.etaxonomy.cdm.remote.controller.BaseController#doGet(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
307
308 @Override
309 @RequestMapping(method = RequestMethod.GET)
310 public TaxonBase doGet(HttpServletRequest request, HttpServletResponse response)throws IOException {
311 logger.info("doGet()");
312 TaxonBase tb = getCdmBase(request, response, TAXON_INIT_STRATEGY, TaxonBase.class);
313 return tb;
314 }
315 */
316 /**
317 * Find Taxa, Synonyms, Common Names by name, either globally or in a specific geographic area.
318 * <p>
319 * URI: <b>&#x002F;{datasource-name}&#x002F;portal&#x002F;taxon&#x002F;find</b>
320 *
321 * @param query
322 * the string to query for. Since the wildcard character '*'
323 * internally always is appended to the query string, a search
324 * always compares the query string with the beginning of a name.
325 * - <i>required parameter</i>
326 * @param treeUuid
327 * the {@link UUID} of a {@link Classification} to which the
328 * search is to be restricted. - <i>optional parameter</i>
329 * @param areas
330 * restrict the search to a set of geographic {@link NamedArea}s.
331 * The parameter currently takes a list of TDWG area labels.
332 * - <i>optional parameter</i>
333 * @param pageNumber
334 * the number of the page to be returned, the first page has the
335 * pageNumber = 1 - <i>optional parameter</i>
336 * @param pageSize
337 * the maximum number of entities returned per page (can be -1
338 * to return all entities in a single page) - <i>optional parameter</i>
339 * @param doTaxa
340 * weather to search for instances of {@link Taxon} - <i>optional parameter</i>
341 * @param doSynonyms
342 * weather to search for instances of {@link Synonym} - <i>optional parameter</i>
343 * @param doTaxaByCommonNames
344 * for instances of {@link Taxon} by a common name used - <i>optional parameter</i>
345 * @param matchMode
346 * valid values are "EXACT", "BEGINNING", "ANYWHERE", "END" (case sensitive !!!)
347 * @return a Pager on a list of {@link IdentifiableEntity}s initialized by
348 * the following strategy {@link #SIMPLE_TAXON_INIT_STRATEGY}
349 * @throws IOException
350 */
351 @RequestMapping(method = RequestMethod.GET,
352 value = {"/portal/taxon/find"}) //TODO map to path /*/portal/taxon/
353 public Pager<IdentifiableEntity> doFind(
354 @RequestParam(value = "query", required = false) String query,
355 @RequestParam(value = "tree", required = false) UUID treeUuid,
356 @RequestParam(value = "area", required = false) Set<NamedArea> areas,
357 @RequestParam(value = "pageNumber", required = false) Integer pageNumber,
358 @RequestParam(value = "pageSize", required = false) Integer pageSize,
359 @RequestParam(value = "doTaxa", required = false) Boolean doTaxa,
360 @RequestParam(value = "doSynonyms", required = false) Boolean doSynonyms,
361 @RequestParam(value = "doMisappliedNames", required = false) Boolean doMisappliedNames,
362 @RequestParam(value = "doTaxaByCommonNames", required = false) Boolean doTaxaByCommonNames,
363 @RequestParam(value = "matchMode", required = false) MatchMode matchMode,
364 HttpServletRequest request,
365 HttpServletResponse response
366 )
367 throws IOException {
368
369 logger.info("doFind : " + request.getRequestURI() + "?" + request.getQueryString() );
370
371 PagerParameters pagerParams = new PagerParameters(pageSize, pageNumber);
372 pagerParams.normalizeAndValidate(response);
373
374 ITaxonServiceConfigurator config = new TaxonServiceConfiguratorImpl();
375 config.setPageNumber(pagerParams.getPageIndex());
376 config.setPageSize(pagerParams.getPageSize());
377 config.setTitleSearchString(query);
378 config.setDoTaxa(doTaxa!= null ? doTaxa : Boolean.FALSE );
379 config.setDoSynonyms(doSynonyms != null ? doSynonyms : Boolean.FALSE );
380 config.setDoMisappliedNames(doMisappliedNames != null ? doMisappliedNames : Boolean.FALSE);
381 config.setDoTaxaByCommonNames(doTaxaByCommonNames != null ? doTaxaByCommonNames : Boolean.FALSE );
382 config.setMatchMode(matchMode != null ? matchMode : MatchMode.BEGINNING);
383 config.setTaxonPropertyPath(SIMPLE_TAXON_INIT_STRATEGY);
384 config.setNamedAreas(areas);
385 if(treeUuid != null){
386 Classification classification = classificationService.find(treeUuid);
387 config.setClassification(classification);
388 }
389
390 return (Pager<IdentifiableEntity>) service.findTaxaAndNames(config);
391 }
392
393 /**
394 * Get the synonymy for a taxon identified by the <code>{taxon-uuid}</code>.
395 * The synonymy consists
396 * of two parts: The group of homotypic synonyms of the taxon and the
397 * heterotypic synonymy groups of the taxon. The synonymy is ordered
398 * historically by the type designations and by the publication date of the
399 * nomenclatural reference
400 * <p>
401 * URI:
402 * <b>&#x002F;{datasource-name}&#x002F;portal&#x002F;taxon&#x002F;{taxon-uuid}&#x002F;synonymy</b>
403 *
404 *
405 * @param request
406 * @param response
407 * @return a Map with to entries which are mapped by the following keys:
408 * "homotypicSynonymsByHomotypicGroup", "heterotypicSynonymyGroups",
409 * containing lists of {@link Synonym}s which are initialized using the
410 * following initialization strategy: {@link #SYNONYMY_INIT_STRATEGY}
411 *
412 * @throws IOException
413 */
414 @RequestMapping(
415 value = {"synonymy"},
416 method = RequestMethod.GET)
417 public ModelAndView doGetSynonymy(@PathVariable("uuid") UUID uuid,
418 HttpServletRequest request, HttpServletResponse response)throws IOException {
419
420 if(request != null){
421 logger.info("doGetSynonymy() " + request.getServletPath());
422 }
423 ModelAndView mv = new ModelAndView();
424 Taxon taxon = getCdmBaseInstance(Taxon.class, uuid, response, (List<String>)null);
425 Map<String, List<?>> synonymy = new Hashtable<String, List<?>>();
426 synonymy.put("homotypicSynonymsByHomotypicGroup", service.getHomotypicSynonymsByHomotypicGroup(taxon, SYNONYMY_INIT_STRATEGY));
427 synonymy.put("heterotypicSynonymyGroups", service.getHeterotypicSynonymyGroups(taxon, SYNONYMY_INIT_STRATEGY));
428 mv.addObject(synonymy);
429 return mv;
430 }
431
432 /**
433 * Get the set of accepted {@link Taxon} entities for a given
434 * {@link TaxonBase} entity identified by the <code>{taxon-uuid}</code>.
435 * <p>
436 * URI: <b>&#x002F;{datasource-name}&#x002F;portal&#x002F;taxon&#x002F;{taxon-uuid}&#x002F;accepted</b>
437 *
438 * @param request
439 * @param response
440 * @return a Set of {@link Taxon} entities which are initialized
441 * using the following initialization strategy:
442 * {@link #SYNONYMY_INIT_STRATEGY}
443 * @throws IOException
444 */
445 @RequestMapping(value = "accepted/{classification_uuid}", method = RequestMethod.GET)
446 public Set<TaxonBase> getAccepted(
447 @PathVariable("uuid") UUID uuid,
448 @PathVariable("classification_uuid") UUID classification_uuid,
449 HttpServletRequest request,
450 HttpServletResponse response)
451 throws IOException {
452
453 if(request != null){
454 logger.info("getAccepted() " + request.getServletPath());
455 }
456
457 TaxonBase tb = service.load(uuid, SYNONYMY_WITH_NODES_INIT_STRATEGY);
458 if(tb == null){
459 response.sendError(HttpServletResponse.SC_NOT_FOUND, "A taxon with the uuid " + uuid + " does not exist");
460 return null;
461 }
462
463 HashSet<TaxonBase> resultset = new HashSet<TaxonBase>();
464
465 if (tb instanceof Taxon){
466 Taxon taxon = (Taxon) tb;
467 Set<TaxonNode> nodes = taxon.getTaxonNodes();
468 for (TaxonNode taxonNode : nodes) {
469 if (taxonNode.getClassification().compareTo(classification_uuid) == 0){
470 resultset.add((Taxon) tb);
471 }
472 }
473 if (resultset.size() > 1){
474 //error!! A taxon is not allow to have more taxonnodes for a given classification
475 response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
476 "A taxon with the uuid " + uuid + " has more than one taxon node for the given classification" + classification_uuid);
477 }
478 }else{
479 Synonym syn = (Synonym) tb;
480 for(TaxonBase accepted : syn.getAcceptedTaxa()){
481 tb = service.load(accepted.getUuid(), SIMPLE_TAXON_WITH_NODES_INIT_STRATEGY);
482 if (tb instanceof Taxon){
483 Taxon taxon = (Taxon) tb;
484 Set<TaxonNode> nodes = taxon.getTaxonNodes();
485 for (TaxonNode taxonNode : nodes) {
486 if (taxonNode.getClassification().compareTo(classification_uuid) == 0){
487 resultset.add((Taxon) tb);
488 }
489 }
490 if (resultset.size() > 1){
491 //error!! A taxon is not allow to have more taxonnodes for a given classification
492 response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
493 "A taxon with the uuid " + uuid + " has more than one taxon node for the given classification" + classification_uuid);
494 }
495 }else{
496 //ERROR!! perhaps missapplied name????
497 //syn.getRelationType((Taxon)accepted);
498 }
499 }
500 }
501 /**
502 * OLD CODE!!
503 if(tb instanceof Taxon){
504 //the taxon already is accepted
505 //FIXME take the current view into account once views are implemented!!!
506 resultset.add((Taxon)tb);
507 } else {
508 Synonym syn = (Synonym)tb;
509 for(TaxonBase accepted : syn.getAcceptedTaxa()){
510 accepted = service.load(accepted.getUuid(), SIMPLE_TAXON_INIT_STRATEGY);
511 resultset.add(accepted);
512 }
513 }
514 */
515 return resultset;
516 }
517
518 /**
519 * Get the list of {@link TaxonRelationship}s for the given
520 * {@link TaxonBase} instance identified by the <code>{taxon-uuid}</code>.
521 * <p>
522 * URI: <b>&#x002F;{datasource-name}&#x002F;portal&#x002F;taxon&#x002F;{taxon-uuid}&#x002F;taxonRelationships</b>
523 *
524 * @param request
525 * @param response
526 * @return a List of {@link TaxonRelationship} entities which are initialized
527 * using the following initialization strategy:
528 * {@link #TAXONRELATIONSHIP_INIT_STRATEGY}
529 * @throws IOException
530 */
531 @RequestMapping(
532 value = {"taxonRelationships"},
533 method = RequestMethod.GET)
534 public List<TaxonRelationship> doGetTaxonRelations(@PathVariable("uuid") UUID uuid,
535 HttpServletRequest request, HttpServletResponse response)throws IOException {
536
537 logger.info("doGetTaxonRelations()" + request.getServletPath());
538 Taxon taxon = getCdmBaseInstance(Taxon.class, uuid, response, (List<String>)null);
539 List<TaxonRelationship> toRelationships = service.listToTaxonRelationships(taxon, null, null, null, null, TAXONRELATIONSHIP_INIT_STRATEGY);
540 List<TaxonRelationship> fromRelationships = service.listFromTaxonRelationships(taxon, null, null, null, null, TAXONRELATIONSHIP_INIT_STRATEGY);
541
542 List<TaxonRelationship> allRelationships = new ArrayList<TaxonRelationship>(toRelationships.size() + fromRelationships.size());
543 allRelationships.addAll(toRelationships);
544 allRelationships.addAll(fromRelationships);
545
546 return allRelationships;
547 }
548
549 /**
550 * Get the list of {@link NameRelationship}s of the Name associated with the
551 * {@link TaxonBase} instance identified by the <code>{taxon-uuid}</code>.
552 * <p>
553 * URI: <b>&#x002F;{datasource-name}&#x002F;portal&#x002F;taxon&#x002F;{taxon-uuid}&#x002F;nameRelationships</b>
554 *
555 * @param request
556 * @param response
557 * @return a List of {@link NameRelationship} entities which are initialized
558 * using the following initialization strategy:
559 * {@link #NAMERELATIONSHIP_INIT_STRATEGY}
560 * @throws IOException
561 */
562 @RequestMapping(
563 value = {"toNameRelationships"},
564 method = RequestMethod.GET)
565 public List<NameRelationship> doGetToNameRelations(@PathVariable("uuid") UUID uuid,
566 HttpServletRequest request, HttpServletResponse response)throws IOException {
567 logger.info("doGetNameRelations()" + request.getServletPath());
568 TaxonBase taxonBase = getCdmBaseInstance(TaxonBase.class, uuid, response, (List<String>)null);
569 List<NameRelationship> list = nameService.listNameRelationships(taxonBase.getName(), Direction.relatedTo, null, null, 0, null, NAMERELATIONSHIP_INIT_STRATEGY);
570 //List<NameRelationship> list = nameService.listToNameRelationships(taxonBase.getName(), null, null, null, null, NAMERELATIONSHIP_INIT_STRATEGY);
571 return list;
572 }
573
574 /**
575 * Get the list of {@link NameRelationship}s of the Name associated with the
576 * {@link TaxonBase} instance identified by the <code>{taxon-uuid}</code>.
577 * <p>
578 * URI: <b>&#x002F;{datasource-name}&#x002F;portal&#x002F;taxon&#x002F;{taxon-uuid}&#x002F;nameRelationships</b>
579 *
580 * @param request
581 * @param response
582 * @return a List of {@link NameRelationship} entities which are initialized
583 * using the following initialization strategy:
584 * {@link #NAMERELATIONSHIP_INIT_STRATEGY}
585 * @throws IOException
586 */
587 @RequestMapping(
588 value = {"fromNameRelationships"},
589 method = RequestMethod.GET)
590 public List<NameRelationship> doGetFromNameRelations(@PathVariable("uuid") UUID uuid,
591 HttpServletRequest request, HttpServletResponse response)throws IOException {
592 logger.info("doGetNameFromNameRelations()" + request.getServletPath());
593
594 TaxonBase taxonbase = getCdmBaseInstance(TaxonBase.class, uuid, response, SIMPLE_TAXON_INIT_STRATEGY);
595 List<NameRelationship> list = nameService.listNameRelationships(taxonbase.getName(), Direction.relatedFrom, null, null, 0, null, NAMERELATIONSHIP_INIT_STRATEGY);
596 //List<NameRelationship> list = nameService.listFromNameRelationships(taxonbase.getName(), null, null, null, null, NAMERELATIONSHIP_INIT_STRATEGY);
597 return list;
598 }
599
600 /**
601 * Get the list of {@link TypeDesignationBase}s of the
602 * {@link TaxonBase} instance identified by the <code>{taxon-uuid}</code>.
603 * <p>
604 * URI: <b>&#x002F;{datasource-name}&#x002F;portal&#x002F;taxon&#x002F;{taxon-uuid}&#x002F;nameTypeDesignations</b>
605 *
606 * @param request
607 * @param response
608 * @return a List of {@link TypeDesignationBase} entities which are initialized
609 * using the following initialization strategy:
610 * {@link #TYPEDESIGNATION_INIT_STRATEGY}
611 * @throws IOException
612 * @Deprecated use &#x002F;name&#x002F;{uuid}&#x002F;typeDesignations & &#x002F;derivedunitfacade&#x002F;{uuid} instead
613 * also see http://dev.e-taxonomy.eu/trac/ticket/2280
614 */
615 @Deprecated
616 @RequestMapping(
617 value = {"nameTypeDesignations"},
618 method = RequestMethod.GET)
619 public List<TypeDesignationBase> doGetNameTypeDesignations(@PathVariable("uuid") UUID uuid,
620 HttpServletRequest request, HttpServletResponse response)throws IOException {
621 logger.info("doGetNameTypeDesignations()" + request.getServletPath());
622 Taxon taxon = getCdmBaseInstance(Taxon.class, uuid, response, SIMPLE_TAXON_INIT_STRATEGY);
623 Pager<TypeDesignationBase> p = nameService.getTypeDesignations(taxon.getName(), null, null, null, TYPEDESIGNATION_INIT_STRATEGY);
624 return p.getRecords();
625 }
626
627 @RequestMapping(value = "taxonNodes", method = RequestMethod.GET)
628 public Set<TaxonNode> doGetTaxonNodes(
629 @PathVariable("uuid") UUID uuid,
630 HttpServletRequest request,
631 HttpServletResponse response) throws IOException {
632 TaxonBase tb = service.load(uuid, TAXONNODE_INIT_STRATEGY);
633 if(tb instanceof Taxon){
634 return ((Taxon)tb).getTaxonNodes();
635 } else {
636 HttpStatusMessage.UUID_REFERENCES_WRONG_TYPE.send(response);
637 return null;
638 }
639 }
640
641 /**
642 * Get the list of {@link TaxonDescription}s of the
643 * {@link Taxon} instance identified by the <code>{taxon-uuid}</code>.
644 * <p>
645 * URI: <b>&#x002F;{datasource-name}&#x002F;portal&#x002F;taxon&#x002F;{taxon-uuid}&#x002F;descriptions</b>
646 *
647 * @param request
648 * @param response
649 * @return a List of {@link TaxonDescription} entities which are initialized
650 * using the following initialization strategy:
651 * {@link #TAXONDESCRIPTION_INIT_STRATEGY}
652 * @throws IOException
653 */
654 @RequestMapping(
655 value = {"descriptions"},
656 method = RequestMethod.GET)
657 public List<TaxonDescription> doGetDescriptions(
658 @PathVariable("uuid") UUID uuid,
659 HttpServletRequest request,
660 HttpServletResponse response)throws IOException {
661 if(request != null){
662 logger.info("doGetDescriptions()" + request.getServletPath());
663 }
664 Taxon t = getCdmBaseInstance(Taxon.class, uuid, response, (List<String>)null);
665 Pager<TaxonDescription> p = descriptionService.getTaxonDescriptions(t, null, null, null, null, TAXONDESCRIPTION_INIT_STRATEGY);
666 return p.getRecords();
667 }
668
669 @RequestMapping(value = "descriptions/elementsByType/{classSimpleName}", method = RequestMethod.GET)
670 public ModelAndView doGetDescriptionElementsByType(
671 @PathVariable("uuid") UUID uuid,
672 @PathVariable("classSimpleName") String classSimpleName,
673 @RequestParam(value = "count", required = false, defaultValue = "false") Boolean doCount,
674 HttpServletRequest request,
675 HttpServletResponse response) throws IOException {
676 logger.info("doGetDescriptionElementsByType() - " + request.getServletPath());
677
678 ModelAndView mv = new ModelAndView();
679
680 List<DescriptionElementBase> allElements = new ArrayList<DescriptionElementBase>();
681 List<DescriptionElementBase> elements;
682 int count = 0;
683
684 List<String> initStrategy = doCount ? null : DESCRIPTION_ELEMENT_INIT_STRATEGY;
685
686 List<TaxonDescription> taxonDescriptions = doGetDescriptions(uuid, request, response);
687 try {
688 Class type;
689 type = Class.forName("eu.etaxonomy.cdm.model.description."
690 + classSimpleName);
691 if (taxonDescriptions != null) {
692 for (TaxonDescription description : taxonDescriptions) {
693 elements = descriptionService.listDescriptionElements(description, null, type, null, 0, initStrategy);
694 allElements.addAll(elements);
695 count += elements.size();
696 }
697
698 }
699 } catch (ClassNotFoundException e) {
700 HttpStatusMessage.fromString(e.getLocalizedMessage()).send(response);
701 }
702 if(doCount){
703 mv.addObject(count);
704 } else {
705 mv.addObject(allElements);
706 }
707 return mv;
708 }
709
710 // @RequestMapping(value = "specimens", method = RequestMethod.GET)
711 // public ModelAndView doGetSpecimens(
712 // @PathVariable("uuid") UUID uuid,
713 // HttpServletRequest request,
714 // HttpServletResponse response) throws IOException, ClassNotFoundException {
715 // logger.info("doGetSpecimens() - " + request.getServletPath());
716 //
717 // ModelAndView mv = new ModelAndView();
718 //
719 // List<DerivedUnitFacade> derivedUnitFacadeList = new ArrayList<DerivedUnitFacade>();
720 //
721 // // find speciemens in the TaxonDescriptions
722 // List<TaxonDescription> taxonDescriptions = doGetDescriptions(uuid, request, response);
723 // if (taxonDescriptions != null) {
724 //
725 // for (TaxonDescription description : taxonDescriptions) {
726 // derivedUnitFacadeList.addAll( occurrenceService.listDerivedUnitFacades(description, null) );
727 // }
728 // }
729 // // TODO find speciemens in the NameDescriptions ??
730 //
731 // // TODO also find type specimens
732 //
733 // mv.addObject(derivedUnitFacadeList);
734 //
735 // return mv;
736 // }
737
738 /**
739 * Get the {@link Media} attached to the {@link Taxon} instance
740 * identified by the <code>{taxon-uuid}</code>.
741 *
742 * Usage &#x002F;{datasource-name}&#x002F;portal&#x002F;taxon&#x002F;{taxon-
743 * uuid}&#x002F;media&#x002F;{mime type
744 * list}&#x002F;{size}[,[widthOrDuration}][,{height}]&#x002F;
745 *
746 * Whereas
747 * <ul>
748 * <li><b>{mime type list}</b>: a comma separated list of mime types, in the
749 * order of preference. The forward slashes contained in the mime types must
750 * be replaced by a colon. Regular expressions can be used. Each media
751 * associated with this given taxon is being searched whereas the first
752 * matching mime type matching a representation always rules.</li>
753 * <li><b>{size},{widthOrDuration},{height}</b>: <i>not jet implemented</i>
754 * valid values are an integer or the asterisk '*' as a wildcard</li>
755 * </ul>
756 *
757 * @param request
758 * @param response
759 * @return a List of {@link Media} entities which are initialized
760 * using the following initialization strategy:
761 * {@link #TAXONDESCRIPTION_INIT_STRATEGY}
762 * @throws IOException
763 */
764 @RequestMapping(
765 value = {"media"},
766 method = RequestMethod.GET)
767 public List<Media> doGetMedia(
768 @PathVariable("uuid") UUID uuid,
769 @RequestParam(value = "type", required = false) Class<? extends MediaRepresentationPart> type,
770 @RequestParam(value = "mimeTypes", required = false) String[] mimeTypes,
771 @RequestParam(value = "widthOrDuration", required = false) Integer widthOrDuration,
772 @RequestParam(value = "height", required = false) Integer height,
773 @RequestParam(value = "size", required = false) Integer size,
774 HttpServletRequest request, HttpServletResponse response) throws IOException {
775
776 logger.info("doGetMedia()" + request.getServletPath());
777 Taxon t = getCdmBaseInstance(Taxon.class, uuid, response, (List<String>)null);
778 String path = request.getServletPath();
779 List<Media> returnMedia = getMediaForTaxon(t, type, mimeTypes, widthOrDuration, height, size);
780 return returnMedia;
781 }
782
783 @RequestMapping(
784 value = {"subtree/media"},
785 method = RequestMethod.GET)
786 public List<Media> doGetSubtreeMedia(
787 @PathVariable("uuid") UUID uuid,
788 @RequestParam(value = "type", required = false) Class<? extends MediaRepresentationPart> type,
789 @RequestParam(value = "mimeTypes", required = false) String[] mimeTypes,
790 @RequestParam(value = "widthOrDuration", required = false) Integer widthOrDuration,
791 @RequestParam(value = "height", required = false) Integer height,
792 @RequestParam(value = "size", required = false) Integer size,
793 HttpServletRequest request, HttpServletResponse response)throws IOException {
794 logger.info("doGetMedia()" + request.getServletPath());
795 Taxon taxon = getCdmBaseInstance(Taxon.class, uuid, response, TAXON_WITH_NODES_INIT_STRATEGY);
796 String requestPath = request.getServletPath();
797 List<Media> returnMedia = getMediaForTaxon(taxon, type, mimeTypes, widthOrDuration, height, size);
798 TaxonNode node;
799 //looking for all medias of genus
800 if (taxon.getTaxonNodes().size()>0){
801 Set<TaxonNode> nodes = taxon.getTaxonNodes();
802 Iterator<TaxonNode> iterator = nodes.iterator();
803 //TaxonNode holen
804 node = iterator.next();
805 //Check if TaxonNode belongs to the current tree
806
807 node = classificationService.loadTaxonNode(node, TAXONNODE_WITHTAXON_INIT_STRATEGY);
808 Set<TaxonNode> children = node.getChildNodes();
809 Taxon childTaxon;
810 for (TaxonNode child : children){
811 childTaxon = child.getTaxon();
812 childTaxon = (Taxon)taxonService.load(childTaxon.getUuid(), null);
813 returnMedia.addAll(getMediaForTaxon(childTaxon, type, mimeTypes, widthOrDuration, height, size));
814 }
815 }
816 return returnMedia;
817 }
818
819
820 private List<Media> getMediaForTaxon(Taxon taxon, Class<? extends MediaRepresentationPart> type, String[] mimeTypes,
821 Integer widthOrDuration, Integer height, Integer size){
822
823 Pager<TaxonDescription> p =
824 descriptionService.getTaxonDescriptions(taxon, null, null, null, null, TAXONDESCRIPTION_MEDIA_INIT_STRATEGY);
825
826 // pars the media and quality parameters
827
828
829 // collect all media of the given taxon
830 boolean limitToGalleries = false;
831 List<Media> taxonMedia = new ArrayList<Media>();
832 List<Media> taxonGalleryMedia = new ArrayList<Media>();
833 for(TaxonDescription desc : p.getRecords()){
834
835 if(desc.isImageGallery()){
836 for(DescriptionElementBase element : desc.getElements()){
837 for(Media media : element.getMedia()){
838 taxonGalleryMedia.add(media);
839 }
840 }
841 } else if(!limitToGalleries){
842 for(DescriptionElementBase element : desc.getElements()){
843 for(Media media : element.getMedia()){
844 taxonMedia.add(media);
845 }
846 }
847 }
848
849 }
850
851 taxonGalleryMedia.addAll(taxonMedia);
852
853 List<Media> returnMedia = MediaUtils.findPreferredMedia(taxonGalleryMedia, type,
854 mimeTypes, null, widthOrDuration, height, size);
855
856 return returnMedia;
857 }
858
859
860 // ---------------------- code snippet preserved for possible later use --------------------
861 // @RequestMapping(
862 // value = {"/*/portal/taxon/*/descriptions"},
863 // method = RequestMethod.GET)
864 // public List<TaxonDescription> doGetDescriptionsbyFeatureTree(HttpServletRequest request, HttpServletResponse response)throws IOException {
865 // TaxonBase tb = getCdmBase(request, response, null, Taxon.class);
866 // if(tb instanceof Taxon){
867 // //T O D O this is a quick and dirty implementation -> generalize
868 // UUID featureTreeUuid = readValueUuid(request, featureTreeUuidPattern);
869 //
870 // FeatureTree featureTree = descriptionService.getFeatureTreeByUuid(featureTreeUuid);
871 // Pager<TaxonDescription> p = descriptionService.getTaxonDescriptions((Taxon)tb, null, null, null, null, TAXONDESCRIPTION_INIT_STRATEGY);
872 // List<TaxonDescription> descriptions = p.getRecords();
873 //
874 // if(!featureTree.isDescriptionSeparated()){
875 //
876 // TaxonDescription superDescription = TaxonDescription.NewInstance();
877 // //put all descriptionElements in superDescription and make it invisible
878 // for(TaxonDescription description: descriptions){
879 // for(DescriptionElementBase element: description.getElements()){
880 // superDescription.addElement(element);
881 // }
882 // }
883 // List<TaxonDescription> separatedDescriptions = new ArrayList<TaxonDescription>(descriptions.size());
884 // separatedDescriptions.add(superDescription);
885 // return separatedDescriptions;
886 // }else{
887 // return descriptions;
888 // }
889 // } else {
890 // response.sendError(HttpServletResponse.SC_NOT_FOUND, "invalid type; Taxon expected but " + tb.getClass().getSimpleName() + " found.");
891 // return null;
892 // }
893 // }
894
895 }