Tuesday, 7 June 2016

Understanding and Developing Custom Email Notifcation in OIM 11G R2P3


In this post I will talk about implementing a custom email notification event using OIM API.

By custom I mean, everything would be custom – ‘The Notification Resolver ‘, Templates, Triggering code :) 

Background:
OIM notification framework supports creation of custom notification events, templates and notification resolver apart from using default ones. It supports notification mechanism based on events, notification templates and template resolver. Following things are important while implementing custom notification service.

Notification Event:
An event is an operation that occurs in Oracle Identity Manager, such as user creation, request initiation, or any custom event created by the user.  Events are associated with Event Definitions. Event definition is the metadata that describes the event. This are defined as XML file and imported as part of MDS database in order to make notification event available for use.

Notification Template:
The templates are used for defining the format of the notification. A notification template is used to send notifications. The template supports text based and HTML based messages.It also supports different encoding formats .These templates contains the message and which could have some variables that gets replaced at run-time by resolver. Notification templates are associated to specific events.
You can create new notification templates and link them to the existing events (In this post we are going to create custom event and not using existing one). In addition, you can define new notification events by using notification APIs and resolver class, as described in the subsequent sections.
 
Notification Resolver Class:
As the name suggests, the resolver is a java class which is responsible to resolve or substitute the values for the variables defined in the notification template.

Notification Triggering Code:
This class will actually have the triggering logic /sending email notification. It makes use of NotificationService API.

Configuring the SMTP Service for Notification:
By default, the SMTP Email Notification Provider is disabled. This is enabled by setting the value of the enabled attribute to true. To configure SMTP Email Notification Provider properties by using the EmailNotificationProviderMBean,you'll have to login to EM Console and follow the link for detailed steps: https://docs.oracle.com/cd/E27559_01/admin.1112/e27149/notification.htm#OMADM873
 
Flow of Notification is:
The triggering code which is in process task, scheduler or event handler will be invoked based on the request type, from the code the template name and template parameters are identified. The event (selected while creating template) in it will be invoked that is nothing but the resolver class, so through the event the actual values of attributes will be substituted and a email will be sent to the receiver's email ids as defined in template parameter hash map.

Implementation:

Implementing the Resolver Class: 
To develop a custom resolver class, one has to implement interface oracle.iam.notification.impl.NotificationEventResolver and override the implemented methods with actual implementation. As mentioned earlier this would resolve the data dynamically at run-time. This interface has two methods:

The getAvailableData Method
public List<NotificationAttribute> getAvailableData(String eventType, Map<String, Object> params);
This API will return the list of available data variables. These variables will be available on the UI while creating/modifying the templates and would allow users to select the variables so that they can be embedded as a token as part of the messages on the template. These tokens are replaced by the value passed by the resolver class at run time. Available data is displayed in a drop down list.
The parameter "eventType" specifies the event Name for which template is to be read.
The parameter "params" is the map which has the entity name and the corresponding value for which available data is to be fetched
.

The getReplacedData Method
This API would return the resolved value of the variables present on the template at the runtime when notification is being sent.
The parameter "eventType" specifies the event Name for which template is to be read.
The parameter "params" is the map which has the base values such as usr_key, obj_keyetc required by the resolver implementation to resolve the rest of the variables in the template.
   
Use OimServer.jar to implement this interface.
public class CustomNotificationResolver implements NotificationEventResolver {
    /**
     * Returns the list of available data variables.
     * @see oracle.iam.notification.impl.NotificationEventResolver#getAvailableData
     * (java.lang.String, java.util.Map)
     */
    @Override
    public List<NotificationAttribute> getAvailableData
           (String eventType, Map<String, Object> params) {
         List<NotificationAttribute> listAvaiableData =
             new ArrayList<NotificationAttribute>();
         return listAvaiableData ;
     }
    /**
     * This method returns return the resolved value of the variables present in
     * the template at the runtime when notification is being sent.
     * @see oracle.iam.notification.impl.NotificationEventResolver#getReplacedData
     * (java.lang.String, java.util.Map)
     */
    @SuppressWarnings("rawtypes")
    @Override
    public HashMap<String, Object> getReplacedData
                (String eventType, Map<String, Object>
                eventParams) throws Exception {
                                            
        String methodName = "#getReplacedData()";
        UserManager userManager = Platform.getService(UserManager.class);
        HashMap<String, Object> resolverData =
                       new HashMap<String, Object>();
        logger.info(className + methodName + "  EventType : [" +
                    eventType + "]");
        // getting the notfication parameter
        String userKey = (String)eventParams.get("usr_key");
        logger.info(className + methodName + "Userkey : [" + userKey + "]");

        // Mapping token with their actual value for user attributes.
        if (userKey != null) {
            NotificationService notificationService =
              Platform.getService(NotificationService.class);
            // getting the list of all notification attributes
            List<NotificationAttribute> notificationAttributes =
                 notificationService.getStaticData(eventType);
            logger.info(className + methodName +
               " Notification Attributes: ["
                 +notificationAttributes + "]");
            // setting the attributes for user search
               based on the notification attributes
            Set<String> userReturnAttrs = new HashSet<String>();
            for (NotificationAttribute notificationAttribute :
                notificationAttributes.get(0).getSubtree()) {
                userReturnAttrs.add(notificationAttribute.getName());
            }
            logger.info(className + methodName +
             " User Attributes: [" +userReturnAttrs+ "]");
          //searching the user
          //searching the user by user key and retrive
            all attributes which are added in userRetAttrs
           User oUser = userManager.getDetails(userKey, userRetAttrs, false);
           HashMap<String, Object> userAttributes = oUser.getAttributes();
         
          logger.info(className + methodName +
          "Retrieving user with UserKey : [" + userKey +"]");
          // setting the values in the resolved notification data Map
          String key = null;
          for (Map.Entry<String, Object> entry : userAttributes.entrySet()) {
              key = entry.getKey();
              if (key != null) {
                  if ((entry.getValue() instanceof java.util.Map) &&
                        (key.equalsIgnoreCase(""))) {
                         key = key.replace(' ', '_');
                         resolverData.put(key,
                        ((HashMap)entry.getValue()).get(""));
                    } else {
                        key = key.replace(' ', '_');
                        resolverData.put(key, entry.getValue());
                    }
                }
            }
        
        }
        //returning the resolved data with all user information
        return resolverData;
       
    }
}

Creating Event Metadata:
<?xml version="1.0" encoding="UTF-8"?>
<Events xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../metadata/NotificationEvent.xsd">
  <EventType name="Custom Email Notification Event">
    <StaticData>
      <Attribute DataType="X2-Entity" EntityName="User" Name="User Login"/>
        </StaticData>
    <Resolver class="com.idm.notification.resolver.CustomNotificationResolver ">
      <Param DataType="X2-Entity" EntityName="User" Name="usr_key"/>
      </Resolver>
  </EventType>
</Events>



plugin.xml :


<?xml version="1.0" encoding="UTF-8"?>
<oimplugins xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <plugins pluginpoint="oracle.iam.notification.impl.NotificationEventResolver">
   <plugin pluginclass="com.idm.notification.resolver.CustomNotificationResolver"
                    version="1.0" name="CustomNotificationResolver"/>
    </plugins>
</oimplugins>


Implementing the Notification Event Triggering Code:
Now you may have a question,how exactly or what exactly will send/trigger the emails. OR where to write the notification logic ,what OIM entity i can use to send/trigger email and the answer is below.
OIM allows triggering email notification through: 
  • Process Tasks
  • Schedulers 
  • Event Handlers

We will see  "Process task" approach for sending email notification to users and user's manager on success of target resource provisioning :
1. Go to Design Console
2. Open Adapter Factory
3. Create a Process Task Adapter "SendEmailOnResourceProvisioning"
4. Create variables and Click on add task
5. Select the java method,here it is the below method and map the input variables
6. Click save and compile
7. Status should be OK


    /*This method sends notification to userand to its
        * @param userKey,userLogin,managersLogin
        * @return void
        * */
       public void sendEmailNotificationOnResourceProvisioning
                (String userKey,String
                userLogin, String managersLogin){
          String methodName = "#sendEmailNotificationOnResourceProvisioning()";
          logger.entering(className, methodName);
          String[] receiverUserIds = new String[] {userLogin, managersLogin};
          String templateName="Email Notification Demo";
          boolean status=this.notifyUser(userKey,receiverUserIds, templateName);
          logger.info(className + methodName+
                    "Email Notification Sent Successfully" +status);
          logger.exiting(className, methodName);
       }

Pass the notification template parameters:


       /**
        * This method is used to notify user
        * @param notificationTemplateName - Notification Template Name
        * @param userKey - user key of user
        * @param userLogin
        * @return status
        */
       private boolean notifyUser(String
                 userKey,String[] receiverUserIds, String  
                 notificationTemplateName) {
          String methodName = "#notifyUser";
          logger.log(Level.FINEST, className + " " +
                                   methodName + " START.");
                 HashMap<String, Object> templateParams =
                                   new HashMap<String, Object>();
          templateParams.put("usr_key", userKey);
          boolean status=sendNotification(receiverUserIds,
                       templateParams, notificationTemplateName);
          logger.log(Level.FINEST, className + " " + methodName + " END");
          return status;
    } 

Set the notification template parameters,NotificationEvent API is used to create the event  and set the event parameters:
/**This method sends notification to given receivers id's using notification event
     * @param receiverUserIds
     * @param templateParams
     * @param templateName
     * @return notificationStatus: Notification sent successfully or not
     * */
       public static boolean sendNotification(String[]
             receiverUserIds,HashMap<String, Object>
                 templateParams,String templateName) {

           String methodName = "#sendNotification()";
           logger.entering(className, methodName);
           boolean notificationStatus =false;
           NotificationEvent notificationEvent = new
                        NotificationEvent();
           NotificationService notificationService =
                      Platform.getService(NotificationService.class);
           try {
               notificationEvent.setUserIds(receiverUserIds);
               notificationEvent.setTemplateName(templateName);
               notificationEvent.setParams(templateParams);
               logger.info(className + privateMethodName +
                    "Notification Service params:
                     ["+notificationEvent+"]");
               notificationStatus = notificationService.
                              notify(notificationEvent);
               logger.info(className + privateMethodName
                        +"Email Notification Sent : "
                        + notificationStatus);
           } catch (UserDetailsNotFoundException e) {
              
               e.printStackTrace();
           } catch (EventException e) {
               e.printStackTrace();
           } catch (UnresolvedNotificationDataException e) {
               e.printStackTrace();
           } catch (TemplateNotFoundException e) {
               e.printStackTrace();
           } catch (MultipleTemplateException e) {
               e.printStackTrace();
           } catch (NotificationResolverNotFoundException e) {
               e.printStackTrace();
           } catch (NotificationException e) {
               e.printStackTrace();
           }
        return notificationStatus;
       }


8. After creating the process task adapter,go to process definition of the resource,let say OID/AD.
9. Create a Process task "Send Email Notification".Select the properties as required.
10.Select the adapter "SendEmailOnResourceProvisioning" from list  and map the variables.
11. Click Save.
12. Now open "Create User" process task and go to Responses tab.
13. From Responses ,select "SUCCESS" and click assign.
14. Now select the task we just created "Send Email Notification".
15. Click Save.
16. Provision a resource to a user whose email - id is set and also his managers id should be set to check the flow.
17. You can check the resource history if the task was triggered or not / successful or not.
18. If success ,an email should be sent to user and his manager.



Thanks !!

4 comments:

  1. Nice blog and absolutely outstanding. You can do something much better but i still say this perfect.Keep trying for the best. Email templates google workspace

    ReplyDelete
  2. Nice blog and absolutely outstanding. You can do something much better but i still say this perfect.Keep trying for the best. online calculator template

    ReplyDelete
  3. cool stuff you have got and you keep update all of us. create your own quiz

    ReplyDelete
  4. Really I enjoy your site with effective and useful information. It is included very nice post with a lot of our resources.thanks for share. i enjoy this post. media kit templates The intention of web templates is to design a web site.

    ReplyDelete