Extensions
#
Current VersionsReference | Version |
---|---|
#parent# | 4.7.50 |
#process# | 4.9.4 |
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 SetupStart with setting up the maven project configuration:
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<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>
</project>
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 ClassThe 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.
#
Skip (deprecated)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; }
warning
The targetObject
can be null
in cases where no target object exists yet
note
Skipping of items was introduced when no query filtering was available to enable skipping specific items. Now that query filtering is available the skip extension point is deprecated and subject to be removed in one of the next releases. Please make sure to use a specific query instead matching your extension filter criteria.
#
MissingTargetThe missingTarget
method is executed when a persistence entry exists for a source issue but the target issue is missing unexpectedly. You can decide what to do in such a situation. One example would be to update a flag on the source object so that it is excluded from the query.
@Overridepublic void missingTarget( ExtensionContext context, DataObject sourceObject) throws AdapterException { ImmutableDataObject.Builder flagAttribute = ImmutableDataObject.builder() .putAttributes("includeInSync", ImmutableAttribute.builder() .value(ImmutableValueBoolean.builder() .value(Boolean.FALSE) .build()).build());
adapterContext.source().update().accept(flagAttribute.build()); }
note
DataObject
is an immutable object, you can not directly change it. Instead use the
ImmutableDataObject.builder()
to create a new object with your modifications
#
CreateThe 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
.
note
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(targetBuilder.build()) .build(); }
#
Extension ContextThe 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 CreateThe 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 ) {
LOGGER.info("sourceUrl={}", context.source().url()); LOGGER.info("sourceId={}", context.source().id());
LOGGER.info("targetUrl={}", context.target().url()); LOGGER.info("targetId={}", context.target().id()); }
#
UpdateThe 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(); }
#
NameThe name
method is used to identify your extension. You have to make sure that the
extension name is unqiue throughout the application.
note
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"; }};
#
Install ExtensionAfter you have successfully built your extension, copy it to the bundle/extensions
folder and restart the application
in order to install it.
#
Remove ExtensionTo remove the extension you simply need to remove the according jar file from the bundle/extensions
folder.
note
In case the extension is used in a sync already please unselect in the sync before removing it from the folder.
#
Update ExtensionFirst remove the existing version of your extension from the bundle/extensions
folder, then copy the new version into that
folder.
#
Workflow ManagerWhen specifying state mappings, state transitions can require multiple states to be transitioned in order to reach the target state. To support this use case you can use the workflow manager to define these paths along with mandatory fields per transition. To trigger state transitions before updating the item you could run the update on the workflow object using the input data:
Workflow workflow = ImmutableWorkflow.builder() .addTransitions( ImmutableTransition.builder().from("In Progress").to("Tested").addAllAttributes(Arrays.asList("MandatoryFieldA","MandatoryFieldA")).build(), ImmutableTransition.builder().from("To Do").to("In Progress").build(), ImmutableTransition.builder().from("Tested").to("Done").build(), ImmutableTransition.builder().from("In Progress").to("Rejected").build() ).build();
workflow.updateObject(context.target().update(), targetObject, targetUpdate, targetWorkflow, "Status");
targetWorkflow
will include all mapped target attributes with activated workflow
flag. These should match the mandatory fields specified on the state transitions and will be set when triggering the state updates.