=== 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 @@ + org.springframework + spring-core + + + org.springframework + spring-context + + + org.springframework + spring-web + + javax.servlet servlet-api @@ -44,10 +56,18 @@ jasperreports + org.hibernate + hibernate-core + + org.javassist javassist + org.apache.velocity + velocity + + org.scijava jep === 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> 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 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 Torgeir Lorange Ostby + */ +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. + * + * -Ddhis.skip.startup=true + * + * @author Torgeir Lorange Ostby + */ +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 routines = new ArrayList<>(); + + // ------------------------------------------------------------------------- + // Add methods + // ------------------------------------------------------------------------- + + @Override + public void addStartupRoutine( StartupRoutine routine ) + { + routines.add( routine ); + } + + @Override + public void addStartupRoutines( Collection 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 Torgeir Lorange Ostby + */ +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 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 Torgeir Lorange Ostby + * @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 Torgeir Lorange Ostby + * @version $Id: StartupRoutineComparator.java 3217 2007-04-02 08:54:21Z torgeilo $ + */ +public class StartupRoutineComparator + implements Comparator +{ + @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 Torgeir Lorange Ostby + */ +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 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 getAnnotatedMethods( Object target, Class annotationType ) + { + final List 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 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 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 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 getAllFields( Class clazz ) + { + Class searchType = clazz; + List fields = new ArrayList<>(); + + while ( !Object.class.equals( searchType ) && searchType != null ) + { + fields.addAll( Arrays.asList( searchType.getDeclaredFields() ) ); + searchType = searchType.getSuperclass(); + } + + return fields; + } + + public static List getAllFieldNames( Class klass ) + { + List fields = getAllFields( klass ); + List 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 getMethodMap( Class klass ) + { + Map methodMap = new HashMap<>(); + List methods = getAllMethods( klass ); + + for ( Method method : methods ) + { + methodMap.put( method.getName(), method ); + } + + return methodMap; + } + + public static List getAllMethods( Class clazz ) + { + Class searchType = clazz; + List 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 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 getFieldObject( Field field, T target ) + { + return (T) invokeGetterMethod( field.getName(), target ); + } + + public static void executeOnFields( Class clazz, Function1 function ) + { + executeOnFields( clazz, function, null ); + } + + public static void executeOnFields( Class clazz, Function1 function, Predicate 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 collectFields( Class clazz, Predicate predicate ) + { + Class type = clazz; + Collection 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 Collection 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 @@ org.hisp.dhis dhis-support-test - - - - - org.springframework - spring-core - - - org.springframework - spring-context - - - org.springframework - spring-web - @@ -126,10 +111,6 @@ commons-lang3 - org.apache.velocity - velocity - - commons-codec commons-codec === 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;