#5297 Refactor ProgressMonitorController, Add Remoting Progress monitor
authorCherian Mathew <c.mathew@bgbm.org>
Wed, 14 Oct 2015 16:11:36 +0000 (18:11 +0200)
committerCherian Mathew <c.mathew@bgbm.org>
Tue, 27 Oct 2015 15:24:10 +0000 (16:24 +0100)
#5297 Add progress monitor service, Add test services

#5297 Add monit import method

#5297 Update no. of work units

#5297 Add new thread class for remoting monitors

#5297 Add owner field to monitor thread and user checks in service

#5297 Add javadoc

19 files changed:
cdmlib-commons/src/main/java/eu/etaxonomy/cdm/common/monitor/IProgressMonitor.java
cdmlib-commons/src/main/java/eu/etaxonomy/cdm/common/monitor/IRemotingProgressMonitor.java [new file with mode: 0644]
cdmlib-commons/src/main/java/eu/etaxonomy/cdm/common/monitor/RemotingProgressMonitor.java [new file with mode: 0644]
cdmlib-io/src/main/java/eu/etaxonomy/cdm/io/service/IIOService.java
cdmlib-io/src/main/java/eu/etaxonomy/cdm/io/service/IOServiceImpl.java
cdmlib-io/src/main/java/eu/etaxonomy/cdm/io/specimen/abcd206/in/Abcd206Import.java
cdmlib-model/src/main/java/eu/etaxonomy/cdm/model/common/User.java
cdmlib-remote/src/main/java/eu/etaxonomy/cdm/remote/controller/ProgressMonitorController.java
cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/application/CdmApplicationController.java
cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/application/CdmApplicationDefaultConfiguration.java
cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/application/ICdmApplicationConfiguration.java
cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/IProgressMonitorService.java [new file with mode: 0644]
cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/ITestService.java
cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/ProgressMonitorManager.java [new file with mode: 0644]
cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/ProgressMonitorServiceImpl.java [new file with mode: 0644]
cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/TestServiceImpl.java
cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/util/RemotingProgressMonitorThread.java [new file with mode: 0644]
cdmlib-services/src/main/resources/eu/etaxonomy/cdm/httpInvokerServices.xml
cdmlib-services/src/main/resources/eu/etaxonomy/cdm/remoting-services.xml

index ba3298b12ff66d94c89f14208b09806e7cda2dd9..01db757b4ebcb63575ebcc1dd2ad44300f067f0a 100644 (file)
@@ -1,12 +1,14 @@
 \r
 package eu.etaxonomy.cdm.common.monitor;\r
 \r
+import java.io.Serializable;\r
+\r
 \r
 \r
 /**\r
- * This progress monitor interface is ad adaptation of the eclipse \r
+ * This progress monitor interface is ad adaptation of the eclipse\r
  * org.eclipse.core.runtime.IProgressMonitor ;\r
- * \r
+ *\r
  * The <code>IProgressMonitor</code> interface is implemented\r
  * by objects that monitor the progress of an activity; the methods\r
  * in this interface are invoked by code that performs the activity.\r
@@ -40,7 +42,7 @@ package eu.etaxonomy.cdm.common.monitor;
  * Clients may implement this interface.\r
  * </p>\r
  */\r
-public interface IProgressMonitor {\r
+public interface IProgressMonitor extends Serializable {\r
 \r
        /** Constant indicating an unknown amount of work.\r
         */\r
@@ -49,18 +51,18 @@ public interface IProgressMonitor {
        /**\r
         * Notifies that the main task is beginning.  This must only be called once\r
         * on a given progress monitor instance.\r
-        * \r
+        *\r
         * @param name the name (or description) of the main task\r
         * @param totalWork the total number of work units into which\r
-        *  the main task is been subdivided. If the value is <code>UNKNOWN</code> \r
-        *  the implementation is free to indicate progress in a way which \r
+        *  the main task is been subdivided. If the value is <code>UNKNOWN</code>\r
+        *  the implementation is free to indicate progress in a way which\r
         *  doesn't require the total number of work units in advance.\r
         */\r
        public void beginTask(String name, int totalWork);\r
 \r
        /**\r
-        * Notifies that the work is done; that is, either the main task is completed \r
-        * or the user canceled it. This method may be called more than once \r
+        * Notifies that the work is done; that is, either the main task is completed\r
+        * or the user canceled it. This method may be called more than once\r
         * (implementations should be prepared to handle this case).\r
         */\r
        public void done();\r
@@ -79,7 +81,7 @@ public interface IProgressMonitor {
 \r
        /**\r
         * Sets the cancel state to the given value.\r
-        * \r
+        *\r
         * @param value <code>true</code> indicates that cancelation has\r
         *     been requested (but not necessarily acknowledged);\r
         *     <code>false</code> clears this flag\r
@@ -88,8 +90,8 @@ public interface IProgressMonitor {
        public void setCanceled(boolean value);\r
 \r
        /**\r
-        * Sets the task name to the given value. This method is used to \r
-        * restore the task label after a nested operation was executed. \r
+        * Sets the task name to the given value. This method is used to\r
+        * restore the task label after a nested operation was executed.\r
         * Normally there is no need for clients to call this method.\r
         *\r
         * @param name the name (or description) of the main task\r
@@ -114,30 +116,30 @@ public interface IProgressMonitor {
         * @param work a non-negative number of work units just completed\r
         */\r
        public void worked(int work);\r
-       \r
+\r
     /**\r
      * Internal method to handle scaling correctly. This method\r
-     * must not be called by a client. Clients should \r
+     * must not be called by a client. Clients should\r
      * always use the method </code>worked(int)</code>.\r
-     * \r
+     *\r
      * @param work the amount of work done\r
      */\r
     public void internalWorked(double work);\r
-       \r
-       \r
+\r
+\r
        /**\r
         * Notifies about a warning\r
         * @param message\r
         */\r
        public void warning(String message);\r
-       \r
+\r
        /**\r
         * Notifies about a warning that was caused by an exception.\r
         * @param message\r
         * @param throwable\r
         */\r
        public void warning(String message, Throwable throwable);\r
-       \r
+\r
 }\r
 \r
 \r
diff --git a/cdmlib-commons/src/main/java/eu/etaxonomy/cdm/common/monitor/IRemotingProgressMonitor.java b/cdmlib-commons/src/main/java/eu/etaxonomy/cdm/common/monitor/IRemotingProgressMonitor.java
new file mode 100644 (file)
index 0000000..a7df8dc
--- /dev/null
@@ -0,0 +1,60 @@
+// $Id$
+/**
+* Copyright (C) 2015 EDIT
+* European Distributed Institute of Taxonomy
+* http://www.e-taxonomy.eu
+*
+* The contents of this file are subject to the Mozilla Public License Version 1.1
+* See LICENSE.TXT at the top of this package for the full license terms.
+*/
+package eu.etaxonomy.cdm.common.monitor;
+
+import java.util.List;
+
+/**
+ * Interface for progress monitor to be used in the context of
+ * remoting (spring httpinvoker)
+ *
+ * @author cmathew
+ * @date 14 Oct 2015
+ *
+ */
+public interface IRemotingProgressMonitor extends IRestServiceProgressMonitor {
+
+    /**
+     * Returns the result of the monitored job
+     * @return result of the monitored job
+     */
+    public Object getResult();
+
+    /**
+     * Sets the result of the monitored job
+     * @param result of the monitored job
+     */
+    public void setResult(Object result);
+
+    /**
+     * Returns the reports generated by the monitored job
+     * @return the reports generated by the monitored job
+     */
+    public List<String> getReports();
+
+    /**
+     * Adds a report generated by the monitored job
+     * @param report generated by the monitored job
+     */
+    public void addReport(String report);
+
+    /**
+     * Returns the user who started the monitored job
+     * @return the user who started the monitored job
+     */
+    public String getOwner();
+
+    /**
+     * Sets the user who started the monitored job
+     * @param owner the user who started the monitored job
+     */
+    public void setOwner(String owner);
+
+}
diff --git a/cdmlib-commons/src/main/java/eu/etaxonomy/cdm/common/monitor/RemotingProgressMonitor.java b/cdmlib-commons/src/main/java/eu/etaxonomy/cdm/common/monitor/RemotingProgressMonitor.java
new file mode 100644 (file)
index 0000000..547bab0
--- /dev/null
@@ -0,0 +1,82 @@
+// $Id$
+/**
+* Copyright (C) 2015 EDIT
+* European Distributed Institute of Taxonomy
+* http://www.e-taxonomy.eu
+*
+* The contents of this file are subject to the Mozilla Public License Version 1.1
+* See LICENSE.TXT at the top of this package for the full license terms.
+*/
+package eu.etaxonomy.cdm.common.monitor;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+/**
+ * @author cmathew
+ * @date 14 Oct 2015
+ *
+ */
+public class RemotingProgressMonitor extends RestServiceProgressMonitor implements IRemotingProgressMonitor {
+
+    private Object result;
+    private List<String> reports = new ArrayList<String>();
+    private String owner;
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Object getResult() {
+        return result;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setResult(Object result) {
+        this.result = result;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public List<String> getReports() {
+        return reports;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void addReport(String report) {
+        reports.add(report);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String getOwner() {
+        return owner;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setOwner(String owner) {
+        this.owner = owner;
+    }
+
+}
index 9b41c9e029f85207dfe8edcb6b789e1617289ee1..7b01a28c4457a7c015b796ed209fa139cbe26a65 100644 (file)
@@ -9,6 +9,8 @@
 */
 package eu.etaxonomy.cdm.io.service;
 
+import java.util.UUID;
+
 import eu.etaxonomy.cdm.io.common.ExportResult;
 import eu.etaxonomy.cdm.io.common.IExportConfigurator;
 import eu.etaxonomy.cdm.io.common.IImportConfigurator;
@@ -24,6 +26,15 @@ public interface IIOService {
 
     public ExportResult export(IExportConfigurator configurator);
 
+
+    /**
+     * @param configurator
+     * @param importData
+     * @param type
+     * @return
+     */
+    public UUID monitImportData(IImportConfigurator configurator, byte[] importData, SOURCE_TYPE type);
+
     /**
      * @param configurator
      * @param importData
@@ -46,4 +57,5 @@ public interface IIOService {
      */
     public ImportResult importDataFromInputStream(IImportConfigurator configurator, byte[] importData);
 
+
 }
index b6d1072f158e70bffae1bce47d148d395857c16d..1e41383caf020e9a2ec0ba5118f68ce547ec176d 100644 (file)
@@ -14,12 +14,17 @@ import java.io.FileOutputStream;
 import java.io.IOException;
 import java.nio.file.Files;
 import java.nio.file.Path;
+import java.util.UUID;
 
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
+import eu.etaxonomy.cdm.api.service.ProgressMonitorManager;
+import eu.etaxonomy.cdm.api.service.util.RemotingProgressMonitorThread;
+import eu.etaxonomy.cdm.common.monitor.IRemotingProgressMonitor;
+import eu.etaxonomy.cdm.common.monitor.RemotingProgressMonitor;
 import eu.etaxonomy.cdm.io.common.CdmApplicationAwareDefaultExport;
 import eu.etaxonomy.cdm.io.common.CdmApplicationAwareDefaultImport;
 import eu.etaxonomy.cdm.io.common.ExportResult;
@@ -46,6 +51,9 @@ public class IOServiceImpl implements IIOService {
     @Qualifier("defaultImport")
     CdmApplicationAwareDefaultImport cdmImport;
 
+    @Autowired
+    ProgressMonitorManager<IRemotingProgressMonitor> progressMonitorManager;
+
 
 
     /* (non-Javadoc)
@@ -58,6 +66,25 @@ public class IOServiceImpl implements IIOService {
     }
 
 
+    @Override
+    public UUID monitImportData(final IImportConfigurator configurator, final byte[] importData, final SOURCE_TYPE type) {
+        final IRemotingProgressMonitor monitor = new RemotingProgressMonitor();
+        RemotingProgressMonitorThread monitThread = new RemotingProgressMonitorThread(monitor) {
+            @Override
+            public Object doRun(IRemotingProgressMonitor monitor) {
+                configurator.setProgressMonitor(monitor);
+                ImportResult result = importData(configurator, importData, type);
+                for(byte[] report : result.getReports()) {
+                    monitor.addReport(new String(report));
+                }
+                return result;
+            }
+        };
+        UUID uuid = progressMonitorManager.registerMonitor(monitor);
+        monitThread.setPriority(3);
+        monitThread.start();
+        return uuid;
+    }
 
     @Override
     public ImportResult importData(IImportConfigurator configurator, byte[] importData, SOURCE_TYPE type) {
index 7680d102864ed765bebd649fd5a3e8b0ae882296..eeb714a3f8414569f16170f86c02935731bfc5a7 100644 (file)
@@ -103,6 +103,7 @@ public class Abcd206Import extends SpecimenImportBase<Abcd206ImportConfigurator,
 
     private Abcd206ImportReport report;
 
+
     public Abcd206Import() {
         super();
     }
@@ -223,8 +224,8 @@ public class Abcd206Import extends SpecimenImportBase<Abcd206ImportConfigurator,
             if (unitsList != null) {
                 String message = "nb units to insert: " + unitsList.getLength();
                 logger.info(message);
+                state.getConfig().getProgressMonitor().beginTask("Importing ABCD file", unitsList.getLength() + 2);
                 updateProgress(state, message);
-                state.getConfig().getProgressMonitor().beginTask("Importing ABCD file", unitsList.getLength());
 
                 state.setDataHolder(new Abcd206DataHolder());
                 state.getDataHolder().reset();
index 2f48bf60e205228f5872274ba3e96212e48f68af..f6594a77157c4134f06e25e02db8d65c77eb5ff2 100644 (file)
@@ -40,7 +40,9 @@ import org.hibernate.search.annotations.Analyze;
 import org.hibernate.search.annotations.Field;\r
 import org.hibernate.search.annotations.Indexed;\r
 import org.hibernate.search.annotations.IndexedEmbedded;\r
+import org.springframework.security.core.Authentication;\r
 import org.springframework.security.core.GrantedAuthority;\r
+import org.springframework.security.core.context.SecurityContextHolder;\r
 import org.springframework.security.core.userdetails.UserDetails;\r
 \r
 import eu.etaxonomy.cdm.model.agent.Person;\r
@@ -67,8 +69,8 @@ public class User extends CdmBase implements UserDetails {
     private static final long serialVersionUID = 6582191171369439163L;\r
     private static final Logger logger = Logger.getLogger(User.class);\r
 \r
- // **************************** FACTORY *****************************************/   \r
-    \r
+ // **************************** FACTORY *****************************************/\r
+\r
     public static User NewInstance(String username, String pwd){\r
         User user = new User();\r
         user.setUsername(username);\r
@@ -98,7 +100,7 @@ public class User extends CdmBase implements UserDetails {
     }\r
 \r
 //***************************** Fields *********************** /\r
-    \r
+\r
     @XmlElement(name = "Username")\r
     @Column(unique = true)\r
     @Field(analyze = Analyze.NO)\r
@@ -159,13 +161,13 @@ public class User extends CdmBase implements UserDetails {
     private Set<GrantedAuthority> authorities;  //authorities of this user and of all groups the user belongs to\r
 \r
 //***************************** Constructor *********************** /\r
-    \r
+\r
     protected User(){\r
         super();\r
     }\r
-    \r
+\r
 // ***************************** METHODS ******************************/\r
-    \r
+\r
     /**\r
      * Initializes or refreshes the collection of authorities, See\r
      * {@link #getAuthorities()}\r
@@ -286,6 +288,14 @@ public class User extends CdmBase implements UserDetails {
         this.person = person;\r
     }\r
 \r
+    public static User getCurrentAuthenticatedUser() {\r
+        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();\r
+        if(authentication != null && authentication.getPrincipal() != null && authentication.getPrincipal() instanceof User) {\r
+            return (User)authentication.getPrincipal();\r
+        }\r
+        return null;\r
+    }\r
+\r
 //*********************** CLONE ********************************************************/\r
 \r
     /**\r
index 6694817b9bb06a4909ac02a381412904a2d3f1d8..fd561b7c23d81a8e289f9a5547b1a01bbe23a8c5 100644 (file)
@@ -10,9 +10,6 @@
 package eu.etaxonomy.cdm.remote.controller;
 
 import java.io.IOException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
 import java.util.Map;
 import java.util.UUID;
 
@@ -20,6 +17,7 @@ import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
 import org.apache.commons.io.FilenameUtils;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Controller;
 import org.springframework.web.bind.WebDataBinder;
 import org.springframework.web.bind.annotation.InitBinder;
@@ -30,6 +28,7 @@ import org.springframework.web.servlet.ModelAndView;
 
 import com.wordnik.swagger.annotations.Api;
 
+import eu.etaxonomy.cdm.api.service.ProgressMonitorManager;
 import eu.etaxonomy.cdm.common.monitor.IRestServiceProgressMonitor;
 import eu.etaxonomy.cdm.remote.editor.UUIDPropertyEditor;
 
@@ -45,94 +44,21 @@ import eu.etaxonomy.cdm.remote.editor.UUIDPropertyEditor;
 @RequestMapping(value="/progress/")
 public class ProgressMonitorController {
 
-    private final Map<UUID, IRestServiceProgressMonitor> monitors = new HashMap<UUID, IRestServiceProgressMonitor>();
 
-    private final Map<UUID, Long> timeoutMap = new HashMap<UUID, Long>();
-
-    private Thread cleanUpThread = null;
-
-    /**
-     * Time out in minutes for monitors which are done.
-     * A monitor which is set done will be removed after this interval.
-     */
-    private final int cleanUpTimeout = 1;
-
-    /**
-     *
-     */
-    private final int cleanUpInterval = 1000 * 10; // 10 seconds
+    @Autowired
+    private ProgressMonitorManager<IRestServiceProgressMonitor> progressMonitorManager;
 
     @InitBinder
     public void initBinder(WebDataBinder binder) {
         binder.registerCustomEditor(UUID.class, new UUIDPropertyEditor());
     }
 
-    public ProgressMonitorController(){
-
-        this.cleanUpThread = new Thread(){
-
-            @Override
-            public void run() {
-                while(true){
-                    scheduledCeanUp();
-                    try {
-                        sleep(cleanUpInterval);
-                    } catch (InterruptedException e) {
-                        /* IGNORE */
-                    }
-                }
-            }
-
-        };
-        cleanUpThread.start();
-    }
-
-
-    /**
-     * run every n minutes clean up monitors which have been marked done x minutes ago
-     */
-    private void scheduledCeanUp() {
-
-        List<UUID> timedOutMonitors = new ArrayList<UUID>();
-        IRestServiceProgressMonitor monitor;
-
-        long now = System.currentTimeMillis();
-        long nextTimeout = now + cleanUpTimeout * 1000 * 60;
-
-
-        // add monitors which are stopped or done to the timeoutMap
-        for(UUID uuid : monitors.keySet()){
-            monitor = monitors.get(uuid);
-            if((monitor.isFailed() || monitor.isDone())){
-                if(!timeoutMap.containsKey(uuid)){
-                    timeoutMap.put(uuid, nextTimeout);
-                }
-            }
-        }
-
-        // check with monitor has timed out
-        for(UUID uuid : timeoutMap.keySet()){
-            if(timeoutMap.get(uuid) <= now){
-                timedOutMonitors.add(uuid);
-            }
-        }
-
-        //finally remove the monitors
-        for(UUID uuid : timedOutMonitors){
-            timeoutMap.remove(uuid);
-            monitors.remove(uuid);
-        }
-
-    }
-
     public UUID registerMonitor(IRestServiceProgressMonitor monitor){
-        UUID uuid = UUID.randomUUID();
-        monitors.put(uuid, monitor);
-        return uuid;
+        return progressMonitorManager.registerMonitor(monitor);
     }
 
     public IRestServiceProgressMonitor getMonitor(UUID uuid) {
-        return monitors.get(uuid);
+        return progressMonitorManager.getMonitor(uuid);
     }
 
     /**
@@ -142,8 +68,7 @@ public class ProgressMonitorController {
      * @return
      */
     public boolean isMonitorRunning(UUID uuid) {
-        IRestServiceProgressMonitor monitor = getMonitor(uuid);
-        return monitor != null && !monitor.isCanceled() && !monitor.isDone() && !monitor.isFailed();
+        return progressMonitorManager.isMonitorRunning(uuid);
     }
 
     /**
@@ -169,7 +94,7 @@ public class ProgressMonitorController {
             throws IOException {
 
         ModelAndView mv = new ModelAndView();
-
+        Map<UUID, IRestServiceProgressMonitor> monitors = progressMonitorManager.getMonitors();
         if (monitors.containsKey(uuid)) {
             mv.addObject(monitors.get(uuid));
         } else {
index 6eab5f37cd241697f53d485fbd7258addc602a91..a70cd41e96ce8a478d49953ee314076376bb00f3 100644 (file)
@@ -1,15 +1,16 @@
-// $Id$
-/**
- * Copyright (C) 2007 EDIT
- * European Distributed Institute of Taxonomy
- * http://www.e-taxonomy.eu
- *
- * The contents of this file are subject to the Mozilla Public License Version 1.1
- * See LICENSE.TXT at the top of this package for the full license terms.
- */
-
-package eu.etaxonomy.cdm.api.application;
 
+// $Id$\r
+/**\r
+ * Copyright (C) 2007 EDIT\r
+ * European Distributed Institute of Taxonomy\r
+ * http://www.e-taxonomy.eu\r
+ *\r
+ * The contents of this file are subject to the Mozilla Public License Version 1.1\r
+ * See LICENSE.TXT at the top of this package for the full license terms.\r
+ */\r
+\r
+package eu.etaxonomy.cdm.api.application;\r
+\r
 import java.util.EnumSet;
 import java.util.List;
 import java.util.UUID;
@@ -52,6 +53,7 @@ import eu.etaxonomy.cdm.api.service.INameService;
 import eu.etaxonomy.cdm.api.service.IOccurrenceService;
 import eu.etaxonomy.cdm.api.service.IPolytomousKeyNodeService;
 import eu.etaxonomy.cdm.api.service.IPolytomousKeyService;
+import eu.etaxonomy.cdm.api.service.IProgressMonitorService;
 import eu.etaxonomy.cdm.api.service.IReferenceService;
 import eu.etaxonomy.cdm.api.service.IService;
 import eu.etaxonomy.cdm.api.service.ITaxonNodeService;
@@ -74,613 +76,623 @@ import eu.etaxonomy.cdm.model.common.CdmBase;
 import eu.etaxonomy.cdm.model.common.DefinedTermBase;
 import eu.etaxonomy.cdm.persistence.hibernate.permission.CRUD;
 import eu.etaxonomy.cdm.persistence.hibernate.permission.ICdmPermissionEvaluator;
+\r
+/**\r
+ * @author a.mueller\r
+ */\r
+public class CdmApplicationController implements ICdmApplicationConfiguration {\r
+       private static final Logger logger = Logger.getLogger(CdmApplicationController.class);\r
+\r
+       public static final String DEFAULT_APPLICATION_CONTEXT_RESOURCE = "/eu/etaxonomy/cdm/defaultApplicationContext.xml";\r
+\r
+       public AbstractApplicationContext applicationContext;\r
+       protected ICdmApplicationConfiguration configuration;\r
+       private final Resource applicationContextResource;\r
+\r
+       private final IProgressMonitor progressMonitor;\r
+\r
+       final protected static DbSchemaValidation defaultDbSchemaValidation = DbSchemaValidation.VALIDATE;\r
+\r
+\r
+       /**\r
+        * Constructor, opens a spring ApplicationContext by using the default data source\r
+        *\r
+        * @throws DataSourceNotFoundException\r
+        */\r
+       public static CdmApplicationController NewInstance() throws DataSourceNotFoundException{\r
+               logger.info("Start CdmApplicationController with default data source");\r
+               CdmPersistentDataSource dataSource = getDefaultDatasource();\r
+               DbSchemaValidation dbSchemaValidation = defaultDbSchemaValidation;\r
+               return CdmApplicationController.NewInstance(null, dataSource, dbSchemaValidation, false);\r
+       }\r
+\r
+\r
+       /**\r
+        * Constructor, opens a spring ApplicationContext by using the default data source\r
+        *\r
+        * @param dbSchemaValidation\r
+        *            validation type for database schema\r
+        * @throws DataSourceNotFoundException\r
+        */\r
+       public static CdmApplicationController NewInstance(DbSchemaValidation dbSchemaValidation) throws DataSourceNotFoundException{\r
+               logger.info("Start CdmApplicationController with default data source");\r
+               CdmPersistentDataSource dataSource = getDefaultDatasource();\r
+               return CdmApplicationController.NewInstance(null, dataSource, dbSchemaValidation, false);\r
+       }\r
+\r
+\r
+       /**\r
+        * Constructor, opens an spring ApplicationContext by using the according data source\r
+        * and the default database schema validation type\r
+        *\r
+        * @param dataSource\r
+        */\r
+       public static CdmApplicationController NewInstance(ICdmDataSource dataSource){\r
+               return CdmApplicationController.NewInstance(null, dataSource, defaultDbSchemaValidation, false);\r
+       }\r
+\r
+\r
+       public static CdmApplicationController NewInstance(ICdmDataSource dataSource, DbSchemaValidation dbSchemaValidation){\r
+               return CdmApplicationController.NewInstance(null, dataSource, dbSchemaValidation, false);\r
+       }\r
+\r
+\r
+       public static CdmApplicationController NewInstance(ICdmDataSource dataSource, DbSchemaValidation dbSchemaValidation, boolean omitTermLoading){\r
+               return CdmApplicationController.NewInstance(null, dataSource, dbSchemaValidation, omitTermLoading);\r
+       }\r
+\r
+       public static CdmApplicationController NewInstance(Resource applicationContextResource, ICdmDataSource dataSource,\r
+                       DbSchemaValidation dbSchemaValidation, boolean omitTermLoading){\r
+               return CdmApplicationController.NewInstance(applicationContextResource, dataSource, dbSchemaValidation, omitTermLoading, null);\r
+       }\r
+\r
+       public static CdmApplicationController NewInstance(Resource applicationContextResource, ICdmDataSource dataSource,\r
+                       DbSchemaValidation dbSchemaValidation, boolean omitTermLoading, IProgressMonitor progressMonitor){\r
+               return new CdmApplicationController(applicationContextResource, dataSource, dbSchemaValidation, omitTermLoading, progressMonitor, null);\r
+       }\r
+\r
+\r
+       //TODO discuss need for listeners before commit to trunk\r
+       //      public static CdmApplicationController NewInstance(Resource applicationContextResource, ICdmDataSource dataSource, DbSchemaValidation dbSchemaValidation, boolean omitTermLoading, IProgressMonitor progressMonitor, List<ApplicationListener> listeners) {\r
+       //              return new CdmApplicationController(applicationContextResource, dataSource, dbSchemaValidation, omitTermLoading, progressMonitor,listeners);\r
+       //      }\r
+\r
+       /**\r
+        * @return\r
+        */\r
+       protected static ClassPathResource getClasspathResource(){\r
+               return new ClassPathResource(DEFAULT_APPLICATION_CONTEXT_RESOURCE);\r
+       }\r
+\r
+\r
+       /**\r
+        * @return\r
+        * @throws DataSourceNotFoundException\r
+        */\r
+       protected static CdmPersistentDataSource getDefaultDatasource() throws DataSourceNotFoundException{\r
+               CdmPersistentDataSource dataSource = CdmPersistentDataSource.NewDefaultInstance();\r
+               return dataSource;\r
+       }\r
+\r
+\r
+       /**\r
+        *\r
+        * FIXME:Remoting this constructor is added only to allow extension of this cntroller\r
+        * class. and should be removed after refactoring\r
+        */\r
+       protected CdmApplicationController(){\r
+               applicationContextResource = null;\r
+               progressMonitor = null;\r
+       }\r
+\r
+\r
+       /**\r
+        * Constructor, opens an spring 2.5 ApplicationContext by using the according data\r
+        * source\r
+        *\r
+        * @param dataSource\r
+        * @param dbSchemaValidation\r
+        * @param omitTermLoading\r
+        */\r
+       protected CdmApplicationController(Resource applicationContextResource, ICdmDataSource dataSource, DbSchemaValidation dbSchemaValidation,\r
+                       boolean omitTermLoading, IProgressMonitor progressMonitor, List<ApplicationListener> listeners){\r
+               logger.info("Start CdmApplicationController with datasource: " + dataSource.getName());\r
+\r
+               if (dbSchemaValidation == null) {\r
+                       dbSchemaValidation = defaultDbSchemaValidation;\r
+               }\r
+               this.applicationContextResource = applicationContextResource != null ? applicationContextResource : getClasspathResource();\r
+               this.progressMonitor = progressMonitor != null ? progressMonitor : new NullProgressMonitor();\r
+\r
+               setNewDataSource(dataSource, dbSchemaValidation, omitTermLoading, listeners);\r
+       }\r
+\r
+\r
+       /**\r
+        * Sets the application context to a new spring ApplicationContext by using the\r
+        * according data source and initializes the Controller.\r
+        *\r
+        * @param dataSource\r
+        */\r
+       private boolean setNewDataSource(ICdmDataSource dataSource, DbSchemaValidation dbSchemaValidation, boolean omitTermLoading,\r
+                       List<ApplicationListener> listeners){\r
+\r
+               if (dbSchemaValidation == null) {\r
+                       dbSchemaValidation = defaultDbSchemaValidation;\r
+               }\r
+               logger.info("Connecting to '" + dataSource.getName() + "'");\r
+\r
+               MonitoredGenericApplicationContext applicationContext = new MonitoredGenericApplicationContext();\r
+               int refreshTasks = 45;\r
+               int nTasks = 5 + refreshTasks;\r
+               //              nTasks += applicationContext.countTasks();\r
+               progressMonitor.beginTask("Connecting to '" + dataSource.getName() + "'", nTasks);\r
+\r
+               //              progressMonitor.worked(1);\r
+\r
+               BeanDefinition datasourceBean = dataSource.getDatasourceBean();\r
+               datasourceBean.setAttribute("isLazy", false);\r
+               progressMonitor.subTask("Registering datasource.");\r
+               applicationContext.registerBeanDefinition("dataSource", datasourceBean);\r
+               progressMonitor.worked(1);\r
+\r
+               BeanDefinition hibernatePropBean = dataSource.getHibernatePropertiesBean(dbSchemaValidation);\r
+               applicationContext.registerBeanDefinition("hibernateProperties", hibernatePropBean);\r
+\r
+               XmlBeanDefinitionReader xmlReader = new XmlBeanDefinitionReader(applicationContext);\r
+               progressMonitor.subTask("Registering resources.");\r
+               xmlReader.loadBeanDefinitions(applicationContextResource);\r
+               progressMonitor.worked(1);\r
+\r
+               //omitTerms\r
+               if (omitTermLoading == true) {\r
+                       String initializerName = "persistentTermInitializer";\r
+                       BeanDefinition beanDef = applicationContext.getBeanDefinition(initializerName);\r
+                       MutablePropertyValues values = beanDef.getPropertyValues();\r
+                       values.addPropertyValue("omit", omitTermLoading);\r
+               }\r
+\r
+               if (listeners != null) {\r
+                       for (ApplicationListener listener : listeners) {\r
+                               applicationContext.addApplicationListener(listener);\r
+                       }\r
+               }\r
+\r
+               //              String message = "Start application context. This might take a while ...";\r
+               ////            progressMonitor.subTask(message);\r
+               //              SubProgressMonitor subMonitor= new SubProgressMonitor(progressMonitor, 10);\r
+               //              subMonitor.beginTask(message, 2);\r
+               //              applicationContext.setProgressMonitor(subMonitor);\r
+\r
+               applicationContext.refresh(new SubProgressMonitor(progressMonitor, refreshTasks));\r
+               applicationContext.start();\r
+               //              progressMonitor.worked(1);\r
+\r
+               progressMonitor.subTask("Cleaning up.");\r
+               setApplicationContext(applicationContext);\r
+               progressMonitor.worked(1);\r
+\r
+               progressMonitor.done();\r
+               return true;\r
+       }\r
+\r
+\r
+       /**\r
+        * Tests if some DefinedTermsAreMissing.\r
+        *\r
+        * @return true, if at least one is missing, else false\r
+        */\r
+       public boolean testDefinedTermsAreMissing(){\r
+               UUID englishUuid = UUID.fromString("e9f8cdb7-6819-44e8-95d3-e2d0690c3523");\r
+               DefinedTermBase<?> english = this.getTermService().load(englishUuid);\r
+               if (english == null || !english.getUuid().equals(englishUuid)) {\r
+                       return true;\r
+               }\r
+               else {\r
+                       return false;\r
+               }\r
+       }\r
+\r
+\r
+       /**\r
+        * Changes the ApplicationContext to the new dataSource\r
+        *\r
+        * @param dataSource\r
+        */\r
+       public boolean changeDataSource(ICdmDataSource dataSource){\r
+               //logger.info("Change datasource to : " + dataSource);\r
+               return setNewDataSource(dataSource, DbSchemaValidation.VALIDATE, false, null);\r
+       }\r
+\r
+\r
+       /**\r
+        * Changes the ApplicationContext to the new dataSource\r
+        *\r
+        * @param dataSource\r
+        * @param dbSchemaValidation\r
+        */\r
+       public boolean changeDataSource(ICdmDataSource dataSource, DbSchemaValidation dbSchemaValidation){\r
+               //logger.info("Change datasource to : " + dataSource);\r
+               return setNewDataSource(dataSource, dbSchemaValidation, false, null);\r
+       }\r
+\r
+\r
+       /**\r
+        * Changes the ApplicationContext to the new dataSource\r
+        *\r
+        * @param dataSource\r
+        * @param dbSchemaValidation\r
+        * @param omitTermLoading\r
+        */\r
+       public boolean changeDataSource(ICdmDataSource dataSource, DbSchemaValidation dbSchemaValidation, boolean omitTermLoading){\r
+               logger.info("Change datasource to : " + dataSource);\r
+               return setNewDataSource(dataSource, dbSchemaValidation, omitTermLoading, null);\r
+       }\r
+\r
+\r
+       /**\r
+        * Changes the ApplicationContext to the new dataSource\r
+        *\r
+        * @param dataSource\r
+        * @param dbSchemaValidation\r
+        * @param omitTermLoading\r
+        */\r
+       public boolean changeDataSource(ICdmDataSource dataSource, DbSchemaValidation dbSchemaValidation, boolean omitTermLoading,\r
+                       List<ApplicationListener> listeners){\r
+               logger.info("Change datasource to : " + dataSource);\r
+               return setNewDataSource(dataSource, dbSchemaValidation, omitTermLoading, listeners);\r
+       }\r
+\r
+\r
+       /**\r
+        * Sets a new application Context.\r
+        *\r
+        * @param ac\r
+        */\r
+       public void setApplicationContext(AbstractApplicationContext ac){\r
+               closeApplicationContext(); //closes old application context if necessary\r
+               applicationContext = ac;\r
+               applicationContext.registerShutdownHook();\r
+               init();\r
+       }\r
+\r
+\r
+       /*\r
+        * (non-Javadoc)\r
+        *\r
+        * @see java.lang.Object#finalize()\r
+        */\r
+       @Override\r
+       public void finalize(){\r
+               close();\r
+       }\r
+\r
+\r
+       /**\r
+        * closes the application\r
+        */\r
+       public void close(){\r
+               closeApplicationContext();\r
+       }\r
+\r
+\r
+       /**\r
+        * closes the application context\r
+        */\r
+       protected void closeApplicationContext(){\r
+               if (applicationContext != null) {\r
+                       logger.info("Close ApplicationContext");\r
+                       applicationContext.close();\r
+               }\r
+       }\r
+\r
+\r
+       protected void init(){\r
+               logger.debug("Init " + this.getClass().getName() + " ... ");\r
+               if (logger.isDebugEnabled()) {\r
+                       for (String beanName : applicationContext.getBeanDefinitionNames()) {\r
+                               logger.debug(beanName);\r
+                       }\r
+               }\r
+               //TODO delete next row (was just for testing)\r
+               if (logger.isInfoEnabled()) {\r
+                       logger.info("Registered Beans: ");\r
+                       String[] beanNames = applicationContext.getBeanDefinitionNames();\r
+                       for (String beanName : beanNames) {\r
+                               logger.info(beanName);\r
+                       }\r
+               }\r
+               configuration = (ICdmApplicationConfiguration) applicationContext.getBean("cdmApplicationDefaultConfiguration");\r
+               try {\r
+                       //FIXME:Remoting catching exection to allow for remoting\r
+                       getDatabaseService().setApplicationController(this);\r
+               }\r
+               catch (UnsupportedOperationException uoe) {\r
+                       logger.warn("getDatabaseService() is not implmented for current application context");\r
+               }\r
+       }\r
+\r
+\r
+       /* ****** Services ******** */\r
+       @Override\r
+       public final IAnnotationService getAnnotationService(){\r
+           return configuration.getAnnotationService();\r
+       }\r
+\r
+       @Override\r
+       public final INameService getNameService(){\r
+           return configuration.getNameService();\r
+       }\r
+\r
+\r
+       @Override\r
+       public final ITaxonService getTaxonService(){\r
+               return configuration.getTaxonService();\r
+       }\r
+\r
+\r
+       @Override\r
+       public final IClassificationService getClassificationService(){\r
+               return configuration.getClassificationService();\r
+       }\r
+\r
+\r
+       @Override\r
+       public final ITaxonNodeService getTaxonNodeService(){\r
+               return configuration.getTaxonNodeService();\r
+       }\r
+\r
+\r
+       @Override\r
+       public final IReferenceService getReferenceService(){\r
+               return configuration.getReferenceService();\r
+       }\r
+\r
+\r
+       @Override\r
+       public final IAgentService getAgentService(){\r
+               return configuration.getAgentService();\r
+       }\r
+\r
+\r
+       @Override\r
+       public final IDatabaseService getDatabaseService(){\r
+               return configuration.getDatabaseService();\r
+       }\r
+\r
+\r
+       @Override\r
+       public final ITermService getTermService(){\r
+               return configuration.getTermService();\r
+       }\r
+\r
+\r
+       @Override\r
+       public final IDescriptionService getDescriptionService(){\r
+               return configuration.getDescriptionService();\r
+       }\r
+\r
+\r
+       @Override\r
+       public final IOccurrenceService getOccurrenceService(){\r
+               return configuration.getOccurrenceService();\r
+       }\r
+\r
+       @Override\r
+       public IAmplificationService getAmplificationService(){\r
+               return configuration.getAmplificationService();\r
+       }\r
+\r
+       @Override\r
+       public ISequenceService getSequenceService(){\r
+               return configuration.getSequenceService();\r
+       }\r
+\r
+\r
+       @Override\r
+       public final IPrimerService getPrimerService(){\r
+               return configuration.getPrimerService();\r
+       }\r
+\r
+\r
+       @Override\r
+       public final IMediaService getMediaService(){\r
+               return configuration.getMediaService();\r
+       }\r
+\r
+\r
+       @Override\r
+       public final ICommonService getCommonService(){\r
+               return configuration.getCommonService();\r
+       }\r
+\r
+\r
+       @Override\r
+       public final ILocationService getLocationService(){\r
+               return configuration.getLocationService();\r
+       }\r
+\r
+\r
+       @Override\r
+       public final IUserService getUserService(){\r
+               return configuration.getUserService();\r
+       }\r
+\r
+\r
+       @Override\r
+       public final IGrantedAuthorityService getGrantedAuthorityService(){\r
+               return configuration.getGrantedAuthorityService();\r
+       }\r
+\r
+\r
+       @Override\r
+       public IGroupService getGroupService(){\r
+               return configuration.getGroupService();\r
+       }\r
+\r
+\r
+       @Override\r
+       public final ICollectionService getCollectionService(){\r
+               return configuration.getCollectionService();\r
+       }\r
+\r
+\r
+       @Override\r
+       public final IFeatureTreeService getFeatureTreeService(){\r
+               return configuration.getFeatureTreeService();\r
+       }\r
+\r
+\r
+       @Override\r
+       public final IFeatureNodeService getFeatureNodeService(){\r
+               return configuration.getFeatureNodeService();\r
+       }\r
+\r
+\r
+       @Override\r
+       public final IVocabularyService getVocabularyService(){\r
+               return configuration.getVocabularyService();\r
+       }\r
+\r
+\r
+       @Override\r
+       public final IIdentificationKeyService getIdentificationKeyService(){\r
+               return configuration.getIdentificationKeyService();\r
+       }\r
+\r
+\r
+       @Override\r
+       public final IPolytomousKeyService getPolytomousKeyService(){\r
+               return configuration.getPolytomousKeyService();\r
+       }\r
+\r
+\r
+       @Override\r
+       public final IPolytomousKeyNodeService getPolytomousKeyNodeService(){\r
+               return configuration.getPolytomousKeyNodeService();\r
+       }\r
+\r
+\r
+    /**\r
+     * {@inheritDoc}\r
+     */\r
+    @Override\r
+    public IProgressMonitorService getProgressMonitorService() {\r
+        return configuration.getProgressMonitorService();\r
+    }\r
+\r
+\r
+       @Override\r
+       public IEntityValidationService getEntityValidationService(){\r
+               return configuration.getEntityValidationService();\r
+       }\r
+\r
+\r
+       @Override\r
+       public IEntityConstraintViolationService getEntityConstraintViolationService(){\r
+               return configuration.getEntityConstraintViolationService();\r
+       }\r
+\r
+\r
+       @Override\r
+       public final IService<CdmBase> getMainService(){\r
+               return configuration.getMainService();\r
+       }\r
+\r
+\r
+       @Override\r
+       public final IWorkingSetService getWorkingSetService(){\r
+               return configuration.getWorkingSetService();\r
+       }\r
+\r
+\r
+       @Override\r
+       public final ConversationHolder NewConversation(){\r
+               //return (ConversationHolder)applicationContext.getBean("conversationHolder");\r
+               return configuration.NewConversation();\r
+       }\r
+\r
+\r
+       /* **** Security ***** */\r
+\r
+       @Override\r
+       public void authenticate(String username, String password){\r
+               UsernamePasswordAuthenticationToken tokenForUser = new UsernamePasswordAuthenticationToken(username, password);\r
+               Authentication authentication = this.getAuthenticationManager().authenticate(tokenForUser);\r
+               SecurityContext context = SecurityContextHolder.getContext();\r
+               context.setAuthentication(authentication);\r
+       }\r
+\r
+       @Override\r
+       public final ProviderManager getAuthenticationManager(){\r
+               return configuration.getAuthenticationManager();\r
+       }\r
+\r
+\r
+       @Override\r
+       public ICdmPermissionEvaluator getPermissionEvaluator(){\r
+               return configuration.getPermissionEvaluator();\r
+       }\r
+\r
+       /**\r
+        * @see org.springframework.security.access.PermissionEvaluator#hasPermission(org.springframework.security.core.Authentication,\r
+        *      java.lang.Object, java.lang.Object)\r
+        *\r
+        * @param targetDomainObject\r
+        * @param permission\r
+        * @return\r
+        */\r
+       public boolean currentAuthentiationHasPermissions(CdmBase targetDomainObject, EnumSet<CRUD> permission){\r
+               SecurityContext context = SecurityContextHolder.getContext();\r
+               return getPermissionEvaluator().hasPermission(context.getAuthentication(), targetDomainObject, permission);\r
+       }\r
+\r
+\r
+       @Override\r
+       public final PlatformTransactionManager getTransactionManager(){\r
+               return configuration.getTransactionManager();\r
+       }\r
+\r
+\r
+       @Override\r
+       public final Object getBean(String name){\r
+               return this.applicationContext.getBean(name);\r
+       }\r
+\r
+\r
+       /*\r
+        * OLD TRANSACTION STUFF\r
+        */\r
+\r
+       /* **** flush ********** */\r
+       public void flush(){\r
+               SessionFactory sf = (SessionFactory) applicationContext.getBean("sessionFactory");\r
+               sf.getCurrentSession().flush();\r
+       }\r
+\r
+\r
+       public SessionFactory getSessionFactory(){\r
+               return (SessionFactory) applicationContext.getBean("sessionFactory");\r
+       }\r
+\r
+\r
+       @Override\r
+       public TransactionStatus startTransaction(){\r
+               return startTransaction(false);\r
+       }\r
+\r
+\r
+       @Override\r
+       public TransactionStatus startTransaction(Boolean readOnly){\r
+               return configuration.startTransaction(readOnly);\r
+       }\r
+\r
+       @Override\r
+       public void commitTransaction(TransactionStatus txStatus){\r
+               PlatformTransactionManager txManager = configuration.getTransactionManager();\r
+               txManager.commit(txStatus);\r
+               return;\r
+       }\r
+\r
+}\r
 
-/**
- * @author a.mueller
- */
-public class CdmApplicationController implements ICdmApplicationConfiguration {
-       private static final Logger logger = Logger.getLogger(CdmApplicationController.class);
-
-       public static final String DEFAULT_APPLICATION_CONTEXT_RESOURCE = "/eu/etaxonomy/cdm/defaultApplicationContext.xml";
-
-       public AbstractApplicationContext applicationContext;
-       protected ICdmApplicationConfiguration configuration;
-       private final Resource applicationContextResource;
-
-       private final IProgressMonitor progressMonitor;
-
-       final protected static DbSchemaValidation defaultDbSchemaValidation = DbSchemaValidation.VALIDATE;
-
-
-       /**
-        * Constructor, opens a spring ApplicationContext by using the default data source
-        *
-        * @throws DataSourceNotFoundException
-        */
-       public static CdmApplicationController NewInstance() throws DataSourceNotFoundException{
-               logger.info("Start CdmApplicationController with default data source");
-               CdmPersistentDataSource dataSource = getDefaultDatasource();
-               DbSchemaValidation dbSchemaValidation = defaultDbSchemaValidation;
-               return CdmApplicationController.NewInstance(null, dataSource, dbSchemaValidation, false);
-       }
-
-
-       /**
-        * Constructor, opens a spring ApplicationContext by using the default data source
-        *
-        * @param dbSchemaValidation
-        *            validation type for database schema
-        * @throws DataSourceNotFoundException
-        */
-       public static CdmApplicationController NewInstance(DbSchemaValidation dbSchemaValidation) throws DataSourceNotFoundException{
-               logger.info("Start CdmApplicationController with default data source");
-               CdmPersistentDataSource dataSource = getDefaultDatasource();
-               return CdmApplicationController.NewInstance(null, dataSource, dbSchemaValidation, false);
-       }
-
-
-       /**
-        * Constructor, opens an spring ApplicationContext by using the according data source
-        * and the default database schema validation type
-        *
-        * @param dataSource
-        */
-       public static CdmApplicationController NewInstance(ICdmDataSource dataSource){
-               return CdmApplicationController.NewInstance(null, dataSource, defaultDbSchemaValidation, false);
-       }
-
-
-       public static CdmApplicationController NewInstance(ICdmDataSource dataSource, DbSchemaValidation dbSchemaValidation){
-               return CdmApplicationController.NewInstance(null, dataSource, dbSchemaValidation, false);
-       }
-
-
-       public static CdmApplicationController NewInstance(ICdmDataSource dataSource, DbSchemaValidation dbSchemaValidation, boolean omitTermLoading){
-               return CdmApplicationController.NewInstance(null, dataSource, dbSchemaValidation, omitTermLoading);
-       }
-
-       public static CdmApplicationController NewInstance(Resource applicationContextResource, ICdmDataSource dataSource,
-                       DbSchemaValidation dbSchemaValidation, boolean omitTermLoading){
-               return CdmApplicationController.NewInstance(applicationContextResource, dataSource, dbSchemaValidation, omitTermLoading, null);
-       }
-
-       public static CdmApplicationController NewInstance(Resource applicationContextResource, ICdmDataSource dataSource,
-                       DbSchemaValidation dbSchemaValidation, boolean omitTermLoading, IProgressMonitor progressMonitor){
-               return new CdmApplicationController(applicationContextResource, dataSource, dbSchemaValidation, omitTermLoading, progressMonitor, null);
-       }
-
-
-       //TODO discuss need for listeners before commit to trunk
-       //      public static CdmApplicationController NewInstance(Resource applicationContextResource, ICdmDataSource dataSource, DbSchemaValidation dbSchemaValidation, boolean omitTermLoading, IProgressMonitor progressMonitor, List<ApplicationListener> listeners) {
-       //              return new CdmApplicationController(applicationContextResource, dataSource, dbSchemaValidation, omitTermLoading, progressMonitor,listeners);
-       //      }
-
-       /**
-        * @return
-        */
-       protected static ClassPathResource getClasspathResource(){
-               return new ClassPathResource(DEFAULT_APPLICATION_CONTEXT_RESOURCE);
-       }
-
-
-       /**
-        * @return
-        * @throws DataSourceNotFoundException
-        */
-       protected static CdmPersistentDataSource getDefaultDatasource() throws DataSourceNotFoundException{
-               CdmPersistentDataSource dataSource = CdmPersistentDataSource.NewDefaultInstance();
-               return dataSource;
-       }
-
-
-       /**
-        *
-        * FIXME:Remoting this constructor is added only to allow extension of this cntroller
-        * class. and should be removed after refactoring
-        */
-       protected CdmApplicationController(){
-               applicationContextResource = null;
-               progressMonitor = null;
-       }
-
-
-       /**
-        * Constructor, opens an spring 2.5 ApplicationContext by using the according data
-        * source
-        *
-        * @param dataSource
-        * @param dbSchemaValidation
-        * @param omitTermLoading
-        */
-       protected CdmApplicationController(Resource applicationContextResource, ICdmDataSource dataSource, DbSchemaValidation dbSchemaValidation,
-                       boolean omitTermLoading, IProgressMonitor progressMonitor, List<ApplicationListener> listeners){
-               logger.info("Start CdmApplicationController with datasource: " + dataSource.getName());
-
-               if (dbSchemaValidation == null) {
-                       dbSchemaValidation = defaultDbSchemaValidation;
-               }
-               this.applicationContextResource = applicationContextResource != null ? applicationContextResource : getClasspathResource();
-               this.progressMonitor = progressMonitor != null ? progressMonitor : new NullProgressMonitor();
-
-               setNewDataSource(dataSource, dbSchemaValidation, omitTermLoading, listeners);
-       }
-
-
-       /**
-        * Sets the application context to a new spring ApplicationContext by using the
-        * according data source and initializes the Controller.
-        *
-        * @param dataSource
-        */
-       private boolean setNewDataSource(ICdmDataSource dataSource, DbSchemaValidation dbSchemaValidation, boolean omitTermLoading,
-                       List<ApplicationListener> listeners){
-
-               if (dbSchemaValidation == null) {
-                       dbSchemaValidation = defaultDbSchemaValidation;
-               }
-               logger.info("Connecting to '" + dataSource.getName() + "'");
-
-               MonitoredGenericApplicationContext applicationContext = new MonitoredGenericApplicationContext();
-               int refreshTasks = 45;
-               int nTasks = 5 + refreshTasks;
-               //              nTasks += applicationContext.countTasks();
-               progressMonitor.beginTask("Connecting to '" + dataSource.getName() + "'", nTasks);
-
-               //              progressMonitor.worked(1);
-
-               BeanDefinition datasourceBean = dataSource.getDatasourceBean();
-               datasourceBean.setAttribute("isLazy", false);
-               progressMonitor.subTask("Registering datasource.");
-               applicationContext.registerBeanDefinition("dataSource", datasourceBean);
-               progressMonitor.worked(1);
-
-               BeanDefinition hibernatePropBean = dataSource.getHibernatePropertiesBean(dbSchemaValidation);
-               applicationContext.registerBeanDefinition("hibernateProperties", hibernatePropBean);
-
-               XmlBeanDefinitionReader xmlReader = new XmlBeanDefinitionReader(applicationContext);
-               progressMonitor.subTask("Registering resources.");
-               xmlReader.loadBeanDefinitions(applicationContextResource);
-               progressMonitor.worked(1);
-
-               //omitTerms
-               if (omitTermLoading == true) {
-                       String initializerName = "persistentTermInitializer";
-                       BeanDefinition beanDef = applicationContext.getBeanDefinition(initializerName);
-                       MutablePropertyValues values = beanDef.getPropertyValues();
-                       values.addPropertyValue("omit", omitTermLoading);
-               }
-
-               if (listeners != null) {
-                       for (ApplicationListener listener : listeners) {
-                               applicationContext.addApplicationListener(listener);
-                       }
-               }
-
-               //              String message = "Start application context. This might take a while ...";
-               ////            progressMonitor.subTask(message);
-               //              SubProgressMonitor subMonitor= new SubProgressMonitor(progressMonitor, 10);
-               //              subMonitor.beginTask(message, 2);
-               //              applicationContext.setProgressMonitor(subMonitor);
-
-               applicationContext.refresh(new SubProgressMonitor(progressMonitor, refreshTasks));
-               applicationContext.start();
-               //              progressMonitor.worked(1);
-
-               progressMonitor.subTask("Cleaning up.");
-               setApplicationContext(applicationContext);
-               progressMonitor.worked(1);
-
-               progressMonitor.done();
-               return true;
-       }
-
-
-       /**
-        * Tests if some DefinedTermsAreMissing.
-        *
-        * @return true, if at least one is missing, else false
-        */
-       public boolean testDefinedTermsAreMissing(){
-               UUID englishUuid = UUID.fromString("e9f8cdb7-6819-44e8-95d3-e2d0690c3523");
-               DefinedTermBase<?> english = this.getTermService().load(englishUuid);
-               if (english == null || !english.getUuid().equals(englishUuid)) {
-                       return true;
-               }
-               else {
-                       return false;
-               }
-       }
-
-
-       /**
-        * Changes the ApplicationContext to the new dataSource
-        *
-        * @param dataSource
-        */
-       public boolean changeDataSource(ICdmDataSource dataSource){
-               //logger.info("Change datasource to : " + dataSource);
-               return setNewDataSource(dataSource, DbSchemaValidation.VALIDATE, false, null);
-       }
-
-
-       /**
-        * Changes the ApplicationContext to the new dataSource
-        *
-        * @param dataSource
-        * @param dbSchemaValidation
-        */
-       public boolean changeDataSource(ICdmDataSource dataSource, DbSchemaValidation dbSchemaValidation){
-               //logger.info("Change datasource to : " + dataSource);
-               return setNewDataSource(dataSource, dbSchemaValidation, false, null);
-       }
-
-
-       /**
-        * Changes the ApplicationContext to the new dataSource
-        *
-        * @param dataSource
-        * @param dbSchemaValidation
-        * @param omitTermLoading
-        */
-       public boolean changeDataSource(ICdmDataSource dataSource, DbSchemaValidation dbSchemaValidation, boolean omitTermLoading){
-               logger.info("Change datasource to : " + dataSource);
-               return setNewDataSource(dataSource, dbSchemaValidation, omitTermLoading, null);
-       }
-
-
-       /**
-        * Changes the ApplicationContext to the new dataSource
-        *
-        * @param dataSource
-        * @param dbSchemaValidation
-        * @param omitTermLoading
-        */
-       public boolean changeDataSource(ICdmDataSource dataSource, DbSchemaValidation dbSchemaValidation, boolean omitTermLoading,
-                       List<ApplicationListener> listeners){
-               logger.info("Change datasource to : " + dataSource);
-               return setNewDataSource(dataSource, dbSchemaValidation, omitTermLoading, listeners);
-       }
-
-
-       /**
-        * Sets a new application Context.
-        *
-        * @param ac
-        */
-       public void setApplicationContext(AbstractApplicationContext ac){
-               closeApplicationContext(); //closes old application context if necessary
-               applicationContext = ac;
-               applicationContext.registerShutdownHook();
-               init();
-       }
-
-
-       /*
-        * (non-Javadoc)
-        *
-        * @see java.lang.Object#finalize()
-        */
-       @Override
-       public void finalize(){
-               close();
-       }
-
-
-       /**
-        * closes the application
-        */
-       public void close(){
-               closeApplicationContext();
-       }
-
-
-       /**
-        * closes the application context
-        */
-       protected void closeApplicationContext(){
-               if (applicationContext != null) {
-                       logger.info("Close ApplicationContext");
-                       applicationContext.close();
-               }
-       }
-
-
-       protected void init(){
-               logger.debug("Init " + this.getClass().getName() + " ... ");
-               if (logger.isDebugEnabled()) {
-                       for (String beanName : applicationContext.getBeanDefinitionNames()) {
-                               logger.debug(beanName);
-                       }
-               }
-               //TODO delete next row (was just for testing)
-               if (logger.isInfoEnabled()) {
-                       logger.info("Registered Beans: ");
-                       String[] beanNames = applicationContext.getBeanDefinitionNames();
-                       for (String beanName : beanNames) {
-                               logger.info(beanName);
-                       }
-               }
-               configuration = (ICdmApplicationConfiguration) applicationContext.getBean("cdmApplicationDefaultConfiguration");
-               try {
-                       //FIXME:Remoting catching exection to allow for remoting
-                       getDatabaseService().setApplicationController(this);
-               }
-               catch (UnsupportedOperationException uoe) {
-                       logger.warn("getDatabaseService() is not implmented for current application context");
-               }
-       }
-
-
-       /* ****** Services ******** */
-       @Override
-       public final IAnnotationService getAnnotationService(){
-           return configuration.getAnnotationService();
-       }
-
-       @Override
-       public final INameService getNameService(){
-           return configuration.getNameService();
-       }
-
-
-       @Override
-       public final ITaxonService getTaxonService(){
-               return configuration.getTaxonService();
-       }
-
-
-       @Override
-       public final IClassificationService getClassificationService(){
-               return configuration.getClassificationService();
-       }
-
-
-       @Override
-       public final ITaxonNodeService getTaxonNodeService(){
-           return configuration.getTaxonNodeService();
-       }
-
-
-       @Override
-       public final IReferenceService getReferenceService(){
-               return configuration.getReferenceService();
-       }
-
-
-       @Override
-       public final IAgentService getAgentService(){
-               return configuration.getAgentService();
-       }
-
-
-       @Override
-       public final IDatabaseService getDatabaseService(){
-               return configuration.getDatabaseService();
-       }
-
-
-       @Override
-       public final ITermService getTermService(){
-               return configuration.getTermService();
-       }
-
-
-       @Override
-       public final IDescriptionService getDescriptionService(){
-               return configuration.getDescriptionService();
-       }
-
-
-       @Override
-       public final IOccurrenceService getOccurrenceService(){
-               return configuration.getOccurrenceService();
-       }
-
-       @Override
-       public IAmplificationService getAmplificationService(){
-               return configuration.getAmplificationService();
-       }
-
-       @Override
-       public ISequenceService getSequenceService(){
-               return configuration.getSequenceService();
-       }
-
-
-       @Override
-       public final IPrimerService getPrimerService(){
-               return configuration.getPrimerService();
-       }
-
-
-       @Override
-       public final IMediaService getMediaService(){
-               return configuration.getMediaService();
-       }
-
-
-       @Override
-       public final ICommonService getCommonService(){
-               return configuration.getCommonService();
-       }
-
-
-       @Override
-       public final ILocationService getLocationService(){
-               return configuration.getLocationService();
-       }
-
-
-       @Override
-       public final IUserService getUserService(){
-               return configuration.getUserService();
-       }
-
-
-       @Override
-       public final IGrantedAuthorityService getGrantedAuthorityService(){
-               return configuration.getGrantedAuthorityService();
-       }
-
-
-       @Override
-       public IGroupService getGroupService(){
-               return configuration.getGroupService();
-       }
-
-
-       @Override
-       public final ICollectionService getCollectionService(){
-               return configuration.getCollectionService();
-       }
-
-
-       @Override
-       public final IFeatureTreeService getFeatureTreeService(){
-               return configuration.getFeatureTreeService();
-       }
-
-
-       @Override
-       public final IFeatureNodeService getFeatureNodeService(){
-               return configuration.getFeatureNodeService();
-       }
-
-
-       @Override
-       public final IVocabularyService getVocabularyService(){
-               return configuration.getVocabularyService();
-       }
-
-
-       @Override
-       public final IIdentificationKeyService getIdentificationKeyService(){
-               return configuration.getIdentificationKeyService();
-       }
-
-
-       @Override
-       public final IPolytomousKeyService getPolytomousKeyService(){
-               return configuration.getPolytomousKeyService();
-       }
-
-
-       @Override
-       public final IPolytomousKeyNodeService getPolytomousKeyNodeService(){
-               return configuration.getPolytomousKeyNodeService();
-       }
-
-
-       @Override
-       public IEntityValidationService getEntityValidationService(){
-               return configuration.getEntityValidationService();
-       }
-
-
-       @Override
-       public IEntityConstraintViolationService getEntityConstraintViolationService(){
-               return configuration.getEntityConstraintViolationService();
-       }
-
-
-       @Override
-       public final IService<CdmBase> getMainService(){
-               return configuration.getMainService();
-       }
-
-
-       @Override
-       public final IWorkingSetService getWorkingSetService(){
-               return configuration.getWorkingSetService();
-       }
-
-
-       @Override
-       public final ConversationHolder NewConversation(){
-               //return (ConversationHolder)applicationContext.getBean("conversationHolder");
-               return configuration.NewConversation();
-       }
-
-
-       /* **** Security ***** */
-
-       @Override
-       public void authenticate(String username, String password){
-               UsernamePasswordAuthenticationToken tokenForUser = new UsernamePasswordAuthenticationToken(username, password);
-               Authentication authentication = this.getAuthenticationManager().authenticate(tokenForUser);
-               SecurityContext context = SecurityContextHolder.getContext();
-               context.setAuthentication(authentication);
-       }
-
-       @Override
-       public final ProviderManager getAuthenticationManager(){
-               return configuration.getAuthenticationManager();
-       }
-
-
-       @Override
-       public ICdmPermissionEvaluator getPermissionEvaluator(){
-               return configuration.getPermissionEvaluator();
-       }
-
-
-       /**
-        * @see org.springframework.security.access.PermissionEvaluator#hasPermission(org.springframework.security.core.Authentication,
-        *      java.lang.Object, java.lang.Object)
-        *
-        * @param targetDomainObject
-        * @param permission
-        * @return
-        */
-       public boolean currentAuthentiationHasPermissions(CdmBase targetDomainObject, EnumSet<CRUD> permission){
-               SecurityContext context = SecurityContextHolder.getContext();
-               return getPermissionEvaluator().hasPermission(context.getAuthentication(), targetDomainObject, permission);
-       }
-
-
-       @Override
-       public final PlatformTransactionManager getTransactionManager(){
-               return configuration.getTransactionManager();
-       }
-
-
-       @Override
-       public final Object getBean(String name){
-               return this.applicationContext.getBean(name);
-       }
-
-
-       /*
-        * OLD TRANSACTION STUFF
-        */
-
-       /* **** flush ********** */
-       public void flush(){
-               SessionFactory sf = (SessionFactory) applicationContext.getBean("sessionFactory");
-               sf.getCurrentSession().flush();
-       }
-
-
-       public SessionFactory getSessionFactory(){
-               return (SessionFactory) applicationContext.getBean("sessionFactory");
-       }
-
-
-       @Override
-       public TransactionStatus startTransaction(){
-               return startTransaction(false);
-       }
-
-
-       @Override
-       public TransactionStatus startTransaction(Boolean readOnly){
-               return configuration.startTransaction(readOnly);
-       }
-
-       @Override
-       public void commitTransaction(TransactionStatus txStatus){
-               PlatformTransactionManager txManager = configuration.getTransactionManager();
-               txManager.commit(txStatus);
-               return;
-       }
-}
index 89eed44a449aa115225cd71f165f450e0b58468c..9208c3319730aff24899ec6dacfdf4573f39e0ba 100644 (file)
@@ -51,6 +51,7 @@ import eu.etaxonomy.cdm.api.service.INameService;
 import eu.etaxonomy.cdm.api.service.IOccurrenceService;\r
 import eu.etaxonomy.cdm.api.service.IPolytomousKeyNodeService;\r
 import eu.etaxonomy.cdm.api.service.IPolytomousKeyService;\r
+import eu.etaxonomy.cdm.api.service.IProgressMonitorService;\r
 import eu.etaxonomy.cdm.api.service.IReferenceService;\r
 import eu.etaxonomy.cdm.api.service.IService;\r
 import eu.etaxonomy.cdm.api.service.ITaxonNodeService;\r
@@ -155,6 +156,8 @@ public class CdmApplicationDefaultConfiguration implements ICdmApplicationConfig
        @Autowired\r
        private IPolytomousKeyNodeService polytomousKeyNodeService;\r
        @Autowired\r
+       private IProgressMonitorService progressMonitorService;\r
+       @Autowired\r
        private IEntityValidationService entityValidationService;\r
        @Autowired\r
        private IEntityConstraintViolationService entityConstraintViolationService;\r
@@ -360,6 +363,14 @@ public class CdmApplicationDefaultConfiguration implements ICdmApplicationConfig
                return polytomousKeyNodeService;\r
        }\r
 \r
+    /**\r
+     * {@inheritDoc}\r
+     */\r
+    @Override\r
+    public IProgressMonitorService getProgressMonitorService() {\r
+        return progressMonitorService;\r
+    }\r
+\r
        @Override\r
        public IWorkingSetService getWorkingSetService(){\r
                return workingSetService;\r
@@ -433,4 +444,5 @@ public class CdmApplicationDefaultConfiguration implements ICdmApplicationConfig
                context.setAuthentication(authentication);\r
        }\r
 \r
+\r
 }\r
index 8a78217a42af404f66a07d62a2a6daf24224441c..9f4478103c6afc4af13b71a415aa9f349a766e16 100644 (file)
@@ -35,6 +35,7 @@ import eu.etaxonomy.cdm.api.service.INameService;
 import eu.etaxonomy.cdm.api.service.IOccurrenceService;\r
 import eu.etaxonomy.cdm.api.service.IPolytomousKeyNodeService;\r
 import eu.etaxonomy.cdm.api.service.IPolytomousKeyService;\r
+import eu.etaxonomy.cdm.api.service.IProgressMonitorService;\r
 import eu.etaxonomy.cdm.api.service.IReferenceService;\r
 import eu.etaxonomy.cdm.api.service.IService;\r
 import eu.etaxonomy.cdm.api.service.ITaxonNodeService;\r
@@ -267,6 +268,10 @@ public interface ICdmApplicationConfiguration{
         */\r
        public IPolytomousKeyNodeService getPolytomousKeyNodeService();\r
 \r
+       /**\r
+     * @return\r
+     */\r
+       public IProgressMonitorService getProgressMonitorService();\r
 \r
        /**\r
         * @return\r
diff --git a/cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/IProgressMonitorService.java b/cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/IProgressMonitorService.java
new file mode 100644 (file)
index 0000000..4da8715
--- /dev/null
@@ -0,0 +1,58 @@
+// $Id$
+/**
+* Copyright (C) 2015 EDIT
+* European Distributed Institute of Taxonomy
+* http://www.e-taxonomy.eu
+*
+* The contents of this file are subject to the Mozilla Public License Version 1.1
+* See LICENSE.TXT at the top of this package for the full license terms.
+*/
+package eu.etaxonomy.cdm.api.service;
+
+import java.util.UUID;
+
+import eu.etaxonomy.cdm.common.monitor.IRemotingProgressMonitor;
+
+/**
+ *
+ * Service interface to manage progress monitors
+ *
+ * @author cmathew
+ * @date 14 Oct 2015
+ *
+ */
+public interface IProgressMonitorService {
+
+    /**
+     * Registers new remoting progress monitor
+     *
+     * @return uuid of remoting monitor
+     */
+    public UUID registerNewRemotingMonitor();
+
+    /**
+     * Return remoting monitor corresponding to give uuid
+     *
+     * @param uuid of remoting monitor
+     * @return remoting monitor
+     */
+    public IRemotingProgressMonitor getRemotingMonitor(UUID uuid);
+
+    /**
+     * Interrupt thread corresponding to remoting monitor with
+     * given uuid
+     *
+     * @param uuid of remoting monitor
+     */
+    public void interrupt(UUID uuid);
+
+    /**
+     * Checks whether thread corresponding to remoting monitor with
+     * given uuid is currently in progress
+     *
+     * @param uuid of remoting monitor
+     * @return true if corresponding thread is in progres, o/w false
+     */
+    public boolean isMonitorThreadRunning(UUID uuid);
+
+}
index fe43f250c4764a633f9ea18c7edbac805f8628fa..4fdf5a3c3b852ad8addbf0c7a46510d56dfedf90 100644 (file)
@@ -9,7 +9,10 @@
 */
 package eu.etaxonomy.cdm.api.service;
 
+import java.util.UUID;
+
 import eu.etaxonomy.cdm.api.service.dto.CdmEntityIdentifier;
+import eu.etaxonomy.cdm.common.monitor.IRemotingProgressMonitor;
 
 /**
  * Service interface for the testing of client applications using the service
@@ -30,4 +33,21 @@ public interface ITestService {
 
     public UpdateResult addChild(CdmEntityIdentifier taxonNodeCei);
 
+
+    /**
+     * @param monitor
+     * @return
+     */
+    public String longRunningMethod(IRemotingProgressMonitor monitor, RuntimeException ex);
+
+
+    /**
+     * @return
+     */
+    public UUID monitLongRunningMethod(RuntimeException ex);
+
+
+
+
+
 }
diff --git a/cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/ProgressMonitorManager.java b/cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/ProgressMonitorManager.java
new file mode 100644 (file)
index 0000000..97e162c
--- /dev/null
@@ -0,0 +1,131 @@
+// $Id$
+/**
+* Copyright (C) 2015 EDIT
+* European Distributed Institute of Taxonomy
+* http://www.e-taxonomy.eu
+*
+* The contents of this file are subject to the Mozilla Public License Version 1.1
+* See LICENSE.TXT at the top of this package for the full license terms.
+*/
+package eu.etaxonomy.cdm.api.service;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+import org.springframework.stereotype.Component;
+
+import eu.etaxonomy.cdm.common.monitor.IRestServiceProgressMonitor;
+
+/**
+ * Manages monitors for long running jobs.
+ *
+ * @author cmathew
+ * @date 14 Oct 2015
+ *
+ */
+@Component
+public class ProgressMonitorManager<T extends IRestServiceProgressMonitor> {
+
+    private final Map<UUID, T> monitors = new HashMap<UUID, T>();
+
+    private final Map<UUID, Long> timeoutMap = new HashMap<UUID, Long>();
+
+    private Thread cleanUpThread = null;
+
+    /**
+     * Time out in minutes for monitors which are done.
+     * A monitor which is set done will be removed after this interval.
+     */
+    private final int cleanUpTimeout = 1;
+
+    /**
+     *
+     */
+    private final int cleanUpInterval = 1000 * 10; // 10 seconds
+
+    public ProgressMonitorManager() {
+
+        this.cleanUpThread = new Thread(){
+
+            @Override
+            public void run() {
+                while(true){
+                    scheduledCleanUp();
+                    try {
+                        sleep(cleanUpInterval);
+                    } catch (InterruptedException e) {
+                        /* IGNORE */
+                    }
+                }
+            }
+
+        };
+        cleanUpThread.start();
+    }
+
+    /**
+     * run every n minutes clean up monitors which have been marked done x minutes ago
+     */
+    private void scheduledCleanUp() {
+
+        List<UUID> timedOutMonitors = new ArrayList<UUID>();
+        IRestServiceProgressMonitor monitor;
+
+        long now = System.currentTimeMillis();
+        long nextTimeout = now + cleanUpTimeout * 1000 * 60;
+
+
+        // add monitors which are stopped or done to the timeoutMap
+        for(UUID uuid : monitors.keySet()){
+            monitor = monitors.get(uuid);
+            if((monitor.isFailed() || monitor.isDone())){
+                if(!timeoutMap.containsKey(uuid)){
+                    timeoutMap.put(uuid, nextTimeout);
+                }
+            }
+        }
+
+        // check with monitor has timed out
+        for(UUID uuid : timeoutMap.keySet()){
+            if(timeoutMap.get(uuid) <= now){
+                timedOutMonitors.add(uuid);
+            }
+        }
+
+        //finally remove the monitors
+        for(UUID uuid : timedOutMonitors){
+            timeoutMap.remove(uuid);
+            monitors.remove(uuid);
+        }
+
+    }
+
+    public UUID registerMonitor(T monitor){
+        UUID uuid = UUID.randomUUID();
+        monitors.put(uuid, monitor);
+        return uuid;
+    }
+
+    public IRestServiceProgressMonitor getMonitor(UUID uuid) {
+        return monitors.get(uuid);
+    }
+
+    /**
+     * returns true if the {@link IRestServiceProgressMonitor} identified by the <code>uuid</code>
+     * exists and if it is still indicating a running thread
+     * @param uuid
+     * @return
+     */
+    public boolean isMonitorRunning(UUID uuid) {
+        IRestServiceProgressMonitor monitor = getMonitor(uuid);
+        return monitor != null && !monitor.isCanceled() && !monitor.isDone() && !monitor.isFailed();
+    }
+
+    public Map<UUID, T> getMonitors() {
+        return monitors;
+    }
+
+}
diff --git a/cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/ProgressMonitorServiceImpl.java b/cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/ProgressMonitorServiceImpl.java
new file mode 100644 (file)
index 0000000..1ae2d74
--- /dev/null
@@ -0,0 +1,92 @@
+// $Id$
+/**
+* Copyright (C) 2015 EDIT
+* European Distributed Institute of Taxonomy
+* http://www.e-taxonomy.eu
+*
+* The contents of this file are subject to the Mozilla Public License Version 1.1
+* See LICENSE.TXT at the top of this package for the full license terms.
+*/
+package eu.etaxonomy.cdm.api.service;
+
+import java.util.UUID;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.stereotype.Service;
+
+import eu.etaxonomy.cdm.api.service.util.RemotingProgressMonitorThread;
+import eu.etaxonomy.cdm.common.monitor.IRemotingProgressMonitor;
+import eu.etaxonomy.cdm.common.monitor.IRestServiceProgressMonitor;
+import eu.etaxonomy.cdm.common.monitor.RemotingProgressMonitor;
+import eu.etaxonomy.cdm.model.common.User;
+import eu.etaxonomy.cdm.persistence.hibernate.permission.CdmPermissionEvaluator;
+import eu.etaxonomy.cdm.persistence.hibernate.permission.Role;
+
+/**
+ * @author cmathew
+ * @date 14 Oct 2015
+ *
+ */
+@Service
+public class ProgressMonitorServiceImpl implements IProgressMonitorService {
+
+    @Autowired
+    public ProgressMonitorManager<IRestServiceProgressMonitor> progressMonitorManager;
+
+    @Autowired
+    public CdmPermissionEvaluator permissionEvaluator;
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public UUID registerNewRemotingMonitor() {
+        RemotingProgressMonitor monitor = new RemotingProgressMonitor();
+        UUID uuid = progressMonitorManager.registerMonitor(monitor);
+        return uuid;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public IRemotingProgressMonitor getRemotingMonitor(UUID uuid) {
+        IRestServiceProgressMonitor monitor = progressMonitorManager.getMonitor(uuid);
+        // lookup remoting monitors
+        if(monitor != null && monitor instanceof IRemotingProgressMonitor ) {
+            IRemotingProgressMonitor remotingMonitor = (IRemotingProgressMonitor)monitor;
+            String monitorOwner = remotingMonitor.getOwner();
+            User currentUser = User.getCurrentAuthenticatedUser();
+            // ensure that current user is admin or is the same as the owner of
+            // the monitor
+            if(currentUser != null &&
+                    (currentUser.getUsername().equals(monitorOwner) ||
+                            permissionEvaluator.hasOneOfRoles(SecurityContextHolder.getContext().getAuthentication(), Role.ROLE_ADMIN))) {
+                return remotingMonitor;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void interrupt(UUID uuid) {
+        RemotingProgressMonitorThread monitorThread = RemotingProgressMonitorThread.getMonitorThread(getRemotingMonitor(uuid));
+        if(monitorThread != null) {
+            monitorThread.interrupt();
+        }
+
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean isMonitorThreadRunning(UUID uuid) {
+        return RemotingProgressMonitorThread.getMonitorThread(getRemotingMonitor(uuid)) != null;
+    }
+
+}
index 5260f33babb4ca70cd949039fb8a48c5f85e2716..13997ab174087e9070b81280032330b3763a518f 100644 (file)
@@ -9,12 +9,18 @@
 */
 package eu.etaxonomy.cdm.api.service;
 
+import java.util.UUID;
+
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
 import eu.etaxonomy.cdm.api.service.UpdateResult.Status;
 import eu.etaxonomy.cdm.api.service.dto.CdmEntityIdentifier;
+import eu.etaxonomy.cdm.api.service.util.RemotingProgressMonitorThread;
+import eu.etaxonomy.cdm.common.monitor.IRemotingProgressMonitor;
+import eu.etaxonomy.cdm.common.monitor.RemotingProgressMonitor;
 import eu.etaxonomy.cdm.model.taxon.Taxon;
 import eu.etaxonomy.cdm.model.taxon.TaxonNode;
 
@@ -29,10 +35,14 @@ public class TestServiceImpl implements ITestService {
     @Autowired
     ITaxonNodeService taxonNodeService;
 
+    @Autowired
+    ProgressMonitorManager<IRemotingProgressMonitor> progressMonitorManager;
+
     /* (non-Javadoc)
      * @see eu.etaxonomy.cdm.api.service.ITestService#wait(int)
      */
     @Override
+    @PreAuthorize("hasRole('ROLE_ADMIN')")
     public void waitFor(long timeToWaitInMs) throws InterruptedException {
         Thread.sleep(timeToWaitInMs);
     }
@@ -67,4 +77,43 @@ public class TestServiceImpl implements ITestService {
         return result;
     }
 
+
+    @Override
+    public UUID monitLongRunningMethod(final RuntimeException ex) {
+        RemotingProgressMonitor monitor = new RemotingProgressMonitor();
+        RemotingProgressMonitorThread monitThread = new RemotingProgressMonitorThread(monitor) {
+            @Override
+            public Object doRun(IRemotingProgressMonitor monitor)  {
+                Object result = longRunningMethod(monitor, ex);
+                monitor.addReport("Report");
+                return result;
+            }
+        };
+
+        UUID uuid = progressMonitorManager.registerMonitor(monitor);
+        monitThread.setPriority(3);
+        monitThread.start();
+        return uuid;
+    }
+
+    @Override
+    public String longRunningMethod(IRemotingProgressMonitor monitor, RuntimeException ex) {
+        int noOfSteps = 10;
+        int stepToThrowException = noOfSteps / 2;
+        monitor.beginTask("Long Running Task", noOfSteps);
+        for(int i=0; i<noOfSteps; i++) {
+            try {
+                Thread.sleep(1000);
+                if(i == stepToThrowException && ex != null) {
+                    throw ex;
+                }
+            } catch (InterruptedException e) {
+                throw ex;
+            }
+            monitor.worked(1);
+        }
+        monitor.done();
+        return "Success";
+    }
+
 }
diff --git a/cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/util/RemotingProgressMonitorThread.java b/cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/util/RemotingProgressMonitorThread.java
new file mode 100644 (file)
index 0000000..e645afc
--- /dev/null
@@ -0,0 +1,95 @@
+// $Id$
+/**
+* Copyright (C) 2015 EDIT
+* European Distributed Institute of Taxonomy
+* http://www.e-taxonomy.eu
+*
+* The contents of this file are subject to the Mozilla Public License Version 1.1
+* See LICENSE.TXT at the top of this package for the full license terms.
+*/
+package eu.etaxonomy.cdm.api.service.util;
+
+import java.util.concurrent.ConcurrentHashMap;
+
+import eu.etaxonomy.cdm.common.monitor.IRemotingProgressMonitor;
+import eu.etaxonomy.cdm.model.common.User;
+
+/**
+ * Thread class to be used to run monitored jobs
+ *
+ * @author cmathew
+ * @date 22 Oct 2015
+ *
+ */
+public abstract class RemotingProgressMonitorThread extends Thread {
+
+    private static ConcurrentHashMap<IRemotingProgressMonitor, RemotingProgressMonitorThread> monitorsInProgress =
+            new ConcurrentHashMap<IRemotingProgressMonitor, RemotingProgressMonitorThread>();
+
+    private IRemotingProgressMonitor monitor;
+
+
+    /**
+     * Allocates a new RemotingProgressMonitorThread object
+     *
+     * @param monitor of job which is to be run in this thread
+     */
+    public RemotingProgressMonitorThread(IRemotingProgressMonitor monitor) {
+        if(monitor == null) {
+            throw new IllegalStateException("Monitor is null");
+        }
+        User user = User.getCurrentAuthenticatedUser();
+        if(user == null) {
+            throw new IllegalStateException("Current authenticated user is null");
+        }
+        this.monitor = monitor;
+        this.monitor.setOwner(user.getUsername());
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void run() {
+        try {
+            monitorsInProgress.put(monitor, this);
+            monitor.setResult(doRun(monitor));
+        } catch(Exception ex) {
+            monitor.setResult(ex);
+            monitor.setIsFailed(true);
+        }
+        monitor.done();
+        monitorsInProgress.remove(monitor);
+    }
+
+    /**
+     * Executes the monitored job.
+     *
+     * @param monitor to be updated by the monitored job
+     * @return result object
+     */
+    public abstract Object doRun(IRemotingProgressMonitor monitor);
+
+    /**
+     * Returns a currently running monitor thread corresponding to the
+     * given monitor.
+     *
+     * @param monitor for which the thread
+     * @return
+     */
+    public static RemotingProgressMonitorThread getMonitorThread(IRemotingProgressMonitor monitor) {
+        return monitorsInProgress.get(monitor);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void interrupt() {
+        super.interrupt();
+        monitor.setCanceled(true);
+        monitor.done();
+        monitorsInProgress.remove(monitor);
+    }
+
+}
index 3799c34e02c3e8e0fb7faedf66702930526a4955..86913493b3573f626804c7f58af28aa2b817d207 100644 (file)
       <value>eu.etaxonomy.cdm.api.service.IPolytomousKeyService</value>\r
     </property>\r
   </bean>\r
+  \r
+  <bean id="httpProgressMonitorService"\r
+    class="org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter">\r
+    <property name="service">\r
+      <ref bean="progressMonitorServiceImpl" />\r
+    </property>\r
+    <property name="serviceInterface">\r
+      <value>eu.etaxonomy.cdm.api.service.IProgressMonitorService</value>\r
+    </property>\r
+  </bean>\r
 \r
   <bean id="httpReferenceService"\r
     class="org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter">\r
index 61552715862dba510119d03fa44928289e4eb897..1ba78b03e1f68c71e18c0eebcec7c37c94fbcd46 100644 (file)
@@ -50,6 +50,7 @@
         <prop key="/remoting/polytomouskeynode.service">httpPolytomousKeyNodeService</prop>
         <prop key="/remoting/polytomouskey.service">httpPolytomousKeyService</prop>
         <prop key="/remoting/primer.service">httpPrimerService</prop>
+        <prop key="/remoting/progressmonitor.service">httpProgressMonitorService</prop>
         <prop key="/remoting/reference.service">httpReferenceService</prop>        
         <prop key="/remoting/sequence.service">httpSequenceService</prop> 
         <prop key="/remoting/taxonnode.service">httpTaxonNodeService</prop>