Content Synchronization with SAP and Nuxeo Integration


Thu 16 April 2015 By Mike Obrebski

The Nuxeo Platform is Designed to be Massively Extensible


One of the core constructs and guiding principles of the Nuxeo Platform is extensibility. Our users demonstrate a wide range of applications and often integrate with other systems and applications. As opposed to many other Content Management Systems, the Nuxeo Platform is inherently capable of being easily customized because it’s built on an extension framework. Behaviors can be modified or extended by simply deploying an XML based configuration file. Further, deploying functional additions is a matter of extending and implementing Nuxeo Java classes and associated XML based extension configuration.

Being designed with this in mind, requires minimal amount of overhead to extend and fit the Nuxeo platform into your environment and process. An appropriate analogy would be a Lego set delivered as a built product. Ready to go out of the box, but easily reconfigured without cutting anything off and easily customized by adding new pieces.

The SAP & Nuxeo Use Case


Let's demonstrate the above mentioned concepts with a specific use case and example as follows. Consider an environment where SAP is used along with the Nuxeo Platform. Here most business processes are handled by SAP, while the Nuxeo Platform is used for Document Management. In this example the content is Documentation publications related to the company's products. The products are managed in SAP and related to Documentation publications by a reference Part Number. We want to integrate by providing a link to the Documentation in the Nuxeo Platform from SAP while keeping these systems in sync, dynamically and reliably. The relationships of the systems should be transparent to the users and automatic.

Implementation


We will implement this from the Nuxeo Platform side by using the Event framework to respond to changes and making a Web Service call to SAP to deliver the changes and related information. The first phase is to create listeners and define the appropriate response conditions. Nuxeo already includes the necessary libraries to create SOAP based Web Service calls, so we will create an SAP Connector to make the particular call to SAP. This Web Service is defined in SAP to accept the appropriate information to update the referenced content with links to the Documentation publications in the Nuxeo Platform.

The Listeners


Nuxeo Event Bus Nuxeo Event Bus

The Event Bus receives more than 20 different event notifications related to changes to documents such as creation, modification, deletion, versioning, etc. We want to capture those that indicate the need to update content in SAP. We implement our own listeners by implementing the Nuxeo EventListener interface and registering it for the appropriate events. In our listener we need to filter for the chosen document type and the particular field of interest.

Implement the listener by implementing the EventListener interface:

public class FieldValueChangeCaptureListener implements EventListener {
...
public void handleEvent(Event event) throws ClientException {

First check for DocumentTypes, FieldNames, Changes, etc. and evaluate the Type of event. Basically check for the conditions needed to continue with the notification chain, for the given Document for which the event was called.

currentDoc = ((DocumentEventContext) ctx).getSourceDocument();
...
if (currentDoc == null || !currentDoc.getType().equals(DOCTYPE)) {
...
if (event.getName().equals(DocumentEventTypes.BEFORE_DOC_UPDATE)){
modified();
} else if (event.getName().equals(DocumentEventTypes.ABOUT_TO_REMOVE)){
removed();
...

Event responses can be synchronous or asynchronous. In the case of synchronous ones, this means that the listener has to complete its execution before the document transaction can complete. If we need to perform a longer job in response to an event it's best to transfer this to an asynchronous job, which will execute independent of the document modification or creation. In our case, since we're going to be calling a Web Service, we don't want a document modification transaction to be dependent on an external system. We will therefore send our own events into the event queue and create another listener to deal with our custom response processing.

In the initial event handler:

...
ctx.setProperty(FieldValueChangeActionListener.PREV_VALUES, null);
ctx.setProperty(FieldValueChangeActionListener.NEW_VALUES, newValues);
eventProducer.fireEvent(ctx.newEvent(FieldValueChangeActionListener.FIELD_CREATED_EVENT));

In the other asynchronous handler:

...
private void fieldCreated() throws ClientRuntimeException {
DocumentModel document = ((DocumentEventContext) ctx).getSourceDocument();
String[] newValues = (String[]) ctx.getProperty(NEW_VALUES);
String[] oldValues = (String[]) ctx.getProperty(PREV_VALUES);
Framework.getService(ServiceConnector.class).notify(document, oldValues, newValues);

SAP Connector


Finally, we create an SAP Connector that will make the Web Service call. It takes a list of part numbers to add and remove and the document link to update. Here we use already included CXF Web Service libraries to make a SOAP call to the the SAP endpoint. If we were to create various methods of notifications, we could also create a different implementation of the Connector and notify methods as alternatives to SOAP.

The SAPConnector showing relevant lines of code:

public class SAPConnector implements ServiceConnector {
...
private static final String SAP_USERNAME = Framework.getProperty("sap.username");
private static final String SAP_PASSWORD = Framework.getProperty("sap.password");
private static final String ENDPOINT_ADDRESS = Framework.getProperty("sap.endpoint");
...
public void notify(DocumentModel document, Serializable propertyValueBefore, Serializable propertyValueAfter) throws ClientRuntimeException {
...
Service service = Service.create(SERVICE_NAME);
// Add a port to the Service
service.addPort(PORT_NAME, SOAPBinding.SOAP11HTTP_BINDING, ENDPOINT_ADDRESS);
PartNumberMaintainURL port = service.getPort(PORT_NAME, PartNumberMaintainURL.class);
Client client = ClientProxy.getClient(port);
HTTPConduit http = (HTTPConduit) client.getConduit();
http.getAuthorization().setUserName(SAP_USERNAME);
http.getAuthorization().setPassword(SAP_PASSWORD);
...
response = port.UpdatePartNumbersURL(addedNumbers, removedNumbers, document.getTitle(), documentURL);
...


So, this is how you can synchronize content with SAP Integration. The code snippets here just outline some relevant sections, but you can try implementing similar responders. Check out the Events and Listeners documentation to explore more!

 


Category: Product & Development
Tagged: How to, Nuxeo Integration, SAP