(no commit message)
[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 java.io.IOException;
14 import java.util.ArrayList;
15 import java.util.Arrays;
16 import java.util.HashMap;
17 import java.util.HashSet;
18 import java.util.Hashtable;
19 import java.util.Iterator;
20 import java.util.List;
21 import java.util.Map;
22 import java.util.NoSuchElementException;
23 import java.util.Set;
24 import java.util.SortedMap;
25 import java.util.TreeMap;
26 import java.util.UUID;
27 import java.util.regex.Matcher;
28 import java.util.regex.Pattern;
29
30 import javax.servlet.http.HttpServletRequest;
31 import javax.servlet.http.HttpServletResponse;
32
33 import org.apache.commons.lang.ObjectUtils;
34 import org.apache.log4j.Logger;
35 import org.springframework.beans.factory.annotation.Autowired;
36 import org.springframework.beans.factory.parsing.ParseState.Entry;
37 import org.springframework.stereotype.Controller;
38 import org.springframework.web.bind.WebDataBinder;
39 import org.springframework.web.bind.annotation.InitBinder;
40 import org.springframework.web.bind.annotation.RequestMapping;
41 import org.springframework.web.bind.annotation.RequestMethod;
42 import org.springframework.web.bind.annotation.RequestParam;
43 import org.springframework.web.servlet.ModelAndView;
44
45 import eu.etaxonomy.cdm.api.service.IDescriptionService;
46 import eu.etaxonomy.cdm.api.service.INameService;
47 import eu.etaxonomy.cdm.api.service.IReferenceService;
48 import eu.etaxonomy.cdm.api.service.ITaxonService;
49 import eu.etaxonomy.cdm.api.service.ITaxonTreeService;
50 import eu.etaxonomy.cdm.api.service.config.ITaxonServiceConfigurator;
51 import eu.etaxonomy.cdm.api.service.config.impl.TaxonServiceConfiguratorImpl;
52 import eu.etaxonomy.cdm.api.service.pager.Pager;
53 import eu.etaxonomy.cdm.database.UpdatableRoutingDataSource;
54 import eu.etaxonomy.cdm.model.common.IdentifiableEntity;
55 import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
56 import eu.etaxonomy.cdm.model.description.TaxonDescription;
57 import eu.etaxonomy.cdm.model.description.TaxonNameDescription;
58 import eu.etaxonomy.cdm.model.location.NamedArea;
59 import eu.etaxonomy.cdm.model.media.Media;
60 import eu.etaxonomy.cdm.model.media.MediaRepresentation;
61 import eu.etaxonomy.cdm.model.name.NameRelationship;
62 import eu.etaxonomy.cdm.model.name.TaxonNameBase;
63 import eu.etaxonomy.cdm.model.name.TypeDesignationBase;
64 import eu.etaxonomy.cdm.model.taxon.Synonym;
65 import eu.etaxonomy.cdm.model.taxon.Taxon;
66 import eu.etaxonomy.cdm.model.taxon.TaxonBase;
67 import eu.etaxonomy.cdm.model.taxon.TaxonNode;
68 import eu.etaxonomy.cdm.model.taxon.TaxonRelationship;
69 import eu.etaxonomy.cdm.model.taxon.TaxonRelationshipType;
70 import eu.etaxonomy.cdm.model.taxon.TaxonomicTree;
71 import eu.etaxonomy.cdm.persistence.query.MatchMode;
72 import eu.etaxonomy.cdm.remote.editor.NamedAreaPropertyEditor;
73 import eu.etaxonomy.cdm.remote.editor.UUIDPropertyEditor;
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/*", "/*/portal/taxon/*/*", "/*/portal/name/*/*", "/*/portal/taxon/*/media/*/*"})
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 @Autowired
106 private IDescriptionService descriptionService;
107 @Autowired
108 private IReferenceService referenceService;
109
110 @Autowired
111 private ITaxonTreeService taxonTreeService;
112
113 @Autowired
114 private ITaxonService taxonService;
115
116 private static final List<String> TAXON_INIT_STRATEGY = Arrays.asList(new String []{
117 "*",
118 // taxon relations
119 "relationsToThisName.fromTaxon.name.taggedName",
120 // the name
121 "name.$",
122 "name.taggedName",
123 "name.rank.representations",
124 "name.status.type.representations",
125
126 // taxon descriptions
127 "descriptions.elements.$",
128 "descriptions.elements.area",
129 "descriptions.elements.area.$",
130 "descriptions.elements.multilanguageText",
131 "descriptions.elements.media.representations.parts",
132
133 // // typeDesignations
134 // "name.typeDesignations.$",
135 // "name.typeDesignations.citation.authorTeam",
136 // "name.typeDesignations.typeName.$",
137 // "name.typeDesignations.typeStatus.representations",
138 // "name.typeDesignations.typeSpecimen.media.representations.parts"
139
140 });
141
142 private static final List<String> SIMPLE_TAXON_INIT_STRATEGY = Arrays.asList(new String []{
143 "*",
144 // taxon relations
145 "relationsToThisName.fromTaxon.name.taggedName",
146 // the name
147 "name.$",
148 "name.taggedName",
149 "name.rank.representations",
150 "name.status.type.representations"
151 });
152
153 private static final List<String> SYNONYMY_INIT_STRATEGY = Arrays.asList(new String []{
154 // initialize homotypical and heterotypical groups; needs synonyms
155 "synonymRelations.$",
156 "synonymRelations.synonym.$",
157 "synonymRelations.synonym.name.taggedName",
158 "synonymRelations.synonym.name.nomenclaturalReference.inBook.authorTeam",
159 "synonymRelations.synonym.name.nomenclaturalReference.inJournal",
160 "synonymRelations.synonym.name.nomenclaturalReference.inProceedings",
161 "synonymRelations.synonym.name.homotypicalGroup.typifiedNames.$",
162 "synonymRelations.synonym.name.homotypicalGroup.typifiedNames.name.taggedName",
163 "synonymRelations.synonym.name.homotypicalGroup.typifiedNames.taxonBases.$",
164 "synonymRelations.synonym.name.homotypicalGroup.typifiedNames.taxonBases.name.taggedName",
165
166 "name.homotypicalGroup.$",
167 "name.homotypicalGroup.typifiedNames.$",
168 "name.homotypicalGroup.typifiedNames.name.taggedName",
169
170 "name.homotypicalGroup.typifiedNames.taxonBases.$",
171 "name.homotypicalGroup.typifiedNames.taxonBases.name.taggedName"
172
173 });
174
175 private static final List<String> TAXONRELATIONSHIP_INIT_STRATEGY = Arrays.asList(new String []{
176 "$",
177 "type.inverseRepresentations",
178 "fromTaxon.sec.authorTeam",
179 "fromTaxon.name.taggedName"
180 });
181
182 private static final List<String> NAMERELATIONSHIP_INIT_STRATEGY = Arrays.asList(new String []{
183 "$",
184 "type.inverseRepresentations",
185 "fromName.taggedName",
186 });
187
188
189 protected static final List<String> TAXONDESCRIPTION_INIT_STRATEGY = Arrays.asList(new String []{
190 "$",
191 "elements.$",
192 "elements.sources.citation.",
193 "elements.sources.citation.authorTeam.$",
194 //"elements.sources.citation.authorTeam.teamMembers.",
195 "elements.multilanguageText",
196 "elements.media.representations.parts",
197 });
198
199 protected static final List<String> TAXON_MEDIA_INIT_STRATEGY = Arrays.asList(new String[]{
200 "$",
201 "media.representations.",
202 "media.representations.parts"
203 });
204
205 private static final List<String> NAMEDESCRIPTION_INIT_STRATEGY = Arrays.asList(new String []{
206 "uuid",
207 "feature",
208 "elements.$",
209 "elements.multilanguageText",
210 "elements.media.representations.parts",
211 });
212
213 private static final List<String> TYPEDESIGNATION_INIT_STRATEGY = Arrays.asList(new String []{
214 //"$",
215 "typeSpecimen.$",
216 "typeStatus.representations",
217 "citation.authorTeam",
218 "typeName.taggedName"
219 });
220
221
222
223 private static final String featureTreeUuidPattern = "^/(?:[^/]+)/taxon(?:(?:/)([^/?#&\\.]+))+.*";
224
225 public TaxonPortalController(){
226 super();
227 setInitializationStrategy(TAXON_INIT_STRATEGY);
228 setUuidParameterPattern("^/(?:[^/]+)/portal/(?:[^/]+)/([^/?#&\\.]+).*");
229 }
230
231 /* (non-Javadoc)
232 * @see eu.etaxonomy.cdm.remote.controller.GenericController#setService(eu.etaxonomy.cdm.api.service.IService)
233 */
234 @Autowired
235 @Override
236 public void setService(ITaxonService service) {
237 this.service = service;
238 }
239
240 @InitBinder
241 public void initBinder(WebDataBinder binder) {
242 binder.registerCustomEditor(UUID.class, new UUIDPropertyEditor());
243 binder.registerCustomEditor(NamedArea.class, new NamedAreaPropertyEditor());
244 }
245
246
247 /* (non-Javadoc)
248 * @see eu.etaxonomy.cdm.remote.controller.BaseController#doGet(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
249
250 @Override
251 @RequestMapping(method = RequestMethod.GET)
252 public TaxonBase doGet(HttpServletRequest request, HttpServletResponse response)throws IOException {
253 logger.info("doGet()");
254 TaxonBase tb = getCdmBase(request, response, TAXON_INIT_STRATEGY, TaxonBase.class);
255 return tb;
256 }
257 */
258 /**
259 * Find Taxa, Synonyms, Common Names by name, either globally or in a specific geographic area.
260 * <p>
261 * URI: <b>&#x002F;{datasource-name}&#x002F;portal&#x002F;taxon&#x002F;find</b>
262 *
263 * @param query
264 * the string to query for. Since the wildcard character '*'
265 * internally always is appended to the query string, a search
266 * always compares the query string with the beginning of a name.
267 * - <i>required parameter</i>
268 * @param treeUuid
269 * the {@link UUID} of a {@link TaxonomicTree} to which the
270 * search is to be restricted. - <i>optional parameter</i>
271 * @param areas
272 * restrict the search to a set of geographic {@link NamedArea}s.
273 * The parameter currently takes a list of TDWG area labels.
274 * - <i>optional parameter</i>
275 * @param page
276 * the number of the page to be returned, the first page has the
277 * pageNumber = 1 - <i>optional parameter</i>
278 * @param pageSize
279 * the maximum number of entities returned per page (can be null
280 * to return all entities in a single page) - <i>optional parameter</i>
281 * @param doTaxa
282 * weather to search for instances of {@link Taxon} - <i>optional parameter</i>
283 * @param doSynonyms
284 * weather to search for instances of {@link Synonym} - <i>optional parameter</i>
285 * @param doTaxaByCommonNames
286 * for instances of {@link Taxon} by a common name used - <i>optional parameter</i>
287 * @return a Pager on a list of {@link IdentifiableEntity}s initialized by
288 * the following strategy {@link #SIMPLE_TAXON_INIT_STRATEGY}
289 * @throws IOException
290 */
291 @RequestMapping(method = RequestMethod.GET,
292 value = {"/*/portal/taxon/find"}) //TODO map to path /*/portal/taxon/
293 public Pager<IdentifiableEntity> doFind(
294 @RequestParam(value = "query", required = false) String query,
295 @RequestParam(value = "tree", required = false) UUID treeUuid,
296 @RequestParam(value = "area", required = false) Set<NamedArea> areas,
297 @RequestParam(value = "page", required = false) Integer page,
298 @RequestParam(value = "pageSize", required = false) Integer pageSize,
299 @RequestParam(value = "doTaxa", required = false) Boolean doTaxa,
300 @RequestParam(value = "doSynonyms", required = false) Boolean doSynonyms,
301 @RequestParam(value = "doTaxaByCommonNames", required = false) Boolean doTaxaByCommonNames)
302 throws IOException {
303
304 logger.info("doFind( " +
305 "query=\"" + ObjectUtils.toString(query) + "\", treeUuid=" + ObjectUtils.toString(treeUuid) +
306 ", area=" + ObjectUtils.toString(areas) +
307 ", pageSize=" + ObjectUtils.toString(pageSize) + ", page=" + ObjectUtils.toString(page) +
308 ", doTaxa=" + ObjectUtils.toString(doTaxa) + ", doSynonyms=" + ObjectUtils.toString(doSynonyms) +")" );
309
310 if(page == null){ page = BaseListController.DEFAULT_PAGE_NUMBER;}
311 if(pageSize == null){ pageSize = BaseListController.DEFAULT_PAGESIZE;}
312
313 ITaxonServiceConfigurator config = new TaxonServiceConfiguratorImpl();
314 config.setPageNumber(page);
315 config.setPageSize(pageSize);
316 config.setSearchString(query);
317 config.setDoTaxa(doTaxa!= null ? doTaxa : Boolean.FALSE );
318 config.setDoSynonyms(doSynonyms != null ? doSynonyms : Boolean.FALSE );
319 config.setDoTaxaByCommonNames(doTaxaByCommonNames != null ? doTaxaByCommonNames : Boolean.FALSE );
320 config.setMatchMode(MatchMode.BEGINNING);
321 config.setTaxonPropertyPath(SIMPLE_TAXON_INIT_STRATEGY);
322 config.setNamedAreas(areas);
323 if(treeUuid != null){
324 TaxonomicTree taxonomicTree = taxonTreeService.find(treeUuid);
325 config.setTaxonomicTree(taxonomicTree);
326 }
327
328 return (Pager<IdentifiableEntity>) service.findTaxaAndNames(config);
329 }
330
331 /**
332 * Get the synonymy for a taxon identified by the <code>{taxon-uuid}</code>.
333 * The synonymy consists
334 * of two parts: The group of homotypic synonyms of the taxon and the
335 * heterotypic synonymy groups of the taxon. The synonymy is ordered
336 * historically by the type designations and by the publication date of the
337 * nomenclatural reference
338 * <p>
339 * URI:
340 * <b>&#x002F;{datasource-name}&#x002F;portal&#x002F;taxon&#x002F;{taxon-uuid}&#x002F;synonymy</b>
341 *
342 *
343 * @param request
344 * @param response
345 * @return a Map with to entries which are mapped by the following keys:
346 * "homotypicSynonymsByHomotypicGroup", "heterotypicSynonymyGroups",
347 * containing lists of {@link Synonym}s which are initialized using the
348 * following initialization strategy: {@link #SYNONYMY_INIT_STRATEGY}
349 *
350 * @throws IOException
351 */
352 @RequestMapping(
353 value = {"/*/portal/taxon/*/synonymy"},
354 method = RequestMethod.GET)
355 public ModelAndView doGetSynonymy(HttpServletRequest request, HttpServletResponse response)throws IOException {
356
357 logger.info("doGetSynonymy() " + request.getServletPath());
358 ModelAndView mv = new ModelAndView();
359 TaxonBase tb = getCdmBase(request, response, null, Taxon.class);
360 Taxon taxon = (Taxon)tb;
361 Map<String, List<?>> synonymy = new Hashtable<String, List<?>>();
362 synonymy.put("homotypicSynonymsByHomotypicGroup", service.getHomotypicSynonymsByHomotypicGroup(taxon, SYNONYMY_INIT_STRATEGY));
363 synonymy.put("heterotypicSynonymyGroups", service.getHeterotypicSynonymyGroups(taxon, SYNONYMY_INIT_STRATEGY));
364 mv.addObject(synonymy);
365 return mv;
366 }
367
368 /**
369 * Get the set of accepted {@link Taxon} entities for a given
370 * {@link TaxonBase} entity identified by the <code>{taxon-uuid}</code>.
371 * <p>
372 * URI: <b>&#x002F;{datasource-name}&#x002F;portal&#x002F;taxon&#x002F;{taxon-uuid}&#x002F;accepted</b>
373 *
374 * @param request
375 * @param response
376 * @return a Set of {@link Taxon} entities which are initialized
377 * using the following initialization strategy:
378 * {@link #SYNONYMY_INIT_STRATEGY}
379 * @throws IOException
380 */
381 @RequestMapping(value = "/*/portal/taxon/*/accepted", method = RequestMethod.GET)
382 public Set<TaxonBase> getAccepted(HttpServletRequest request, HttpServletResponse response) throws IOException {
383
384 logger.info("getAccepted() " + request.getServletPath());
385
386 UUID uuid = readValueUuid(request, null);
387 TaxonBase tb = service.load(uuid, SYNONYMY_INIT_STRATEGY);
388 if(tb == null){
389 response.sendError(HttpServletResponse.SC_NOT_FOUND, "A taxon with the uuid " + uuid + " does not exist");
390 return null;
391 }
392 HashSet<TaxonBase> resultset = new HashSet<TaxonBase>();
393 if(tb instanceof Taxon){
394 //the taxon already is accepted
395 //FIXME take the current view into account once views are implemented!!!
396 resultset.add((Taxon)tb);
397 } else {
398 Synonym syn = (Synonym)tb;
399 for(TaxonBase accepted : syn.getAcceptedTaxa()){
400 accepted = service.load(accepted.getUuid(), SIMPLE_TAXON_INIT_STRATEGY);
401 resultset.add(accepted);
402 }
403 }
404 return resultset;
405 }
406
407 /**
408 * Get the list of {@link TaxonRelationship}s for the given
409 * {@link TaxonBase} instance identified by the <code>{taxon-uuid}</code>.
410 * <p>
411 * URI: <b>&#x002F;{datasource-name}&#x002F;portal&#x002F;taxon&#x002F;{taxon-uuid}&#x002F;taxonRelationships</b>
412 *
413 * @param request
414 * @param response
415 * @return a List of {@link TaxonRelationship} entities which are initialized
416 * using the following initialization strategy:
417 * {@link #TAXONRELATIONSHIP_INIT_STRATEGY}
418 * @throws IOException
419 */
420 @RequestMapping(
421 value = {"/*/portal/taxon/*/taxonRelationships"},
422 method = RequestMethod.GET)
423 public List<TaxonRelationship> doGetTaxonRelations(HttpServletRequest request, HttpServletResponse response)throws IOException {
424
425 logger.info("doGetTaxonRelations()" + request.getServletPath());
426 TaxonBase tb = getCdmBase(request, response, null, Taxon.class);
427 Taxon taxon = (Taxon)tb;
428 List<TaxonRelationship> relations = new ArrayList<TaxonRelationship>();
429 List<TaxonRelationship> results = service.listToTaxonRelationships(taxon, TaxonRelationshipType.MISAPPLIED_NAME_FOR(), null, null, null, TAXONRELATIONSHIP_INIT_STRATEGY);
430 relations.addAll(results);
431 results = service.listToTaxonRelationships(taxon, TaxonRelationshipType.INVALID_DESIGNATION_FOR(), null, null, null, TAXONRELATIONSHIP_INIT_STRATEGY);
432 relations.addAll(results);
433
434 return relations;
435 }
436
437 /**
438 * Get the list of {@link NameRelationship}s of the Name associated with the
439 * {@link TaxonBase} instance identified by the <code>{taxon-uuid}</code>.
440 * <p>
441 * URI: <b>&#x002F;{datasource-name}&#x002F;portal&#x002F;taxon&#x002F;{taxon-uuid}&#x002F;nameRelationships</b>
442 *
443 * @param request
444 * @param response
445 * @return a List of {@link NameRelationship} entities which are initialized
446 * using the following initialization strategy:
447 * {@link #NAMERELATIONSHIP_INIT_STRATEGY}
448 * @throws IOException
449 */
450 @RequestMapping(
451 value = {"/*/portal/taxon/*/nameRelationships"},
452 method = RequestMethod.GET)
453 public List<NameRelationship> doGetNameRelations(HttpServletRequest request, HttpServletResponse response)throws IOException {
454 logger.info("doGetNameRelations()" + request.getServletPath());
455 TaxonBase tb = getCdmBase(request, response, SIMPLE_TAXON_INIT_STRATEGY, Taxon.class);
456 List<NameRelationship> list = nameService.listToNameRelationships(tb.getName(), null, null, null, null, NAMERELATIONSHIP_INIT_STRATEGY);
457 return list;
458 }
459
460 /**
461 * Get the list of {@link TaxonNameDescription}s of the Name associated with the
462 * {@link TaxonNameBase} instance identified by the <code>{name-uuid}</code>.
463 * <p>
464 * URI: <b>&#x002F;{datasource-name}&#x002F;portal&#x002F;name&#x002F;{name-uuid}&#x002F;descriptions</b>
465 *
466 * @param request
467 * @param response
468 * @return a List of {@link TaxonNameDescription} entities which are initialized
469 * using the following initialization strategy:
470 * {@link #NAMEDESCRIPTION_INIT_STRATEGY}
471 * @throws IOException
472 */
473 @RequestMapping(
474 value = {"/*/portal/name/*/descriptions"},
475 method = RequestMethod.GET)
476 public List<TaxonNameDescription> doGetNameDescriptions(HttpServletRequest request, HttpServletResponse response)throws IOException {
477 logger.info("doGetNameDescriptions()" + request.getServletPath());
478 UUID nameUuuid = readValueUuid(request, null);
479 TaxonNameBase tnb = nameService.load(nameUuuid, null);
480 Pager<TaxonNameDescription> p = descriptionService.getTaxonNameDescriptions(tnb, null, null, NAMEDESCRIPTION_INIT_STRATEGY);
481 return p.getRecords();
482 }
483
484 /**
485 * Get the list of {@link TypeDesignationBase}s of the
486 * {@link TaxonBase} instance identified by the <code>{taxon-uuid}</code>.
487 * <p>
488 * URI: <b>&#x002F;{datasource-name}&#x002F;portal&#x002F;taxon&#x002F;{taxon-uuid}&#x002F;nameTypeDesignations</b>
489 *
490 * @param request
491 * @param response
492 * @return a List of {@link TypeDesignationBase} entities which are initialized
493 * using the following initialization strategy:
494 * {@link #TYPEDESIGNATION_INIT_STRATEGY}
495 * @throws IOException
496 */
497 @RequestMapping(
498 value = {"/*/portal/taxon/*/nameTypeDesignations"},
499 method = RequestMethod.GET)
500 public List<TypeDesignationBase> doGetNameTypeDesignations(HttpServletRequest request, HttpServletResponse response)throws IOException {
501 logger.info("doGetNameTypeDesignations()" + request.getServletPath());
502 TaxonBase tb = getCdmBase(request, response, SIMPLE_TAXON_INIT_STRATEGY, Taxon.class);
503 Pager<TypeDesignationBase> p = nameService.getTypeDesignations(tb.getName(), null, null, null, TYPEDESIGNATION_INIT_STRATEGY);
504 return p.getRecords();
505 }
506
507 /**
508 * Get the list of {@link TaxonDescription}s of the
509 * {@link Taxon} instance identified by the <code>{taxon-uuid}</code>.
510 * <p>
511 * URI: <b>&#x002F;{datasource-name}&#x002F;portal&#x002F;taxon&#x002F;{taxon-uuid}&#x002F;descriptions</b>
512 *
513 * @param request
514 * @param response
515 * @return a List of {@link TaxonDescription} entities which are initialized
516 * using the following initialization strategy:
517 * {@link #TAXONDESCRIPTION_INIT_STRATEGY}
518 * @throws IOException
519 */
520 @RequestMapping(
521 value = {"/*/portal/taxon/*/descriptions"},
522 method = RequestMethod.GET)
523 public List<TaxonDescription> doGetDescriptions(HttpServletRequest request, HttpServletResponse response)throws IOException {
524 logger.info("doGetDescriptions()" + request.getServletPath());
525 Taxon t = getCdmBase(request, response, null, Taxon.class);
526 Pager<TaxonDescription> p = descriptionService.getTaxonDescriptions(t, null, null, null, null,
527 TAXONDESCRIPTION_INIT_STRATEGY);
528 return p.getRecords();
529 }
530
531 /**
532 * Get the {@link Media} attached to the {@link Taxon} instance
533 * identified by the <code>{taxon-uuid}</code>.
534 *
535 * Usage &#x002F;{datasource-name}&#x002F;portal&#x002F;taxon&#x002F;{taxon-
536 * uuid}&#x002F;media&#x002F;{mime type
537 * list}&#x002F;{size}[,[widthOrDuration}][,{height}]&#x002F;
538 *
539 * Whereas
540 * <ul>
541 * <li><b>{mime type list}</b>: a comma separated list of mime types, in the
542 * order of preference. The forward slashes contained in the mime types must
543 * be replaced by a colon. Regular expressions can be used. Each media
544 * associated with this given taxon is being searched whereas the first
545 * matching mime type matching a representation always rules.</li>
546 * <li><b>{size},{widthOrDuration},{height}</b>: <i>not jet implemented</i>
547 * valid values are an integer or the asterisk '*' as a wildcard</li>
548 * </ul>
549 *
550 * @param request
551 * @param response
552 * @return a List of {@link Media} entities which are initialized
553 * using the following initialization strategy:
554 * {@link #TAXONDESCRIPTION_INIT_STRATEGY}
555 * @throws IOException
556 */
557 @RequestMapping(
558 value = {"/*/portal/taxon/*/media/*/*"},
559 method = RequestMethod.GET)
560 public ModelAndView doGetMedia(HttpServletRequest request, HttpServletResponse response)throws IOException {
561 logger.info("doGetMedia()" + request.getServletPath());
562 Taxon t = getCdmBase(request, response, null, Taxon.class);
563 Map<String,List<MediaRepresentation>> p = new HashMap<String,List<MediaRepresentation>>();
564 boolean hasChildren = false;
565 if (!t.getTaxonNodes().isEmpty()){
566 Iterator<TaxonNode> nodes = t.getTaxonNodes().iterator();
567 TaxonNode node = nodes.next();
568 hasChildren = !node.getChildNodes().isEmpty();
569 Map<UUID,List<MediaRepresentation>> allMedia;
570 if (hasChildren){
571 allMedia = taxonTreeService.getAllMediaForChildNodes(node, TAXON_MEDIA_INIT_STRATEGY, null, null, null, null);
572 Set<Map.Entry<UUID, List<MediaRepresentation>>> entries = allMedia.entrySet();
573 for (Map.Entry<UUID, List<MediaRepresentation>> entry : entries){
574 p.put(entry.toString(), entry.getValue());
575 }
576 }
577 }else{
578 String path = request.getServletPath();
579 String[] pathTokens = path.split("/");
580 String[] mimeTypes = pathTokens[6].split(",");
581 String[] sizeTokens = pathTokens[7].split(",");
582 Integer widthOrDuration = null;
583 Integer height = null;
584 Integer size = null;
585
586 for(int i=0; i<mimeTypes.length; i++){
587 mimeTypes[i] = mimeTypes[i].replace(':', '/');
588 }
589
590 if(sizeTokens.length > 0){
591 try {
592 size = Integer.valueOf(sizeTokens[0]);
593 } catch (NumberFormatException nfe) {
594 /* IGNORE */
595 }
596 }
597 if(sizeTokens.length > 1){
598 try {
599 widthOrDuration = Integer.valueOf(sizeTokens[1]);
600 } catch (NumberFormatException nfe) {
601 /* IGNORE */
602 }
603 }
604 if(sizeTokens.length > 2){
605 try {
606 height = Integer.valueOf(sizeTokens[2]);
607 } catch (NumberFormatException nfe) {
608 /* IGNORE */
609 }
610 }
611
612 List<MediaRepresentation> mr =
613 taxonService.getAllMedia(t, size, height, widthOrDuration, mimeTypes, TAXON_INIT_STRATEGY);
614
615 p.put(t.getUuid().toString(), mr);
616 }
617 // pars the media and quality parameters
618
619
620 /* collect all media of the given taxon
621 boolean limitToGalleries = false;
622 List<Media> taxonMedia = new ArrayList<Media>();
623 for(TaxonDescription desc : p.getRecords()){
624 if(!limitToGalleries || desc.isImageGallery()){
625 for(DescriptionElementBase element : desc.getElements()){
626 for(Media media : element.getMedia()){
627 taxonMedia.add(media);
628 }
629 }
630 }
631 }
632 */
633 // move into media ...
634
635 // find best matching representations of each media
636
637
638 ModelAndView mv = new ModelAndView();
639 mv.addAllObjects(p);
640 return mv;
641 }
642
643 /**
644 * @param media
645 * @param mimeTypeRegexes
646 * @param size
647 * @param widthOrDuration
648 * @param height
649 * @return
650 *
651 * TODO move into a media utils class
652 * TODO implement the quality filter
653 */
654 private SortedMap<String, MediaRepresentation> orderMediaRepresentations(Media media, String[] mimeTypeRegexes,
655 Integer size, Integer widthOrDuration, Integer height) {
656 SortedMap<String, MediaRepresentation> prefRepr = new TreeMap<String, MediaRepresentation>();
657 for (String mimeTypeRegex : mimeTypeRegexes) {
658 // getRepresentationByMimeType
659 Pattern mimeTypePattern = Pattern.compile(mimeTypeRegex);
660 int representationCnt = 0;
661 for (MediaRepresentation representation : media.getRepresentations()) {
662 Matcher mather = mimeTypePattern.matcher(representation.getMimeType());
663 if (mather.matches()) {
664 int dwa = 0;
665
666 /* TODO the quality filter part is being skipped
667 * // look for representation with the best matching parts
668 for (MediaRepresentationPart part : representation.getParts()) {
669 if (part instanceof ImageFile) {
670 ImageFile image = (ImageFile) part;
671 int dw = image.getWidth() * image.getHeight() - height * widthOrDuration;
672 if (dw < 0) {
673 dw *= -1;
674 }
675 dwa += dw;
676 }
677 dwa = (representation.getParts().size() > 0 ? dwa / representation.getParts().size() : 0);
678 }*/
679 prefRepr.put((dwa + representationCnt++) + '_' + representation.getMimeType(), representation);
680
681 // preferred mime type found => end loop
682 break;
683 }
684 }
685 }
686 return prefRepr;
687 }
688
689 // ---------------------- code snippet preserved for possible later use --------------------
690 // @RequestMapping(
691 // value = {"/*/portal/taxon/*/descriptions"},
692 // method = RequestMethod.GET)
693 // public List<TaxonDescription> doGetDescriptionsbyFeatureTree(HttpServletRequest request, HttpServletResponse response)throws IOException {
694 // TaxonBase tb = getCdmBase(request, response, null, Taxon.class);
695 // if(tb instanceof Taxon){
696 // //T O D O this is a quick and dirty implementation -> generalize
697 // UUID featureTreeUuid = readValueUuid(request, featureTreeUuidPattern);
698 //
699 // FeatureTree featureTree = descriptionService.getFeatureTreeByUuid(featureTreeUuid);
700 // Pager<TaxonDescription> p = descriptionService.getTaxonDescriptions((Taxon)tb, null, null, null, null, TAXONDESCRIPTION_INIT_STRATEGY);
701 // List<TaxonDescription> descriptions = p.getRecords();
702 //
703 // if(!featureTree.isDescriptionSeparated()){
704 //
705 // TaxonDescription superDescription = TaxonDescription.NewInstance();
706 // //put all descriptionElements in superDescription and make it invisible
707 // for(TaxonDescription description: descriptions){
708 // for(DescriptionElementBase element: description.getElements()){
709 // superDescription.addElement(element);
710 // }
711 // }
712 // List<TaxonDescription> separatedDescriptions = new ArrayList<TaxonDescription>(descriptions.size());
713 // separatedDescriptions.add(superDescription);
714 // return separatedDescriptions;
715 // }else{
716 // return descriptions;
717 // }
718 // } else {
719 // response.sendError(HttpServletResponse.SC_NOT_FOUND, "invalid type; Taxon expected but " + tb.getClass().getSimpleName() + " found.");
720 // return null;
721 // }
722 // }
723
724 }