Sunday, March 28, 2010

Create Weblogic JMS Foreign Server and Use It in Spring

The following steps are performed in Weblogic 9.2. Notice that you must have the valid values for the third party JMS server. These values are the value for java.naming.factory.initial and java.naming.provider.url of the third party JMS provider, the JNDI name of the destination and the connection factory on the third party JMS provider.

  1. Open Weblogic Admin Console.
  2. Navigate to Services/Messaging/JMS Modules.
  3. Click "New" to create a new module. Give the new module name "DemoModule". Then click on "Next". Choose the target server and click on "Next". Click "Finish" and then "Activate Changes" to finish the creation of the module.
  4. Now it is back on the JMS Modules main page. Click on "DemoModule".
  5. Click "Edit" and "New". The next page will show a list of resources that can be created. Click on "Foreign Server" and "Next".
  6. Give the foreign server a name "DemoForeignServer" and click on "Next".
  7. The next page will show that the target server has been selected. Just click on "Finish" and "Activate Changes".
  8. Click on "DemoForeignServer". Give the value for "JNDI Initial Context Factory" and "JNDI Connection URL". Note that the JNDI connection URL can be an LDAP url with the format "ldap://......". Click "Save" and "Activate Changes".
  9. Now on the same page, click on the tab "Connection Factories".
  10. Click "New". Specify the name, the local JNDI name and the remote JNDI name for the connection factory. The remote JNDI name must be a valid name that is already configured on the actual third party JMS provider. You can use a local JNDI name as you like. Suppose the local JNDI name is "demoLocalForeignConnectionFactoryJNDIName". You can optionally configure a user name and password to secure the foreign factory. Click "OK" and "Activate Changes".
  11. Click on "Destinations" tab. Click on "New".
  12. Specify the name, the local JNDI name and the remote JNDI name for the destination for the destination. The remote JNDI name must be a valid name that is already configured on the actual third party JMS provider. You can pick a local JNDI name as you like. Suppose the local JNDI name is "demoLocalForeignDestinationJNDIName". Click "OK" and "Activate Changes".
That's it! Now you can use this foreign JMS server in your application.

Sample Spring JMS configuration File

If you are using Springframework, you can configure the JMS beans as in the following file. Note that the message sender and listener use the same destination in this file. In the actual application, they should be different.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//Spring//DTD Bean//EN" 
"http://www.springframework.org/dtd/spring-beans.dtd">
<!-- Application Context -->
<beans>
 <bean id="jmsQueueConnectionFactory"
  class="org.springframework.jndi.JndiObjectFactoryBean">
  <property name="jndiName">
   <value>demoLocalForeignConnectionFactoryJNDIName</value>
  </property>
 </bean>
 <bean id="myDestination"
  class="org.springframework.jndi.JndiObjectFactoryBean">
  <property name="jndiName">
   <value>demoLocalForeignDestinationJNDIName</value>
  </property>
 </bean>
 <bean id="jmsTemplate"
  class="org.springframework.jms.core.JmsTemplate">
  <property name="connectionFactory">
   <ref bean="jmsQueueConnectionFactory" />
  </property>
  <property name="defaultDestination">
   <ref bean="myDestination" />
  </property>
 </bean>
 <bean id="jmsSender"
  class="com.mycompany.myapp.server.common.jms.JmsSender">
  <property name="jmsTemplate">
   <ref bean="jmsTemplate" />
  </property>
 </bean>
 <bean id="messageListener"
  class="com.mycompany.myapp.server.common.jms.ExampleListener">
 </bean>
 <bean id="jmsContainer"
  class="org.springframework.jms.listener.DefaultMessageListenerContainer">
  <property name="connectionFactory"
   ref="jmsQueueConnectionFactory" />
  <property name="destination" ref="myDestination" />
  <property name="sessionAcknowledgeModeName"
   value="AUTO_ACKNOWLEDGE" />
  <property name="messageListener" ref="messageListener" />
  <property name="sessionTransacted" value="true" />
 </bean>
</beans>

Suppose the name of the above file is myapp-spring-jms.xml. Then in the web.xml, add the following parameter:
<context-param>
  <param-name>contextConfigLocation<param-name>
  <param-value>/WEB-INF/myapp-spring-jms.xml</param-value>
 </context-param>

The Sample Message Sender

The sample java class to send the message. This class implements the interface IJmsSender, which is a user defined interface. Its only method is sendMessage(String). The interface is just for the Spring bean configuration purpose. With this interface, other Spring beans can use IJmsSender to inject an instance of JmsSender.
package com.mycompany.myapp.server.common.jms;

public interface IJmsSender {
 public void sendMessage(final String message);
}
package com.mycompany.myapp.server.common.jms;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Session;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;

public class JmsSender implements IJmsSender
{
  private static Log log = LogFactory.getLog(Test.class);
  private JmsTemplate jmsTemplate;

  public JmsTemplate getJmsTemplate()
  {
    return jmsTemplate;
  }

  public void setJmsTemplate(JmsTemplate jmsTemplate)
  {
    this.jmsTemplate = jmsTemplate;
  }

  public void sendMessage(final String message)
  {
    jmsTemplate.send(new MessageCreator()
    {
      public Message createMessage(Session session) throws JMSException
      {
        log.debug("Creating the message from text " + message);
        Message textMsg = session.createTextMessage(message);
        return textMsg;
      }
    });
  }
}

The Sample Message Listener

The samle JMS listener to receive the message:
package com.mycompany.myapp.server.common.jms;

import javax.jms.JMSException;
import javax.jms.Message; 
import javax.jms.MessageListener;
import javax.jms.TextMessage;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class ExampleListener implements MessageListener
{
  private static Log logger = LogFactory.getLog(ExampleListener.class);

  public void onMessage(Message message)
  {
    logger.info("onMessage() message=" + message);
    if (message instanceof TextMessage)
    {
      try
      {
        logger.info(((TextMessage) message).getText());
        // process message
      }
      catch (JMSException ex)
      {
        throw new RuntimeException(ex);
      }
    }
    else
    {
      logger.info("non-TextMessage");
    }
  }
}

A Sample WLST Script to Create the JMS Foreign Server

Note that this file was obtained by editing the script generated by the WLST configToScripy command. Suppose the name of this file is config_tibco.py. It loads the property file config_tibco.py.properties. To run the configuration, first execute C:\bea921\weblogic92\common\bin\wlst.cmd. Then under the prompt wls:/offline> type
execfile('c:/workshop/myApp/temp/config_tibco.py')
"""
@author Copyright (c) 2004-2005 by BEA Systems, Inc. All Rights Reserved.

This script will first try to connect to a running server using the 
values in the properties file. If there is no server running, WLST
will start a server with the values in the properties file. You should change
these values to suit your environmental needs. After running the script, 
the server that is started(if started one) will be shutdown. 
This might exit you from your WLST shell."""

from weblogic.descriptor import BeanAlreadyExistsException
from java.lang.reflect import UndeclaredThrowableException
from java.lang import System
import javax
from javax import management
from javax.management import MBeanException
from javax.management import RuntimeMBeanException
import javax.management.MBeanException
from java.lang import UnsupportedOperationException

def initConfigToScriptRun():
global startedNewServer
loadProperties("c:/workshop/myApp/temp/config_tibco.py.properties")
hideDisplay()
hideDumpStack("true")
# try connecting to a running server if it is already running ... 
if connected=="false":
try:
URL="t3://"+adminServerListenAddress+":"+adminServerListenPort
connect(userName, passWord, URL)
except WLSTException:
print 'No server is running at '+URL+', the script will start a new server'
hideDumpStack("false")
if connected=="false":
print 'Starting a brand new server at '+URL+' with server name '+adminServerName
print 'Please see the server log files for startup messages available at '+domainDir
# If a config.xml exists in the domainDir, WLST will use that config.xml to bring up the server. 
# If you would like WLST to overwrite this directory, you should specify overWriteRootDir='true' as shown below
# startNewServer(adminServerName, domName, URL, userName, passWord,domainDir, overWriteRootDir='true')
_timeOut = Integer(TimeOut)
# If you want to specify additional JVM arguments, set them using startServerJvmArgs in the property file or below
_startServerJvmArgs=startServerJvmArgs
if (_startServerJvmArgs=="" and (System.getProperty("java.vendor").find("Sun")>=0 or System.getProperty("java.vendor").find("Hewlett")>=0)):
_startServerJvmArgs = " -XX:MaxPermSize=128m"
if overWriteRootDir=='true':
startServer(adminServerName, domName, URL, userName, passWord,domainDir, timeout=_timeOut.intValue(), overWriteRootDir='true', block='true', jvmArgs=_startServerJvmArgs)
else:
startServer(adminServerName, domName, URL, userName, passWord,domainDir, timeout=_timeOut.intValue(), block='true', jvmArgs=_startServerJvmArgs)
startedNewServer=1
print "Started Server. Trying to connect to the server ... "
connect(userName, passWord, URL)
if connected=='false':
stopExecution('You need to be connected.')

def startTransaction():
edit()
startEdit()

def endTransaction():
startEdit()
save()
activate(block="true")

from javax.management import InstanceAlreadyExistsException
from java.lang import Exception
from jarray import array

def endOfConfigToScriptRun():
global startedNewServer
#Save the changes you have made
# shutdown the server you have started
if startedNewServer==1:
print 'Shutting down the server that is started... '
shutdown(force='true', block='true')
print 'Done executing the script.'

def create_JMSSystemResource_0(path, beanName):
cd(path)
try:
print "creating mbean of type JMSSystemResource ... "
theBean = cmo.lookupJMSSystemResource(beanName)
if theBean == None:
cmo.createJMSSystemResource(beanName)
except java.lang.UnsupportedOperationException, usoe:
pass
except weblogic.descriptor.BeanAlreadyExistsException,bae:
pass
except java.lang.reflect.UndeclaredThrowableException,udt:
pass

def create_ForeignServer_4(path, beanName):
cd(path)
try:
print "creating mbean of type ForeignServer ... "
theBean = cmo.lookupForeignServer(beanName)
if theBean == None:
cmo.createForeignServer(beanName)
except java.lang.UnsupportedOperationException, usoe:
pass
except weblogic.descriptor.BeanAlreadyExistsException,bae:
pass
except java.lang.reflect.UndeclaredThrowableException,udt:
pass

def create_ForeignDestination_6(path, beanName):
cd(path)
try:
print "creating mbean of type ForeignDestination ... "
theBean = cmo.lookupForeignDestination(beanName)
if theBean == None:
cmo.createForeignDestination(beanName)
except java.lang.UnsupportedOperationException, usoe:
pass
except weblogic.descriptor.BeanAlreadyExistsException,bae:
pass
except java.lang.reflect.UndeclaredThrowableException,udt:
pass

def create_ForeignConnectionFactory_8(path, beanName):
cd(path)
try:
print "creating mbean of type ForeignConnectionFactory ... "
theBean = cmo.lookupForeignConnectionFactory(beanName)
if theBean == None:
cmo.createForeignConnectionFactory(beanName)
except java.lang.UnsupportedOperationException, usoe:
pass
except weblogic.descriptor.BeanAlreadyExistsException,bae:
pass
except java.lang.reflect.UndeclaredThrowableException,udt:
pass

def setAttributesFor_TibcoForeignServer_13():
cd("/JMSSystemResources/myAppTibcoJMSModule/JMSResource/myAppTibcoJMSModule/ForeignServers/TibcoForeignServer")
print "setting attributes for mbean type ForeignServer"
set("InitialContextFactory", "com.tibco.tibjms.naming.TibjmsInitialContextFactory")
set("DefaultTargetingEnabled", "true")
set("Name", "TibcoForeignServer")
set("ConnectionURL", "ldap://a_valid_url_here")

def setAttributesFor_myAppTibcoFCF_17():
cd("/JMSSystemResources/myAppTibcoJMSModule/JMSResource/myAppTibcoJMSModule/ForeignServers/TibcoForeignServer/ForeignConnectionFactories/myAppTibcoFCF")
print "setting attributes for mbean type ForeignConnectionFactory"
set("LocalJNDIName", "jms/testTibcoFCF")
set("Name", "myAppTibcoFCF")
set("RemoteJNDIName", "a_valid_remote_JNDI_ForConnectionFactory")

def setAttributesFor_testTibcoQueueForeignDestination_15():
cd("/JMSSystemResources/myAppTibcoJMSModule/JMSResource/myAppTibcoJMSModule/ForeignServers/TibcoForeignServer/ForeignDestinations/testTibcoQueueForeignDestination")
print "setting attributes for mbean type ForeignDestination"
set("LocalJNDIName", "jms/testTibcoQueueDestination")
set("Name", "testTibcoQueueForeignDestination")
set("RemoteJNDIName", "a_valid_remote_JNDI_for_destination")

def setAttributesFor_myAppTibcoJMSModule_11():
cd("/JMSSystemResources/myAppTibcoJMSModule")
print "setting attributes for mbean type JMSSystemResource"
refBean0 = getMBean("/Servers/myAppAdminServer")
theValue = jarray.array([refBean0], Class.forName("weblogic.management.configuration.TargetMBean"))
cmo.setTargets(theValue)

try:
initConfigToScriptRun()
startTransaction()
create_JMSSystemResource_0("/", "myAppTibcoJMSModule")
create_ForeignServer_4("/JMSSystemResources/myAppTibcoJMSModule/JMSResource/myAppTibcoJMSModule", "TibcoForeignServer")
create_ForeignDestination_6("/JMSSystemResources/myAppTibcoJMSModule/JMSResource/myAppTibcoJMSModule/ForeignServers/TibcoForeignServer", "testTibcoQueueForeignDestination")
create_ForeignConnectionFactory_8("/JMSSystemResources/myAppTibcoJMSModule/JMSResource/myAppTibcoJMSModule/ForeignServers/TibcoForeignServer", "myAppTibcoFCF")
setAttributesFor_myAppTibcoJMSModule_11()
setAttributesFor_TibcoForeignServer_13()
setAttributesFor_testTibcoQueueForeignDestination_15()
setAttributesFor_myAppTibcoFCF_17()
endTransaction()
finally:
endOfConfigToScriptRun()

Sample Property File for WLST Script

#WLST ConfigToScript Default Properties file 
#Mon Mar 29 09:53:26 EDT 2010
exitonerror=false
adminServerListenAddress=localhost
adminServerName=myAppAdminServer
domName=myAppwls9loc
overWriteRootDir=false
TimeOut=240000
startedNewServer=0
domainDir=C:/bea921/user_projects/domains/myAppwls9loc
userName=wlsadmin
passWord=wlsadmin1
adminServerListenPort=7001
startServerJvmArgs=

Reference

1. http://download.oracle.com/docs/cd/E13222_01/wls/docs92/ConsoleHelp/taskhelp/jms_modules/foreign_servers/ConfigureForeignServers.html
2. http://forum.springsource.org/showthread.php?t=34180

1 comment: