49d473f3d48a56e62ca0f02895769d200d103a15
[cdmlib.git] / cdmlib-remote / src / main / java / eu / etaxonomy / cdm / remote / controller / checklist / ChecklistDemoController.java
1 /*
2 * Copyright EDIT
3 * 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 1.1
7 * See LICENSE.TXT at the top of this package for the full license terms.
8 */
9 package eu.etaxonomy.cdm.remote.controller.checklist;
10
11 import java.io.File;
12 import java.io.IOException;
13 import java.io.InputStream;
14 import java.util.ArrayList;
15 import java.util.Arrays;
16 import java.util.HashMap;
17 import java.util.HashSet;
18 import java.util.List;
19 import java.util.Map;
20 import java.util.Set;
21 import java.util.UUID;
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.beans.propertyeditors.UUIDEditor;
29 import org.springframework.context.ApplicationContext;
30 import org.springframework.context.ResourceLoaderAware;
31 import org.springframework.core.io.Resource;
32 import org.springframework.core.io.ResourceLoader;
33 import org.springframework.stereotype.Controller;
34 import org.springframework.web.bind.WebDataBinder;
35 import org.springframework.web.bind.annotation.InitBinder;
36 import org.springframework.web.bind.annotation.RequestMapping;
37 import org.springframework.web.bind.annotation.RequestMethod;
38 import org.springframework.web.bind.annotation.RequestParam;
39 import org.springframework.web.servlet.ModelAndView;
40
41 import eu.etaxonomy.cdm.api.service.IClassificationService;
42 import eu.etaxonomy.cdm.api.service.IService;
43 import eu.etaxonomy.cdm.api.service.ITaxonService;
44 import eu.etaxonomy.cdm.api.service.ITermService;
45 import eu.etaxonomy.cdm.api.service.config.IncludedTaxonConfiguration;
46 import eu.etaxonomy.cdm.api.service.dto.IncludedTaxaDTO;
47 import eu.etaxonomy.cdm.api.service.pager.impl.DefaultPagerImpl;
48 import eu.etaxonomy.cdm.common.DocUtils;
49 import eu.etaxonomy.cdm.common.monitor.IRestServiceProgressMonitor;
50 import eu.etaxonomy.cdm.io.common.CdmApplicationAwareDefaultExport;
51 import eu.etaxonomy.cdm.io.csv.redlist.demo.CsvDemoExportConfigurator;
52 import eu.etaxonomy.cdm.io.csv.redlist.demo.CsvDemoRecord;
53 import eu.etaxonomy.cdm.model.description.Feature;
54 import eu.etaxonomy.cdm.model.location.NamedArea;
55 import eu.etaxonomy.cdm.model.taxon.Classification;
56 import eu.etaxonomy.cdm.model.taxon.Taxon;
57 import eu.etaxonomy.cdm.remote.controller.AbstractController;
58 import eu.etaxonomy.cdm.remote.controller.ProgressMonitorController;
59 import eu.etaxonomy.cdm.remote.controller.util.PagerParameters;
60 import eu.etaxonomy.cdm.remote.controller.util.ProgressMonitorUtil;
61 import eu.etaxonomy.cdm.remote.editor.TermBaseListPropertyEditor;
62 import eu.etaxonomy.cdm.remote.editor.UUIDListPropertyEditor;
63 import eu.etaxonomy.cdm.remote.editor.UuidList;
64 import eu.etaxonomy.cdm.remote.view.FileDownloadView;
65 import eu.etaxonomy.cdm.remote.view.HtmlView;
66
67 /**
68 * @author a.oppermann
69 * @created 20.09.2012
70 * <p>
71 * This controller enables an export of the cdm platform via a
72 * REST request. It is debatable if this a wanted behavior.
73 * For the time being it serves its purpose.
74 */
75 @Controller
76 @RequestMapping(value = { "/checklist" })
77 public class ChecklistDemoController extends AbstractController implements ResourceLoaderAware{
78
79 @Autowired
80 private ApplicationContext appContext;
81
82 @Autowired
83 private ITermService termService;
84
85 @Autowired
86 private ITaxonService taxonService;
87
88 @Autowired
89 private IClassificationService classificationService;
90
91 @Autowired
92 public ProgressMonitorController progressMonitorController;
93
94 private ResourceLoader resourceLoader;
95
96
97 /**
98 * There should only be one processes operating on the export
99 * therefore the according progress monitor uuid is stored in this static
100 * field.
101 */
102 private static UUID indexMonitorUuid = null;
103
104 private final static long DAY_IN_MILLIS = 86400000;
105
106
107
108 private static final Logger logger = Logger.getLogger(ChecklistDemoController.class);
109
110 /**
111 * Helper method, which allows to convert strings directly into uuids.
112 *
113 * @param binder Special DataBinder for data binding from web request parameters to JavaBean objects.
114 */
115 @InitBinder
116 public void initBinder(WebDataBinder binder) {
117 binder.registerCustomEditor(UuidList.class, new UUIDListPropertyEditor());
118 binder.registerCustomEditor(NamedArea.class, new TermBaseListPropertyEditor<NamedArea>(termService));
119 binder.registerCustomEditor(UUID.class, new UUIDEditor());
120 }
121
122
123
124
125 @RequestMapping(value = {""}, method = { RequestMethod.GET})
126 public ModelAndView exportGetExplanation(HttpServletResponse response,
127 HttpServletRequest request) throws IOException{
128 ModelAndView mv = new ModelAndView();
129 // Read apt documentation file.
130 Resource resource = resourceLoader.getResource("classpath:eu/etaxonomy/cdm/doc/remote/apt/checklist-catalogue-default.apt");
131 // using input stream as this works for both files in the classes directory
132 // as well as files inside jars
133 InputStream aptInputStream = resource.getInputStream();
134 // Build Html View
135 Map<String, String> modelMap = new HashMap<String, String>();
136 // Convert Apt to Html
137 modelMap.put("html", DocUtils.convertAptToHtml(aptInputStream));
138 mv.addAllObjects(modelMap);
139
140 HtmlView hv = new HtmlView();
141 mv.setView(hv);
142 return mv;
143 }
144
145 /**
146 * This service endpoint is for generating the documentation site.
147 * If any request of the other endpoint below is incomplete or false
148 * then this method will be triggered.
149 *
150 * @param response
151 * @param request
152 * @return
153 * @throws IOException
154 */
155 public ModelAndView exportGetExplanation(HttpServletResponse response,
156 HttpServletRequest request, Resource res) throws IOException{
157 ModelAndView mv = new ModelAndView();
158 // Read apt documentation file.
159 Resource resource = (res!= null) ? res : resourceLoader.getResource("classpath:eu/etaxonomy/cdm/doc/remote/apt/checklist-catalogue-default.apt");
160 // using input stream as this works for both files in the classes directory
161 // as well as files inside jars
162 InputStream aptInputStream = resource.getInputStream();
163 // Build Html View
164 Map<String, String> modelMap = new HashMap<String, String>();
165 // Convert Apt to Html
166 modelMap.put("html", DocUtils.convertAptToHtml(aptInputStream));
167 mv.addAllObjects(modelMap);
168
169 HtmlView hv = new HtmlView();
170 mv.setView(hv);
171 return mv;
172 }
173
174 /**
175 *
176 * This service endpoint generates a json and xml view of the exported list.
177 * It takes advantage of pagination.
178 *
179 * @param classificationUUID
180 * @param pageNumber
181 * @param pageSize
182 * @param response
183 * @param request
184 * @return
185 * @throws IOException
186 */
187 @RequestMapping(value = { "export" }, method = { RequestMethod.GET })
188 public ModelAndView doGeneralExport(
189 @RequestParam(value = "classification", required = false) String classificationUUID,
190 @RequestParam(value = "pageNumber", required = false) Integer pageNumber,
191 @RequestParam(value = "pageSize", required = false) Integer pageSize,
192 HttpServletResponse response,
193 HttpServletRequest request) throws IOException {
194
195 try{
196 if(pageSize == null) {
197 pageSize = 20;
198 }
199 if(pageNumber == null) {
200 pageNumber = 0;
201 }
202
203 PagerParameters pagerParams = new PagerParameters(pageSize, pageNumber);
204 pagerParams.normalizeAndValidate(response);
205
206 List<CsvDemoRecord> recordList = new ArrayList<CsvDemoRecord>();
207
208 CsvDemoExportConfigurator config = setTaxExportConfigurator(null ,classificationUUID, null, null, null);
209 config.setPageSize(pagerParams.getPageSize());
210 config.setPageNumber(pagerParams.getPageIndex());
211 config.setRecordList(recordList);
212
213 CdmApplicationAwareDefaultExport<?> defaultExport = (CdmApplicationAwareDefaultExport<?>) appContext.getBean("defaultExport");
214 defaultExport.invoke(config);
215
216 DefaultPagerImpl<CsvDemoRecord> dpi = new DefaultPagerImpl<CsvDemoRecord>(pagerParams.getPageIndex(), config.getTaxonNodeListSize(), pagerParams.getPageSize(), recordList);
217 ModelAndView mv = new ModelAndView();
218 // mv.addObject(recordList);f
219 mv.addObject(dpi);
220 return mv;
221 }catch(Exception e){
222 Resource resource = resourceLoader.getResource("classpath:eu/etaxonomy/cdm/doc/remote/apt/checklist-catalogue-export.apt");
223 return exportGetExplanation(response, request, resource);
224 }
225
226 }
227
228
229 /**
230 *
231 * This Service endpoint will offer a csv file. It caches the csv-file in the system temp directory
232 * and will only generate a new one after 24 hours. Or if explicitly triggerd by noCache parameter.
233 *
234 * @param featureUuids List of uuids to download/select {@link Feature feature}features
235 * @param clearCache will trigger export and avoids cached file
236 * @param classificationUUID Selected {@link Classification classification} to iterate the {@link Taxon}
237 * @param response HttpServletResponse which returns the ByteArrayOutputStream
238 * @throws Exception
239 */
240 @RequestMapping(value = { "exportCSV" }, method = { RequestMethod.GET })
241 public synchronized ModelAndView doExportRedlist(
242 @RequestParam(value = "features", required = false) final UuidList featureUuids,
243 @RequestParam(value = "clearCache", required = false) final boolean clearCache,
244 @RequestParam(value = "demoExport", required = false) boolean demoExport,
245 @RequestParam(value = "conceptExport", required = false) boolean conceptExport,
246 @RequestParam(value = "classification", required = false) final String classificationUUID,
247 @RequestParam(value = "area", required = false) final UuidList areas,
248 @RequestParam(value = "downloadTokenValueId", required = false) final String downloadTokenValueId,
249 @RequestParam(value = "priority", required = false) Integer priority,
250 final HttpServletResponse response,
251 final HttpServletRequest request) throws Exception {
252 /**
253 * ========================================
254 * progress monitor & new thread for export
255 * ========================================
256 */
257 try{
258 ModelAndView mv = new ModelAndView();
259 String fileName = classificationService.find(UUID.fromString(classificationUUID)).getTitleCache();
260 final File cacheFile = new File(new File(System.getProperty("java.io.tmpdir")), classificationUUID);
261 final String origin = request.getRequestURL().append('?').append(request.getQueryString()).toString();
262
263 Long result = null;
264 if(cacheFile.exists()){
265 result = System.currentTimeMillis() - cacheFile.lastModified();
266 }
267 //if file exists return file instantly
268 //timestamp older than one day?
269 if(clearCache == false && result != null){ //&& result < 7*(DAY_IN_MILLIS)
270 logger.info("result of calculation: " + result);
271 Map<String, File> modelMap = new HashMap<String, File>();
272 modelMap.put("file", cacheFile);
273 mv.addAllObjects(modelMap);
274 FileDownloadView fdv = new FileDownloadView("text/csv", fileName, "txt", "UTF-8");
275 mv.setView(fdv);
276 return mv;
277 }else{//trigger progress monitor and performExport()
278 String processLabel = "Exporting...";
279 final String frontbaseUrl = null;
280 ProgressMonitorUtil progressUtil = new ProgressMonitorUtil(progressMonitorController);
281 if (!progressMonitorController.isMonitorRunning(indexMonitorUuid)) {
282 indexMonitorUuid = progressUtil.registerNewMonitor();
283 Thread subThread = new Thread() {
284 @Override
285 public void run() {
286 try {
287 cacheFile.createNewFile();
288 } catch (IOException e) {
289 logger.info("Could not create file "+ e);
290 }
291 performExport(cacheFile, featureUuids, classificationUUID, areas, downloadTokenValueId, origin, response, progressMonitorController.getMonitor(indexMonitorUuid));
292 }
293 };
294 if (priority == null) {
295 priority = AbstractController.DEFAULT_BATCH_THREAD_PRIORITY;
296 }
297 subThread.setPriority(priority);
298 subThread.start();
299 }
300 mv = progressUtil.respondWithMonitorOrDownload(frontbaseUrl, origin, request, response, processLabel, indexMonitorUuid);
301 }
302 return mv;
303 }catch(Exception e){
304 //TODO: Write an specific documentation for this service endpoint
305 Resource resource = resourceLoader.getResource("classpath:eu/etaxonomy/cdm/doc/remote/apt/checklist-catalogue-exportCSV.apt");
306 return exportGetExplanation(response, request, resource);
307 }
308 }
309
310 /**
311 * This webservice endpoint returns all taxa which are congruent or included in the taxon represented by the given taxon uuid.
312 * The result also returns the path to these taxa represented by the uuids of the taxon relationships types and doubtful information.
313 * If classificationUuids is set only taxa of classifications are returned which are included in the given classifications.
314 * Also the path to these taxa may not include taxa from other classifications.
315 *
316 * @param taxonUUIDString
317 * @param classificationStringList
318 * @param includeDoubtful
319 * @param onlyCongruent
320 * @param response
321 * @param request
322 * @return
323 * @throws IOException
324 */
325
326 @RequestMapping(value = { "flockSearch" }, method = { RequestMethod.GET })
327 public ModelAndView doFlockSearchOfIncludedTaxa(
328 @RequestParam(value="taxonUUID", required=false) final String taxonUUIDString,
329 @RequestParam(value="classificationFilter", required=false) final List<String> classificationStringList,
330 @RequestParam(value="includeDoubtful", required=false) final boolean includeDoubtful,
331 @RequestParam(value="onlyCongruent", required=false) final boolean onlyCongruent,
332 HttpServletResponse response,
333 HttpServletRequest request) throws IOException {
334 try{
335 ModelAndView mv = new ModelAndView();
336 UUID taxonUuid = UUID.fromString(taxonUUIDString);
337 /**
338 * List<UUID> classificationFilter,
339 * boolean includeDoubtful,
340 * boolean onlyCongruent)
341 */
342 List<UUID> classificationFilter = null;
343 if( classificationStringList != null ){
344 classificationFilter = new ArrayList<UUID>();
345 for(String classString :classificationStringList){
346 classificationFilter.add(UUID.fromString(classString));
347 }
348 }
349 final IncludedTaxonConfiguration configuration = new IncludedTaxonConfiguration(classificationFilter, includeDoubtful, onlyCongruent);
350 IncludedTaxaDTO listIncludedTaxa = taxonService.listIncludedTaxa(taxonUuid, configuration);
351 mv.addObject(listIncludedTaxa);
352 return mv;
353 }catch(Exception e){
354 //TODO: Write an specific documentation for this service endpoint
355 Resource resource = resourceLoader.getResource("classpath:eu/etaxonomy/cdm/doc/remote/apt/checklist-catalogue-flockSearch.apt");
356 return exportGetExplanation(response, request, resource);
357 }
358 }
359
360 //=========== Helper Methods ===============//
361
362 /**
363 *
364 * This private methods finally triggers the export back in the io-package and will create a cache file
365 * in system temp directory.
366 *
367 * @param downloadTokenValueId
368 * @param response
369 * @param byteArrayOutputStream
370 * @param config
371 * @param defaultExport
372 */
373 private void performExport(File cacheFile, UuidList featureUuids,String classificationUUID, UuidList areas,
374 String downloadTokenValueId, String origin, HttpServletResponse response, IRestServiceProgressMonitor progressMonitor) {
375
376 progressMonitor.subTask("configure export");
377 CsvDemoExportConfigurator config = setTaxExportConfigurator(cacheFile, classificationUUID, featureUuids, areas, progressMonitor);
378 CdmApplicationAwareDefaultExport<?> defaultExport = (CdmApplicationAwareDefaultExport<?>) appContext.getBean("defaultExport");
379 progressMonitor.subTask("invoke export");
380 defaultExport.invoke(config); //triggers export
381 progressMonitor.subTask("wrote results to cache");
382 progressMonitor.done();
383 progressMonitor.setOrigin(origin);
384 }
385
386 /**
387 * Cofiguration method to set the configuration details for the defaultExport in the application context.
388 * @param cacheFile
389 *
390 * @param classificationUUID pass-through the selected {@link Classification classification}
391 * @param featureUuids pass-through the selected {@link Feature feature} of a {@link Taxon}, in order to fetch it.
392 * @param areas
393 * @param byteArrayOutputStream pass-through the stream to write out the data later.
394 * @param progressMonitor
395 * @return the CsvTaxExportConfiguratorRedlist config
396 */
397 private CsvDemoExportConfigurator setTaxExportConfigurator(File cacheFile, String classificationUUID, UuidList featureUuids, UuidList areas, IRestServiceProgressMonitor progressMonitor) {
398
399 @SuppressWarnings({ "unchecked", "rawtypes" })
400 Set<UUID> classificationUUIDS = new HashSet
401 (Arrays.asList(new UUID[] {UUID.fromString(classificationUUID)}));
402 if(cacheFile == null){
403 String destination = System.getProperty("java.io.tmpdir");
404 cacheFile = new File(destination);
405 }
406 List<Feature> features = new ArrayList<Feature>();
407 if(featureUuids != null){
408 for(UUID uuid : featureUuids) {
409 features.add((Feature) termService.find(uuid));
410 }
411 }
412 List<NamedArea> selectedAreas = new ArrayList<NamedArea>();
413 if(areas != null){
414 for(UUID area:areas){
415 logger.info(area);
416 selectedAreas.add((NamedArea)termService.find(area));
417 }
418 }
419
420 CsvDemoExportConfigurator config = CsvDemoExportConfigurator.NewInstance(null, cacheFile);
421 config.setDestination(cacheFile);
422 config.setProgressMonitor(progressMonitor);
423 config.setHasHeaderLines(true);
424 config.setFieldsTerminatedBy("\t");
425 config.setClassificationUuids(classificationUUIDS);
426 config.createPreSelectedExport(false, true);
427 if(features != null) {
428 config.setFeatures(features);
429 }
430 config.setNamedAreas(selectedAreas);
431 return config;
432 }
433
434 /* (non-Javadoc)
435 * @see eu.etaxonomy.cdm.remote.controller.AbstractController#setService(eu.etaxonomy.cdm.api.service.IService)
436 */
437 @Override
438 public void setService(IService service) {
439 // TODO Auto-generated method stub
440
441 }
442
443 /* (non-Javadoc)
444 * @see org.springframework.context.ResourceLoaderAware#setResourceLoader(org.springframework.core.io.ResourceLoader)
445 */
446 @Override
447 public void setResourceLoader(ResourceLoader resourceLoader) {
448 this.resourceLoader = resourceLoader;
449 }
450
451 }