Pages

Tuesday, September 7, 2010

SOAP over JMS with Oracle Service Bus 11g

In a previous blog I already showed you how you can do SOAP over JMS with a JAX-RPC Web Service. In this blogpost I will use OSB 11g ( Also works in 10.3 ). The OSB Proxy Services is also based on the JAX-RPC framework, so it works almost the same as a normal Java JAX-RPC Service.

You need to start with a new Proxy Service based on a WSDL

Choose for JMS. OSB will generates a default Endpoint Uri. You need to remember the QueueName of this Endpoint uri, you will use this in your Java proxy client.
OSB automatically creates a new Queue with this name when it does not already exists.

In the JMS Transport tab you need to select Is Response Required and JMSMessageID as Response Pattern.

In the Message Flow Tab I will use a simple File Busines Service and in the Response Action an Assign to set the WSDL response in the body variable.
In the Response Action you need add a Transport Header.

In the Transport Header you need to add the _wls_mimehdrContent_Type Header with as value 'text/xml; charset=utf-8' and use Inbound Response as Direction.
If you don't set this Transport Header you can get a content type null error on the JAX-RPC Client side
Deploy this project to the OSB Server.

Now you can download the WSDL of the Proxy Service in the SB Console, you need this to generate the JAX-RPC Client.

extract this jar and optional you can change the Endpoint to this Uri jms://servername:7001?URI=JMSProxyServiceRequest . Change the servername, the port number and change the Queue name.  That's enough to find the Queue.

The last step is to generate a Java Web Service Proxy client. Please read this blogpost how to generate a client.
This is the ANT Target I used to generate the client classes based on the WSDL
<target name="clientOSB">
  <clientgen wsdl="file:/c:/temp/jms/HelloworldNormal.wsdl"
             destdir="src" 
             packagename="nl.whitehorses.clientosb.jms"
             type="JAXRPC"/>
  <javac srcdir="src" 
         destdir="classes"
         includes="nl/whitehorses/clientosb/jms/**/*.java"/>
 </target>

And the java test client. If you change the WSDL Endpoint you don't need to set JmsTransportInfo
package nl.whitehorses.clientosb.jms;

import java.net.URISyntaxException;

import java.rmi.RemoteException;

import javax.xml.rpc.ServiceException;
import javax.xml.rpc.Stub;

import weblogic.wsee.connection.transport.jms.JmsTransportInfo;

public class TestService {

    public TestService() {
    }


    public static void main(String[] args) {

        try {
            HelloWorldServiceSoapHttpPortBindingQSService hello = new HelloWorldServiceSoapHttpPortBindingQSService_Impl();
            HelloWorldService port = hello.getHelloWorldServiceSoapHttpPortBindingQSPort();

            String uri = "jms://laptopedwin:7001?URI=JMSProxyServiceRequest";  
            JmsTransportInfo ti =  new JmsTransportInfo(uri);  
            ((Stub)port)._setProperty("weblogic.wsee.connection.transportinfo", ti);  
           
            System.out.println(port.sayHello());

        } catch (ServiceException e) {
            e.printStackTrace();
        } catch (RemoteException e) {
            e.printStackTrace();
        } catch (URISyntaxException e) {
            e.printStackTrace();
        }
    }

}
Here you can download the OSB workspace.

34 comments:

  1. Hello, I have a question on another subject, could you help?

    I have a parent table that has a relationship with a child table, the child table has a composite key, the following image explains better relations

    http://i26.servimg.com/u/f26/12/26/78/42/casoco10.png

    The problem is with the parent table (tabla4), how I can make the view object for use in a form? if I put two selectOneChoice for the ID of the child table (tabla3) does not guarantee the consistency or completeness

    How do I create an attribute or component that contains both ID?

    ReplyDelete
  2. Hi,

    you should do this with a adf bc viewlink between the view table3 and table 4.

    Make a form of table of table3 and table4 as detail table. When you add a new record on table 4 then the fk is automatically filled and just provide the new pk.

    Hope this helps

    ReplyDelete
  3. Hello!

    This post was very useful for getting up and running with Soap Over JMS in the OSB environment. Thank you!

    One question I have is the use of JAX-RPC to support Soap Over JMS. Can you see Oracle improving this to cover the JAX-WS standard?

    And are we forced to generate the client using the WL tool? What about other tools such as CXF or Axis2?

    Anyway, once again thanks for your efforts in this area. They make a huge difference :)


    Mark.

    ReplyDelete
  4. Hi,

    dont think Oracle will change this, jax-ws client only supports HTTP. Dont know what the jax-ws standard says about this.

    thanks

    ReplyDelete
  5. Hello, Edwin. Thank you so much for this post, it has been very useful to me. But I have a question: is there a way to expose the WSDL in this setup without having to get it from the sb console?
    Thanks again, Humberto

    ReplyDelete
  6. Hi

    Don't think so, you need to use the sbconsole for the wsdl.

    thanks

    ReplyDelete
  7. First of all congratulations for this great post.

    I had one proxy service using http as protocol, but due the large size of the request in my case, I decided to change the protocol from http to jms and make it assync.

    I was using SOAPUI to test the http service, but since it is quite complicated to import the WSDL using JMS on this tool, I tried to implement a java project in Netbeans and created a WS client using JAX-WS as you did.

    Unfortunately when I run the method I got this error:

    Exception in thread "main" javax.xml.ws.WebServiceException: Unsupported endpoint address: jms://WN7-6J6VJN1.poagdc.amer.dell.com:7001/weblogic.jms.XAConnectionFactory/JMSProxyServiceRequest
    at com.sun.xml.internal.ws.api.pipe.TransportTubeFactory.create(TransportTubeFactory.java:133)
    at com.sun.xml.internal.ws.transport.DeferredTransportPipe.processRequest(DeferredTransportPipe.java:101)
    at com.sun.xml.internal.ws.api.pipe.Fiber.__doRun(Fiber.java:587)
    at com.sun.xml.internal.ws.api.pipe.Fiber._doRun(Fiber.java:546)
    at com.sun.xml.internal.ws.api.pipe.Fiber.doRun(Fiber.java:531)
    at com.sun.xml.internal.ws.api.pipe.Fiber.runSync(Fiber.java:428)
    at com.sun.xml.internal.ws.client.Stub.process(Stub.java:211)
    at com.sun.xml.internal.ws.client.sei.SEIStub.doProcess(SEIStub.java:124)
    at com.sun.xml.internal.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:98)
    at com.sun.xml.internal.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:78)
    at com.sun.xml.internal.ws.client.sei.SEIStub.invoke(SEIStub.java:107)
    at $Proxy29.bookInfoleaseContract(Unknown Source)
    at JMSBookingContractMain.bookInfoleaseContract(JMSBookingContractMain.java:396)
    at JMSBookingContractMain.main(JMSBookingContractMain.java:384)


    Did I miss something ?

    cheers,
    Davinod

    ReplyDelete
  8. Hi,

    Yes jax-ws won't support it, you need to use jax-rpc. jax-ws only supports http.

    thanks

    ReplyDelete
  9. Hi
    Can we invoke any xml-rpc service from OSB? I really dont understand difference between xml-rpc service and a REST service.
    -Sam

    ReplyDelete
  10. Hi
    Can we invoke any xml-rpc service from OSB? I really dont understand difference between xml-rpc service and a REST service.
    -Sam

    ReplyDelete
  11. Hi,

    basically, An XML-RPC message is an HTTP-POST request. The body of the request is in XML. A procedure executes on the server and the value it returns is also formatted in XML

    Rest basically means that each unique URL is a representation of some object. You can get the contents of that object using an HTTP GET, to delete it, you then might use a POST, PUT, or DELETE to modify the object. REST is more about CRUD operations against a resource. And it can also return JSON

    Hope this helps

    ReplyDelete
  12. Hi

    Thanks for the clarification.
    So that means from OSB we can easily call a xml-rpc based service since it requires HTTP-POST request only? From OSB I just need to POST an xml body with 'methodName' as the actual procedure name and 'params' to pass parameters.

    Let me know if my understanding is correct.

    -Sameer

    ReplyDelete
  13. Yep ,

    you are right ,before you do it , use netmon or something else and monitor the http traffic so you know for sure.

    thanks

    ReplyDelete
  14. Hi Edwin,good article,I have a question i configured jms connetion factory and queue in admin console,i create a business service with jms uri like http://host:port/connectionfactory/queuename.My environment is like one admin server for soa and osb server.when i test the business service i got the invokation error due to connection factory and queue.The connection factrory is targetting the soa jms server,Plz help me,Thanks in advance.

    ReplyDelete
  15. Hi,

    Can you check if you target the cf to the managed servers and else use the internal cf . Check your sub deployments , don't use default targeting

    You can test it with qbrowser , see if you can add a message to the queue.

    Thanks

    ReplyDelete
  16. Hi Edwin thanks for reply,Actually i create a new jms server which targets the osb server with file store and create a jmsmodule.Then i create connection factory and queue.Then in Eclipse i create new business-service in protocal i select jms and url i give it like jms://host:port/cf/queue.but i'm getting the error as The invocation resulted in an error: [JMSPool:169803]JNDI lookup of the JMS connection factory demoCF failed: javax.naming.NameNotFoundException: Unable to resolve 'demoCF'. Resolved '' [Root exception is javax.naming.NameNotFoundException: Unable to resolve 'demoCF'. Resolved '']; remaining name 'demoCF'.Please help it's very urgent for me.Presently I'm working on 11.1.1.5.Thanks again.

    ReplyDelete
  17. Hi,

    you use jms://host:port/cf/queue , so this will lookup the cf on this "host" server . you need to target the CF on this server and not on the jms server. cf is always a connection to a wls server.

    thanks

    ReplyDelete
  18. Hi Edwin,Thx for reply I got it.
    I have another issue regarding the dynamic X-Query.
    I have a requirement like three different requests(schemas) all are converted in to standard format(schema).For this scenario I use dyamic X-query transformation.For Example RequestA,RequestB and RequesrC what ever request it should be converted into one standard format say Response.For this I create three X-Query transformations,and proxy service.If i get the request from RequestA related XQuery will execute (RequstA to Response transformation).
    RequestA------Response
    RequestB------Response
    RequestC------Response
    Actually my idea is based on requset schema name (like RequestA) it will convert,for this scenario how can I set condition in dynamicXquery.

    Once again Thanks for your reply

    ReplyDelete
  19. Hi,

    you can read the soap header, a http property or some element and make an if case for a ,b and in the message flow.

    thanks

    ReplyDelete
  20. Hi Edwin,I have query regarding the x query.I have a stored procedure,how can i retrive the details by using execute-sql function or other function,can u plz explian with one example.

    ReplyDelete
  21. Hi Edwin,

    You said that JAX-WS doesnt support SOAP/JMS but I have found one IBM article saying it does
    http://www.ibm.com/developerworks/websphere/library/tutorials/0903_adams/index.html

    have you tried this in IBM WAS?

    Thanks,
    Deepak.

    ReplyDelete
  22. Hi,

    For execute custom sql inside xquery you can use this fn-bea:execute-sql( $datasource as xs:string, $rowElemName as xs:QName, $sql as xs:string, $param1, ..., $paramk) as element()*


    fn-bea:execute-sql( 'jdbc.hr', xs:QName('hashvalue'), 'select TO_CHAR(ORA_HASH(?)) as value from dual',xs:string('ABC') ) as element()*


    thanks

    ReplyDelete
  23. Hi,

    I see that IBM added this to its own version jax-ws. In Version 7.0, however, the SOAP over JMS capabilities have been expanded to include JAX-WS Web services and clients.

    and you need to have this IBM WebSphere Application Server V7.0 and IBM Rational Application Developer V7.5 installed. And probably you need a license.

    thanks

    this is not standard and probably

    ReplyDelete
  24. Is it possible for OSB BS to invoke the JMSProxyService. I guess the BS has to be of JMS type and the end point uri of the BS has to be jms://localhost:7001/weblogic.jms.XAConnectionFactory/JMSProxyServiceRequest which is same as the endpoint uri of JMSProxyService. I tried passing the transport headers also. I also set the is response required option to true and specified the message id as the mechanism of the response correlation. Specified the same CF and queue as the response queues. But it didn't work. The BS didn't get a response. It errored out. Does the JMSProxyService in this case need to explicitly copy the jms message id from the request set it into the corrleationid of the response ?

    ReplyDelete
    Replies
    1. Ok

      your BS should publish to the jms queue where the proxy is listening on. Do expect a response. mostly with jms its one way. Did you read this blogpost http://eelzinga.wordpress.com/2009/10/28/oracle-service-bus-jms-requestresponse-pattern/

      thanks

      Delete
    2. Hi Thanks.
      Yep I read the blog from eelzinga and got it working for jms correlation id and used different queues for request and response.Was wondering can use the same queue for same request and response as we did in this example.

      Delete
    3. Hi,

      Don't think so, because your proxy reads all the messages from that queue ( maybe not when you use jms filtering ).

      thanks

      Delete
  25. Hi Edwin,
    I have tried the soap over jms with OSB and business class that use @WLJmsTransport defined in the same machine by using CorrelationID, which it can work fine.
    we are using qpid for message broker.

    But when I deploy the osb and business in distributed environment , business can not write the response back to response queue.
    Should it have to use JmsMessageID in distributed environment?

    thanks

    ReplyDelete
    Replies
    1. Hi,

      Don't know if it works with a distributed queue, I see this in the documentation
      Clustering Considerations:
      If you are using the Web service JMS transport feature in a cluster, you must:
      Create a local JMS queue, rather than a distributed queue, when creating the JMS queue.
      Explicitly target this JMS queue to each server in the cluster.

      hope this helps.

      thanks

      Delete
    2. Hello,

      I managed to connect to the distributed queue adding the line ti.setJndiURL("t3://managedServer1:7003,managedServer1:7004");

      try {
      HelloWorldServiceSoapHttpPortBindingQSService hello = new HelloWorldServiceSoapHttpPortBindingQSService_Impl();
      HelloWorldService port = hello.getHelloWorldServiceSoapHttpPortBindingQSPort();

      String uri = "jms://laptopedwin:7001?URI=JMSProxyServiceRequest";
      JmsTransportInfo ti = new JmsTransportInfo(uri);
      ti.setJndiURL("t3://managedServer1:7003,managedServer1:7004");
      ((Stub)port)._setProperty("weblogic.wsee.connection.transportinfo", ti);

      System.out.println(port.sayHello());

      } catch (ServiceException e) {
      e.printStackTrace();
      } catch (RemoteException e) {
      e.printStackTrace();
      } catch (URISyntaxException e) {
      e.printStackTrace();
      }

      I've tested load balancing feature and works quite well,

      Hope this helps,
      Regards

      Delete
  26. Hi
    Thanks for the useful details. I have one question related to JMS queue. If the targeted service is down, and what we can do to fullfill our complete request. That means i need to complete my queue requests even though my target service is down. It should pull the requests from service when it is up.

    Please help me
    Biswa

    ReplyDelete
    Replies
    1. Hi,

      you mean the service went down and there are still some responses in the queue. Is this a problem with synchronous services?

      can you explain it a little bit more.

      thanks

      Delete
  27. Hello very nice article,

    I have a problem. Id like to add my own transport header in PS(outbound request) which calls queueBS on response action from other BS where i have logic. I can see in my log result that it has been added properly. In my PS JMSConusmer (get all headers turned ON)id like to pull this header. I log $inbound/ctx:transport but there is no any header I have added. Have u ever faced this problem?

    Thank you for your help
    Regards

    ReplyDelete
  28. Hai Edwin

    Can we set custom message id jms queue..?

    ReplyDelete