Project

General

Profile

Download (17.3 KB) Statistics
| Branch: | Tag: | Revision:
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.ITermService;
44
import eu.etaxonomy.cdm.api.service.pager.impl.DefaultPagerImpl;
45
import eu.etaxonomy.cdm.common.DocUtils;
46
import eu.etaxonomy.cdm.common.monitor.IRestServiceProgressMonitor;
47
import eu.etaxonomy.cdm.io.common.CdmApplicationAwareDefaultExport;
48
import eu.etaxonomy.cdm.io.csv.redlist.demo.CsvDemoExportConfigurator;
49
import eu.etaxonomy.cdm.io.csv.redlist.demo.CsvDemoRecord;
50
import eu.etaxonomy.cdm.model.description.Feature;
51
import eu.etaxonomy.cdm.model.location.NamedArea;
52
import eu.etaxonomy.cdm.model.taxon.Classification;
53
import eu.etaxonomy.cdm.model.taxon.Taxon;
54
import eu.etaxonomy.cdm.remote.controller.AbstractController;
55
import eu.etaxonomy.cdm.remote.controller.ProgressMonitorController;
56
import eu.etaxonomy.cdm.remote.controller.util.PagerParameters;
57
import eu.etaxonomy.cdm.remote.controller.util.ProgressMonitorUtil;
58
import eu.etaxonomy.cdm.remote.editor.TermBaseListPropertyEditor;
59
import eu.etaxonomy.cdm.remote.editor.UUIDListPropertyEditor;
60
import eu.etaxonomy.cdm.remote.editor.UuidList;
61
import eu.etaxonomy.cdm.remote.view.FileDownloadView;
62
import eu.etaxonomy.cdm.remote.view.HtmlView;
63

    
64
/**
65
 * @author a.oppermann
66
 * @since 20.09.2012
67
 * <p>
68
 *  This controller enables an export of the cdm platform via a
69
 *  REST request. It is debatable if this a wanted behavior.
70
 *  For the time being it serves its purpose.
71
 */
72
@Controller
73
@RequestMapping(value = { "/checklist" })
74
public class ChecklistDemoController extends AbstractController implements ResourceLoaderAware{
75

    
76
    @Autowired
77
    private ApplicationContext appContext;
78

    
79
    @Autowired
80
    private ITermService termService;
81

    
82
    @Autowired
83
    private IClassificationService classificationService;
84

    
85
    @Autowired
86
    public ProgressMonitorController progressMonitorController;
87

    
88
    private ResourceLoader resourceLoader;
89

    
90

    
91
    /**
92
     * There should only be one processes operating on the export
93
     * therefore the according progress monitor uuid is stored in this static
94
     * field.
95
     */
96
    private static UUID indexMonitorUuid = null;
97

    
98
    private final static long DAY_IN_MILLIS = 86400000;
99

    
100

    
101

    
102
    private static final Logger logger = Logger.getLogger(ChecklistDemoController.class);
103

    
104
    /**
105
     * Helper method, which allows to convert strings directly into uuids.
106
     *
107
     * @param binder Special DataBinder for data binding from web request parameters to JavaBean objects.
108
     */
109
    @InitBinder
110
    public void initBinder(WebDataBinder binder) {
111
        binder.registerCustomEditor(UuidList.class, new UUIDListPropertyEditor());
112
        binder.registerCustomEditor(NamedArea.class, new TermBaseListPropertyEditor<>(termService));
113
        binder.registerCustomEditor(UUID.class, new UUIDEditor());
114
    }
115

    
116

    
117

    
118

    
119
    /**
120
     * Documentation webservice for this controller.
121
     *
122
     * @param response unused
123
     * @param request unused
124
     * @return
125
     * @throws IOException
126
     */
127
    @RequestMapping(value = {""}, method = { RequestMethod.GET})
128
    public ModelAndView exportGetExplanation(HttpServletResponse response,
129
            HttpServletRequest request) throws IOException{
130
        ModelAndView mv = new ModelAndView();
131
        // Read apt documentation file.
132
        Resource resource = resourceLoader.getResource("classpath:eu/etaxonomy/cdm/doc/remote/apt/checklist-catalogue-default.apt");
133
        // using input stream as this works for both files in the classes directory
134
        // as well as files inside jars
135
        InputStream aptInputStream = resource.getInputStream();
136
        // Build Html View
137
        Map<String, String> modelMap = new HashMap<>();
138
        // Convert Apt to Html
139
        modelMap.put("html", DocUtils.convertAptToHtml(aptInputStream));
140
        mv.addAllObjects(modelMap);
141

    
142
        HtmlView hv = new HtmlView();
143
        mv.setView(hv);
144
        return mv;
145
    }
146

    
147
    /**
148
     * This service endpoint is for generating the documentation site.
149
     * If any request of the other endpoint below is incomplete or false
150
     * then this method will be triggered.
151
     *
152
     * @param response
153
     * @param request
154
     * @return
155
     * @throws IOException
156
     */
157
    public ModelAndView exportGetExplanation(HttpServletResponse response,
158
            HttpServletRequest request, Resource res) throws IOException{
159
        ModelAndView mv = new ModelAndView();
160
        // Read apt documentation file.
161
        Resource resource = (res!= null) ? res : resourceLoader.getResource("classpath:eu/etaxonomy/cdm/doc/remote/apt/checklist-catalogue-default.apt");
162
        // using input stream as this works for both files in the classes directory
163
        // as well as files inside jars
164
        InputStream aptInputStream = resource.getInputStream();
165
        // Build Html View
166
        Map<String, String> modelMap = new HashMap<>();
167
        // Convert Apt to Html
168
        modelMap.put("html", DocUtils.convertAptToHtml(aptInputStream));
169
        mv.addAllObjects(modelMap);
170

    
171
        HtmlView hv = new HtmlView();
172
        mv.setView(hv);
173
        return mv;
174
    }
175

    
176
    /**
177
     *
178
     * This service endpoint generates a json and xml view of the exported list.
179
     * It takes advantage of pagination.
180
     *
181
     * @param classification uuid of the classification to export
182
     * @param pageIndex
183
     * @param pageSize
184
     * @param response
185
     * @param request
186
     * @return
187
     * @throws IOException
188
     */
189
    @RequestMapping(value = { "export" }, method = { RequestMethod.GET })
190
    public ModelAndView doGeneralExport(
191
            @RequestParam(value = "classification", required = false) String classificationUUID,
192
            @RequestParam(value = "pageIndex", required = false) Integer pageIndex,
193
            @RequestParam(value = "pageSize", required = false) Integer pageSize,
194
            HttpServletResponse response,
195
            HttpServletRequest request) throws IOException {
196

    
197
        try{
198
            if(pageSize == null) {
199
                pageSize = 20;
200
            }
201
            if(pageIndex == null) {
202
                pageIndex = 0;
203
            }
204

    
205
            PagerParameters pagerParams = new PagerParameters(pageSize, pageIndex);
206
            pagerParams.normalizeAndValidate(response);
207

    
208
            List<CsvDemoRecord> recordList = new ArrayList<>();
209

    
210
            CsvDemoExportConfigurator config = setTaxExportConfigurator(null ,classificationUUID,
211
                    null, null, null, false, false);
212
            config.setPageSize(pagerParams.getPageSize());
213
            config.setPageNumber(pagerParams.getPageIndex());
214
            config.setRecordList(recordList);
215

    
216
            @SuppressWarnings("unchecked")
217
            CdmApplicationAwareDefaultExport<CsvDemoExportConfigurator> defaultExport =
218
                    (CdmApplicationAwareDefaultExport<CsvDemoExportConfigurator>) appContext.getBean("defaultExport");
219
            defaultExport.invoke(config);
220

    
221
            DefaultPagerImpl<CsvDemoRecord> dpi = new DefaultPagerImpl<>(pagerParams.getPageIndex(), config.getTaxonNodeListSize(), pagerParams.getPageSize(), recordList);
222
            ModelAndView mv = new ModelAndView();
223
//            mv.addObject(recordList);f
224
            mv.addObject(dpi);
225
            return mv;
226
        }catch(Exception e){
227
            Resource resource = resourceLoader.getResource("classpath:eu/etaxonomy/cdm/doc/remote/apt/checklist-catalogue-export.apt");
228
            return exportGetExplanation(response, request, resource);
229
        }
230

    
231
    }
232

    
233

    
234
    /**
235
     *
236
     * This Service endpoint will offer a csv file. It caches the csv-file in the system temp directory
237
     * and will only generate a new one after 24 hours. Or if explicitly triggerd by noCache parameter.
238
     *
239
     * @param featureUuids List of uuids to download/select {@link Feature feature}features
240
     * @param clearCache will trigger export and avoids cached file
241
     * @param classificationUUID Selected {@link Classification classification} to iterate the {@link Taxon}
242
     * @param response HttpServletResponse which returns the ByteArrayOutputStream
243
     * @throws Exception
244
     */
245
    @RequestMapping(value = { "exportCSV" }, method = { RequestMethod.GET })
246
    public synchronized ModelAndView doExportRedlist(
247
            @RequestParam(value = "features", required = false) final UuidList featureUuids,
248
            @RequestParam(value = "clearCache", required = false) final boolean clearCache,
249
            @RequestParam(value = "demoExport", required = false) final boolean demoExport,
250
            @RequestParam(value = "conceptExport", required = false) final boolean conceptExport,
251
            @RequestParam(value = "classification", required = false) final String classificationUUID,
252
            @RequestParam(value = "area", required = false) final UuidList areas,
253
            @RequestParam(value = "downloadTokenValueId", required = false) final String downloadTokenValueId,
254
            @RequestParam(value = "priority", required = false) Integer priority,
255
            final HttpServletResponse response,
256
            final HttpServletRequest request) throws Exception {
257
        /**
258
         * ========================================
259
         * progress monitor & new thread for export
260
         * ========================================
261
         */
262
        try{
263
            ModelAndView mv = new ModelAndView();
264
            String fileName = classificationService.find(UUID.fromString(classificationUUID)).getTitleCache();
265
            final File cacheFile = new File(new File(System.getProperty("java.io.tmpdir")), classificationUUID);
266
            final String origin = request.getRequestURL().append('?').append(request.getQueryString()).toString();
267

    
268
            Long result = null;
269
            if(cacheFile.exists()){
270
                result = System.currentTimeMillis() - cacheFile.lastModified();
271
            }
272
            //if file exists return file instantly
273
            //timestamp older than one day?
274
            if(clearCache == false && result != null){ //&& result < 7*(DAY_IN_MILLIS)
275
                logger.info("result of calculation: " + result);
276
                Map<String, File> modelMap = new HashMap<String, File>();
277
                modelMap.put("file", cacheFile);
278
                mv.addAllObjects(modelMap);
279
                FileDownloadView fdv = new FileDownloadView("text/csv", fileName, "txt", "UTF-8");
280
                mv.setView(fdv);
281
                return mv;
282
            }else{//trigger progress monitor and performExport()
283
                String processLabel = "Exporting...";
284
                final String frontbaseUrl = null;
285
                ProgressMonitorUtil progressUtil = new ProgressMonitorUtil(progressMonitorController);
286
                if (!progressMonitorController.isMonitorRunning(indexMonitorUuid)) {
287
                    indexMonitorUuid = progressUtil.registerNewMonitor();
288
                    Thread subThread = new Thread() {
289
                        @Override
290
                        public void run() {
291
                            try {
292
                                cacheFile.createNewFile();
293
                            } catch (IOException e) {
294
                                logger.info("Could not create file "+ e);
295
                            }
296
                            performExport(cacheFile, featureUuids, classificationUUID, areas, downloadTokenValueId, demoExport, conceptExport, origin, response, progressMonitorController.getMonitor(indexMonitorUuid));
297
                        }
298
                    };
299
                    if (priority == null) {
300
                        priority = AbstractController.DEFAULT_BATCH_THREAD_PRIORITY;
301
                    }
302
                    subThread.setPriority(priority);
303
                    subThread.start();
304
                }
305
                mv = progressUtil.respondWithMonitorOrDownload(frontbaseUrl, origin, processLabel, indexMonitorUuid, false, request, response);
306
            }
307
            return mv;
308
        }catch(Exception e){
309
            //TODO: Write an specific documentation for this service endpoint
310
           Resource resource = resourceLoader.getResource("classpath:eu/etaxonomy/cdm/doc/remote/apt/checklist-catalogue-exportCSV.apt");
311
           return exportGetExplanation(response, request, resource);
312
        }
313
    }
314

    
315

    
316
    //=========== Helper Methods ===============//
317

    
318
    /**
319
     *
320
     * This private methods finally triggers the export back in the io-package and will create a cache file
321
     * in system temp directory.
322
     *
323
     * @param downloadTokenValueId
324
     * @param conceptExport
325
     * @param demoExport
326
     * @param response
327
     * @param byteArrayOutputStream
328
     * @param config
329
     * @param defaultExport
330
     */
331
    private void performExport(File cacheFile, UuidList featureUuids,String classificationUUID, UuidList areas,
332
            String downloadTokenValueId, boolean demoExport, boolean conceptExport, String origin, HttpServletResponse response, IRestServiceProgressMonitor progressMonitor) {
333

    
334
        progressMonitor.subTask("configure export");
335
        CsvDemoExportConfigurator config = setTaxExportConfigurator(cacheFile, classificationUUID, featureUuids, areas, progressMonitor, demoExport, conceptExport);
336
        CdmApplicationAwareDefaultExport<CsvDemoExportConfigurator> defaultExport =
337
                (CdmApplicationAwareDefaultExport<CsvDemoExportConfigurator>) appContext.getBean("defaultExport");
338
        progressMonitor.subTask("invoke export");
339
        defaultExport.invoke(config);  //triggers export
340
        progressMonitor.subTask("wrote results to cache");
341
        progressMonitor.done();
342
        progressMonitor.setOrigin(origin);
343
    }
344

    
345
    /**
346
     * Cofiguration method to set the configuration details for the defaultExport in the application context.
347
     * @param cacheFile
348
     *
349
     * @param classificationUUID pass-through the selected {@link Classification classification}
350
     * @param featureUuids pass-through the selected {@link Feature feature} of a {@link Taxon}, in order to fetch it.
351
     * @param areas
352
     * @param byteArrayOutputStream pass-through the stream to write out the data later.
353
     * @param progressMonitor
354
     * @param conceptExport
355
     * @param demoExport
356
     * @return the CsvTaxExportConfiguratorRedlist config
357
     */
358
    private CsvDemoExportConfigurator setTaxExportConfigurator(File cacheFile, String classificationUUID, UuidList featureUuids, UuidList areas, IRestServiceProgressMonitor progressMonitor, boolean demoExport, boolean conceptExport) {
359

    
360
        @SuppressWarnings({ "unchecked", "rawtypes" })
361
        Set<UUID> classificationUUIDS = new HashSet
362
        (Arrays.asList(new UUID[] {UUID.fromString(classificationUUID)}));
363
        if(cacheFile == null){
364
            String destination = System.getProperty("java.io.tmpdir");
365
            cacheFile = new File(destination);
366
        }
367
        List<Feature> features = new ArrayList<>();
368
        if(featureUuids != null){
369
            for(UUID uuid : featureUuids) {
370
                features.add((Feature) termService.find(uuid));
371
            }
372
        }
373
        List<NamedArea> selectedAreas = new ArrayList<>();
374
        if(areas != null){
375
            for(UUID area:areas){
376
                logger.info(area);
377
                selectedAreas.add((NamedArea)termService.find(area));
378
            }
379
        }
380

    
381
        CsvDemoExportConfigurator config = CsvDemoExportConfigurator.NewInstance(null, cacheFile);
382
        config.setDestination(cacheFile);
383
        config.setProgressMonitor(progressMonitor);
384
        config.setHasHeaderLines(true);
385
        config.setFieldsTerminatedBy("\t");
386
        config.setClassificationUuids(classificationUUIDS);
387
        if(demoExport == false && conceptExport == false){
388
        	config.createPreSelectedExport(false, true);
389
        }else{
390
        	config.createPreSelectedExport(demoExport, conceptExport);
391
        }
392
        config.setFeatures(features);
393
        config.setNamedAreas(selectedAreas);
394
        return config;
395
    }
396

    
397
    @Override
398
    public void setService(IService service) {
399
        // TODO Auto-generated method stub
400
    }
401

    
402
    @Override
403
    public void setResourceLoader(ResourceLoader resourceLoader) {
404
        this.resourceLoader = resourceLoader;
405
    }
406

    
407
}
(1-1/3)