Event-Based Example Products Linked to Classification

Problem: Sometimes an external system is only interested in data about products linked into a specific classification hierarchy (e.g., a website hierarchy) and needs different types of messages depending on whether a product has just been linked into the hierarchy ('create' to the external system), is in the hierarchy and has been edited ('modify' to the external system) or has been taken out of the hierarchy ('remove / delete' to the external system).

Assumptions: For this example the setup shown below is used and a number of assumptions are made.

  • Only leaf level (Sales Item) can be linked into the classification hierarchy and only leaves should be published.
  • The Product to Classification Link Type ('WebsiteLink') is only used for this specific website and all Sales Item objects in Approved that have the link should be on the website.

Solution: A naive approach to this problem could be to have an event filter condition for Sales Items that only let events for the objects with a WebsiteLink pass. The problem with this approach is that it would not allow you to detect the cases where a link has just been removed, so you would not be able to communicate this to the external system. Also, you would not be able to differentiate between cases where the link has just been added ('create' to an external system) and cases where a Sales Item already linked into the classification hierarchy has been modified.

A better approach is to use three derived events with IDs 'webAdd', 'webModify', and 'webRemove' in an event-based OIEP. The conditions for triggering the different events are listed below:

  • webAdd - Sales Item with WebsiteLink is approved for the first time; earlier approved Sales Item where WebsiteLink has been added is approved
  • webModify - Sales Item with WebsiteLink has been modified and is approved; externally maintained data for Sales Item with WebsiteLink in Approved is modified
  • webRemove - Earlier approved Sales Item where WebsiteLink has been removed is approved; Sales Item with WebsiteLink is approve deleted (core Delete Event)

Important: The following scripts are only an example and should not be used as-is without thorough testing.

A setup for this case could use the following triggering object types:

Event Filter - As data will be published based on derived events alone, all core events for Sales Items should be discarded. The script below does this and also, for debugging purposes, logs to the main Java log.

If logging is not required, the script could be:

return !(currentEventType instanceof com.stibo.core.domain.eventqueue.BasicEventType);

Event Generator - This logic is much more complex as it will have to perform the analysis to figure out which type of derived event should be generated. An example without logging is shown below. Notice that the business action should only generate derived events based on core events. If this check is not in place, an endless loop will be created.

The script uses the following bindings:

Keeping in mind that the following script is strictly to illustrate the solution, and can be difficult to read, this list outlines the intended logic:

  • Check if current event is a core event, do nothing if it is a derived event.
  • Check if the Approve Context is available. If so, the event is generated based on an approval. If not, the event is based on some other change, for example, externally maintained data being modified.
  • If Approve Context is available, use it to get hold of current object in both Main and Approved.
  • Check if current core event is a Delete.
  • Check for WebsiteLinks in Main and Approved.
  • If current event is a Delete, and current object has a WebsiteLink in Approved, generate a derived 'webRemove' event.
  • If current object has WebsiteLink in both Main and Approved, generate a derived 'webModify' event.
  • If none of the above, the Approve Context is used to figure out whether the addition or removal of a WebsiteLink is currently being approved (is a part object). The link type is not accessible directly from a ClassificationLinkPartObject and thus, the target classification object type is used to figure out if the link type is correct. Also, because there is a risk that the target classification does not exist in the Approved workspace and the link would not be synchronized even though it is in the part object set, it is checked that the classification exists there.
  • If WebsiteLink exists in Main and is to be approved, generate a derived 'webAdd' event.
  • If WebsiteLink exists in Approved and is to be approved, generate a derived 'webRemove' event.
  • If no Approve Context is available, check whether current object exists in Approved with WebsiteLink. If it does, generate derived 'webModify' event.
Copy
var prodClassLinkTypeID = "WebsiteLink"
var ClassObjTypeID = "WebLevel2";
var linkType = manager.getLinkTypeHome().getClassificationProductLinkTypeByID(prodClassLinkTypeID);

//Utility function to check whether a Classification exists in Approved

function classInApp(classID) {
    var res;
    manager.executeInWorkspace("Approved", function(appManager) {
        res = appManager.getClassificationHome().getClassificationByID(classID) != null;
    });
    return res;
}

if(currentEventType instanceof com.stibo.core.domain.eventqueue.BasicEventType) {
    var appProd;
    //Event generated based on an approval
    if(appContext) {
        var mainProd = appContext.getMainNode();
        appProd = appContext.getApprovedNodeBeforeApproval();
        var stepDelete = currentEventType == com.stibo.core.domain.eventqueue.BasicEventType.Delete;

        var linkInMain = !mainProd.getClassificationProductLinks().get(linkType).isEmpty();
        var linkInApp = false;

        if(appProd) {
            linkInApp = !appProd.getClassificationProductLinks().get(linkType).isEmpty();
        }

        //Case A - Prod has been delete approved and has link in Approved > WebRemove
        if(stepDelete && linkInApp) {
            currentEventQueue.queueDerivedEvent(webRemove, mainProd);
        }

        //Case B - Prod has link in both Main and Approved > WebModify
        else if(linkInMain && linkInApp) {
            currentEventQueue.queueDerivedEvent(webModify, mainProd);
        }
        else {
            var partObjects = appContext.getPartObjects().toArray();
            var linkToBeApproved = false;
            for(var i = 0; i < partObjects.length; i++) {
                if(partObjects[i] instanceof com.stibo.core.domain.partobject.ClassificationLinkPartObject) {
                   var currentClassID = partObjects[i].getClassificationID();
                   var currentClassObjTypeID = manager.getClassificationHome().getClassificationByID(currentClassID).getObjectType().getID();   
                   if(currentClassObjTypeID == ClassObjTypeID && classInApp(currentClassID)) {
                        linkToBeApproved = true;
                        break;   
                   }
               }
            }

            //Case C - Prod has link in Main but not in Approved and link is part object > WebAdd
            if(linkInMain && linkToBeApproved) {
                currentEventQueue.queueDerivedEvent(webAdd, mainProd);
            }
            
            //Case D - Prod has link in Approved but not in Main and link is part object > WebRemove
            if(linkInApp && linkToBeApproved) {
                currentEventQueue.queueDerivedEvent(webRemove, mainProd);
            }
        }
    }

     //Event based on republish or change to externally maintained data
    else {
        manager.executeInWorkspace("Approved", function(appManager) {
            appProd = appManager.getProductHome().getProductByID(currentObject.getID());
        });

         //Case E - Non approval based event has been generated and prod is in Approved with link > WebModify
        if (appProd && !appProd.getClassificationProductLinks().get(linkType).isEmpty()) {
            currentEventQueue.queueDerivedEvent(webModify, currentObject);
        }
    }
}   

Output Template - If different messages are to be output dependent on the selected derived event type, three output templates should be configured as shown below. This can be one or multiple lines, depending on the need for different messages for the different events.