Skip to main content
Version: 3.4.6


Current Versions#


The code samples do contain the references listed above. Replace the reference with the specified version.

When upgrading, check your existing extensions and update the versions accordingly.

Project Setup#

Start with setting up the maven project configuration:

<project xmlns:xsi=""         xmlns=""         xsi:schemaLocation="">
    <modelVersion>4.0.0</modelVersion>    <groupId>com.agosense.symphony.process</groupId>    <artifactId>extension</artifactId>    <packaging>bundle</packaging>    <name>Process Extension</name>    <description>Process Extension</description>    <version>4.7.50</version>
    <parent>        <groupId>com.agosense.pom</groupId>        <artifactId>process</artifactId>        <version>#parent#</version>    </parent>
    <properties>        <custom.imports>            com.agosense.symphony.process.merge        </custom.imports>        <custom.exports>            com.agosense.symphony.process.extension        </custom.exports>    </properties>
    <dependencies>        <dependency>            <groupId>com.agosense.symphony.process</groupId>            <artifactId>merge</artifactId>            <version>#process#</version>            <scope>provided</scope>        </dependency>    </dependencies>

The package in this example is com.agosense.symphony.process.extension, referenced in custom.exports. When adjusting the package in your implementation, make sure you update the reference.

Create a default folder structure for a maven project and add the package to the source folder.

Extension Class#

The extension is implemented as a single class that provides an Extension style micro service in the applications OSGi environment:

@Component(provides = Extension.class)public class MyExtension implements Extension {

The @Component annotation is mandatory, otherwise the extension will not register properly.


The skip method is intended to let you decide if an object synchronization should be skipped. If you return Boolean.TRUE, that is the case. You can base your decision on the sourceObject or the targetObject:

    @Override    public Boolean skip(DataObject sourceObject, DataObject targetObject) {        return Boolean.TRUE;    }

The targetObject can be null in cases where no target object exists yet


The create method is executed short before the application is going to create a new target object. The data object targetCreate is what the application would use to create the new target object. The CreateResult that you provide back should contain your modifications to the targetCreate.


DataObject is an immutable object, you can not directly change it. Instead use the ImmutableDataObject.builder() to create a new object with your modifications

    @Override    public CreateResult create(        DataObject sourceObject,         DataObject targetCreate    ) {
        ImmutableDataObject.Builder targetBuilder = ImmutableDataObject.builder()                .putAllAttributes(targetCreate.attributes());
        targetBuilder.putAttributes("MyAttribute", ImmutableAttribute.builder()                .value(ImmutableValueString.builder()                        .value("MyValue")                        .build())                .build());
        return ImmutableCreateResult.builder()            .target(            .build();    }

Extension Context#

The extension context object is injected into the postCreate and update method to provide further flexibility. It contains a reference to the source and the target object through its source and target properties.

Each object reference provides the following properties:

  • url - The base url of the connection
  • id - The identifier of the object

Further more each object reference has an update method that allows to update the corresponding object using a DataObject.

Post Create#

The postCreate method is triggered short after a new target object was created. The extensionContext provided allows you to run updates on either the source or the target object.

    @Override    public void postCreate(        ExtensionContext context,         DataObject sourceObject,         DataObject targetObject    ) {"sourceUrl={}", context.source().url());"sourceId={}", context.source().id());"targetUrl={}",;"targetId={}",;    }


The update method is triggered short before the source and target object updates happen. The extensionContext provided allows you to run intermediate updates on either the source or the target object.

    @Override    public UpdateResult update(        ExtensionContext extensionContext,         DataObject sourceObject,         DataObject targetObject,         DataObject sourceUpdate,         DataObject targetUpdate    ) {        return ImmutableUpdateResult.builder()            .source(sourceUpdate)            .target(targetUpdate)            .build();    }


The name method is used to identify your extension. You have to make sure that the extension name is unqiue throughout the application.


The name is used to render the selection list of extensions in the user interface of the application. Make sure to use a readable and meaningful name.

    @Override    public String name() {        return "MyExtension";    }};


After you have successfully built your extension, copy it to the /bundle folder and restart the application in order to install it.


First remove the existing version of your extension from the /bundle folder, then copy the new version into that folder. Then stop the application, remove the /tmp/felix-cache folder and start the application.