Project

General

Profile

Download (11.5 KB) Statistics
| Branch: | Tag: | Revision:
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.HashSet;
18
import java.util.Hashtable;
19
import java.util.List;
20
import java.util.Set;
21
import java.util.UUID;
22
import java.util.regex.Matcher;
23
import java.util.regex.Pattern;
24

    
25
import javax.servlet.http.HttpServletRequest;
26
import javax.servlet.http.HttpServletResponse;
27

    
28
import org.apache.commons.io.FilenameUtils;
29
import org.apache.log4j.Logger;
30
import org.springframework.beans.factory.annotation.Autowired;
31
import org.springframework.stereotype.Controller;
32
import org.springframework.web.bind.WebDataBinder;
33
import org.springframework.web.bind.annotation.InitBinder;
34
import org.springframework.web.bind.annotation.RequestMapping;
35
import org.springframework.web.bind.annotation.RequestMethod;
36
import org.springframework.web.bind.annotation.RequestParam;
37

    
38
import eu.etaxonomy.cdm.api.service.IReferenceService;
39
import eu.etaxonomy.cdm.api.service.ITaxonService;
40
import eu.etaxonomy.cdm.model.name.Rank;
41
import eu.etaxonomy.cdm.model.reference.ReferenceBase;
42
import eu.etaxonomy.cdm.model.taxon.Taxon;
43
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
44
import eu.etaxonomy.cdm.remote.editor.RankPropertyEditor;
45
import eu.etaxonomy.cdm.remote.editor.UUIDPropertyEditor;
46
import eu.etaxonomy.cdm.strategy.exceptions.UnknownCdmTypeException;
47

    
48
/**
49
 * @author a.kohlbecker
50
 * @date 20.03.2009
51
 */
52
@Controller
53
public class TaxonomyController extends AbstractListController<TaxonBase, ITaxonService> {
54
	
55
	/**
56
	 * 
57
	 */
58
	private static final List<String> TAXON_INIT_STRATEGY = Arrays.asList(new String[]{
59
			"sec", 
60
			"relationsToThisTaxon.toTaxon.$",
61
			//"name.rank.$",
62
			"name.rank.representations",
63
			"name.nomenclaturalReference.authorTeam.*"
64
			});
65
	
66
	private static final List<String> CHILD_TAXON_INIT_STRATEGY = Arrays.asList(new String[]{
67
			"sec", 
68
			"relationsToThisTaxon.fromTaxon.$",
69
			"relationsToThisTaxon.fromTaxon.name.taggedName",
70
			"name.taggedName",
71
			});
72
	
73
	private static final List<String> PARENT_TAXON_INIT_STRATEGY = Arrays.asList(new String[]{
74
			"sec", 
75
			"relationsFromThisTaxon.toTaxon.$",
76
			"relationsFromThisTaxon.toTaxon.name.rank.representations",
77
			"name.taggedName",
78
			"name.rank.representations",
79
			"name.nomenclaturalReference.authorTeam.*"
80
			});
81
	
82
	//TODO get rid of the bloodyRankLabelMap ------ can be deleted once the FIXME in getPathToRoot is solved
83
	private static Hashtable<String, String> bloodyRankLabelMap = new Hashtable<String, String>();	
84
	static{
85
		bloodyRankLabelMap.put("Subfamily", "Subfamilia");
86
		bloodyRankLabelMap.put("Family", "Familia");
87
		bloodyRankLabelMap.put("Suborder", "Subordo");
88
		bloodyRankLabelMap.put("Order", "Ordo");
89
		
90
	}
91
	// --------------------------------------------
92

    
93
	public static final Logger logger = Logger.getLogger(TaxonomyController.class);
94

    
95
	private ITaxonService service;
96
	
97
	private IReferenceService referenceService;
98
	
99
	private Pattern parameterPattern = Pattern.compile("^/(?:[^/]+)/taxonomy/([^?#&\\.]+).*");
100

    
101
	@Autowired
102
	public void setService(ITaxonService service) {
103
		this.service = service; 
104
	}
105
	
106
	@Autowired
107
	public void setReferenceService(IReferenceService referenceService) {
108
		this.referenceService = referenceService;
109
	}
110
	
111
	@InitBinder
112
    public void initBinder(WebDataBinder binder) {
113
		binder.registerCustomEditor(UUID.class, new UUIDPropertyEditor());
114
		binder.registerCustomEditor(Rank.class, new RankPropertyEditor());
115
	}
116
	
117
	/**
118
	 * @param uuid
119
	 * @param rank
120
	 * @param request
121
	 * @param response
122
	 * @return
123
	 * @throws IOException 
124
	 */
125
	@RequestMapping(
126
			value = {"/*/taxonomy/"},
127
			params = {"uuid"},
128
			method = RequestMethod.GET)
129
	public String findTaxon(
130
			@RequestParam(value = "uuid", required = true) UUID uuid,
131
			@RequestParam(value = "rank", required = false) Rank rank,
132
			//TODO implement view uuid parameter
133
			HttpServletRequest request, HttpServletResponse response) throws IOException {
134
		
135
		String msg404 = rank != null ? "Taxon not found within rank "+ rank.getLabel() : "Taxon not found.";
136
		
137
		TaxonBase tb = service.load(uuid, TAXON_INIT_STRATEGY);
138
				
139
		if(tb != null && Taxon.class.isAssignableFrom(tb.getClass())){			
140
			Taxon t = (Taxon)tb;
141
			String relPath = "";
142
			String basePath = FilenameUtils.removeExtension(request.getServletPath()); 
143
			basePath += "/" + t.getSec().getUuid().toString();
144
			if(rank != null){
145
				basePath += "," + rank.getLabel();
146
			}
147
			
148
			// compose path of parent uuids
149
			Taxon taxon = t;
150
			while( taxon != null && (rank == null || taxon.getName().getRank() == null || taxon.getName().getRank().compareTo(rank) <= 0) ) {
151
				relPath = "/" + taxon.getUuid().toString() + relPath;
152
				taxon  = taxon.getTaxonomicParent();
153
				if(taxon != null){
154
					taxon = (Taxon)service.load(taxon.getUuid(), TAXON_INIT_STRATEGY);
155
				}
156
			};
157
			
158
			if(relPath.length() > 0){
159
				URI redirectUri;
160
				try {
161
					redirectUri = relativeToFullUri(request, basePath + relPath);
162
					if(logger.isInfoEnabled()){
163
						logger.info("redirecting to " + redirectUri);
164
					}
165
					response.sendRedirect(redirectUri.toString());
166
					return "";
167
				} catch (URISyntaxException e) {
168
					logger.error(e.getMessage(), e);
169
				}
170
			}
171
		} else {
172
			msg404 = "The taxon is not accepted";
173
		}
174
		response.sendError(HttpServletResponse.SC_NOT_FOUND, msg404);
175
		return "";
176
	}
177
	
178
	/**
179
	 * @param request
180
	 * @return
181
	 */
182
	@RequestMapping(
183
			value = {"/*/taxonomy/*"}, 
184
			method = RequestMethod.GET)
185
	public List<Taxon> getRootTaxa(HttpServletRequest request, HttpServletResponse response) throws IOException {
186
		
187
		List<String> uriParams = readUriParameters(request);
188
		ReferenceBase secref = null;
189
		Rank rank = null;
190
		if(uriParams == null){
191
			return (List<Taxon>) service.getRootTaxa(rank, null, true, false, TAXON_INIT_STRATEGY);
192
			//response.sendError(HttpServletResponse.SC_NOT_FOUND, "");
193
			//return null;
194
		}
195
		if(uriParams.size() == 1){
196
			// get secuuid and rank
197
			secref = readSecByUuid(uriParams.get(0));
198
			rank = readRankByLabel(uriParams.get(0));
199
			
200
			if(secref == null) {
201
				response.sendError(404 , "SecReference not found by " + stringToUuid(uriParams.get(0)) );
202
				return null;
203
			}
204
			
205
		}
206
		if(uriParams.size() > 1){
207
			response.sendError(400, "Only one uuid parameter expected but found  " + uriParams.size());
208
			return null;
209
		}
210
		return (List<Taxon>) service.getRootTaxa(rank, secref, true, false, TAXON_INIT_STRATEGY);
211
	}
212

    
213

    
214

    
215
	/**
216
	 * @param request
217
	 * @return
218
	 * @throws IOException 
219
	 */
220
	@RequestMapping(
221
			value = {"/*/taxonomy/*/*", "/*/taxonomy/*/**/*"}, 
222
			method = RequestMethod.GET)
223
	public Set<Taxon> getChildTaxa(HttpServletRequest request, HttpServletResponse response) throws IOException {
224
		
225
		List<String> uriParameters = readUriParameters(request);
226
		if(uriParameters.size() <= 1){
227
			response.sendError(400, "At least two uuid parameters expected but found " + uriParameters.size());
228
			return null;
229
		}
230
		try {
231
			UUID uuid = stringToUuid(uriParameters.get(uriParameters.size() - 1));
232
			Taxon taxon = (Taxon) service.load(uuid, CHILD_TAXON_INIT_STRATEGY);
233
			return taxon.getTaxonomicChildren();
234
		} catch (ClassCastException cce) {
235
			response.sendError(500, "The specified instance is not a taxon");
236
			return null;
237
		}
238
	}
239
	
240
	/**
241
	 * @param request
242
	 * @return
243
	 * @throws IOException 
244
	 */
245
	@RequestMapping(
246
			value = {"/*/taxonomy/*/*/path", "/*/taxonomy/*/**/*/path"}, 
247
			method = RequestMethod.GET)
248
	public List<Taxon> getPathToRoot(HttpServletRequest request, HttpServletResponse response) throws IOException {
249
		
250
		List<Taxon> pathToRoot = new ArrayList<Taxon>();
251
		List<String> uriParameters = readUriParameters(request);
252
		if(uriParameters.size() <= 1){
253
			response.sendError(400, "At least two uuid parameters expected but found " + uriParameters.size());
254
			return null;
255
		}
256
		// get rank
257
		Rank rank = readRankByLabel(uriParameters.get(0));
258
		
259
		try {
260
			UUID uuid = stringToUuid(uriParameters.get(uriParameters.size() - 2));
261
			Taxon parentTaxon = (Taxon) service.load(uuid, PARENT_TAXON_INIT_STRATEGY);
262
			while(parentTaxon != null){
263
				//FIXME orderindex in parentTaxon.getName().getRank() is not set !!!
264
				// original: if(rank != null && rank.isLower(parentTaxon.getName().getRank())){
265
				// Preliminary solution below:
266
				if(rank != null){
267
					try {
268
						String bloodyRankLabel = bloodyRankLabelMap.get(parentTaxon.getName().getRank().getLabel());
269
						if(bloodyRankLabel == null){
270
							bloodyRankLabel = parentTaxon.getName().getRank().getLabel();
271
						}
272
						Rank compareToRank = Rank.getRankByName(bloodyRankLabel);
273
						if(rank.isLower(compareToRank)){
274
							break;
275
						}
276
					} catch (UnknownCdmTypeException e) {
277
						logger.error(e);
278
					}
279
				}
280
				pathToRoot.add(parentTaxon);
281
				parentTaxon = parentTaxon.getTaxonomicParent();
282
				if(parentTaxon != null){
283
					parentTaxon = (Taxon)service.load(parentTaxon.getUuid(), PARENT_TAXON_INIT_STRATEGY);
284
				}
285
			}
286
			
287
			return pathToRoot;
288
		} catch (ClassCastException cce) {
289
			logger.warn("The specified instance is not a taxon", cce);
290
			response.sendError(500, "The specified instance is not a taxon");
291
			return null;
292
		}
293
	}
294
	
295
	/**
296
	 * reads  <code>{secuuid},{rank label}/..</code> from <code>/{database key}/taxonomy/{secuuid},{rank label}/..<code>
297
	 * @param request
298
	 * @return
299
	 */
300
	protected List<String> readUriParameters(HttpServletRequest request) {
301
		
302
		List<String> parameters = null;
303
		String path = request.getServletPath();
304
		if(path != null) {
305
			Matcher uuidMatcher = parameterPattern .matcher(path);
306
			if(uuidMatcher.matches() && uuidMatcher.groupCount() > 0){
307
				String[] pa = uuidMatcher.group(1).split("/");
308
				parameters = Arrays.asList(pa);
309
			}
310
		}
311
		return parameters;
312
	}
313
	
314
	/**
315
	 * @param string
316
	 * @return
317
	 */
318
	private Rank readRankByLabel(String paramStr) throws IllegalArgumentException{
319
		int pos;
320
		if((pos = paramStr.indexOf(',')) > 0){
321
			String rankLabel = paramStr.substring(pos + 1);
322
			try {
323
				return Rank.getRankByName(rankLabel);
324
			} catch (UnknownCdmTypeException e) {
325
				throw new IllegalArgumentException("400Not a valid rank name");
326
			}
327
		}
328
		return null;
329
	}
330

    
331
	/**
332
	 * @param paramStr
333
	 * @return
334
	 */
335
	private ReferenceBase readSecByUuid(String paramStr) {
336
		UUID secRefuuid; 
337
		int pos;
338
		if((pos = paramStr.indexOf(',')) > 0){
339
			
340
			secRefuuid = stringToUuid(paramStr.substring(0, pos));
341
		} else {
342
			secRefuuid = stringToUuid(paramStr);
343
		}
344
		return referenceService.findByUuid(secRefuuid);			
345
	}
346

    
347
	/**
348
	 * @param uuidStr
349
	 * @return
350
	 */
351
	private UUID stringToUuid(String uuidStr) {
352
		
353
		try {
354
			UUID uuid = UUID.fromString(uuidStr);
355
			return uuid;
356
		} catch (Exception e) {
357
			throw new IllegalArgumentException(uuidStr + " is not a uuid");
358
		}
359
	}
360
	
361
	private URI relativeToFullUri(HttpServletRequest request,
362
			String relativePath) throws URISyntaxException {
363
			return new URI(
364
					request.getScheme(), 
365
					null, //user info
366
					request.getServerName(), 
367
					request.getServerPort(),  
368
					relativePath, 
369
					null,
370
					null); 
371
	}
372
	
373
}
(26-26/26)