Wednesday, May 22, 2013

Java Web Service Resource Injection Fails on JMS Connection Factory When JMS Server Migrates

Here is the problem:
We have a clustered Weblogic environment. Let's say two managed servers M1 and M2. We have JMS server that needs be migrated among the managed servers. The JMS server is initially targeted to M1.

We have web services running on the cluster. One service publishes messages to the JMS server. This web service uses Java resource injection for the JMS connection factory like:
    @Resource(mappedName="ll.jmsprovider.XAConnectionFactory")
    private ConnectionFactory connectionFactory;

When the service is deployed to the cluster. "connectionFactory" is properly initialized, everything is fine. Even when we shutdown M1, the JMS resource is migrated to M2, the "connectionFactory" still works fine on M2. We can still publish messages.

The problem is when we bring back up M1, and shutdown M2. That's when "connectionFactory" doesn't work anymore. I suspect there might be some configurations on migration policy to make "connectionFactory" work seamlessly when the migration happens. But I don't know how. So my kludge is to recreate the "connectionFactory" on the fly. Here is the entire "hack":

package pubmsg;
import javax.annotation.Resource;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.JMSException;
import javax.jms.MessageProducer;
import javax.jms.Queue;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.jws.Oneway;
import javax.jws.WebMethod;
import javax.jws.WebService;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.transaction.SystemException;

@WebService(targetNamespace = "http://pubmsg.org/")
public class msgSender {
    @Resource(mappedName="ll.jmsprovider.XAConnectionFactory")
    private ConnectionFactory connectionFactory;
    @Resource(mappedName="ll.jms.partner.enroll.queue")
    private javax.jms.Queue queue;
      
    public msgSender() {
        super();
    }

    @WebMethod
    @Oneway
    public void sendMessage(String msg) {
        Connection conn = null;
        try {
            try {
                 conn = connectionFactory.createConnection(); // my "hack"
            }
            catch (Exception e) {
                InitialContext ctx = new InitialContext();      
                connectionFactory = (ConnectionFactory) ctx.lookup("ll.jmsprovider.XAConnectionFactory");
                conn = connectionFactory.createConnection();
                queue = (Queue) ctx.lookup("ll.jms.partner.enroll.queue");
            }
   Session session = conn.createSession(false, Session.CLIENT_ACKNOWLEDGE);
   TextMessage message = session.createTextMessage(msg);
   MessageProducer messageProducer = session.createProducer(queue);
   messageProducer.send(message);
        }
        catch (NamingException e) {}
        catch (JMSException e) {}
        finally {
                if (conn!=null) {
                        try {
                                conn.close();
                        } catch (JMSException e) {}
                }
        }
    }
}

Not the most elegant solution. Oh, well, i need to move on...

Ironically, the purpose of this blog is keep track what i did and how i did it. But it has been several weeks since I worked on it, I already forgot the steps how I created the project :( So I just clicked through JDeveloper try to re-construct the same thing. I believe this is a sequence that can create a java based web service in Jdeveloper (11.1.1.6):

Part I - Ceate a "Web Project"
 1. select project name
 2. select default "serverlet 2.5..."
 3. chose "None" on the "page flow technology" screen
 4. chose no libraries.
 5. select doc root, app name, context root etc.
 6. finish

Part II - add a Java class,
    add the public methods as you need

Part III - add "Web Services->Java Web Service"
   select your java class, from that point on, pretty much follow the screen. That should just work.

====
hmm, i did find another way to create the Java web service: you can start with a generic application, then select "Web Services" for the default project, then "java" is selected by default. However, this process only works for the 1st default project. Once the application is created, and you try to add new project, and you pick "web services", you'll get different options, talking about confused...

1 comment: