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