Pages

Saturday, May 1, 2010

Lets SOA Suite UMS do your Application Messaging

With User Messaging Service you can let Soa Suite 11g do all your Messaging. And UMS can do a lot: like Email with Attachments, Instant Messaging (XMPP, like Google Talk), SMS Text messages (SMPP), Fax or Voice Messages and deliver messages to the Soa & Webcenter Task List. Besides this, UMS keeps track of delivery status information provided by messaging gateways and makes this information available to applications so that they can respond to a failed delivery.
In Patch Set 2 of Soa Suite 11g Oracle added a simple java API for UMS and in this blogpost I will use this API in a EJB Session Bean with a Remote Interface and also expose this Session Bean as a Web Service. This Session Bean & Web Service can be used in your custom applications so you don't need to have or build your own messaging methods because Soa Suite can do more and much better and even keeps track of your messages. Just call the Web Service or the Session Bean, deliver a list of Receivers with names and the media delivery type and it will return a MessageId with this you can check the status of your send messages.

In this blogpost I will use the email and instant messaging driver to deliver my messages. And as a demo I can send email attachements, deliver a message to IM and Email Client. ( Multi part Message , plain text part for IM and HTML part for Email ) and at last get retrieve the status of these messages. And you can use this in SoapUI, a web service proxy or in a EJB java client.

First you need to enable and configure the UMS Email and Instant Messaging Driver ( XMPP).
Go to the Weblogic console of your Soa Domain probably http://xxxxx:7001/console and select the XMPP UMS driver and go the the target tab and enable the Soa servers or soa cluster.

You need to reboot the Soa Server managed Servers.
In the User Messaging Service part of the Enterprise Manager Website http://xxxx:7001/em you can select the xmpp driver and go the XMPP Driver Properties.
In my case I will use Google Talk as IM service. Provide the server and a Talk user account.
Do the Same for your UMS Email driver. Provide the SMTP server.
And enable all the Work Flow communications in the WorkFlow Notifications Properties page of the Soa Infrastructure part..

You need to reboot the Soa Server managed Servers.

Now you can go to the developer part and create a JDeveloper project and add an new Application. Your project needs to have the UMS library located at jdeveloper\communications\modules\oracle.sdp.messaging_11.1.1\sdpmessaging.jar and your application also needs to have a reference to the oracle.sdp.messaging shared library. Do this in the weblogic-application.xml.
This EJB / WS needs to deployed on the Soa Suite Managed Servers.

To make things more simple I made two entities Receiver and Status.
The Receiver just needs an email address and type ( EMAIL or IM )
package nl.whitehorses.soa.ums.entities;

import java.io.Serializable;

public class Receiver implements Serializable{
    public Receiver() {

    }

    private String receiver;
    private String channel;

    public Receiver(String receiver, String channel) {
        super();
        this.receiver = receiver;
        this.channel = channel;
    }

    public void setReceiver(String receiver) {
        this.receiver = receiver;
    }

    public String getReceiver() {
        return receiver;
    }

    public void setChannel(String channel) {
        this.channel = channel;
    }

    public String getChannel() {
        return channel;
    }
}
The Status entity gives some simple info about the send messages.
package nl.whitehorses.soa.ums.entities;

import java.io.Serializable;
import java.util.Date;

public class Status implements Serializable {
    public Status() {
    }
      
    private String messageId;
    private Date   sendTime;
    private String receiver;
    private String status;

    public Status(String messageId, Date sendTime, String receiver,
                  String status) {
        super();
        this.messageId = messageId;
        this.sendTime = sendTime;
        this.receiver = receiver;
        this.status = status;
    }

    public void setMessageId(String messageId) {
        this.messageId = messageId;
    }

    public String getMessageId() {
        return messageId;
    }

    public void setSendTime(Date sendTime) {
        this.sendTime = sendTime;
    }

    public Date getSendTime() {
        return sendTime;
    }

    public void setReceiver(String receiver) {
        this.receiver = receiver;
    }

    public String getReceiver() {
        return receiver;
    }

    public void setStatus(String status) {
        this.status = status;
    }

    public String getStatus() {
        return status;
    }
    
    public String toString() {
      return "message id: "+ messageId+" time: "+sendTime.toString()+ " status: " +status + " receiver: " + receiver;  
    }
}
Here the main code with three method sendMailAttachmentMsg, sendMixedMsg and getMessageStatus.
The sendMailAttachmentMsg method will only send Mail with Attachments and sendMixedMsg method can send messages to Google Talk and Email, it depends on the receivers and getMessageStatus returns the Statusses of the send messages.
package nl.whitehorses.soa.ums.services;


import javax.ejb.Remote;
import javax.ejb.Stateless;

import java.util.HashMap;
import java.util.Map;

import java.util.ArrayList;
import java.util.List;

import javax.activation.DataHandler;

import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;

import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMultipart;

import nl.whitehorses.soa.ums.entities.Receiver;
import nl.whitehorses.soa.ums.utilities.ReceiverConvertor;

import oracle.sdp.messaging.Address;
import oracle.sdp.messaging.ApplicationInfo;
import oracle.sdp.messaging.DeliveryType;
import oracle.sdp.messaging.Message;
import oracle.sdp.messaging.MessagingFactory;
import oracle.sdp.messaging.MessagingClient;
import oracle.sdp.messaging.MessagingClientFactory;
import oracle.sdp.messaging.MessagingException;
import oracle.sdp.messaging.Status;
import oracle.sdp.messaging.util.ByteArrayDataSource;
import oracle.sdp.messaging.util.StringDataSource;

@Stateless(name="SessionEJB", mappedName = "SoaUMSMessaging-SessionEJB")
@Remote
@WebService(name        = "UMSMessagingService", 
            serviceName = "UMSMessagingService",
            portName    = "UMSMessagingServicePort")
public class SessionEJBBean implements SessionEJB {

    MessagingClient mClient = null;
    Map<String, Object> params = new HashMap<String, Object>();

    public SessionEJBBean() {
      params.put(ApplicationInfo.APPLICATION_NAME, "CompanyMsgr");
      params.put(ApplicationInfo.APPLICATION_INSTANCE_NAME, "CompanyInstance");
    }

    @WebMethod
    @WebResult(name = "messageId")
    public String sendMailAttachmentMsg(
                                        @WebParam(name = "sender")    String sender, 
                                        @WebParam(name = "receivers") List<Receiver> receivers,
                                        @WebParam(name = "subject")   String subject,
                                        @WebParam(name = "message")   String message,
                                        @WebParam(name = "data") byte[] data,
                                        @WebParam(name = "mimetype") String mimetype,
                                        @WebParam(name = "filename") String fileName) {

      MimeMultipart mp = null;

      try {
          // plain msg for the body
          MimeBodyPart mp_partPlain = new MimeBodyPart();
          mp_partPlain.setText(message);
        
          // binary attachement
          MimeBodyPart mp_partBinary = new MimeBodyPart();
          ByteArrayDataSource dataSource = new ByteArrayDataSource(data, mimetype);
          mp_partBinary.setDataHandler(new DataHandler(dataSource));
          mp_partBinary.setFileName(fileName);

          mp = new MimeMultipart("alternative");
          mp.addBodyPart(mp_partPlain);
          mp.addBodyPart(mp_partBinary);
      
      } catch (javax.mail.MessagingException e) {
          e.printStackTrace();
      }   

        try {
          Message soaMessage = MessagingFactory.createMessage();
          Address soaSender =
              MessagingFactory.buildAddress(sender, 
                                            DeliveryType.EMAIL,
                                            null);

          soaMessage.setSubject(subject);
          soaMessage.setContent(mp, "multipart/alternative");
          
          soaMessage.addSender(soaSender);
          soaMessage.addAllRecipients(ReceiverConvertor.convertReceiver(receivers));

          mClient = MessagingClientFactory.createMessagingClient(params);
          String messageId = mClient.send(soaMessage);
          return messageId;

        } catch (MessagingException e) {
             e.printStackTrace();
        }
 
        return null;
    }


    @WebMethod
    @WebResult(name = "statusses")    
    public List<nl.whitehorses.soa.ums.entities.Status> getMessageStatus(
            @WebParam(name = "messageId") String messageId) {

        try {
            mClient = MessagingClientFactory.createMessagingClient(params);
            Status[] msgStatuses = mClient.getStatus(messageId);
            List<nl.whitehorses.soa.ums.entities.Status> statusses =
                new ArrayList<nl.whitehorses.soa.ums.entities.Status>();

            for (Status msgStatus : msgStatuses) {
                nl.whitehorses.soa.ums.entities.Status status =
                    new nl.whitehorses.soa.ums.entities.Status();
                status.setMessageId(msgStatus.getMessageId());
                status.setReceiver(msgStatus.getAddress().toString());
                status.setStatus(msgStatus.getType().toString());
                status.setSendTime(msgStatus.getDate().getTime());
                statusses.add(status);
            }
            return statusses;
        } catch (MessagingException e) {
            e.printStackTrace();
        }
        return null;
    }

    @WebMethod
    @WebResult(name = "messageId")
    public String sendMixedMsg(@WebParam(name = "subject") String subject,
                               @WebParam(name = "message") String message, 
                               @WebParam(name = "sender") String sender, 
                               @WebParam(name = "receivers") List<Receiver> receivers) {


        Message soaMessage = MessagingFactory.createMessage();
        MimeMultipart part_mp = null;

        try {
          // IM Message  
          MimeBodyPart part_mp_partPlain = new MimeBodyPart();
          // set IM  
          part_mp_partPlain.addHeader(soaMessage.HEADER_SDPM_PAYLOAD_PART_DELIVERY_TYPE,
                                      "IM");
          part_mp_partPlain.setText(message);
 
          // Email Message             
          MimeBodyPart part_mp_partRich = new MimeBodyPart();
          // set Email  
          part_mp_partRich.addHeader(soaMessage.HEADER_SDPM_PAYLOAD_PART_DELIVERY_TYPE,
                                     "EMAIL");
          StringDataSource htmlDataSource = 
              new StringDataSource("<html><head></head><body><b><i>"+
                                   message+ 
                                   "</i></b></body></html>",
                                   "text/html; charset=UTF-8");
          part_mp_partRich.setDataHandler(new DataHandler(htmlDataSource));
    
          part_mp = new MimeMultipart("alternative");
          part_mp.addBodyPart(part_mp_partPlain);
          part_mp.addBodyPart(part_mp_partRich);

        } catch (javax.mail.MessagingException b) {
              b.printStackTrace();
        }


        try {
            mClient = MessagingClientFactory.createMessagingClient(params);

            soaMessage.setSubject(subject);
            soaMessage.setContent(part_mp, "multipart/alternative");
            // Enabled for IM and Email
            soaMessage.setMultiplePayload(true);

            Address soaSender = MessagingFactory.buildAddress(sender,
                                                              DeliveryType.EMAIL,
                                                              null);

            soaMessage.addSender(soaSender);
            soaMessage.addAllRecipients(ReceiverConvertor.convertReceiver(receivers));

            String messageId = mClient.send(soaMessage);
            return messageId;
        } catch (oracle.sdp.messaging.MessagingException b) {
            b.printStackTrace();
        }
        return null;
    }

}

My EJB test client
package nl.whitehorses.soa.ums;

import java.io.FileInputStream;
import java.io.FileNotFoundException;

import java.io.IOException;

import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

import java.util.ArrayList;
import java.util.Hashtable;

import java.util.List;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

import nl.whitehorses.soa.ums.entities.Receiver;
import nl.whitehorses.soa.ums.entities.Status;
import nl.whitehorses.soa.ums.services.SessionEJB;

public class SessionEJBClient {
    public static void main(String[] args) {
        try {
            final Context context = getInitialContext();
            SessionEJB sessionEJB =
                (SessionEJB)context.lookup("SoaUMSMessaging-SessionEJB#nl.whitehorses.soa.ums.services.SessionEJB");

            List<Receiver> receivers = new ArrayList<Receiver>();
            Receiver receiver  = new Receiver("xxx@gmail.com", "EMAIL");
            Receiver receiver2 = new Receiver("xxxx@tiscali.nl", "EMAIL");
            receivers.add(receiver);
            receivers.add(receiver2);



            String messageId =
                sessionEJB.sendMailAttachmentMsg( "xxxx@xs4all.nl",
                                                   receivers,
                                                   "hello subject",
                                                   "hello body"
                                                   ,doDownload("C:/temp/logo.png"),
                                                   "image/png",
                                                   "logo.png");

            System.out.println("MessageId is " + messageId +
                               " lets wait 2 seconds for the status");
            Thread.sleep(2000);

            if (messageId != null) {
              List<Status> statusses =
                  sessionEJB.getMessageStatus(messageId);
              for (Status status : statusses) {
                  System.out.println(status.toString());
              }
            }


            Receiver receiver3 = new Receiver("nl2en@bot.talk.google.com", "IM");
            receivers.add(receiver3);

            messageId = sessionEJB.sendMixedMsg("Hello",
                                                "Hello world",
                                                "xxxx@xs4all.nl",
                                                receivers );


            System.out.println("MessageId is " + messageId +
                               " lets wait for the status");
            Thread.sleep(4000);

            if (messageId != null) {
                List<Status> statusses =
                    sessionEJB.getMessageStatus(messageId);
                for (Status status : statusses) {
                    System.out.println(status.toString());
                }
            }

        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    private static Context getInitialContext() throws NamingException {
        Hashtable env = new Hashtable();
        env.put(Context.INITIAL_CONTEXT_FACTORY,
                "weblogic.jndi.WLInitialContextFactory");
        env.put(Context.PROVIDER_URL, "t3://localhost:8001");
        return new InitialContext(env);
    }

    public static byte[] doDownload(String fileName) {
        FileInputStream fis;
        byte[] data = null;
        FileChannel fc;

        try {
            fis = new FileInputStream(fileName);
            fc = fis.getChannel();
            data = new byte[(int)(fc.size())];
            ByteBuffer bb = ByteBuffer.wrap(data);
            fc.read(bb);
        } catch (FileNotFoundException e) {
            // TODO
        } catch (IOException e) {
            // TODO
        }
        return data;
    }
}
If you send messages with this EJB Session or WS then you can take a look at the application client in the UMS service overview.

Here you can download my example workspace.

24 comments:

  1. Hi Edwin,

    Thanks for this wonderful post, it helped me a lot. I am trying to have this EJB deployed in a remote server and connect to some other UMS server, isn't this possible? I tried by setting the params.put(ApplicationInfo.SDPM_SERVER_JNDI_PROVIDER_URL, "t3://:7001"); in the SessionEJBBean.java file in the Messaging project, but this didn't work. Can you please throw some light here?

    Thanks,
    Sudan

    ReplyDelete
  2. Ok,

    can you check if the port 8001 is the right one, it runs on the soa server.

    can you try from a java class with a main , if that works, it should also work on a remote server.

    thanks

    ReplyDelete
  3. Hi Edwin,

    Thanks for the response. My exact problem is when I run the below code
    sendConfig.put(ApplicationInfo.APPLICATION_NAME, "app1");
    sendConfig.put(ApplicationInfo.APPLICATION_INSTANCE_NAME,"appInstance1");
    sendConfig.put(ApplicationInfo.SDPM_SERVER_JNDI_PROVIDER_URL, "t3://xyz.com:7001");


    MessagingClientFactory.createMessagingClient(sendConfig);

    and running this in a UMS server, say abc.com and trying to connect to the UMS server xyz.com running at 7001. It always sends message through the abc.com ums server only..How can I make it to use the xyz.com UMS server..Is my setting for JNDI_PROVIDER_URL is wrong?

    Thanks,
    Sudan

    ReplyDelete
  4. Hi,

    I think everything works on the SOA server so use that port. 7001 is the adminserver , and this is only the case when you do a developer SOA install.

    It's probably 8001

    And I think you don't need to set this property here . You need to do this in the enterprise manager web app. And off course enable everything about humantasks in the em

    Thanks Edwin

    ReplyDelete
  5. Hi Edwin,

    Thanks for the nice article. I have a simple java class to send a message using UMS java API.

    public String sendNotification(String senderId, String recipientId, String subject, String msg, String channel ){

    ApplicationInfo appInfo = new ApplicationInfo();
    appInfo.setApplicationName("ServiceApp");
    appInfo.setApplicationInstanceName("ServiceAppInstance");
    appInfo.setJNDIInitialFactory("weblogic.jndi.WLInitialContextFactory");
    appInfo.setSecurityPrincipal("weblogic");
    appInfo.setSecurityCredentials("weblogic1");
    appInfo.setServerJNDIProviderURL("t3://abc.com:7012");
    mClient = MessagingClientFactory.createMessagingEJBClient(appInfo);
    String messageId = mClient.send(message);
    }
    abc.com:7012 is where the soa_server is running.

    when I invoke the above method from the main() it throws,

    oracle.sdp.messaging.MessagingException: Error occured while creating the Messaging Client instance: : null
    Cause: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file: java.naming.factory.initial
    at oracle.sdpinternal.messaging.MessagingClientFactoryInternal.createMessagingEJBClient(MessagingClientFactoryInternal.java:219)
    at oracle.sdp.messaging.MessagingClientFactory.createMessagingEJBClient(MessagingClientFactory.java:115)

    I configured everything as per ur post.

    Can you please throw some light here?

    ReplyDelete
  6. Hi Edwin,

    Is it possible to use the UMS Java API in a plain Java Class instead of EJB session bean to send the messages?
    Also, Is it possible to register(through Messaging Client API) the java class with the SOA/ UMS server without deploying it?

    thanks,
    Nag

    ReplyDelete
  7. Hi,

    Don't know if you can do it from a java client. I think I got some security exceptions or it is not supported

    mClient = MessagingClientFactory.createMessagingClient(params);

    So I deployed it to the soa server and invoke my web service.

    thanks

    ReplyDelete
  8. Dear Edwin,

    I have a requirement of sending Fax from SOA. But couldnot get anything regardimg the same. Is it possible for you to help me with this.

    Thanks in advance.


    Regards
    Vaibhav

    ReplyDelete
    Replies
    1. Hi,

      I know some products who are integrated in the email server , so you can send it like a email.

      but do you want to build it yourself.

      thanks

      Delete
  9. Hi Edwin,

    Thanks for ur response. Posting a new comment as I was not able to reply to ur comment.

    Well I am thinking of building it myself. Can you suggest how can I start with it.
    However if there are products who are already integrated I would like to know them too.
    I have to send sms also.. for that I am trying to use SMPP. Did all some config on server but still have to find SMS Server. Can you help me wth that too???

    I have a question, why is it that NotificationService.wsdl already has FaxNotificationMessagetype if it is not supported.

    ************************************************



    ************************************************


    Thanks.
    Vaibhav

    ReplyDelete
    Replies
    1. Sorry you have to do it yourself,

      Fax is old technology and there many applications which you can buy and does it really well and you got support. Else it will take months with lot of bugs, not worth it doing it yourself.

      and look for a commercial sms server, there is no free one, you need to buy a package bundle of 10.000 text messages.

      thanks

      Delete
  10. In Patch Set 2 of Soa Suite 11g Oracle added a simple java API for UMS. Can UMS be exposed as is as a web service? Do we really need to write an EJB session bean with remote interface and then expose it? It just looks like something that should have already be done by Oracle rather than having every body develop their own version of the web service. Iwould appreciate you thoughts on this.

    ReplyDelete
    Replies
    1. Indeed, they do it for HumanTask.

      I think it is supposed to be for SOA only and not for the whole company. But they did it for human workflow. But then you probably get one with ws-security which you need to implement.

      In PS5 you get a beta UMS soa adapter and then you can make your own service.
      thanks

      Delete
  11. Hi Edwin,

    We are using Oracle UMS driver to connect to a SMSC gateway service. Our SOA suite version is 11.1.1.5.0 on Weblogic server 10.3.5.0. We have two sets of installations with this configuration.

    But in one of the installations the driver name is showing as "umsmessagingdriver-smpp" whereas in the other it is showing as "sdpmessagingdriver-smpp" in the EM console.

    Could you please throw some light on this issue with different names?

    Thanks in advance.

    Regards,
    Ranit

    ReplyDelete
    Replies
    1. Hi,

      Sorry don't know the answer. make ask support.

      thanks

      Delete
    2. Hi,

      Could you let me know how you connect the UMS driver to SMSC gateway.
      How to identify SMSC address? Please help.

      Delete
    3. Hi,

      Could you let me know how you connect the UMS driver to SMSC gateway.
      How to identify SMSC address? Please help.

      Delete
  12. Hi, please I need help.

    I built one using BPEL for sending SMS via SMPP.

    He is communicating perfectly, but when occurrs fault is not thrown one exception.

    Example: when I make a request with the SMPP server DOWN the bpel returns a messageID for me, instead of fault (remoteException).

    Thanks!

    ReplyDelete
    Replies
    1. Hi,

      You got a reference to the ums messaage, which you can use to track down the status.
      I think UMS is async and UMS should handle these errors and send it on a later time

      Thanks

      Delete
  13. We are using SOA 11.1.1.6. We have a requirement of receiving SMS, process it in BPEL and send back to the user.
    Could you please throw some light on receiving SMS using UMS Driver at SOA level.

    ReplyDelete
  14. Hi,

    When your SMS provider supports UMS SMPP, but I never tested this.
    but for the rest it should work the same as email etc.

    Thanks

    ReplyDelete
  15. When I send a message with an attachment, the attachment is not readable.
    I tried plain text and jpeg files, none of them worked.

    ReplyDelete
  16. I have created a Human task actionable notification and enabled task from embedding in to it.In the email being send the ACtions link appears at the top of the email and then the Task From content appears.

    I want to move the Actions link below the task form in the email. Is there a way to achieve this?
    Thanks in advance.

    ReplyDelete
  17. Hi Edwin,
    Is it possible to change the From address of the email to set dynamically from the payload. Need Urgent Help..
    TIA
    Swetha

    ReplyDelete