I’ve spent several days, off and on, wrestling with a chicken-and-egg configuration issue.
I have an application that uses Spring 2.0 and is deployed to Tomcat 5.5. We make heavy use of Tomcat’s JNDI for configuring things like our database connections.
We’re adding JMS functionality to our application; at this point, we merely need to send events to an existing Tibco EMS 4.4 Topic.
Following the various online tutorials, I was able to use Spring to make my JMS code very lightweight. I was pretty happy with things overall, until I encountered the final problem of setting up the configuration.
The Tibco EMS Server provides its own JNDI services, which I need to connect to the correct topic connection factory. I can use Spring’s JndiTemplate to configure this additional JNDI connection, but I kept hitting one problem. In every environment I’m going to deploy to, the value for java.naming.provider.url will be different. Because JndiTemplate is using
for setting the environment, I can’t use a separate JNDI lookup to populate that value out of Tomcat’s JNDI.
I needed to abstract this value out of my war file, into a configuration file that can stay on each server, so I don’t have to change it every time. This is an application that gets deployed fresh each new revision, and the client wasn’t going to be happy to have to extract the war file and then edit a config file, when that’s never been needed in the past. In addition, each server we’re deploying to already has a JNDI configuration for the Tibco EMS server. But, no matter how I tried, I could not find a way to configure the Tomcat JNDI to let me access those values from the Spring configuration file within the application.
The solution I found that finally worked was to use a PropertyPlaceholderConfigurer that pointed to a file in the tomcat conf directory. The final hurdle I had to jump was the correct configuration. If I used property=”location” value=”${catalina.home}/conf/jms.properties”, Spring would attempt to resolve the value from the servlet container by prepending a slash in front of the catalina.home directory. If I attempted to use a relative path, tomcat wouldn’t allow me open and read the file. I finally hit on prefixing the path with “file:” which was the magic to let Spring know I meant an absolute file path.
I am annoyed I have to add a configuration file, but at least it’s one more place where we can set the value and forget about it for future deployments.
In case anybody hits this combination of problems, here’s what finally worked:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jee="http://www.springframework.org/schema/jee" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.0.xsd"> <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="locations"> <list> <value>file:${catalina.home}/conf/jms.properties</value> <value>/WEB-INF/jdbc.properties</value> </list> </property> </bean> <bean id="messageSender" class="com.stevideter.spring.jms.MessageSender"> <property name="jmsTemplate" ref="jmsTemplate" /> </bean> <bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate"> <property name="connectionFactory" ref="topicConnectionFactory" /> <property name="defaultDestinationName"> <jee:jndi-lookup jndi-name="java:comp/env/jms/eventdestname"/> </property> <property name="pubSubDomain" value="true" /> </bean> <bean id="topicConnectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean"> <property name="jndiTemplate" ref="jndiTemplate"/> <property name="jndiName" value="FTTopicConnectionFactory"/> </bean> <bean id="jndiTemplate" class="org.springframework.jndi.JndiTemplate"> <property name="environment"> <props> <prop key="java.naming.factory.initial"> com.tibco.tibjms.naming.TibjmsInitialContextFactory </prop> <prop key="java.naming.provider.url"> ${jms.jndicontexturl} </prop> </props> </property> </bean> </beans> |
Hi Stevi,
I have been struggling for last couple of days to configure TIBCO EMS from WebSphere environment. This is the configurations.
I get invalid username and password error when I try to post message to corresponding Topic. I have tried various things w/o any success.
com.tibco.tibjms.naming.TibjmsInitialContextFactory
tcp://EMS-UAT-001.aholdusa.com:26874,tcp://EMS-UAT-002.aholdusa.com:26874
tibusr
tibusr
Please let me know if you see anything obvious here. Also, I do not want to create JNDI entry in WebSphere environment. It should be done through config file at runtime.
Thanks,
- Vikas Kadam
vikas.kadam@ahold.com
Vikas,
Are you able to log into the EMS servers directly using those passwords (e.g. using the EMS Administration Tool)?
How are you setting the username and password into the session?
Based on the error, that’s where I’d start looking, but don’t know if this is useful to what you’ve already tried.
Pingback: How to configure a secure JMS connection using Spring | Moving the Curve
Hi Stevi,
I have everything working fine and the only issue is my application reads the queue on some remote location and when starting the application if the remote application is not runing my application doesn’t start.
com.tibco.tibjms.naming.TibjmsInitialContextFactory
${jms.jndicontexturl}
In above configuration if the java.naming.provider.url is not accessible, application simply doesn’t start.
Any ideas?
Thanks & Regards,
Irfan
Irfan,
I’ve been meaning to do a follow-up post about this very issue. What you want to do is configure to use a proxy interface at startup. You need to add two properties to you connection factory, proxyInterface and lookupOnStartup. We also find that setting the cache property to false also helps, as this allows the application to recover if it fails for any particular attempt to use the topic connection. We have low enough volume that it’s not a performance issue for us.
<bean id=”topicConnectionFactory” class=”org.springframework.jndi.JndiObjectFactoryBean”/>
<property name=”jndiTemplate” ref=”jndiTemplate”/>
<property name=”jndiName” value=”FTTopicConnectionFactory”/>
<property name=”proxyInterface” value=”javax.jms.TopicConnectionFactory” />
<property name=”lookupOnStartup” value=”false” />
<property name=”cache” value=”false” /><br />
</bean>
Thanks Stevi,
I have used these settings for my application as below
QueueConnectionFactory
and
queue/DataQueue
But when deploying this application it throws error for listener
and errors are as below
2009-04-02 16:04:12,500 DEBUG [org.jnp.interfaces.NamingContext] Failed to connect to localhost:2099
javax.naming.CommunicationException: Failed to connect to server localhost:2099 [Root exception is javax.naming.ServiceUnavailableException: Failed to connect to server localhost:2099 [Root exception is java.net.ConnectException: Connection refused: connect]]
at org.jnp.interfaces.NamingContext.getServer(NamingContext.java:274)
at org.jnp.interfaces.NamingContext.checkRef(NamingContext.java:1533)
at org.jnp.interfaces.NamingContext.lookup(NamingContext.java:634)
at org.jnp.interfaces.NamingContext.lookup(NamingContext.java:627)
at javax.naming.InitialContext.lookup(InitialContext.java:392)
at org.springframework.jndi.JndiTemplate$1.doInContext(JndiTemplate.java:123)
at org.springframework.jndi.JndiTemplate.execute(JndiTemplate.java:85)
at org.springframework.jndi.JndiTemplate.lookup(JndiTemplate.java:121)
at org.springframework.jndi.JndiTemplate.lookup(JndiTemplate.java:146)
at org.springframework.jndi.JndiLocatorSupport.lookup(JndiLocatorSupport.java:93)
at org.springframework.jndi.JndiObjectLocator.lookup(JndiObjectLocator.java:105)
at org.springframework.jndi.JndiObjectTargetSource.getTarget(JndiObjectTargetSource.java:126)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:184)
at $Proxy56.createQueueConnection(Unknown Source)
at org.springframework.jms.listener.DefaultMessageListenerContainer102.createConnection(DefaultMessageListenerContainer102.java:71)
.
.
Caused by: javax.naming.ServiceUnavailableException: Failed to connect to server localhost:2099 [Root exception is java.net.ConnectException: Connection refused: connect]
at org.jnp.interfaces.NamingContext.getServer(NamingContext.java:248)
… 173 more
Caused by: java.net.ConnectException: Connection refused: connect
Any ideas?
Best Regards,
Irfan
Here is the config
QueueConnectionFactory
queue/PricingQueue
Regards,
Irfan
Looks like your connection is being refused. Have you verified the username and password?
Hi Stevi,
Thanks for your reply.
I haven’t started the other application which is listening on port 2099 and have queue’s runing.
Actually I wanted to see if my application deploys/starts successfully, if the other application is not runing, but it failed.
I’m not passing any user/password and not sure where its required.
Thanks & Regards,
Irfan
Hi stevi,
Could you please help me doing the above configuration in my project, I am also using Tibco JMS with Tomcat and Spring app, my current serverUrl is hardcoded like below in my spring context file:
I am trying to move the serverUrl out of the code and want to config it in tomcat somewhere like you did above.
I am not able to figure out what should my tomcat serverl.xml should have for the following :
FTTopicConnectionFactory
And also could you please post your configuration from tomcat end, like the jms.properties what it has and the above FTTopicConnectionFactory details.
Thanks for your help.
golamari
Hey nevermind,
I figured out that I have to use “FTQueueConnectionFactory” because I am using queues. I could able to fix all the issues and above method is working great.
Thanks,
Hi,
I am trying to put message into the queue with the help of Tibco EMS and trying to read it with java(jms). Till now we were using Wehsphere, now we are changing it to Tomcat. So could you please help me out in this. I want to know what all configurations I need to do in tomcat for jms thing to run..
changes in web.xml as well..
Thanks,
Girish.
That just get me out of that nightmare …. Thanks thanks a lot …. This has really helped me out