ClassNotFoundException: com.ibm.mq.jms.MQConnectionFactory (Websphere MQ 7.5 + spring jms + maven tomcat 7 plugin)

12.7k views Asked by At

I am trying to create simple Webapp to demonstrate the using WMQ 7.5 in Servlet Container (tomcat). My webbap is based on standalone WMQ sample app. My standalone app works good.

The testcase is also good.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = AppConfig.class)
public class MQMessageTest {

    /**
     * Message count fot test
     */
    private static final int MESSAGE_COUNT = 25;

    /**
     * Setting Environment for getting properties
     */
    @Autowired
    private Environment environment;

    /**
     * MQMessageSender for sending messages
     */
    @Autowired
    private MQMessageSender mqMessageSender;

    /**
     * JmsTemplate of Spring JMS
     */
    @Autowired
    private JmsTemplate jmsTemplate;

    @Test
    public void testEqualsOfSentAndReceivedMessages() {

        /*Sending messages to Queue*/
        for (int i = 0; i < MESSAGE_COUNT; i++) {
            mqMessageSender.send("Message with" + System.nanoTime());
        }

        /*Container for received messages*/
        Set<TextMessage> messages = new HashSet<TextMessage>();

        /*Receiving messages from report Queue*/
        for (int i = 0; i < MESSAGE_COUNT; i++) {
            TextMessage message = (TextMessage) jmsTemplate.receive(environment.getRequiredProperty("wmq.queue.test.input.2"));
            messages.add(message);
        }

        assertEquals(messages.size(), MESSAGE_COUNT);
    }
}

But when I am starting tomcat I have the following issue:

org.springframework.web.context.support.AnnotationConfigWebApplicationContext loadBeanDefinitions
INFO: Registering annotated classes: [class by.iba.config.AppConfig]
июн 08, 2015 9:29:11 AM org.apache.catalina.core.ApplicationContext log
SEVERE: StandardWrapper.Throwable
**java.lang.NoClassDefFoundError: com/ibm/mq/jms/MQConnectionFactory**
    at java.lang.Class.getDeclaredMethods0(Native Method)
    at java.lang.Class.privateGetDeclaredMethods(Class.java:2615)
    at java.lang.Class.getDeclaredMethods(Class.java:1860)
    at org.springframework.core.type.StandardAnnotationMetadata.getAnnotatedMethods(StandardAnnotationMetadata.java:140)

... 30 more

июн 08, 2015 9:29:11 AM org.apache.catalina.core.StandardContext loadOnStartup
**SEVERE: Servlet /mqservice-webapp threw load() exception
java.lang.ClassNotFoundException: com.ibm.mq.jms.MQConnectionFactory**
    at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1702)

......

Please tell me what's the problem. How can I resolve it? Whe it need to be fixed: in tomcat or websphere MQ or spring jms? I was trying to work with jetty but it was fail.

My POM

<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>by.iba</groupId>
    <artifactId>mqservice-webapp</artifactId>
    <packaging>war</packaging>
    <version>1.0-SNAPSHOT</version>
    <name>Web MQ Module</name>
    <url>http://maven.apache.org</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <websphereMq.version>7.5.0.2</websphereMq.version>
        <wmq.jars>${basedir}/lib</wmq.jars>
        <spring.version>4.0.6.RELEASE</spring.version>
    </properties>

    <dependencies>

        <!--Websphere MQ dependencies-->

        <dependency>
            <groupId>com.ibm</groupId>
            <artifactId>com.ibm.mqjms</artifactId>
            <version>${websphereMq.version}</version>
            <scope>system</scope>
            <systemPath>${wmq.jars}/com.ibm.mqjms.jar</systemPath>
        </dependency>

        <dependency>
            <groupId>com.ibm</groupId>
            <artifactId>com.ibm.mq.headers</artifactId>
            <version>${websphereMq.version}</version>
            <scope>system</scope>
            <systemPath>${wmq.jars}/com.ibm.mq.headers.jar</systemPath>
        </dependency>

        <dependency>
            <groupId>com.ibm</groupId>
            <artifactId>com.ibm.mq.jmqi</artifactId>
            <version>${websphereMq.version}</version>
            <scope>system</scope>
            <systemPath>${wmq.jars}/com.ibm.mq.jmqi.jar</systemPath>
        </dependency>

        <dependency>
            <groupId>com.ibm</groupId>
            <artifactId>com.ibm.dhbcore</artifactId>
            <version>${websphereMq.version}</version>
            <scope>system</scope>
            <systemPath>${wmq.jars}/dhbcore.jar</systemPath>
        </dependency>

        <!--Spring-->

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jms</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>org.apache.geronimo.specs</groupId>
            <artifactId>geronimo-jms_1.1_spec</artifactId>
            <version>1.1.1</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <!--Javax Servlet API-->

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <scope>provided</scope>
        </dependency>

        <!--Junit-->

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.6</version>
            <scope>test</scope>
        </dependency>

    </dependencies>

    <build>
        <plugins>

            <!-- Jetty Plugin -->

            <!--<plugin>-->
                <!--<groupId>org.mortbay.jetty</groupId>-->
                <!--<artifactId>maven-jetty-plugin</artifactId>-->
                <!--<version>6.1.10</version>-->
            <!--</plugin>-->

            <!-- Set JDK Compiler Level -->

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.3</version>
                <configuration>
                    <source>1.7</source>
                    <target>1.7</target>
                    <encoding>${project.build.sourceEncoding}</encoding>
                </configuration>
            </plugin>

            <!-- Tomcat Plugin -->

            <plugin>
                <groupId>org.apache.tomcat.maven</groupId>
                <artifactId>tomcat7-maven-plugin</artifactId>
                <version>2.2</version>
                <configuration>
                   <server>local_tomcat</server>
                </configuration>
            </plugin>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>2.4</version>
                <configuration>
                    <warName>mqservice-webapp</warName>
                    <failOnMissingWebXml>false</failOnMissingWebXml>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

WebConfig

@Configuration
@ComponentScan({"..."})
@PropertySource(value = {"classpath:by.iba/wmq.properties"})
public class AppConfig {

    /**
     * Logger is using for tracing status of the application configuration
     */
    public static final Logger LOGGER = Logger.getLogger(AppConfig.class.getName());

    /**
     * Environment Bean for working with properties
     */
    @Autowired
    private Environment environment;

    /**
     * Method provides setting up the MQConnectionFactory Bean in Binding mode
     *
     * @return MQConnectionFactory is set up in binding mode
     * @throws JMSException if setting up MQConnectionFactory failed
     */
    @Bean
    public MQConnectionFactory mqBindingConnectionFactory() {
        MQConnectionFactory connectionFactory = new MQConnectionFactory();
        try {
            connectionFactory.setHostName(environment.getRequiredProperty("wmq.qmgr.host"));
            connectionFactory.setPort(environment.getProperty("wmq.qmgr.port", Integer.class));
            connectionFactory.setQueueManager(environment.getRequiredProperty("wmq.qmgr.name"));
            connectionFactory.setTransportType(environment.getProperty("wmq.qmgr.transport.type.binding", Integer.class));
            connectionFactory.setCCSID(environment.getProperty("wmq.qmgr.ccsid", Integer.class));
        } catch (JMSException e) {
            LOGGER.severe("Cannot set up binding connection factory" + e.getMessage());
        }
        return connectionFactory;
    }

    /**
     * Method provides setting up the MQConnectionFactory Bean in Client mode
     *
     * @return MQConnectionFactory is set up in client mode
     * @throws JMSException if setting up MQConnectionFactory failed
     */
    @Bean
    public MQConnectionFactory mqClientConnectionFactory() {
        MQConnectionFactory connectionFactory = new MQConnectionFactory();
        try {
            connectionFactory.setHostName(environment.getRequiredProperty("wmq.qmgr.host"));
            connectionFactory.setPort(environment.getProperty("wmq.qmgr.port", Integer.class));
            connectionFactory.setQueueManager(environment.getRequiredProperty("wmq.qmgr.name"));
            connectionFactory.setTransportType(environment.getProperty("wmq.qmgr.transport.type.client", Integer.class));
            connectionFactory.setCCSID(environment.getProperty("wmq.qmgr.ccsid", Integer.class));
            connectionFactory.setChannel(environment.getRequiredProperty("wmq.qmgr.channel"));
        } catch (JMSException je) {
            LOGGER.severe("Cannot set up client connection factory" + je.getMessage());
        }
        return connectionFactory;
    }

    /**
     * Method provides setting up Single Connection Factory Bean for using in Binding mode
     *
     * @return SingleConnectionFactory
     */
    @Bean
    public SingleConnectionFactory jmsQueueConnectionFactory() {
        SingleConnectionFactory singleConnectionFactory = new SingleConnectionFactory();
        singleConnectionFactory.setTargetConnectionFactory(mqBindingConnectionFactory());
        singleConnectionFactory.setReconnectOnException(true);
        return singleConnectionFactory;
    }

    /**
     * Method provides setting up UserCredentialsConnectionFactoryAdapter Bean for using in Client mode
     *
     * @return UserCredentialsConnectionFactoryAdapter
     */
    @Bean
    public UserCredentialsConnectionFactoryAdapter jmsQueueConnectionFactorySecured() {
        UserCredentialsConnectionFactoryAdapter connectionFactoryAdapter = new UserCredentialsConnectionFactoryAdapter();
        connectionFactoryAdapter.setTargetConnectionFactory(mqClientConnectionFactory());
        connectionFactoryAdapter.setUsername(environment.getRequiredProperty("wmq.qmgr.username"));
        connectionFactoryAdapter.setPassword(environment.getRequiredProperty("wmq.qmgr.password"));
        return connectionFactoryAdapter;
    }

    /**
     * Method provides setting up CachingConnectionFactory Bean to organize connection pool
     *
     * @return CachingConnectionFactory
     */
    @Bean
    public CachingConnectionFactory cachingConnectionFactory() {
        CachingConnectionFactory cachingConnectionFactory = new CachingConnectionFactory();
        cachingConnectionFactory.setTargetConnectionFactory(jmsQueueConnectionFactorySecured());
        cachingConnectionFactory.setCacheConsumers(true);
        cachingConnectionFactory.setCacheProducers(true);
        cachingConnectionFactory.setSessionCacheSize(5);
        return cachingConnectionFactory;
    }

    /**
     * Method provides setting up DynamicDestinationResolver Bean
     *
     * @return DynamicDestinationResolver
     */
    @Bean
    public DynamicDestinationResolver destinationResolver() {
        return new DynamicDestinationResolver();
    }

    /**
     * Method provides setting up JmsTemplate Bean
     *
     * @return DynamicDestinationResolver
     */
    @Bean
    public JmsTemplate jmsQueueTemplate() {
        JmsTemplate jmsTemplate = new JmsTemplate();
        jmsTemplate.setConnectionFactory(jmsQueueConnectionFactorySecured()); // optionally switching client mode
//        jmsTemplate.setConnectionFactory(jmsQueueConnectionFactory()); // optionally switching binding mode
        jmsTemplate.setDestinationResolver(destinationResolver());
        jmsTemplate.setReceiveTimeout(10000);
        return jmsTemplate;
    }

    /**
     * Method provides setting up MQMessageListener Bean for getting messages
     * from Websphere MQ and his personal settings
     *
     * @return MQMessageListener
     */
    @Bean
    public MQMessageListener mqMessageListener() {
        return new MQMessageListener();
    }

    /**
     * Method provides MQMessageSender Bean for sending messages
     * to Websphere MQ and his personal settings
     *
     * @return @MQMessageSender
     */
    @Bean
    public MQMessageSender mqMessageSender() {
        MQMessageSender mqMessageSender = new MQMessageSender();
        mqMessageSender.setDestinationQueue(environment.getRequiredProperty("wmq.queue.test.input.1"));
        mqMessageSender.setForwardQueue(environment.getRequiredProperty("wmq.queue.test.input.2"));
        return mqMessageSender;
    }

    /**
     * Method provides DefaultMessageListenerContainer Bean for sending messages
     *
     * @return DefaultMessageListenerContainer
     */
    @Bean
    public DefaultMessageListenerContainer jmsListenerContainer() {
        DefaultMessageListenerContainer dmlc = new DefaultMessageListenerContainer();
        try {
            dmlc.setConnectionFactory(mqClientConnectionFactory()); // optionally switching client mode
//            dmlc.setConnectionFactory(mqBindingConnectionFactory()); // optionally switching binding mode
            dmlc.setConcurrentConsumers(environment.getProperty("wmq.listener.concurrent.consumers", Integer.class));
            dmlc.setMessageListener(mqMessageListener());
            dmlc.setDestination(new MQDestination(environment.getRequiredProperty("wmq.queue.test.input.1")));
        } catch (JMSException je) {
            LOGGER.severe(je.getMessage());
        }
        return dmlc;
    }

}

WEB Initializer

public class WebInitializer implements WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
        ctx.register(AppConfig.class);
        ctx.setServletContext(servletContext);

        ServletRegistration.Dynamic servlet = servletContext.addServlet("dispatcher", new DispatcherServlet(ctx));
        servlet.setLoadOnStartup(1);
        servlet.addMapping("/");
    }
}

Thanks a lot. Sorry for my English

1

There are 1 answers

1
Umapathy On

Does the final war include the MQ jar files? I think its a problem with the build where the IBM MQ jar files are missing and hence ClassNotFoundException.

I suggest, go with a filesystem repository for maven instead of directly linking to the source with systempath. Refer Maven: add a dependency to a jar by relative path. Add MQ Jars to this repository and add these as dependencies in your POM.

Another option is to use the shared classloader in catalina.properties. Here you can load the MQ jars directly from /opt/mqm/java/lib.