Chapter 6. Extending SymmetricDS

Table of Contents

6.1. IParameterFilter
6.2. IDataLoaderFilter
6.3. ITableColumnFilter
6.4. IBatchListener
6.5. IAcknowledgeEventListener
6.6. IReloadListener
6.7. IExtractorFilter
6.8. ISyncUrlExtension
6.9. INodeIdGenerator
6.10. ITriggerCreationListener
6.11. IBatchAlgorithm
6.12. IDataRouter
6.13. IHeartbeatListener
6.14. IOfflineClientListener
6.15. IOfflineServerListener
6.16. INodePasswordFilter

SymmetricDS may be extended via a plug-in like architecture where extension point interfaces may be implemented by a custom class and registered with the synchronization engine. All supported extension points extend the IExtensionPoint interface. The currently available extension points are documented in the following sections.

When the synchronization engine starts up, a Spring post processor searches the Spring ApplicationContext for any registered classes which implement IExtensionPoint. An IExtensionPoint designates whether it should be auto registered or not. If the extension point is to be auto registered then the post processor registers the known interface with the appropriate service.

The INodeGroupExtensionPoint interface may be optionally implemented to designate that auto registered extension points should only be auto registered with specific node groups.

/**
 * Only apply this extension point to the 'root' node group.
 */
 public String[] getNodeGroupIdsToApplyTo() {
     return new String[] { "root" };
 }

SymmetricDS will look for Spring configured extensions in the application Classpath by importing any Spring XML configuration files found matching the following pattern: META-INF/services/symmetric-*-ext.xml. When packaged in a jar file the META-INF directory should be at the root of the jar file. When packaged in a war file, the META-INF directory should be in the WEB-INF/classes directory.

6.1. IParameterFilter

Parameter values can be specified in code using a parameter filter. Note that there can be only one parameter filter per engine instance. The IParameterFilter replaces the deprecated IRuntimeConfig from prior releases.

public class MyParameterFilter 
    implements IParameterFilter, INodeGroupExtensionPoint {

    /**
     * Only apply this filter to stores
     */
    public String[] getNodeGroupIdsToApplyTo() {
        return new String[] { "store" };
    }

    public String filterParameter(String key, String value) {
        // look up a store number from an already existing properties file.
        if (key.equals(ParameterConstants.EXTERNAL_ID)) {
            return StoreProperties.getStoreProperties().
              getProperty(StoreProperties.STORE_NUMBER);
        } 
        return value;
    }

    public boolean isAutoRegister() {
        return true;
    }

}

6.2. IDataLoaderFilter

Data can be filtered as it is loaded into the target database. It can also be filtered when it is extracted from the source database. As data is loaded into the target database, a filter can change the data in a column or save it somewhere else. It can also specify by the return value of the function call that the data loader should continue on and load the data (by returning true) or ignore it (by returning false). One possible use of the filter might be to route credit card data to a secure database and blank it out as it loads into a less-restricted reporting database.

An IDataLoaderContext is passed to each of the callback methods. A new context is created for each synchronization. The context provides methods to lookup column indexes by column name, get table meta data, and access to old data if the sync_column_level flag is enabled. The context also provides a means to share data during a synchronization between different rows of data that are committed in a database transaction and are in the same channel. It does so by providing a context cache which can be populated by the extension point.

Many times the IDataLoaderFilter will be combined with the IBatchListener. The XmlPublisherFilter (in the org.jumpmind.symmetric.ext package) is a good example of using the combination of the two extension points in order to create XML messages to be published to JMS.

A class implementing the IDataLoaderFilter interface is injected onto the DataLoaderService in order to receive callbacks when data is inserted, updated, or deleted.

public MyFilter implements IDataLoaderFilter {
                
    public boolean isAutoRegister() {
        return true;
    }
 
    public boolean filterInsert(IDataLoaderContext context,
        String[] columnValues) {
        return true;
    }
    
    public boolean filterUpdate(IDataLoaderContext context, 
        String[] columnValues, String[] keyValues) {
        return true;
    }
    
    public void filterDelete(IDataLoaderContext context, 
        String[] keyValues) {
        return true;
    }

}

The filter class is specified as a Spring-managed bean. A custom Spring XML file is specified as follows in a jar at META-INF/services/symmetric-myfilter-ext.xml.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-3.0.xsd">
 
    <bean id="myFilter" class="com.mydomain.MyFilter"/>
     
</beans>

6.3. ITableColumnFilter

Implement this extension point to filter out specific columns from use by the dataloader. Only one column filter may be added per target table.

6.4. IBatchListener

This extension point is called whenever a batch has completed loading but before the transaction has committed.

6.5. IAcknowledgeEventListener

Implement this extension point to receive callback events when a batch is acknowledged. The callback for this listener happens at the point of extraction.

6.6. IReloadListener

Implement this extension point to listen in and take action before or after a reload is requested for a Node. The callback for this listener happens at the point of extraction.

6.7. IExtractorFilter

This extension point is called after data has been extracted, but before it has been streamed. It has the ability to inspect each row of data to take some action and indicate, if necessary, that the row should not be streamed.

6.8. ISyncUrlExtension

This extension point is used to select an appropriate URL based on the URI provided in the sync_url column of sym_node.

To use this extension point configure the sync_url for a node with the protocol of ext://beanName. The beanName is the name you give the extension point in the extension xml file.

6.9. INodeIdGenerator

This extension point allows SymmetricDS users to implement their own algorithms for how node ids and passwords are generated or selected during the registration process. There may be only one node generator per SymmetricDS instance.

6.10. ITriggerCreationListener

Implement this extension point to get status callbacks during trigger creation.

6.11. IBatchAlgorithm

Implement this extension point and set the name of the Spring bean on the batch_algorithm column of the Channel table to use. This extension point gives fine grained control over how a channel is batched.

6.12. IDataRouter

Implement this extension point and set the name of the Spring bean on the router_type column of the Router table to use. This extension point gives the ability to programatically decide which nodes data should be routed to.

6.13. IHeartbeatListener

Implement this extension point to get callbacks during the heartbeat job.

6.14. IOfflineClientListener

Implement this extension point to get callbacks for offline events on client nodes.

6.15. IOfflineServerListener

Implement this extension point to get callbacks for offline events detected on a server node during monitoring of client nodes.

6.16. INodePasswordFilter

Implement this extension point to intercept the saving and rendering of the node password.