Dashboard > DHIS Documentation > ... > Developer Documentation > Implement a DeletionHandler
  DHIS Documentation Log In | Sign Up   View a printable version of the current page.  
  Implement a DeletionHandler
Added by Lars Helge Ă˜verland, last edited by Lars Helge Ă˜verland on Apr 25, 2008  (view change)
Labels: 
(None)

Implement a DeletionHandler

When deleting objects it's necessary to remove associations from other objects since trying to delete an object referenced from other objects will cause a foreign key exception in the database. Firstly, removing these associations should be decoupled from the various service implementations since it would require lots of dependencies and restrict loose coupling. Secondly, including external modules in the system with objects with associations to the existing object model would cause problems when deleting objects in the core, as the core does not know about the existing objects or modules and cannot remove the associations itself.

To facilitate this DHIS 2 have a DeletionManager which is based on the Observer design pattern. All external modules with objects with associations to the existing object model should implement a DeletionHandler and register it as a listener with the DeletionManager. The following example of an imaginary Benchmark object explains how:

Implement a DeletionHandler

The DeletionHandler should extend the org.hisp.dhis.system.deletion.DeletionHandler abstract class. The implementation should be responsible for cleaning up its own associations to other objects by overriding the apporopriate methods from the superclass. Assume an object Benchmark with associations to DataElement and OrganisationUnit:

public class Benchmark
{
    private int id;
    private String name;
    private Collection<OrganisationUnit> units;
    private DataElement element;

    // more code
}

The corresponding DeletionHandler should look like this:

public class BenchmarkDeletionHandler
    extends DeletionHandler
{
    private BenchmarkService benchmarkService;

    // public set-method

    @Override
    public void deleteDataElement( DataElement dataElement )
    {
        for ( Benchmark benchmark : benchmarkSerice.getAllBenchmarks() )
        {
            if ( benchmark.getDataElement().equals( dataElement )
            {
                benchmark.setDataElement( null );
                benchmarkService.updateBenchmark( benchmark );
            }
        }
    }

    @Override // Notice Source instead of OrganisationUnit
    public void deleteSource( Source source )
    {
        for ( Benchmark benchmark : benchmarkSerice.getAllBenchmarks() )
        {
            if ( benchmark.getOrganisationUnits().remove( source ) )
            {
                benchmarkService.updateBenchmark( benchmark );
            }
        }
    }
}

Remember to map the DeletionHandler as a regular bean with dependencies in the Spring configuration (beans.xml).

Register the DeletionHandler as a listener with the DeletionManager

Put the following AOP configuration in the Spring configuration (beans.xml). If a configuration element already exists only append the DeletionHandler to the arguments list. The bean in the argument list refers to the bean id of the recently created BenchmarkDeletionHandler:

<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
    <property name="targetObject" ref="org.hisp.dhis.system.deletion.DeletionManager"/>
    <property name="targetMethod" value="addDeletionHandlers"/>
    <property name="arguments">
        <list>
            <list>
                <ref local="org.hisp.dhis.benchmark.BenchmarkDeletionHandler"/>
            </list>
        </list>
    </property>
</bean>

Set up the service delete method to be advised by the DeletionInterceptor

The DeletionManager must be executed prior to deleting the object. This is being done through the AOP features of Spring. Advise the delete method with the DeletionInterceptor like this:

<bean class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
    <property name="advice" ref="deletionInterceptor"/>
    <property name="patterns">
        <list>
            <value>.*\.BenchmarkService\.delete.*</value>
        </list>
    </property>
</bean>

That should be it. When a DataElement is deleted by a user, the deleteDataElement-method on every DeletionHandler registered as a listener will be invoked, and thus clean up all associations from other objects. For technical details have a look at the implementations in the org.hisp.dhis.system.deletion package in the dhis-support-system project.

Site powered by a free Open Source Project / Non-profit License (more) of Confluence - the Enterprise wiki.
Learn more or evaluate Confluence for your organisation.
Powered by Atlassian Confluence, the Enterprise Wiki. (Version: 2.5.6 Build:#812 Aug 06, 2007) - Bug/feature request - Contact Administrators