refactoring taxon controllers, reducing code duplication
[cdmlib.git] / cdmlib-remote / src / main / java / eu / etaxonomy / cdm / remote / controller / DescriptionListController.java
index 1cbe0473daa5020d1228b911b3874d923cf36d32..2e99d4785d0f2056f529aaf65ec3b8f85544a27e 100644 (file)
@@ -2,7 +2,7 @@
 /**\r
  * Copyright (C) 2009 EDIT European Distributed Institute of Taxonomy\r
  * http://www.e-taxonomy.eu\r
- * \r
+ *\r
  * The contents of this file are subject to the Mozilla Public License Version\r
  * 1.1 See LICENSE.TXT at the top of this package for the full license terms.\r
  */\r
@@ -12,47 +12,282 @@ package eu.etaxonomy.cdm.remote.controller;
 import java.io.IOException;\r
 import java.util.Arrays;\r
 import java.util.List;\r
+import java.util.UUID;\r
 \r
 import javax.servlet.http.HttpServletRequest;\r
 import javax.servlet.http.HttpServletResponse;\r
 \r
 import org.springframework.beans.factory.annotation.Autowired;\r
 import org.springframework.stereotype.Controller;\r
+import org.springframework.web.bind.WebDataBinder;\r
+import org.springframework.web.bind.annotation.InitBinder;\r
 import org.springframework.web.bind.annotation.RequestMapping;\r
 import org.springframework.web.bind.annotation.RequestMethod;\r
+import org.springframework.web.bind.annotation.RequestParam;\r
+import org.springframework.web.servlet.ModelAndView;\r
 \r
 import eu.etaxonomy.cdm.api.service.IDescriptionService;\r
+import eu.etaxonomy.cdm.api.service.ITaxonService;\r
+import eu.etaxonomy.cdm.api.service.ITermService;\r
+import eu.etaxonomy.cdm.api.service.description.TransmissionEngineDistribution;\r
+import eu.etaxonomy.cdm.api.service.description.TransmissionEngineDistribution.AggregationMode;\r
+import eu.etaxonomy.cdm.api.service.pager.Pager;\r
 import eu.etaxonomy.cdm.model.description.DescriptionBase;\r
-import eu.etaxonomy.cdm.model.description.FeatureTree;\r
+import eu.etaxonomy.cdm.model.description.DescriptionElementBase;\r
+import eu.etaxonomy.cdm.model.description.Feature;\r
+import eu.etaxonomy.cdm.model.location.NamedArea;\r
+import eu.etaxonomy.cdm.model.location.NamedAreaLevel;\r
+import eu.etaxonomy.cdm.model.location.NamedAreaType;\r
+import eu.etaxonomy.cdm.model.name.Rank;\r
+import eu.etaxonomy.cdm.model.taxon.Taxon;\r
+import eu.etaxonomy.cdm.persistence.query.MatchMode;\r
+import eu.etaxonomy.cdm.persistence.query.OrderHint;\r
+import eu.etaxonomy.cdm.remote.controller.util.PagerParameters;\r
+import eu.etaxonomy.cdm.remote.controller.util.ProgressMonitorUtil;\r
+import eu.etaxonomy.cdm.remote.editor.DefinedTermBaseList;\r
+import eu.etaxonomy.cdm.remote.editor.TermBaseListPropertyEditor;\r
 \r
 /**\r
+ * TODO write controller documentation\r
+ *\r
  * @author a.kohlbecker\r
  * @date 24.03.2009\r
  */\r
 @Controller\r
-@RequestMapping(value = {"/*/description", "/*/featuretree"})\r
-public class DescriptionListController extends BaseListController<DescriptionBase, IDescriptionService> {\r
-       \r
-       private static final List<String> FEATURETREE_INIT_STRATEGY = Arrays.asList(\r
-                       new String[]{\r
-                               "representations",\r
-                               "root.feature.representations",\r
-                               "root.children.feature.representations",\r
-                       });\r
-\r
-       /* (non-Javadoc)\r
-        * @see eu.etaxonomy.cdm.remote.controller.BaseListController#setService(eu.etaxonomy.cdm.api.service.IService)\r
-        */\r
-       @Override\r
-       @Autowired\r
-       public void setService(IDescriptionService service) {\r
-               this.service = service;\r
-       }\r
-       \r
-       @RequestMapping(method = RequestMethod.GET, value="/*/featuretree")\r
-       public List<FeatureTree> doGetFeatureTrees(HttpServletRequest request, HttpServletResponse response) throws IOException {\r
-               \r
-               List<FeatureTree> obj = service.getFeatureTreesAll(FEATURETREE_INIT_STRATEGY);\r
-               return obj;\r
-       }\r
+@RequestMapping(value = {"/description"})\r
+public class DescriptionListController extends IdentifiableListController<DescriptionBase, IDescriptionService> {\r
+\r
+\r
+    @Autowired\r
+    private ITermService termService;\r
+\r
+    @Autowired\r
+    private ITaxonService taxonService;\r
+\r
+\r
+    @Autowired\r
+    public TransmissionEngineDistribution transmissionEngineDistribution;\r
+\r
+    @Autowired\r
+    public ProgressMonitorController progressMonitorController;\r
+\r
+    /**\r
+     * There should only be one longtime processes\r
+     * therefore the according progress monitor uuid is stored in\r
+     * this static field.\r
+     */\r
+    private static UUID transmissionEngineMonitorUuid = null;\r
+\r
+\r
+\r
+    /* (non-Javadoc)\r
+     * @see eu.etaxonomy.cdm.remote.controller.BaseListController#setService(eu.etaxonomy.cdm.api.service.IService)\r
+     */\r
+    @Override\r
+    @Autowired\r
+    public void setService(IDescriptionService service) {\r
+        this.service = service;\r
+    }\r
+\r
+    @InitBinder\r
+    @Override\r
+    public void initBinder(WebDataBinder binder) {\r
+        super.initBinder(binder);\r
+        binder.registerCustomEditor(DefinedTermBaseList.class, new TermBaseListPropertyEditor<Feature>(termService));\r
+    }\r
+\r
+\r
+    /**\r
+     * Runs the {@link TransmissionEngineDistribution} in a separate Thread and\r
+     * responds with a redirect to a progress monitor REST service end point.\r
+     * <p>\r
+     * <b>NOTE</b> this is still a special implementation for the Euro+Med project.\r
+     * The parameters for the <i>superAreas</i>, the areas to which the subordinate areas should be projected,\r
+     * <i>lowerRank</i>, <i>upperRank</i> are hardcoded to: <code>TDWG_LEVEL3 areas, SUBSPECIES, GENUS</code>\r
+     *\r
+     * @param mode\r
+     *            one of <code>byAreas</code>, <code>byRanks</code>,\r
+     *            <code>byAreasAndRanks</code>\r
+     * @param frontendBaseUrl\r
+     *            the cdm server instance base URL, this is needed for the a\r
+     *            proper redirect URL when the service is running behind a\r
+     *            reverse HTTP proxy\r
+     * @param priority\r
+     *            the priority for the Thread to spawn, see\r
+     *            {@link Thread#setPriority(int)}, defaults to 3\r
+     * @param request\r
+     * @param response\r
+     * @return\r
+     * @throws IOException\r
+     */\r
+    @RequestMapping(value = { "accumulateDistributions" }, method = RequestMethod.GET)\r
+    public ModelAndView doAccumulateDistributions(\r
+            @RequestParam(value= "mode", required = true) final AggregationMode mode,\r
+            @RequestParam(value = "frontendBaseUrl", required = false) String frontendBaseUrl,\r
+            @RequestParam(value = "priority", required = false) Integer priority,\r
+            HttpServletRequest request,\r
+            HttpServletResponse response) throws IOException {\r
+\r
+        logger.info("doAccumulateDistributions()" + request.getRequestURI());\r
+\r
+//        transmissionEngineDistribution.updatePriorities();\r
+\r
+        String processLabel = "accumulating distributions";\r
+\r
+        ProgressMonitorUtil progressUtil = new ProgressMonitorUtil(progressMonitorController);\r
+\r
+        final List<String> term_init_strategy = Arrays.asList(new String []{\r
+                "representations"\r
+        });\r
+\r
+        if (!progressMonitorController.isMonitorRunning(transmissionEngineMonitorUuid)) {\r
+            transmissionEngineMonitorUuid = progressUtil.registerNewMonitor();\r
+            Thread subThread = new Thread() {\r
+                @Override\r
+                public void run() {\r
+                    Pager<NamedArea> areaPager = termService.list(NamedAreaLevel.TDWG_LEVEL3(), (NamedAreaType) null,\r
+                            null, null, (List<OrderHint>) null, term_init_strategy);\r
+                    transmissionEngineDistribution.accumulate(mode, areaPager.getRecords(), Rank.SUBSPECIES(), Rank.GENUS(),\r
+                            null, progressMonitorController.getMonitor(transmissionEngineMonitorUuid));\r
+                }\r
+            };\r
+            if(priority == null) {\r
+                priority = AbstractController.DEFAULT_BATCH_THREAD_PRIORITY;\r
+            }\r
+            subThread.setPriority(priority);\r
+            subThread.start();\r
+        }\r
+\r
+        // send redirect "see other"\r
+        return progressUtil.respondWithMonitor(frontendBaseUrl, request, response, processLabel, transmissionEngineMonitorUuid);\r
+    }\r
+\r
+    /**\r
+    *\r
+    * @param queryString\r
+    * @param type\r
+    * @param pageSize\r
+    * @param pageNumber\r
+    * @param matchMode\r
+    * @param request\r
+    * @param response\r
+    * @return\r
+    * @throws IOException\r
+    */\r
+   @RequestMapping(value = "//descriptionElement/find", method = RequestMethod.GET) // mapped as absolute path, see CdmAntPathMatcher\r
+   public Pager<DescriptionElementBase> doFindDescriptionElements(\r
+           @RequestParam(value = "query", required = true) String queryString,\r
+           @RequestParam(value = "type", required = false) Class<? extends DescriptionElementBase> type,\r
+           @RequestParam(value = "pageSize", required = false) Integer pageSize,\r
+           @RequestParam(value = "pageNumber", required = false) Integer pageNumber,\r
+           @RequestParam(value = "matchMode", required = false) MatchMode matchMode,\r
+           HttpServletRequest request,\r
+           HttpServletResponse response\r
+           )\r
+            throws IOException {\r
+\r
+       logger.info("doFindDescriptionElements : "  + requestPathAndQuery(request) );\r
+\r
+       PagerParameters pagerParams = new PagerParameters(pageSize, pageNumber);\r
+       pagerParams.normalizeAndValidate(response);\r
+\r
+       Pager<DescriptionElementBase> pager = service.searchElements(type, queryString, pageSize, pageNumber, null, getInitializationStrategy());\r
+\r
+       return pager;\r
+   }\r
+\r
+    /**\r
+     * Requires the query parameter "descriptionType" to be present\r
+     *\r
+     * @param features\r
+     * @param descriptionType\r
+     * @param type\r
+     * @param pageSize\r
+     * @param pageNumber\r
+     * @param request\r
+     * @param response\r
+     * @return\r
+     * @throws IOException\r
+     */\r
+    @RequestMapping(value = "//descriptionElement/byFeature", method = RequestMethod.GET) // mapped as absolute path, see CdmAntPathMatcher\r
+    public Pager<DescriptionElementBase> doPageDescriptionElementsByFeature(\r
+            @RequestParam(value = "features", required = false) DefinedTermBaseList<Feature> features,\r
+            @RequestParam(value = "descriptionType", required = true) Class<? extends DescriptionBase> descriptionType,\r
+            @RequestParam(value = "type", required = false) Class<? extends DescriptionElementBase> type,\r
+            @RequestParam(value = "pageSize", required = false) Integer pageSize,\r
+            @RequestParam(value = "pageNumber", required = false) Integer pageNumber, HttpServletRequest request,\r
+            HttpServletResponse response) throws IOException {\r
+\r
+        logger.info("doPageDescriptionElementsByFeature : " + requestPathAndQuery(request));\r
+\r
+        PagerParameters pagerParams = new PagerParameters(pageSize, pageNumber);\r
+        pagerParams.normalizeAndValidate(response);\r
+\r
+        if(features == null){\r
+            features = new DefinedTermBaseList<Feature>();\r
+        }\r
+\r
+        Pager<DescriptionElementBase> pager = service.pageDescriptionElements(null, descriptionType, features.asSet(),\r
+                type, pagerParams.getPageSize(), pagerParams.getPageIndex(), getInitializationStrategy());\r
+\r
+        return pager;\r
+    }\r
+\r
+    /**\r
+     * Requires the query parameter "taxon"  to be present\r
+     *\r
+     * @param taxon_uuid\r
+     * @param features\r
+     * @param type\r
+     * @param pageSize\r
+     * @param pageNumber\r
+     * @param request\r
+     * @param response\r
+     * @return\r
+     * @throws IOException\r
+     */\r
+    @RequestMapping(value = "//descriptionElement/byTaxon", method = {RequestMethod.GET, RequestMethod.POST}) // mapped as absolute path, see CdmAntPathMatcher\r
+    public <T extends DescriptionElementBase> Pager<T> getDescriptionElementsForTaxon(\r
+            @RequestParam(value = "taxon", required = true) UUID taxon_uuid,\r
+            @RequestParam(value = "features", required = false) DefinedTermBaseList<Feature> features,\r
+            @RequestParam(value = "type", required = false) Class<T> type,\r
+            @RequestParam(value = "pageSize", required = false) Integer pageSize,\r
+            @RequestParam(value = "pageNumber", required = false) Integer pageNumber, HttpServletRequest request,\r
+            HttpServletResponse response) throws IOException {\r
+\r
+        logger.info("getDescriptionElementsForTaxon : " + requestPathAndQuery(request));\r
+\r
+        PagerParameters pagerParams = new PagerParameters(pageSize, pageNumber);\r
+        pagerParams.normalizeAndValidate(response);\r
+\r
+        Taxon taxon = null;\r
+        if( taxon_uuid!= null){\r
+            try {\r
+                taxon = (Taxon) taxonService.load(taxon_uuid);\r
+            } catch (Exception e) {\r
+                HttpStatusMessage.UUID_NOT_FOUND.send(response);\r
+            }\r
+        }\r
+\r
+        Pager<T> pager = service.pageDescriptionElementsForTaxon(taxon, features.asSet(), type, pageSize,\r
+                pageNumber, getInitializationStrategy());\r
+\r
+        return pager;\r
+    }\r
+\r
+    @RequestMapping(value = "namedAreasInUse", method = RequestMethod.GET)\r
+    public Pager<NamedArea> doPageNamedAreasInUse(\r
+            @RequestParam(value = "pageSize", required = false) Integer pageSize,\r
+            @RequestParam(value = "pageNumber", required = false) Integer pageNumber, HttpServletRequest request,\r
+            HttpServletResponse response) throws IOException {\r
+\r
+        logger.info("doPageNamedAreasInUse : " + requestPathAndQuery(request));\r
+\r
+        PagerParameters pagerParams = new PagerParameters(pageSize, pageNumber);\r
+        pagerParams.normalizeAndValidate(response);\r
+\r
+        Pager<NamedArea> pager = service.pageNamedAreasInUse(pageSize, pageNumber, getInitializationStrategy());\r
+\r
+        return pager;\r
+    }\r
 }
\ No newline at end of file