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