dataportal release v2.0
[cdmlib.git] / cdmlib-remote / src / main / java / eu / etaxonomy / cdm / remote / controller / TaxonomicTreeController.java
1 // $Id$
2 /**
3 * Copyright (C) 2009 EDIT European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
5 *
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 See LICENSE.TXT at the top of this package for the full license terms.
8 */
9
10 package eu.etaxonomy.cdm.remote.controller;
11
12 import java.io.IOException;
13 import java.net.URI;
14 import java.net.URISyntaxException;
15 import java.util.ArrayList;
16 import java.util.Arrays;
17 import java.util.Hashtable;
18 import java.util.List;
19 import java.util.UUID;
20 import java.util.regex.Matcher;
21 import java.util.regex.Pattern;
22
23 import javax.servlet.http.HttpServletRequest;
24 import javax.servlet.http.HttpServletResponse;
25
26 import org.apache.log4j.Logger;
27 import org.springframework.beans.factory.annotation.Autowired;
28 import org.springframework.stereotype.Controller;
29 import org.springframework.web.bind.WebDataBinder;
30 import org.springframework.web.bind.annotation.InitBinder;
31 import org.springframework.web.bind.annotation.RequestMapping;
32 import org.springframework.web.bind.annotation.RequestMethod;
33
34 import eu.etaxonomy.cdm.api.service.IReferenceService;
35 import eu.etaxonomy.cdm.api.service.ITaxonService;
36 import eu.etaxonomy.cdm.api.service.ITermService;
37 import eu.etaxonomy.cdm.model.common.DefinedTermBase;
38 import eu.etaxonomy.cdm.model.name.Rank;
39 import eu.etaxonomy.cdm.model.taxon.Taxon;
40 import eu.etaxonomy.cdm.model.taxon.TaxonBase;
41 import eu.etaxonomy.cdm.model.taxon.TaxonNode;
42 import eu.etaxonomy.cdm.model.taxon.TaxonomicTree;
43 import eu.etaxonomy.cdm.remote.editor.RankPropertyEditor;
44 import eu.etaxonomy.cdm.remote.editor.UUIDPropertyEditor;
45 import eu.etaxonomy.cdm.strategy.exceptions.UnknownCdmTypeException;
46
47 /**
48 * @author a.kohlbecker
49 * @date 20.03.2009
50 */
51 @Controller
52 public class TaxonomicTreeController extends AbstractListController<TaxonBase, ITaxonService> {
53
54
55 private static final List<String> TAXONTREE_INIT_STRATEGY = Arrays.asList(new String[]{
56 "reference.authorTeam.titleCache"
57 });
58
59 private static final List<String> NODE_INIT_STRATEGY = Arrays.asList(new String[]{
60 "taxon.sec",
61 "taxon.name.taggedName",
62 });
63
64
65 //TODO get rid of the bloodyRankLabelMap ------ can be deleted once the FIXME in getPathToRoot is solved
66 private static Hashtable<String, String> bloodyRankLabelMap = new Hashtable<String, String>();
67 static{
68 bloodyRankLabelMap.put("Subfamily", "Subfamilia");
69 bloodyRankLabelMap.put("Family", "Familia");
70 bloodyRankLabelMap.put("Suborder", "Subordo");
71 bloodyRankLabelMap.put("Order", "Ordo");
72
73 }
74 // --------------------------------------------
75
76 public static final Logger logger = Logger.getLogger(TaxonomicTreeController.class);
77
78 private ITaxonService service;
79
80
81 private ITermService termService;
82
83 private IReferenceService referenceService;
84
85
86 private Pattern parameterPattern = Pattern.compile("^/(?:[^/]+)/taxontree/([^?#&\\.]+).*");
87
88 @Autowired
89 public void setService(ITaxonService service) {
90 this.service = service;
91 }
92
93 @Autowired
94 public void setTermService(ITermService termService) {
95 this.termService = termService;
96 }
97
98 @Autowired
99 public void setReferenceService(IReferenceService referenceService) {
100 this.referenceService = referenceService;
101 }
102
103 @InitBinder
104 public void initBinder(WebDataBinder binder) {
105 binder.registerCustomEditor(UUID.class, new UUIDPropertyEditor());
106 binder.registerCustomEditor(Rank.class, new RankPropertyEditor());
107 }
108
109 /**
110 * @param uuid
111 * @param rank
112 * @param request
113 * @param response
114 * @return
115 * @throws IOException
116 */
117 // @RequestMapping(
118 // value = {"/*/taxontree/"},
119 // params = {"uuid"},
120 // method = RequestMethod.GET)
121 // public String findTaxon(
122 // @RequestParam(value = "uuid", required = true) UUID uuid,
123 // @RequestParam(value = "rankUuid", required = false) UUID rankUuid,
124 // @RequestParam(value = "viewUuid", required = false) UUID viewUuid,
125 // HttpServletRequest request, HttpServletResponse response) throws IOException {
126 //
127 // String msg404 = rank != null ? "Taxon not found within rank "+ rank.getLabel() : "Taxon not found.";
128 //
129 // TaxonBase tb = service.load(uuid, TAXON_INIT_STRATEGY);
130 //
131 // if(tb != null && Taxon.class.isAssignableFrom(tb.getClass())){
132 // Taxon t = (Taxon)tb;
133 // String relPath = "";
134 // String basePath = FilenameUtils.removeExtension(request.getServletPath());
135 // basePath += "/" + t.getSec().getUuid().toString();
136 // if(rank != null){
137 // basePath += "," + rank.getLabel();
138 // }
139 //
140 // // compose path of parent uuids
141 // Taxon taxon = t;
142 // while( taxon != null && (rank == null || taxon.getName().getRank() == null || taxon.getName().getRank().compareTo(rank) <= 0) ) {
143 // relPath = "/" + taxon.getUuid().toString() + relPath;
144 // taxon = taxon.getTaxonomicParent();
145 // if(taxon != null){
146 // taxon = (Taxon)service.load(taxon.getUuid(), TAXON_INIT_STRATEGY);
147 // }
148 // };
149 //
150 // if(relPath.length() > 0){
151 // URI redirectUri;
152 // try {
153 // redirectUri = relativeToFullUri(request, basePath + relPath);
154 // if(logger.isInfoEnabled()){
155 // logger.info("redirecting to " + redirectUri);
156 // }
157 // response.sendRedirect(redirectUri.toString());
158 // return "";
159 // } catch (URISyntaxException e) {
160 // logger.error(e.getMessage(), e);
161 // }
162 // }
163 // } else {
164 // msg404 = "The taxon is not accepted";
165 // }
166 // response.sendError(HttpServletResponse.SC_NOT_FOUND, msg404);
167 // return "";
168 // }
169
170
171
172 @RequestMapping(value = { "/*/taxontree" }, method = RequestMethod.GET)
173 public List<TaxonomicTree> getTaxonomicTrees(HttpServletRequest request, HttpServletResponse response)
174 throws IOException {
175 logger.info("getTaxonomicTrees()");
176 return service.listTaxonomicTrees(null, null, null, TAXONTREE_INIT_STRATEGY);
177 }
178
179
180 /**
181 * &#x002F;*&#x002F;taxontree&#x002F;{viewUuid},{rankUuid}&#x002F;
182 * @param request
183 * @return
184 */
185 @RequestMapping(
186 value = {"/*/taxontree/?*"},
187 method = RequestMethod.GET)
188 public List<TaxonNode> getRootTaxa(HttpServletRequest request, HttpServletResponse response) throws IOException {
189 logger.info("getRootTaxa()");
190 List<String> uriParams = readUriParameters(request);
191 TaxonomicTree tree = null;
192 Rank rank = null;
193 if(uriParams.size() == 1){
194 // get view and rank
195 tree = readTreeByUuid(uriParams.get(0));
196 rank = readRankByUuid(uriParams.get(0));
197
198 if(tree == null) {
199 response.sendError(404 , "TaxonomicTree not found using " + stringToUuid(uriParams.get(0)) );
200 return null;
201 }
202 }
203 if(uriParams.size() > 1){
204 response.sendError(400, "A maximum of two uuid parameter expected but found " + uriParams.size());
205 return null;
206 }
207 return service.loadRankSpecificRootNodes(tree, rank, NODE_INIT_STRATEGY);
208 }
209
210
211 /**
212 * @param request
213 * @return
214 * @throws IOException
215 */
216 @RequestMapping(
217 value = {"/*/taxontree/*/?*", "/*/taxontree/*/**/?*"},
218 method = RequestMethod.GET)
219 public List<TaxonNode> getChildTaxa(HttpServletRequest request, HttpServletResponse response) throws IOException {
220 logger.info("getChildTaxa()");
221 List<String> uriParams = readUriParameters(request);
222 if(uriParams.size() <= 1){
223 response.sendError(400, "At least two uuid parameters expected but found " + uriParams.size());
224 return null;
225 }
226
227 TaxonomicTree tree = readTreeByUuid(uriParams.get(0));
228 if(tree == null){
229 response.sendError(500, "The specified instance identified by " + uriParams.get(0) + " is not a taxonomicTree");
230 return null;
231 }
232 Rank rank = readRankByUuid(uriParams.get(0));
233 //TODO rank is being ignored
234 try {
235 UUID uuid = stringToUuid(uriParams.get(uriParams.size() - 1));
236 Taxon taxon = (Taxon) service.load(uuid);
237 List<TaxonNode> childs = service.loadChildNodesOfTaxon(taxon, tree, NODE_INIT_STRATEGY);
238 return childs;
239 } catch (ClassCastException cce) {
240 response.sendError(500, "The specified instance is not a taxon");
241 return null;
242 }
243 }
244
245 /**
246 * @param request
247 * @return
248 * @throws IOException
249 */
250 @RequestMapping(
251 value = {"/*/taxontree/*/*/path", "/*/taxontree/*/**/*/path"},
252 method = RequestMethod.GET)
253 public List<TaxonNode> getPathToRoot(HttpServletRequest request, HttpServletResponse response) throws IOException {
254 logger.info("getPathToRoot()");
255 List<Taxon> pathToRoot = new ArrayList<Taxon>();
256 List<String> uriParams = readUriParameters(request);
257 if(uriParams.size() <= 1){
258 response.sendError(400, "At least two uuid parameters expected but found " + uriParams.size());
259 return null;
260 }
261
262 TaxonomicTree tree = readTreeByUuid(uriParams.get(0));
263 Rank rank = readRankByUuid(uriParams.get(0));
264 UUID taxonUuid = stringToUuid(uriParams.get(uriParams.size() - 2));
265 Taxon taxon = (Taxon) service.load(taxonUuid);
266
267 return service.loadTreeBranchToTaxon(taxon, tree, rank, NODE_INIT_STRATEGY);
268 }
269
270 /**
271 * reads <code>{secuuid},{rank label}/..</code> from <code>/{database key}/taxonomy/{secuuid},{rank label}/..<code>
272 * @param request
273 * @return
274 */
275 protected List<String> readUriParameters(HttpServletRequest request) {
276
277 List<String> parameters = null;
278 String path = request.getServletPath();
279 if(path != null) {
280 Matcher uuidMatcher = parameterPattern .matcher(path);
281 if(uuidMatcher.matches() && uuidMatcher.groupCount() > 0){
282 String[] pa = uuidMatcher.group(1).split("/");
283 parameters = Arrays.asList(pa);
284 }
285 }
286 return parameters;
287 }
288
289 /**
290 * @param string
291 * @return
292 */
293 private Rank readRankByLabel(String paramStr) throws IllegalArgumentException{
294 int pos;
295 if((pos = paramStr.indexOf(',')) > 0){
296 String rankLabel = paramStr.substring(pos + 1);
297 try {
298 return Rank.getRankByName(rankLabel);
299 } catch (UnknownCdmTypeException e) {
300 throw new IllegalArgumentException("400Not a valid rank name");
301 }
302 }
303 return null;
304 }
305
306 private Rank readRankByUuid(String paramStr) throws IllegalArgumentException{
307 int pos;
308 if((pos = paramStr.indexOf(',')) > 0){
309 String uuidStr = paramStr.substring(pos + 1);
310 UUID uuid = UUID.fromString(uuidStr);
311 DefinedTermBase dt = termService.findByUuid(uuid);
312 if(dt instanceof Rank){
313 return (Rank)dt;
314 } else {
315 new IllegalArgumentException("Term is not a Rank");
316 }
317 }
318 return null;
319 }
320
321 /**
322 * @param paramStr
323 * @return
324 */
325 private TaxonomicTree readTreeByUuid(String paramStr) {
326 UUID viewUuid;
327 int pos;
328 if((pos = paramStr.indexOf(',')) > 0){
329
330 viewUuid = stringToUuid(paramStr.substring(0, pos));
331 } else {
332 viewUuid = stringToUuid(paramStr);
333 }
334 return service.getTaxonomicTreeByUuid(viewUuid);
335 }
336
337 /**
338 * @param uuidStr
339 * @return
340 */
341 private UUID stringToUuid(String uuidStr) {
342
343 try {
344 UUID uuid = UUID.fromString(uuidStr);
345 return uuid;
346 } catch (Exception e) {
347 throw new IllegalArgumentException(uuidStr + " is not a uuid");
348 }
349 }
350
351 private URI relativeToFullUri(HttpServletRequest request,
352 String relativePath) throws URISyntaxException {
353 return new URI(
354 request.getScheme(),
355 null, //user info
356 request.getServerName(),
357 request.getServerPort(),
358 relativePath,
359 null,
360 null);
361 }
362
363 }