This site contains the documentation that is relevant to older WSO2 product versions and offerings.
For the latest WSO2 documentation, visit https://wso2.com/documentation/.

Notification E-mail Customization Sample

Axis2 Handler is one of many well-defined extension points supported by the WSO2 Governance Registry. Read more on Supported Extension Points for a complete list of extension points supported by WSO2 Governance Registry.

WSO2 Governance Registry generates notifications for events triggered by various operations performed on resources and collections stored in the repository. Notifications can be consumed in a variety of formats including E-mail. Read more about Notifications and also the API-Level Access provided for subscription operations. The contents of notification E-mails can be customized by using an Axis2 Handler. WSO2 Governance Registry contains an Apache Axis2 based runtime as a part of the WSO2 Carbon Framework. We will be reusing the code of the Handler Sample in this example. This sample requires Apache Maven. See Installation Prerequisites for more information on downloading this.

This sample also includes two advanced use-cases which have been included at the bottom of this page.

Instructions

1. Navigate to GREG_HOME/ samples/handler/src to find the source code of the Handler Sample.

2. Add a new Java Class named EmailTransformHandler at 

GREG_HOME/samples/handler/src/src/main/java/org/wso2/carbon/registry/samples/notifications/EmailTransformHandler.java with the following source:

package org.wso2.carbon.registry.samples.notifications;
 
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.xpath.AXIOMXPath;
import org.apache.axiom.soap.SOAPEnvelope;
import org.apache.axis2.AxisFault;
import org.apache.axis2.context.MessageContext;
import org.apache.axis2.engine.Handler;
import org.apache.axis2.handlers.AbstractHandler;
import org.jaxen.JaxenException;
 
import java.util.ArrayList;
 
public class EmailTransformHandler extends AbstractHandler implements Handler {
    private String name;
 
    public String getName() {
        return name;
    }
 
    public InvocationResponse invoke(MessageContext msgContext) throws AxisFault {
        if (msgContext.getTo() != null && msgContext.getTo().getAddress().startsWith("mailto:")) {
            try {
                SOAPEnvelope envelope = msgContext.getEnvelope();
                AXIOMXPath xPath = new AXIOMXPath("//ns:text");
                xPath.addNamespace("ns", "http://ws.apache.org/commons/ns/payload");
                OMElement element = (OMElement) ((ArrayList) xPath.evaluate(envelope)).get(0);
                element.setText(element.getText().replace("--", "This message was intercepted by " +
                        "EmailTransformHandler\n--"));
            } catch (JaxenException e) {
                e.printStackTrace();
            }
        }
        return InvocationResponse.CONTINUE;
    }
 
    public void revoke(MessageContext msgContext) {
    }
 
    public void setName(String name) {
        this.name = name;
    }
}

In order to add HTML formatted responses in your e-mail, you need to set the content type of the outgoing e-mail messages to text/html. This can be done as shown below.

msgContext.getOptions().setProperty(MailConstants.TRANSPORT_MAIL_CUSTOM_HEADERS, Collections.singletonMap("Content-Type", "text/html"));

3. Compile the source code by running the following command inside GREG_HOME/ samples/handler/src:

mvn clean install

The command mvn clean install will trigger an Apache Maven Build in your command line. This requires you having installed Apache Maven. See Installation Prerequisites for more information on downloading this.

A successful run of Apache Maven will generate a report similar to the following:

4. Copy the GREG_HOME/ samples/handler/src/target/ org.wso2.carbon.registry.samples.handler-4.5.0.jar into GREG_HOME/repository/components/dropins.

5. Add the EmailTransformHandler to the MessageOut phase in the OutFlow in  GREG_HOME/repository/conf/axis2/axis2.xml:

<phaseOrder type="OutFlow">
    <phase name="UEPPhase" />
    <phase name="RMPhase"/>
    <phase name="OpPhase"/>
    <phase name="OperationOutPhase"/>
    <phase name="PolicyDetermination"/>
    <!-- The E-mail Transform Handler is added to the MessageOut phase -->
    <phase name="MessageOut">
        <handler name="EmailTransformHandler"
                 class="org.wso2.carbon.registry.samples.notifications.EmailTransformHandler"/>
    </phase>
    <phase name="Security"/>
    <phase name="MsgOutObservation"/>
</phaseOrder>

The axis2.xml file already includes a phaseOrder section with the OutFlow type. You can either replace it with the content above, or simply add the EmailTransformHandler to the MessageOut phase:

<handler name="EmailTransformHandler"
         class="org.wso2.carbon.registry.samples.notifications.EmailTransformHandler"/>

This might be useful if you have already defined any other handlers in the Out Flow.

6. Configure Governance Registry to send E-mails in GREG_HOME/repository/conf/axis2/axis2.xml.

7. Start the server and observe the command prompt. See Running the Product on Windows or Running the Product on Linux and Solaris.

8. Navigate to the / collection of the Resource Browser and add an E-mail subscription for Update events.

Click the "Subscribe" button to create the subscription. Read about Managing the Resources and Managing Breadcrumb to learn how to navigate to the / collection. And read more about Managing Subscriptions.

9. Click on the E-mail Address verification link that you will receive via E-mail.

In this example, John Smith uses a Gmail account.

10. Make some update to the Root collection like adding a new property. Read Managing Properties to learn how to add a new property.

11. You should now receive a Notification E-mail which contains the following text:

This message was intercepted by EmailTransformHandler

See also Notifications and Managing Subscriptions.

Advanced Use-case 1

This sample can be improved to include a clickable link in the E-mail body, making it possible for users to easily navigate to the resources in which changes have been made. The following modification can be made to the code segment to achieve this:

In this example, John Smith uses a Gmail account. Gmail automatically converts URLs into clickable links. This might not be the case if you are using a traditional E-mail client. In such situations, you might have to embed HTML syntax to convert your URL into a clickable link.

package org.wso2.carbon.registry.samples.notifications;
 
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.xpath.AXIOMXPath;
import org.apache.axiom.soap.SOAPEnvelope;
import org.apache.axis2.AxisFault;
import org.apache.axis2.context.MessageContext;
import org.apache.axis2.engine.Handler;
import org.apache.axis2.handlers.AbstractHandler;
import org.apache.axis2.transport.mail.MailConstants;
import org.jaxen.JaxenException;
 
import java.util.ArrayList;
import java.util.Map;
 
public class EmailTransformHandler extends AbstractHandler implements Handler {
    private String name;
 
    public String getName() {
        return name;
    }
 
    public InvocationResponse invoke(MessageContext msgContext) throws AxisFault {
        String address = msgContext.getTo().getAddress();
        if (msgContext.getTo() != null && address.startsWith("mailto:")) {
            try {
                SOAPEnvelope envelope = msgContext.getEnvelope();
                AXIOMXPath xPath = new AXIOMXPath("//ns:text");
                xPath.addNamespace("ns", "http://ws.apache.org/commons/ns/payload");
                OMElement element = (OMElement) ((ArrayList) xPath.evaluate(envelope)).get(0);
                fixPath(msgContext, element);
                element.setText(element.getText().replace("--", "This message was intercepted by " +
                        "EmailTransformHandler\n--"));
            } catch (JaxenException e) {
                e.printStackTrace();
            }
        }
        return InvocationResponse.CONTINUE;
    }
 
    private void fixPath(MessageContext msgContext, OMElement element) {
        String subject = ((Map<String, String>) msgContext.getOptions().getProperty(
                MessageContext.TRANSPORT_HEADERS)).get(MailConstants.MAIL_HEADER_SUBJECT);
        if (!subject.contains("Updated")) {
            return;
        }
        String path = element.getText();
        path = path.substring(path.indexOf("path ") + "path ".length());
        path = path.substring(0, path.indexOf(" was updated"));
        element.setText(element.getText().replace("path " + path, "path https://localhost:9443/" +
                "carbon/resources/resource.jsp?region=region3&item=resource_browser_menu&path=" +
                path + "&screenWidth=1600"));
    }
 
    public void revoke(MessageContext msgContext) {
    }
 
    public void setName(String name) {
        this.name = name;
    }
}

In here, the link that we have used requires the user to sign-in to the management console to browse the resource. Such notifications are useful for approvals. However, there can be situations where those who approve do not need to sing-in to the management console. Such situations can be addressed by providing a clickable link that directs the user to a web service hosted on Governance Registry which does not require authentication. Learn more on how to add web services to Governance Registry by following the Endpoint Look-up Sample.

Please be informed that this might introduce a security risk unless necessary precautions have been taken. As a precaution, for example, a token can be generated at the point of notifying the user, which will also appear on the URL within the E-mail. The web service logic can validate the presence of this token to prevent fraudulent access.

Advanced Use-case 2

This sample can be improved to restrict which users will receive an E-mail notification. For example, it might be required to get an approval from a particular group of users before moving from one state to another. However, this E-mail might not make sense to be delivered to John Smith or Joe Bloggs. The following modification can be made to the code segment to restrict the recipients such that John Doe will receive this E-mail though John Smith or Joe Bloggs would not.

package org.wso2.carbon.registry.samples.notifications;
 
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.xpath.AXIOMXPath;
import org.apache.axiom.soap.SOAPEnvelope;
import org.apache.axis2.AxisFault;
import org.apache.axis2.context.MessageContext;
import org.apache.axis2.engine.Handler;
import org.apache.axis2.handlers.AbstractHandler;
import org.apache.axis2.transport.mail.MailConstants;
import org.jaxen.JaxenException;
 
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Map;
 
public class EmailTransformHandler extends AbstractHandler implements Handler {
    private String[] blacklist = {"john@smith.com", "joe@bloggs.co.uk"};
    private String name;
 
    public String getName() {
        return name;
    }
 
    public InvocationResponse invoke(MessageContext msgContext) throws AxisFault {
        String address = msgContext.getTo().getAddress();
        if (msgContext.getTo() != null && address.startsWith("mailto:")) {
            try {
                SOAPEnvelope envelope = msgContext.getEnvelope();
                AXIOMXPath xPath = new AXIOMXPath("//ns:text");
                xPath.addNamespace("ns", "http://ws.apache.org/commons/ns/payload");
                OMElement element = (OMElement) ((ArrayList) xPath.evaluate(envelope)).get(0);
                if (restrict(msgContext, address, element)) {
                    return InvocationResponse.ABORT;
                }
                element.setText(element.getText().replace("--", "This message was intercepted by " +
                        "EmailTransformHandler\n--"));
            } catch (JaxenException e) {
                e.printStackTrace();
            }
        }
        return InvocationResponse.CONTINUE;
    }
 
    private boolean restrict(MessageContext msgContext, String address, OMElement element) {
        final String checkItem = "Smoke Test Passed";
        final String state = "Testing";
        String subject = ((Map<String, String>) msgContext.getOptions().getProperty(
                MessageContext.TRANSPORT_HEADERS)).get(MailConstants.MAIL_HEADER_SUBJECT);
        return (subject.contains("CheckListItemChecked") && element.getText().contains(
                "CheckList item '" + checkItem + "' of LifeCycle State '" + state + "' was") &&
                Arrays.binarySearch(blacklist, address.substring("mailto:".length())) >= 0);
    }
 
    public void revoke(MessageContext msgContext) {
    }
 
    public void setName(String name) {
        this.name = name;
    }
}

In this example we have used the default ServiceLifeCycle. We have made the restriction in the code above for the event triggered by checking of the Smoke Test Passed checklist item of the Testing state. We have assumed that the Promote button which takes you to the Production state will be restricted to the role to which John Doe belongs. Note that the Transition Permissions must be properly set.

We have also assumed that the Smoke Test Passed checklist item will be the last to be checked in the Testing state and that the immediate next step would be the promotion to the Production state. Because only some users belonging to a particular role (such as John Doe in this case) will get the option to promote, it is required to keep the corresponding users informed, but not spam the others. This can be done by subscribing all users and blacklisting the ones who do not require receiving the E-mails. See below to learn how to subscribe all users for the Check LC Item event.

For this to work, each user on Governance Registry should fill out their User Profile.

In here, we have enumerated a list of E-mail addresses that would be treated as blacklisted. However, in a real-world scenario it might be cumbersome to hard-code all E-mail addresses. In such situations the User Management APIs of Governance Registry can be used. The UserRealm can be obtained from the The RegistryService Interface. This provides operations for managing users and roles. The E-mail address for a particular user can be obtained using claims.

An Axis2 Handler must implement the org.apache.axis2.engine.Handler interface and can optionally extend the org.apache.axis2.handlers.AbstractHandler class. Read more about Axis2 Handlers to get a better understanding of their uses.