← Back to team overview

dhis2-devs team mailing list archive

[Branch ~dhis2-devs-core/dhis2/trunk] Rev 19204: Reverted r 19202. Files were not added.

 

------------------------------------------------------------
revno: 19204
committer: Lars Helge Overland <larshelge@xxxxxxxxx>
branch nick: dhis2
timestamp: Fri 2015-05-29 19:52:51 +0200
message:
  Reverted r 19202. Files were not added.
added:
  dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/system/
  dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/system/scheduling/
  dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/system/scheduling/Scheduler.java
  dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/system/scheduling/SpringScheduler.java
  dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/system/startup/
  dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/system/startup/AbstractStartupRoutine.java
  dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/system/startup/DefaultStartupRoutineExecutor.java
  dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/system/startup/StartupListener.java
  dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/system/startup/StartupRoutine.java
  dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/system/startup/StartupRoutineComparator.java
  dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/system/startup/StartupRoutineExecutor.java
  dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/system/velocity/
  dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/system/velocity/VelocityManager.java
  dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/util/AnnotationUtils.java
  dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/util/ReflectionUtils.java
modified:
  dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/i18n/DefaultI18nService.java
  dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/schema/DefaultSchemaService.java
  dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/schema/Jackson2PropertyIntrospectorService.java
  dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/schema/NodePropertyIntrospectorService.java
  dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/fieldfilter/DefaultFieldFilterService.java
  dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/metadata/DefaultExportService.java
  dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/metadata/DefaultImportService.java
  dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/metadata/DefaultMergeService.java
  dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/metadata/DefaultMetaDataDependencyService.java
  dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/metadata/importers/DefaultIdentifiableObjectImporter.java
  dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/objectfilter/DefaultObjectFilterService.java
  dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/schema/DefaultSchemaValidator.java
  dhis-2/dhis-support/dhis-support-commons/pom.xml
  dhis-2/dhis-support/dhis-support-system/pom.xml
  dhis-2/dhis-support/dhis-support-system/src/test/java/org/hisp/dhis/system/util/ReflectionUtilsTest.java
  dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/view/AbstractGridView.java
  dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-program/src/main/java/org/hisp/dhis/trackedentity/action/schedule/ScheduleCaseAggregateConditionAction.java


--
lp:dhis2
https://code.launchpad.net/~dhis2-devs-core/dhis2/trunk

Your team DHIS 2 developers is subscribed to branch lp:dhis2.
To unsubscribe from this branch go to https://code.launchpad.net/~dhis2-devs-core/dhis2/trunk/+edit-subscription
=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/i18n/DefaultI18nService.java'
--- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/i18n/DefaultI18nService.java	2015-05-29 13:54:46 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/i18n/DefaultI18nService.java	2015-05-29 17:52:51 +0000
@@ -44,7 +44,7 @@
 import java.util.Locale;
 import java.util.Map;
 
-import static org.hisp.dhis.system.util.ReflectionUtils.*;
+import static org.hisp.dhis.util.ReflectionUtils.*;
 
 /**
  * @author Oyvind Brucker

=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/schema/DefaultSchemaService.java'
--- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/schema/DefaultSchemaService.java	2015-05-29 13:54:46 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/schema/DefaultSchemaService.java	2015-05-29 17:52:51 +0000
@@ -33,7 +33,7 @@
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 import org.hibernate.SessionFactory;
-import org.hisp.dhis.system.util.ReflectionUtils;
+import org.hisp.dhis.util.ReflectionUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.core.OrderComparator;
 import org.springframework.util.StringUtils;

=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/schema/Jackson2PropertyIntrospectorService.java'
--- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/schema/Jackson2PropertyIntrospectorService.java	2015-05-29 13:54:46 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/schema/Jackson2PropertyIntrospectorService.java	2015-05-29 17:52:51 +0000
@@ -38,7 +38,7 @@
 import org.hisp.dhis.common.IdentifiableObject;
 import org.hisp.dhis.common.NameableObject;
 import org.hisp.dhis.common.annotation.Description;
-import org.hisp.dhis.system.util.ReflectionUtils;
+import org.hisp.dhis.util.ReflectionUtils;
 import org.springframework.util.StringUtils;
 
 import java.lang.reflect.Method;

=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/schema/NodePropertyIntrospectorService.java'
--- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/schema/NodePropertyIntrospectorService.java	2015-05-29 13:54:46 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/schema/NodePropertyIntrospectorService.java	2015-05-29 17:52:51 +0000
@@ -40,7 +40,7 @@
 import org.hisp.dhis.node.annotation.NodeComplex;
 import org.hisp.dhis.node.annotation.NodeRoot;
 import org.hisp.dhis.node.annotation.NodeSimple;
-import org.hisp.dhis.system.util.ReflectionUtils;
+import org.hisp.dhis.util.ReflectionUtils;
 import org.springframework.util.StringUtils;
 
 import java.lang.annotation.Annotation;

=== modified file 'dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/fieldfilter/DefaultFieldFilterService.java'
--- dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/fieldfilter/DefaultFieldFilterService.java	2015-05-29 13:54:46 +0000
+++ dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/fieldfilter/DefaultFieldFilterService.java	2015-05-29 17:52:51 +0000
@@ -45,7 +45,7 @@
 import org.hisp.dhis.schema.Property;
 import org.hisp.dhis.schema.Schema;
 import org.hisp.dhis.schema.SchemaService;
-import org.hisp.dhis.system.util.ReflectionUtils;
+import org.hisp.dhis.util.ReflectionUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.util.StringUtils;
 

=== modified file 'dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/metadata/DefaultExportService.java'
--- dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/metadata/DefaultExportService.java	2015-05-29 13:54:46 +0000
+++ dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/metadata/DefaultExportService.java	2015-05-29 17:52:51 +0000
@@ -44,7 +44,7 @@
 import org.hisp.dhis.schema.SchemaService;
 import org.hisp.dhis.system.notification.NotificationLevel;
 import org.hisp.dhis.system.notification.Notifier;
-import org.hisp.dhis.system.util.ReflectionUtils;
+import org.hisp.dhis.util.ReflectionUtils;
 import org.hisp.dhis.user.CurrentUserService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;

=== modified file 'dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/metadata/DefaultImportService.java'
--- dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/metadata/DefaultImportService.java	2015-05-29 13:54:46 +0000
+++ dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/metadata/DefaultImportService.java	2015-05-29 17:52:51 +0000
@@ -43,7 +43,7 @@
 import org.hisp.dhis.schema.SchemaService;
 import org.hisp.dhis.system.notification.NotificationLevel;
 import org.hisp.dhis.system.notification.Notifier;
-import org.hisp.dhis.system.util.ReflectionUtils;
+import org.hisp.dhis.util.ReflectionUtils;
 import org.hisp.dhis.user.User;
 import org.hisp.dhis.user.UserService;
 import org.springframework.beans.factory.annotation.Autowired;

=== modified file 'dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/metadata/DefaultMergeService.java'
--- dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/metadata/DefaultMergeService.java	2015-05-29 13:54:46 +0000
+++ dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/metadata/DefaultMergeService.java	2015-05-29 17:52:51 +0000
@@ -32,7 +32,7 @@
 import org.hisp.dhis.schema.Property;
 import org.hisp.dhis.schema.Schema;
 import org.hisp.dhis.schema.SchemaService;
-import org.hisp.dhis.system.util.ReflectionUtils;
+import org.hisp.dhis.util.ReflectionUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 
 import java.util.Collection;

=== modified file 'dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/metadata/DefaultMetaDataDependencyService.java'
--- dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/metadata/DefaultMetaDataDependencyService.java	2015-05-29 13:54:46 +0000
+++ dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/metadata/DefaultMetaDataDependencyService.java	2015-05-29 17:52:51 +0000
@@ -61,7 +61,7 @@
 import org.hisp.dhis.organisationunit.OrganisationUnitService;
 import org.hisp.dhis.schema.Schema;
 import org.hisp.dhis.schema.SchemaService;
-import org.hisp.dhis.system.util.ReflectionUtils;
+import org.hisp.dhis.util.ReflectionUtils;
 import org.hisp.dhis.user.User;
 import org.hisp.dhis.validation.ValidationRule;
 import org.springframework.beans.factory.annotation.Autowired;

=== modified file 'dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/metadata/importers/DefaultIdentifiableObjectImporter.java'
--- dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/metadata/importers/DefaultIdentifiableObjectImporter.java	2015-05-29 13:54:46 +0000
+++ dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/metadata/importers/DefaultIdentifiableObjectImporter.java	2015-05-29 17:52:51 +0000
@@ -80,7 +80,7 @@
 import org.hisp.dhis.program.ProgramTrackedEntityAttribute;
 import org.hisp.dhis.program.ProgramValidation;
 import org.hisp.dhis.schema.SchemaService;
-import org.hisp.dhis.system.util.ReflectionUtils;
+import org.hisp.dhis.util.ReflectionUtils;
 import org.hisp.dhis.trackedentity.TrackedEntity;
 import org.hisp.dhis.trackedentity.TrackedEntityAttribute;
 import org.hisp.dhis.translation.Translation;

=== modified file 'dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/objectfilter/DefaultObjectFilterService.java'
--- dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/objectfilter/DefaultObjectFilterService.java	2015-05-29 13:54:46 +0000
+++ dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/objectfilter/DefaultObjectFilterService.java	2015-05-29 17:52:51 +0000
@@ -35,7 +35,7 @@
 import org.hisp.dhis.schema.Property;
 import org.hisp.dhis.schema.Schema;
 import org.hisp.dhis.schema.SchemaService;
-import org.hisp.dhis.system.util.ReflectionUtils;
+import org.hisp.dhis.util.ReflectionUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 
 import java.util.Collection;

=== modified file 'dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/schema/DefaultSchemaValidator.java'
--- dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/schema/DefaultSchemaValidator.java	2015-05-29 13:54:46 +0000
+++ dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/schema/DefaultSchemaValidator.java	2015-05-29 17:52:51 +0000
@@ -33,7 +33,7 @@
 import org.hisp.dhis.schema.PropertyType;
 import org.hisp.dhis.schema.Schema;
 import org.hisp.dhis.schema.SchemaService;
-import org.hisp.dhis.system.util.ReflectionUtils;
+import org.hisp.dhis.util.ReflectionUtils;
 import org.hisp.dhis.system.util.ValidationUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.util.StringUtils;

=== modified file 'dhis-2/dhis-support/dhis-support-commons/pom.xml'
--- dhis-2/dhis-support/dhis-support-commons/pom.xml	2015-05-29 13:54:46 +0000
+++ dhis-2/dhis-support/dhis-support-commons/pom.xml	2015-05-29 17:52:51 +0000
@@ -16,6 +16,18 @@
 
   <dependencies>
     <dependency>
+      <groupId>org.springframework</groupId>
+      <artifactId>spring-core</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework</groupId>
+      <artifactId>spring-context</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework</groupId>
+      <artifactId>spring-web</artifactId>
+    </dependency>
+    <dependency>
       <groupId>javax.servlet</groupId>
       <artifactId>servlet-api</artifactId>
     </dependency>
@@ -44,10 +56,18 @@
       <artifactId>jasperreports</artifactId>
     </dependency>
     <dependency>
+      <groupId>org.hibernate</groupId>
+      <artifactId>hibernate-core</artifactId>
+    </dependency>
+    <dependency>
       <groupId>org.javassist</groupId>
       <artifactId>javassist</artifactId>
     </dependency>
     <dependency>
+      <groupId>org.apache.velocity</groupId>
+      <artifactId>velocity</artifactId>
+    </dependency>
+    <dependency>
       <groupId>org.scijava</groupId>
       <artifactId>jep</artifactId>
     </dependency>

=== added directory 'dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/system'
=== added directory 'dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/system/scheduling'
=== added file 'dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/system/scheduling/Scheduler.java'
--- dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/system/scheduling/Scheduler.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/system/scheduling/Scheduler.java	2015-05-29 17:52:51 +0000
@@ -0,0 +1,91 @@
+package org.hisp.dhis.system.scheduling;
+
+/*
+ * Copyright (c) 2004-2015, University of Oslo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * Neither the name of the HISP project nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * Scheduler for managing the scheduling and execution of tasks.
+ *
+ * @author Lars Helge Overland
+ */
+public interface Scheduler
+{
+    final String CRON_DAILY_0AM = "0 0 0 * * ?";
+    final String CRON_DAILY_11PM = "0 0 23 * * ?";
+    final String CRON_EVERY_MIN = "0 0/1 * * * ?";
+    final String CRON_EVERY_15MIN = "0 0/15 * * * ?";
+    final String CRON_TEST = "0 * * * * ?";
+    
+    final String STATUS_RUNNING = "running";
+    final String STATUS_DONE = "done";
+    final String STATUS_STOPPED  = "stopped";
+    final String STATUS_NOT_STARTED = "not_started";
+    
+    /**
+     * Execute the given task immediately.
+     * 
+     * @task the task to execute.
+     */
+    void executeTask( Runnable task );
+    
+    /**
+     * Schedule the given task for future execution. The task can be referenced
+     * later through the given task key. A task cannot be scheduled if another
+     * task with the same key is already scheduled. The task must be unique for
+     * the task but can have an arbitrary value.
+     * 
+     * @param key the task key, cannot be null.
+     * @param task the task to schedule.
+     * @param cronExpr the cron expression to use for the task scheduling.
+     * @return true if the task was scheduled for execution as a result of this
+     *         operation, false if not.
+     */
+    boolean scheduleTask( String key, Runnable task, String cronExpr );
+    
+    /**
+     * Deactivates scheduling of the task with the given key.
+     * 
+     * @param key the task key.
+     * @return true if the task was deactivated as a result of this operation,
+     *         false if not.
+     */
+    boolean stopTask( String key );
+    
+    /**
+     * Deactivates scheduling for all tasks.
+     */
+    void stopAllTasks();
+    
+    /**
+     * Gets the status for the task with the given key.
+     * 
+     * @param key the task key.
+     * @return the task status.
+     */
+    String getTaskStatus( String key );
+}

=== added file 'dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/system/scheduling/SpringScheduler.java'
--- dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/system/scheduling/SpringScheduler.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/system/scheduling/SpringScheduler.java	2015-05-29 17:52:51 +0000
@@ -0,0 +1,158 @@
+package org.hisp.dhis.system.scheduling;
+
+/*
+ * Copyright (c) 2004-2015, University of Oslo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * Neither the name of the HISP project nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.concurrent.ScheduledFuture;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.core.task.TaskExecutor;
+import org.springframework.scheduling.TaskScheduler;
+import org.springframework.scheduling.support.CronTrigger;
+
+/**
+ * {@link Scheduler} implementation for use within the Spring framework.
+ * @author Lars Helge Overland
+ */
+public class SpringScheduler
+    implements Scheduler
+{
+    private static final Log log = LogFactory.getLog( SpringScheduler.class );
+    
+    private Map<String, ScheduledFuture<?>> futures = new HashMap<>();
+
+    // -------------------------------------------------------------------------
+    // Dependencies
+    // -------------------------------------------------------------------------
+
+    private TaskScheduler taskScheduler;
+
+    public void setTaskScheduler( TaskScheduler taskScheduler )
+    {
+        this.taskScheduler = taskScheduler;
+    }
+    
+    private TaskExecutor taskExecutor;
+
+    public void setTaskExecutor( TaskExecutor taskExecutor )
+    {
+        this.taskExecutor = taskExecutor;
+    }
+
+    // -------------------------------------------------------------------------
+    // Scheduler implementation
+    // -------------------------------------------------------------------------
+
+    @Override
+    public void executeTask( Runnable task )
+    {
+        taskExecutor.execute( task );
+    }
+    
+    @Override
+    public boolean scheduleTask( String key, Runnable task, String cronExpr )
+    {        
+        if ( key != null && !futures.containsKey( key ) )
+        {
+            ScheduledFuture<?> future = taskScheduler.schedule( task, new CronTrigger( cronExpr ) );
+            
+            futures.put( key, future );
+            
+            log.info( "Scheduled task with key: " + key + " and cron: " + cronExpr );
+            
+            return true;
+        }
+        
+        return false;
+    }
+    
+    @Override
+    public boolean stopTask( String key )
+    {        
+        if ( key != null )
+        {
+            ScheduledFuture<?> future = futures.get( key );
+            
+            boolean result = future != null ? future.cancel( true ) : false;
+            
+            futures.remove( key );
+            
+            log.info( "Stopped task with key: " + key + " successfully: " + result );
+            
+            return result;
+        }
+        
+        return false;
+    }
+    
+    @Override
+    public void stopAllTasks()
+    {
+        Iterator<String> keys = futures.keySet().iterator();
+        
+        while ( keys.hasNext() )
+        {
+            String key = keys.next();
+            
+            ScheduledFuture<?> future = futures.get( key );
+            
+            boolean result = future != null ? future.cancel( true ) : false;
+            
+            keys.remove();
+            
+            log.info( "Stopped task with key: " + key + " successfully: " + result );
+        }
+    }
+
+    @Override
+    public String getTaskStatus( String key )
+    {        
+        ScheduledFuture<?> future = futures.get( key );
+        
+        if ( future == null )
+        {
+            return STATUS_NOT_STARTED;
+        }
+        else if ( future.isCancelled() )
+        {
+            return STATUS_STOPPED;
+        }
+        else if ( future.isDone() )
+        {
+            return STATUS_DONE;
+        }
+        else
+        {
+            return STATUS_RUNNING;
+        }   
+    }
+}

=== added directory 'dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/system/startup'
=== added file 'dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/system/startup/AbstractStartupRoutine.java'
--- dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/system/startup/AbstractStartupRoutine.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/system/startup/AbstractStartupRoutine.java	2015-05-29 17:52:51 +0000
@@ -0,0 +1,82 @@
+package org.hisp.dhis.system.startup;
+
+/*
+ * Copyright (c) 2004-2015, University of Oslo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * Neither the name of the HISP project nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * Convenience class for creating startup routines. Contains a setter for the
+ * runlevel property which should be used in bean mappings.
+ * 
+ * @author <a href="mailto:torgeilo@xxxxxxxxx";>Torgeir Lorange Ostby</a>
+ */
+public abstract class AbstractStartupRoutine
+    implements StartupRoutine
+{
+    private String name = this.getClass().getSimpleName();
+    
+    public void setName( String name )
+    {
+        this.name = name;
+    }
+
+    private int runlevel = 0;
+
+    public void setRunlevel( int runlevel )
+    {
+        this.runlevel = runlevel;
+    }
+    
+    private boolean skipInTests = false;
+
+    public void setSkipInTests( boolean skipInTests )
+    {
+        this.skipInTests = skipInTests;
+    }
+    
+    // -------------------------------------------------------------------------
+    // StartupRoutine implementation
+    // -------------------------------------------------------------------------
+
+    @Override
+    public int getRunlevel()
+    {
+        return runlevel;
+    }
+    
+    @Override
+    public String getName()
+    {
+        return name;
+    }
+
+    @Override
+    public boolean skipInTests()
+    {
+        return skipInTests;
+    }
+}

=== added file 'dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/system/startup/DefaultStartupRoutineExecutor.java'
--- dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/system/startup/DefaultStartupRoutineExecutor.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/system/startup/DefaultStartupRoutineExecutor.java	2015-05-29 17:52:51 +0000
@@ -0,0 +1,125 @@
+package org.hisp.dhis.system.startup;
+
+/*
+ * Copyright (c) 2004-2015, University of Oslo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * Neither the name of the HISP project nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Default implementation of StartupRoutineExecutor. The execute method will
+ * execute the added StartupRoutines ordered by their runlevels. Startup routines
+ * can be ignored from the command line by appending the below.
+ * 
+ * <code>-Ddhis.skip.startup=true</code>
+ * 
+ * @author <a href="mailto:torgeilo@xxxxxxxxx";>Torgeir Lorange Ostby</a>
+ */
+public class DefaultStartupRoutineExecutor
+    extends AbstractStartupRoutine
+    implements StartupRoutineExecutor
+{
+    private static final Log LOG = LogFactory.getLog( DefaultStartupRoutineExecutor.class );
+
+    private static final String TRUE = "true";
+    private static final String SKIP_PROP = "dhis.skip.startup";
+    
+    private List<StartupRoutine> routines = new ArrayList<>();
+
+    // -------------------------------------------------------------------------
+    // Add methods
+    // -------------------------------------------------------------------------
+
+    @Override
+    public void addStartupRoutine( StartupRoutine routine )
+    {
+        routines.add( routine );
+    }
+
+    @Override
+    public void addStartupRoutines( Collection<StartupRoutine> routines )
+    {
+        for ( StartupRoutine routine : routines )
+        {
+            addStartupRoutine( routine );
+        }
+    }
+
+    // -------------------------------------------------------------------------
+    // Execute
+    // -------------------------------------------------------------------------
+
+    @Override
+    public void execute()
+        throws Exception
+    {
+        execute( false );
+    }
+    
+    @Override
+    public void executeForTesting()
+        throws Exception
+    {
+        execute( true );
+    }
+    
+    private void execute( boolean testing )
+        throws Exception
+    {
+        if ( TRUE.equalsIgnoreCase( System.getProperty( SKIP_PROP ) ) )
+        {
+            LOG.info( "Skipping startup routines" );
+            return;
+        }
+        
+        Collections.sort( routines, new StartupRoutineComparator() );
+
+        int total = routines.size();
+        int index = 1;
+
+        for ( StartupRoutine routine : routines )
+        {
+            if ( !( testing && routine.skipInTests() ) )
+            {
+                LOG.info( "Executing startup routine [" + index + " of " + total + ", runlevel " + routine.getRunlevel()
+                    + "]: " + routine.getName() );
+
+                routine.execute();
+                
+                ++index;
+            }
+        }
+
+        LOG.info( "All startup routines done" );
+    }
+}

=== added file 'dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/system/startup/StartupListener.java'
--- dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/system/startup/StartupListener.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/system/startup/StartupListener.java	2015-05-29 17:52:51 +0000
@@ -0,0 +1,100 @@
+package org.hisp.dhis.system.startup;
+
+/*
+ * Copyright (c) 2004-2015, University of Oslo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * Neither the name of the HISP project nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+import java.sql.Driver;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+import java.util.Enumeration;
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hisp.dhis.util.DebugUtils;
+import org.springframework.web.context.WebApplicationContext;
+import org.springframework.web.context.support.WebApplicationContextUtils;
+
+/**
+ * Implementation of {@link javax.servlet.ServletContextListener} which hooks
+ * into the context initialization and executes the configured
+ * {@link StartupRoutineExecutor}.
+ *
+ * @author <a href="mailto:torgeilo@xxxxxxxxx";>Torgeir Lorange Ostby</a>
+ */
+public class StartupListener
+    implements ServletContextListener
+{
+    private static final Log log = LogFactory.getLog( StartupListener.class );
+
+    // -------------------------------------------------------------------------
+    // ServletContextListener implementation
+    // -------------------------------------------------------------------------
+
+    @Override
+    public void contextInitialized( ServletContextEvent event )
+    {
+        WebApplicationContext applicationContext = WebApplicationContextUtils.getWebApplicationContext( event
+            .getServletContext() );
+
+        StartupRoutineExecutor startupRoutineExecutor = (StartupRoutineExecutor) applicationContext
+            .getBean( StartupRoutineExecutor.ID );
+
+        try
+        {
+            startupRoutineExecutor.execute();            
+        }
+        catch ( Exception ex )
+        {
+            log.error( DebugUtils.getStackTrace( ex ) );
+            
+            throw new RuntimeException( "Failed to run startup routines: " + ex.getMessage(), ex );
+        }
+    }
+
+    @Override
+    public void contextDestroyed( ServletContextEvent event )
+    {
+        Enumeration<Driver> drivers = DriverManager.getDrivers();
+        
+        while ( drivers.hasMoreElements() )
+        {
+            Driver driver = drivers.nextElement();
+            try
+            {
+                DriverManager.deregisterDriver( driver );
+                log.info( "De-registering jdbc driver: " + driver );
+            }
+            catch ( SQLException e )
+            {
+                log.info( "Error de-registering driver " + driver + " :" + e.getMessage() );
+            }
+        }
+    }
+}

=== added file 'dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/system/startup/StartupRoutine.java'
--- dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/system/startup/StartupRoutine.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/system/startup/StartupRoutine.java	2015-05-29 17:52:51 +0000
@@ -0,0 +1,70 @@
+package org.hisp.dhis.system.startup;
+
+/*
+ * Copyright (c) 2004-2015, University of Oslo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * Neither the name of the HISP project nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * Defines a startup routine which should be executed when the system is
+ * started. The runlevel can be used to group startup routines that are
+ * dependent on other startup routines, without too much detail and knowledge.
+ * 
+ * @author <a href="mailto:torgeilo@xxxxxxxxx";>Torgeir Lorange Ostby</a>
+ * @version $Id: StartupRoutine.java 5781 2008-10-01 12:12:48Z larshelg $
+ */
+public interface StartupRoutine
+{
+    /**
+     * Executes the startup routine. It should fail hard if it is required to be
+     * executed successfully, or if any other unexpected errors occur.
+     * 
+     * @throws Exception if anything goes wrong.
+     */
+    void execute()
+        throws Exception;
+
+    /**
+     * Returns the name of the startup routine.
+     * 
+     * @return the name.
+     */
+    String getName();
+    
+    /**
+     * StartupRoutines with lower runlevels will be executed before
+     * StartupRoutines with higher runlevel.
+     * 
+     * @return the runlevel for the StartupRoutine.
+     */
+    int getRunlevel();
+    
+    /**
+     * Returns whether this StartupRoutine is to be skipped in tests or not.
+     * @return true if this StartupRoutine is skipped in tests, false otherwise.
+     */
+    boolean skipInTests();
+}

=== added file 'dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/system/startup/StartupRoutineComparator.java'
--- dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/system/startup/StartupRoutineComparator.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/system/startup/StartupRoutineComparator.java	2015-05-29 17:52:51 +0000
@@ -0,0 +1,47 @@
+package org.hisp.dhis.system.startup;
+
+/*
+ * Copyright (c) 2004-2015, University of Oslo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * Neither the name of the HISP project nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+import java.util.Comparator;
+
+/**
+ * Compares StartupRoutines based on their runlevel values.
+ * 
+ * @author <a href="mailto:torgeilo@xxxxxxxxx";>Torgeir Lorange Ostby</a>
+ * @version $Id: StartupRoutineComparator.java 3217 2007-04-02 08:54:21Z torgeilo $
+ */
+public class StartupRoutineComparator
+    implements Comparator<StartupRoutine>
+{
+    @Override
+    public int compare( StartupRoutine routineA, StartupRoutine routineB )
+    {
+        return routineA.getRunlevel() - routineB.getRunlevel();
+    }
+}

=== added file 'dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/system/startup/StartupRoutineExecutor.java'
--- dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/system/startup/StartupRoutineExecutor.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/system/startup/StartupRoutineExecutor.java	2015-05-29 17:52:51 +0000
@@ -0,0 +1,64 @@
+package org.hisp.dhis.system.startup;
+
+/*
+ * Copyright (c) 2004-2015, University of Oslo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * Neither the name of the HISP project nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+import java.util.Collection;
+
+/**
+ * Executes a collection of StartupRoutines when the system is started.
+ * 
+ * @author <a href="mailto:torgeilo@xxxxxxxxx";>Torgeir Lorange Ostby</a>
+ */
+public interface StartupRoutineExecutor
+    extends StartupRoutine
+{
+    String ID = StartupRoutineExecutor.class.getName();
+
+    /**
+     * Executes the StartupRoutines for testing.
+     *
+     * @throws Exception on execution failure.
+     */
+    void executeForTesting()
+        throws Exception;
+
+    /**
+     * Adds a StartupRoutine for execution on system startup.
+     *
+     * @param routine the StartupRoutine to add.
+     */
+    void addStartupRoutine( StartupRoutine routine );
+
+    /**
+     * Adds a Collection of StartupRoutines for execution on system startup.
+     *
+     * @param routines the Collection of StartupRotines to add.
+     */
+    void addStartupRoutines( Collection<StartupRoutine> routines );
+}

=== added directory 'dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/system/velocity'
=== added file 'dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/system/velocity/VelocityManager.java'
--- dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/system/velocity/VelocityManager.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/system/velocity/VelocityManager.java	2015-05-29 17:52:51 +0000
@@ -0,0 +1,92 @@
+package org.hisp.dhis.system.velocity;
+
+/*
+ * Copyright (c) 2004-2015, University of Oslo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * Neither the name of the HISP project nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+import org.apache.velocity.VelocityContext;
+import org.apache.velocity.app.VelocityEngine;
+import org.apache.velocity.runtime.RuntimeConstants;
+import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader;
+
+import java.io.StringWriter;
+
+public class VelocityManager
+{
+    public static final String CONTEXT_KEY = "object";
+
+    private static final String RESOURCE_LOADER_NAME = "class";
+    private static final String VM_SUFFIX = ".vm";
+    
+    private VelocityEngine velocity;
+
+    public VelocityManager()
+    {
+        velocity = new VelocityEngine();
+        velocity.setProperty( RuntimeConstants.RESOURCE_LOADER, RESOURCE_LOADER_NAME );
+        velocity.setProperty( RESOURCE_LOADER_NAME + ".resource.loader.class", ClasspathResourceLoader.class.getName() );
+        velocity.setProperty( "runtime.log.logsystem.log4j.logger", "console" );
+        velocity.setProperty( "runtime.log", "" );
+                
+        velocity.init();
+    }
+
+    public VelocityEngine getEngine()
+    {
+        return velocity;
+    }
+
+    public String render( String template )
+    {
+        return render( null, template );
+    }
+    
+    public String render( Object object, String template )
+    {
+        try
+        {
+            StringWriter writer = new StringWriter();
+
+            VelocityContext context = new VelocityContext();
+
+            if ( object != null )
+            {
+                context.put( CONTEXT_KEY, object );
+            }
+
+            velocity.getTemplate( template + VM_SUFFIX ).merge( context, writer );
+
+            return writer.toString();
+
+            // TODO include encoder in context
+        } 
+        catch ( Exception ex )
+        {
+            throw new RuntimeException( "Failed to merge velocity template", ex );
+        }
+    }
+}

=== added file 'dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/util/AnnotationUtils.java'
--- dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/util/AnnotationUtils.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/util/AnnotationUtils.java	2015-05-29 17:52:51 +0000
@@ -0,0 +1,70 @@
+package org.hisp.dhis.util;
+
+/*
+ * Copyright (c) 2004-2015, University of Oslo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * Neither the name of the HISP project nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author Lars Helge Overland
+ */
+public class AnnotationUtils
+{
+    /**
+     * Returns methods on the given target object which are annotated with the
+     * annotation of the given class.
+     * 
+     * @param target the target object.
+     * @param annotationType the annotation class type.
+     * @return a list of methods annotated with the given annotation.
+     */
+    public static List<Method> getAnnotatedMethods( Object target, Class<? extends Annotation> annotationType )
+    {
+        final List<Method> methods = new ArrayList<>();
+        
+        if ( target == null || annotationType == null )
+        {
+            return methods;
+        }
+        
+        for ( Method method : target.getClass().getMethods() )
+        {
+            Annotation a = org.springframework.core.annotation.AnnotationUtils.findAnnotation( method, annotationType );
+            
+            if ( a != null )
+            {
+                methods.add( method );
+            }
+        }
+        
+        return methods;
+    }
+}

=== added file 'dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/util/ReflectionUtils.java'
--- dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/util/ReflectionUtils.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/util/ReflectionUtils.java	2015-05-29 17:52:51 +0000
@@ -0,0 +1,561 @@
+package org.hisp.dhis.util;
+
+/*
+ * Copyright (c) 2004-2015, University of Oslo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * Neither the name of the HISP project nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+import javassist.util.proxy.ProxyFactory;
+
+import org.hibernate.collection.spi.PersistentCollection;
+import org.hisp.dhis.util.functional.Function1;
+import org.hisp.dhis.util.functional.Predicate;
+import org.springframework.util.StringUtils;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * @author Lars Helge Overland
+ */
+public class ReflectionUtils
+{
+    /**
+     * Invokes method getId() for this object and returns the return value. An
+     * int return type is expected. If the operation fails -1 is returned.
+     *
+     * @param object object to call getId() on.
+     * @return The identifier.
+     */
+    public static int getId( Object object )
+    {
+        try
+        {
+            Method method = object.getClass().getMethod( "getId" );
+
+            return (Integer) method.invoke( object );
+        }
+        catch ( NoSuchMethodException ex )
+        {
+            return -1;
+        }
+        catch ( InvocationTargetException ex )
+        {
+            return -1;
+        }
+        catch ( IllegalAccessException ex )
+        {
+            return -1;
+        }
+    }
+
+    /**
+     * Fetch a property off the object. Returns null if the operation fails.
+     *
+     * @param object   the object.
+     * @param property name of the property to get.
+     * @return the value of the property or null.
+     */
+    public static String getProperty( Object object, String property )
+    {
+        try
+        {
+            property = property.substring( 0, 1 ).toUpperCase() + property.substring( 1, property.length() );
+
+            Method method = object.getClass().getMethod( "get" + property );
+
+            return (String) method.invoke( object );
+        }
+        catch ( NoSuchMethodException ex )
+        {
+            return null;
+        }
+        catch ( InvocationTargetException ex )
+        {
+            return null;
+        }
+        catch ( IllegalAccessException ex )
+        {
+            return null;
+        }
+    }
+
+    /**
+     * Sets a property for the supplied object. Throws an
+     * UnsupportedOperationException if the operation fails.
+     *
+     * @param object Object to modify
+     * @param name   Name of property to set
+     * @param value  Value the property will be set to
+     */
+    public static void setProperty( Object object, String name, String value )
+    {
+        Object[] arguments = new Object[]{ value };
+
+        Class<?>[] parameterTypes = new Class<?>[]{ String.class };
+
+        if ( name.length() > 0 )
+        {
+            name = "set" + name.substring( 0, 1 ).toUpperCase() + name.substring( 1, name.length() );
+
+            try
+            {
+                Method concatMethod = object.getClass().getMethod( name, parameterTypes );
+
+                concatMethod.invoke( object, arguments );
+            }
+            catch ( Exception ex )
+            {
+                throw new UnsupportedOperationException( "Failed to set property", ex );
+            }
+        }
+    }
+
+    /**
+     * Sets a property for the supplied object. Throws an
+     * UnsupportedOperationException if the operation fails.
+     *
+     * @param object     Object to modify
+     * @param namePrefix prefix of the property name to set
+     * @param name       Name of property to set
+     * @param value      Value the property will be set to
+     */
+    public static void setProperty( Object object, String namePrefix, String name, String value )
+    {
+        String prefixed = namePrefix + name.substring( 0, 1 ).toUpperCase() + name.substring( 1, name.length() );
+
+        setProperty( object, prefixed, value );
+    }
+
+    /**
+     * Returns the name of the class that the object is an instance of
+     * org.hisp.dhis.indicator.Indicactor returns Indicator.
+     *
+     * @param object object to determine className for.
+     * @return String containing the class name.
+     */
+    public static String getClassName( Object object )
+    {
+        return object.getClass().getSimpleName();
+    }
+
+    /**
+     * Test whether the object is an array or a Collection.
+     *
+     * @param value the object.
+     * @return true if the object is an array or a Collection, false otherwise.
+     */
+    public static boolean isCollection( Object value )
+    {
+        if ( value != null )
+        {
+            if ( value.getClass().isArray() || value instanceof Collection<?> )
+            {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    public static boolean isCollection( String fieldName, Object object, Class<?> type )
+    {
+        return isCollection( fieldName, object, type, null );
+    }
+
+    public static boolean isCollection( String fieldName, Object object, Class<?> type, Class<? extends Annotation> annotation )
+    {
+        Field field;
+
+        field = _findField( object.getClass(), fieldName );
+
+        if ( field == null )
+        {
+            return false;
+        }
+
+        if ( annotation != null )
+        {
+            if ( !field.isAnnotationPresent( annotation ) )
+            {
+                return false;
+            }
+        }
+
+        try
+        {
+            if ( Collection.class.isAssignableFrom( field.getType() ) )
+            {
+                ParameterizedType parameterizedType = (ParameterizedType) field.getGenericType();
+                Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
+
+                if ( actualTypeArguments.length > 0 )
+                {
+                    if ( type.isAssignableFrom( (Class<?>) actualTypeArguments[0] ) )
+                    {
+                        return true;
+                    }
+                }
+            }
+
+        }
+        catch ( ClassCastException e )
+        {
+            return false;
+        }
+
+        return false;
+    }
+
+    public static Method findGetterMethod( String fieldName, Object target )
+    {
+        return findGetterMethod( fieldName, target.getClass() );
+    }
+
+    public static Method findGetterMethod( String fieldName, Class<?> clazz )
+    {
+        String[] getterNames = new String[]{
+            "get",
+            "is",
+            "has"
+        };
+
+        Field field = _findField( clazz, StringUtils.uncapitalize( fieldName ) );
+        Method method;
+
+        if ( field != null )
+        {
+            for ( String getterName : getterNames )
+            {
+                method = _findMethod( clazz, getterName + StringUtils.capitalize( field.getName() ) );
+
+                if ( method != null )
+                {
+                    return method;
+                }
+            }
+        }
+
+        return null;
+
+    }
+
+    public static <T> T invokeGetterMethod( String fieldName, Object target )
+    {
+        Method method = findGetterMethod( fieldName, target );
+
+        if ( method != null )
+        {
+            return invokeMethod( target, method );
+        }
+
+        return null;
+    }
+
+    public static Method findSetterMethod( String fieldName, Object target )
+    {
+        if ( target == null || StringUtils.isEmpty( fieldName ) )
+        {
+            return null;
+        }
+
+        String[] setterNames = new String[]{
+            "set"
+        };
+
+        Field field = _findField( target.getClass(), StringUtils.uncapitalize( fieldName ) );
+        Method method;
+
+        if ( field != null )
+        {
+            for ( String setterName : setterNames )
+            {
+                method = _findMethod( target.getClass(), setterName + StringUtils.capitalize( field.getName() ), field.getType() );
+
+                if ( method != null )
+                {
+                    return method;
+                }
+            }
+        }
+
+        return null;
+    }
+
+    public static <T> T invokeSetterMethod( String fieldName, Object target, Object... args )
+    {
+        Method method = findSetterMethod( fieldName, target );
+
+        if ( method != null )
+        {
+            return invokeMethod( target, method, args );
+        }
+
+        return null;
+    }
+
+    public static boolean isType( Field field, Class<?> clazz )
+    {
+        Class<?> type = field.getType();
+
+        return clazz.isAssignableFrom( type );
+    }
+
+    private static Field _findField( Class<?> clazz, String name )
+    {
+        return _findField( clazz, name, null );
+    }
+
+    private static Field _findField( Class<?> clazz, String name, Class<?> type )
+    {
+        Class<?> searchType = clazz;
+
+        while ( !Object.class.equals( searchType ) && searchType != null )
+        {
+            Field[] fields = searchType.getDeclaredFields();
+
+            for ( Field field : fields )
+            {
+                // && (type == null || type.equals( field.getType() ))
+                if ( (name == null || name.equals( field.getName() )) )
+                {
+                    return field;
+                }
+            }
+
+            searchType = searchType.getSuperclass();
+        }
+
+        return null;
+    }
+
+    public static List<Field> getAllFields( Class<?> clazz )
+    {
+        Class<?> searchType = clazz;
+        List<Field> fields = new ArrayList<>();
+
+        while ( !Object.class.equals( searchType ) && searchType != null )
+        {
+            fields.addAll( Arrays.asList( searchType.getDeclaredFields() ) );
+            searchType = searchType.getSuperclass();
+        }
+
+        return fields;
+    }
+
+    public static List<String> getAllFieldNames( Class<?> klass )
+    {
+        List<Field> fields = getAllFields( klass );
+        List<String> fieldNames = new ArrayList<>();
+
+        for ( Field field : fields )
+        {
+            fieldNames.add( field.getName() );
+        }
+
+        return fieldNames;
+    }
+
+    private static Method _findMethod( Class<?> clazz, String name )
+    {
+        return _findMethod( clazz, name, new Class[0] );
+    }
+
+    private static Method _findMethod( Class<?> clazz, String name, Class<?>... paramTypes )
+    {
+        Class<?> searchType = clazz;
+
+        while ( searchType != null )
+        {
+            Method[] methods = (searchType.isInterface() ? searchType.getMethods() : searchType.getDeclaredMethods());
+
+            for ( Method method : methods )
+            {
+                if ( name.equals( method.getName() ) && (paramTypes == null || Arrays.equals( paramTypes, method.getParameterTypes() )) )
+                {
+                    return method;
+                }
+            }
+
+            searchType = searchType.getSuperclass();
+        }
+
+        return null;
+    }
+
+    public static Map<String, Method> getMethodMap( Class<?> klass )
+    {
+        Map<String, Method> methodMap = new HashMap<>();
+        List<Method> methods = getAllMethods( klass );
+
+        for ( Method method : methods )
+        {
+            methodMap.put( method.getName(), method );
+        }
+
+        return methodMap;
+    }
+
+    public static List<Method> getAllMethods( Class<?> clazz )
+    {
+        Class<?> searchType = clazz;
+        List<Method> methods = new ArrayList<>();
+
+        while ( searchType != null )
+        {
+            Method[] methodArray = (searchType.isInterface() ? searchType.getMethods() : searchType.getDeclaredMethods());
+            methods.addAll( Arrays.asList( methodArray ) );
+            searchType = searchType.getSuperclass();
+        }
+
+        return methods;
+    }
+
+    @SuppressWarnings( "unchecked" )
+    public static <T> T invokeMethod( Object target, Method method, Object... args )
+    {
+        if ( target == null || method == null )
+        {
+            return null;
+        }
+
+        if ( Modifier.isProtected( method.getModifiers() ) || Modifier.isPrivate( method.getModifiers() ) )
+        {
+            return null;
+        }
+
+        try
+        {
+            return (T) method.invoke( target, args );
+        }
+        catch ( InvocationTargetException | IllegalAccessException e )
+        {
+            throw new RuntimeException( e );
+        }
+    }
+
+    @SuppressWarnings( "unchecked" )
+    public static <T> T getFieldObject( Field field, T target )
+    {
+        return (T) invokeGetterMethod( field.getName(), target );
+    }
+
+    public static void executeOnFields( Class<?> clazz, Function1<Field> function )
+    {
+        executeOnFields( clazz, function, null );
+    }
+
+    public static void executeOnFields( Class<?> clazz, Function1<Field> function, Predicate<Field> predicate )
+    {
+        Class<?> currentType = clazz;
+
+        while ( !Object.class.equals( currentType ) && currentType != null )
+        {
+            Field[] fields = currentType.getDeclaredFields();
+
+            for ( Field field : fields )
+            {
+                if ( Modifier.isStatic( field.getModifiers() ) || (predicate != null && !predicate.evaluate( field )) )
+                {
+                    continue;
+                }
+
+                function.apply( field );
+            }
+
+            currentType = currentType.getSuperclass();
+        }
+    }
+
+    public static Collection<Field> collectFields( Class<?> clazz, Predicate<Field> predicate )
+    {
+        Class<?> type = clazz;
+        Collection<Field> fields = new ArrayList<>();
+
+        while ( !Object.class.equals( type ) && type != null )
+        {
+            Field[] declaredFields = type.getDeclaredFields();
+
+            for ( Field field : declaredFields )
+            {
+                if ( Modifier.isStatic( field.getModifiers() ) || (predicate != null && !predicate.evaluate( field )) )
+                {
+                    continue;
+                }
+
+                fields.add( field );
+            }
+
+            type = type.getSuperclass();
+        }
+
+        return fields;
+    }
+
+    public static <E> Collection<E> newCollectionInstance( Class<?> clazz )
+    {
+        if ( List.class.isAssignableFrom( clazz ) )
+        {
+            return new ArrayList<>();
+        }
+        else if ( Set.class.isAssignableFrom( clazz ) )
+        {
+            return new HashSet<>();
+        }
+        else
+        {
+            throw new RuntimeException( "Unknown Collection type." );
+        }
+    }
+
+    public static Class<?> getRealClass( Class<?> klass )
+    {
+        if ( ProxyFactory.isProxyClass( klass ) )
+        {
+            klass = klass.getSuperclass();
+        }
+
+        while ( PersistentCollection.class.isAssignableFrom( klass ) )
+        {
+            klass = klass.getSuperclass();
+        }
+
+        return klass;
+    }
+}

=== modified file 'dhis-2/dhis-support/dhis-support-system/pom.xml'
--- dhis-2/dhis-support/dhis-support-system/pom.xml	2015-05-29 13:54:46 +0000
+++ dhis-2/dhis-support/dhis-support-system/pom.xml	2015-05-29 17:52:51 +0000
@@ -37,21 +37,6 @@
       <groupId>org.hisp.dhis</groupId>
       <artifactId>dhis-support-test</artifactId>
     </dependency>
-
-    <!-- SpringFramework -->
-
-    <dependency>
-      <groupId>org.springframework</groupId>
-      <artifactId>spring-core</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>org.springframework</groupId>
-      <artifactId>spring-context</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>org.springframework</groupId>
-      <artifactId>spring-web</artifactId>
-    </dependency>
     
     <!-- JasperReports -->
 
@@ -126,10 +111,6 @@
         <artifactId>commons-lang3</artifactId>
     </dependency>
     <dependency>
-      <groupId>org.apache.velocity</groupId>
-      <artifactId>velocity</artifactId>
-    </dependency>
-    <dependency>
       <groupId>commons-codec</groupId>
       <artifactId>commons-codec</artifactId>
     </dependency>

=== modified file 'dhis-2/dhis-support/dhis-support-system/src/test/java/org/hisp/dhis/system/util/ReflectionUtilsTest.java'
--- dhis-2/dhis-support/dhis-support-system/src/test/java/org/hisp/dhis/system/util/ReflectionUtilsTest.java	2015-05-29 13:54:46 +0000
+++ dhis-2/dhis-support/dhis-support-system/src/test/java/org/hisp/dhis/system/util/ReflectionUtilsTest.java	2015-05-29 17:52:51 +0000
@@ -32,11 +32,11 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
-import static org.hisp.dhis.system.util.ReflectionUtils.getClassName;
-import static org.hisp.dhis.system.util.ReflectionUtils.getId;
-import static org.hisp.dhis.system.util.ReflectionUtils.getProperty;
-import static org.hisp.dhis.system.util.ReflectionUtils.isCollection;
-import static org.hisp.dhis.system.util.ReflectionUtils.setProperty;
+import static org.hisp.dhis.util.ReflectionUtils.getClassName;
+import static org.hisp.dhis.util.ReflectionUtils.getId;
+import static org.hisp.dhis.util.ReflectionUtils.getProperty;
+import static org.hisp.dhis.util.ReflectionUtils.isCollection;
+import static org.hisp.dhis.util.ReflectionUtils.setProperty;
 
 import java.util.ArrayList;
 import java.util.Collection;

=== modified file 'dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/view/AbstractGridView.java'
--- dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/view/AbstractGridView.java	2015-05-29 13:54:46 +0000
+++ dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/view/AbstractGridView.java	2015-05-29 17:52:51 +0000
@@ -35,7 +35,7 @@
 import org.hisp.dhis.common.NameableObject;
 import org.hisp.dhis.system.grid.ListGrid;
 import org.hisp.dhis.system.util.PredicateUtils;
-import org.hisp.dhis.system.util.ReflectionUtils;
+import org.hisp.dhis.util.ReflectionUtils;
 import org.springframework.web.servlet.view.AbstractView;
 
 import javax.servlet.http.HttpServletRequest;

=== modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-program/src/main/java/org/hisp/dhis/trackedentity/action/schedule/ScheduleCaseAggregateConditionAction.java'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-program/src/main/java/org/hisp/dhis/trackedentity/action/schedule/ScheduleCaseAggregateConditionAction.java	2015-05-29 13:54:46 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-program/src/main/java/org/hisp/dhis/trackedentity/action/schedule/ScheduleCaseAggregateConditionAction.java	2015-05-29 17:52:51 +0000
@@ -36,6 +36,7 @@
 import org.hisp.dhis.scheduling.CaseAggregateConditionSchedulingManager;
 import org.hisp.dhis.setting.SystemSettingManager;
 import org.hisp.dhis.system.scheduling.Scheduler;
+import org.hisp.dhis.user.CurrentUserService;
 
 import com.opensymphony.xwork2.Action;