Reputation: 1207
I have weird problem with a JMS Listener container. In case I stop the listener container, half of messages are still delivered to the app and processed by listener. Here is my deployment descriptor:
<servlet>
<servlet-name>mvc-dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>mvc-dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/jms-config.xml,WEB-INF/root-context.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>
Here is my Spring configuration:
<context:component-scan base-package="com.con.*" />
<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" />
<!-- Web methods environment mappings -->
<bean id="webMethodProperties"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="file:/opt/app/jboss/current/modules/com/con/commons/logconfiguration/main/webmethods.properties" />
</bean>
<bean id="intialContext" class="javax.naming.InitialContext">
<constructor-arg>
<map>
<entry key="java.naming.factory.initial" value="${java.naming.factory.initial}" />
<entry key="java.naming.provider.url" value="${java.naming.provider.url}" />
<entry key="com.webmethods.jms.naming.clientgroup" value="${com.webmethods.jms.naming.clientgroup}" />
</map>
</constructor-arg>
</bean>
<!-- JNDI Template for accessing Web Method resources -->
<bean id="webMethodsJndiTemplate" class="org.springframework.jndi.JndiTemplate">
<property name="environment">
<map>
<entry key="java.naming.factory.initial" value="${java.naming.factory.initial}" />
<entry key="java.naming.provider.url" value="${java.naming.provider.url}" />
<entry key="com.webmethods.jms.naming.clientgroup" value="${com.webmethods.jms.naming.clientgroup}" />
</map>
</property>
</bean>
<bean id="destinationResolver"
class="org.springframework.jms.support.destination.JndiDestinationResolver">
<property name="jndiTemplate" ref="webMethodsJndiTemplate" />
<property name="cache" value="true" />
<property name="fallbackToDynamicDestination" value="false" />
</bean>
<!-- Custom ConnectionFactory to customize ClientId -->
<bean id="remoteJmsConnectionFactory"
class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetObject" ref="connectionFactoryHelper"/>
<property name="targetMethod" value="createJmsConnectionFactory"/>
</bean>
<!-- JMS MDB Container which recieves messages from Vantage S -->
<jms:listener-container container-type="default"
connection-factory="remoteJmsConnectionFactory" destination-type="durableTopic"
destination-resolver="destinationResolver" acknowledge="auto">
<jms:listener destination="beconEventingJMSTopic" ref="beconListener" id="jmslistener"
selector="${scrmessageselector}" subscription="${screventingsubscriber}"
method="onMessage" />
</jms:listener-container>
<bean id="beconListener" class="com.con.jms.OMIListener"/>
</beans>
Trying to start listener here
@Controller
public class StartJmsController {
@Resource(name="jmslistener")
private DefaultMessageListenerContainer beconListener;
@RequestMapping("/startscrjms")
public String hello(
@RequestParam(value = "name", required = false, defaultValue = "World") String name,
Model model) {
beconListener.start();
model.addAttribute("message", "JMS Listener started.");
return "jmsmessage";
}
}
Stop Listener here.
@Controller
public class StopJmsController {
@Resource(name="jmslistener")
private DefaultMessageListenerContainer beconListener;
@RequestMapping("/stopscrjms" )
public String printWelcome(ModelMap model, HttpSession session) {
beconListener.stop(new Runnable() {
public void run() {
System.out.println("JMS Listener stopped.");
}
});
model.addAttribute("message", "JMS Listener stopped.");
return "jmsmessage";
}
}
root-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- Empty -->
</beans>
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>WebMethodTopicSubscriber</groupId>
<artifactId>OMISCRPayLoad</artifactId>
<version>1.0</version>
<packaging>war</packaging>
<dependencies>
<dependency>
<groupId>com.wm.g11n</groupId>
<artifactId>wm-g11nutils</artifactId>
<version>8.2.2.4</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.webmethods.jms</groupId>
<artifactId>wm-brokerclient</artifactId>
<version>8.2.3</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.webmethods.jms</groupId>
<artifactId>wm-jmsnaming</artifactId>
<version>8.2.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.webmethods.jms</groupId>
<artifactId>wm-jmsclient</artifactId>
<version>8.2.2.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>antlr</groupId>
<artifactId>antlr</artifactId>
<version>2.7.7</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
<version>1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.4</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.1.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>commons-pool</groupId>
<artifactId>commons-pool</artifactId>
<version>1.6</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.logicblaze.fuse.liferay.dependencies</groupId>
<artifactId>jms</artifactId>
<version>fuse-4.1.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.2.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>4.0.3.RELEASE</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.0.3.RELEASE</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>4.0.3.RELEASE</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.0.3.RELEASE</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>4.0.3.RELEASE</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.0.3.RELEASE</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
<version>4.0.3.RELEASE</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>4.0.3.RELEASE</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>4.0.3.RELEASE</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.0.3.RELEASE</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.0.3.RELEASE</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.con.commons</groupId>
<artifactId>Configuration</artifactId>
<version>1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.1</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.1</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<sourceDirectory>src/main/java</sourceDirectory>
<resources>
<resource>
<directory>src/main/java</directory>
<filtering>true</filtering>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
</resources>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>2.3</version>
<configuration>
<warSourceDirectory>WebContent</warSourceDirectory>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
</plugins>
</build>
</project>
Read in the blog that probably this is the error " is that you are loading the container into both the web context (DispatcherServlet's context) and the root context (ContextLoaderListener's context). Which means you have 2 containers and you are only stopping the one in the servlet context"
Issue is similar Spring JMS Listener Container stop only half of listeners
But fix is not clear in the answer.
How can I fix this. ?
Upvotes: 2
Views: 1079
Reputation: 2152
In your web.xml change the Dispatcher Servlet definition to below.
<servlet>
<servlet-name>spring</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/jms-config.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
And remove the following part.
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/jms-config.xml,WEB-INF/root-context.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
Updated as per user comments
The recommended pattern is to have separate context for non web stuff and the web stuff. But in your case there doesn't seem to be anything in the root context, you can skip it if your app works that way.
In future if you require root scope - say you add ORM support in your app - you could always keep the ContextLoaderListener
entry in there with the contextConfigLocation
context param with the value as only your root context config file name.
As a side note, even if you decide to add the ORM support in your app you could very well do that in the web context and the app should work fine, just that it is not recommended.
Update try this.
<servlet>
<servlet-name>spring</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/jms-config.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/root-context.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
Upvotes: 1