3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
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.
9 package eu
.etaxonomy
.cdm
.remote
.controller
.checklist
;
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
;
21 import java
.util
.UUID
;
23 import javax
.servlet
.http
.HttpServletRequest
;
24 import javax
.servlet
.http
.HttpServletResponse
;
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
;
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
;
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.
76 @RequestMapping(value
= { "/checklist" })
77 public class ChecklistDemoController
extends AbstractController
implements ResourceLoaderAware
{
80 private ApplicationContext appContext
;
83 private ITermService termService
;
86 private ITaxonService taxonService
;
89 private IClassificationService classificationService
;
92 public ProgressMonitorController progressMonitorController
;
94 private ResourceLoader resourceLoader
;
98 * There should only be one processes operating on the export
99 * therefore the according progress monitor uuid is stored in this static
102 private static UUID indexMonitorUuid
= null;
104 private final static long DAY_IN_MILLIS
= 86400000;
108 private static final Logger logger
= Logger
.getLogger(ChecklistDemoController
.class);
111 * Helper method, which allows to convert strings directly into uuids.
113 * @param binder Special DataBinder for data binding from web request parameters to JavaBean objects.
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());
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();
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
);
140 HtmlView hv
= new HtmlView();
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.
153 * @throws IOException
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();
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
);
169 HtmlView hv
= new HtmlView();
176 * This service endpoint generates a json and xml view of the exported list.
177 * It takes advantage of pagination.
179 * @param classificationUUID
185 * @throws IOException
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
{
196 if(pageSize
== null) {
199 if(pageNumber
== null) {
203 PagerParameters pagerParams
= new PagerParameters(pageSize
, pageNumber
);
204 pagerParams
.normalizeAndValidate(response
);
206 List
<CsvDemoRecord
> recordList
= new ArrayList
<CsvDemoRecord
>();
208 CsvDemoExportConfigurator config
= setTaxExportConfigurator(null ,classificationUUID
, null, null, null);
209 config
.setPageSize(pagerParams
.getPageSize());
210 config
.setPageNumber(pagerParams
.getPageIndex());
211 config
.setRecordList(recordList
);
213 CdmApplicationAwareDefaultExport
<?
> defaultExport
= (CdmApplicationAwareDefaultExport
<?
>) appContext
.getBean("defaultExport");
214 defaultExport
.invoke(config
);
216 DefaultPagerImpl
<CsvDemoRecord
> dpi
= new DefaultPagerImpl
<CsvDemoRecord
>(pagerParams
.getPageIndex(), config
.getTaxonNodeListSize(), pagerParams
.getPageSize(), recordList
);
217 ModelAndView mv
= new ModelAndView();
218 // mv.addObject(recordList);f
222 Resource resource
= resourceLoader
.getResource("classpath:eu/etaxonomy/cdm/doc/remote/apt/checklist-catalogue-export.apt");
223 return exportGetExplanation(response
, request
, resource
);
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.
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
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
{
253 * ========================================
254 * progress monitor & new thread for export
255 * ========================================
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();
264 if(cacheFile
.exists()){
265 result
= System
.currentTimeMillis() - cacheFile
.lastModified();
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");
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() {
287 cacheFile
.createNewFile();
288 } catch (IOException e
) {
289 logger
.info("Could not create file "+ e
);
291 performExport(cacheFile
, featureUuids
, classificationUUID
, areas
, downloadTokenValueId
, origin
, response
, progressMonitorController
.getMonitor(indexMonitorUuid
));
294 if (priority
== null) {
295 priority
= AbstractController
.DEFAULT_BATCH_THREAD_PRIORITY
;
297 subThread
.setPriority(priority
);
300 mv
= progressUtil
.respondWithMonitorOrDownload(frontbaseUrl
, origin
, request
, response
, processLabel
, indexMonitorUuid
);
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
);
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.
316 * @param taxonUUIDString
317 * @param classificationStringList
318 * @param includeDoubtful
319 * @param onlyCongruent
323 * @throws IOException
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
{
335 ModelAndView mv
= new ModelAndView();
336 UUID taxonUuid
= UUID
.fromString(taxonUUIDString
);
338 * List<UUID> classificationFilter,
339 * boolean includeDoubtful,
340 * boolean onlyCongruent)
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
));
349 final IncludedTaxonConfiguration configuration
= new IncludedTaxonConfiguration(classificationFilter
, includeDoubtful
, onlyCongruent
);
350 IncludedTaxaDTO listIncludedTaxa
= taxonService
.listIncludedTaxa(taxonUuid
, configuration
);
351 mv
.addObject(listIncludedTaxa
);
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
);
360 //=========== Helper Methods ===============//
364 * This private methods finally triggers the export back in the io-package and will create a cache file
365 * in system temp directory.
367 * @param downloadTokenValueId
369 * @param byteArrayOutputStream
371 * @param defaultExport
373 private void performExport(File cacheFile
, UuidList featureUuids
,String classificationUUID
, UuidList areas
,
374 String downloadTokenValueId
, String origin
, HttpServletResponse response
, IRestServiceProgressMonitor progressMonitor
) {
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
);
387 * Cofiguration method to set the configuration details for the defaultExport in the application context.
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.
393 * @param byteArrayOutputStream pass-through the stream to write out the data later.
394 * @param progressMonitor
395 * @return the CsvTaxExportConfiguratorRedlist config
397 private CsvDemoExportConfigurator
setTaxExportConfigurator(File cacheFile
, String classificationUUID
, UuidList featureUuids
, UuidList areas
, IRestServiceProgressMonitor progressMonitor
) {
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
);
406 List
<Feature
> features
= new ArrayList
<Feature
>();
407 if(featureUuids
!= null){
408 for(UUID uuid
: featureUuids
) {
409 features
.add((Feature
) termService
.find(uuid
));
412 List
<NamedArea
> selectedAreas
= new ArrayList
<NamedArea
>();
414 for(UUID area
:areas
){
416 selectedAreas
.add((NamedArea
)termService
.find(area
));
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
);
430 config
.setNamedAreas(selectedAreas
);
435 * @see eu.etaxonomy.cdm.remote.controller.AbstractController#setService(eu.etaxonomy.cdm.api.service.IService)
438 public void setService(IService service
) {
439 // TODO Auto-generated method stub
444 * @see org.springframework.context.ResourceLoaderAware#setResourceLoader(org.springframework.core.io.ResourceLoader)
447 public void setResourceLoader(ResourceLoader resourceLoader
) {
448 this.resourceLoader
= resourceLoader
;