Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Sorry, JMS 2.0 standalone examples are not that simple

DZone's Guide to

Sorry, JMS 2.0 standalone examples are not that simple

· Java Zone
Free Resource

Make it happen: rapid app development on Kubernetes as a managed service.

Well I going to have to leave this one for somebody who is more expert than me, because I have more things to do with my time now. I had a question from a reader about the source code for Java EE 7 Developer Handbook. Does JMS 2.0 standalone work as a client? What I understood from this, was that a developer should be able to run GlassFish 4 and get access to JMS queues and topics from a standalone container. I used to do this for investment banks using J2EE 1.4 with WebSphere and WebLogic application servers and so I said sure that code I worked with several months is bound to work, the reader’s question is more likely my own oversight. I must have been dreaming about these results.

I am sorry say, I spent several days going through this experience of getting GlassFish Embedded 4.0, then Managed Server to work together in order to demonstrate a straightforward JMS 2.0 standalone example. I also a use Arquillian test to work and then also tried a non-Arquillian version and now I am very perturbed. It would appear nobody knows on the Net how to exactly configure a standalone JMS 2.0 as a Java SE application.

This is as far as I get:

package je7hb.jms.essentials;

import static org.junit.Assert.*;

import javax.annotation.Resource;
import javax.ejb.*;
import javax.jms.*;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.container.test.api.RunAsClient;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.shrinkwrap.api.ArchivePaths;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.asset.EmptyAsset;
import org.jboss.shrinkwrap.api.spec.JavaArchive;
import org.jboss.shrinkwrap.api.spec.WebArchive;
import org.junit.*;
import org.junit.runner.RunWith;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

@RunWith(Arquillian.class)
public class AsynchronousJMSMessageArquillianTest {

    @Deployment
    public static WebArchive createDeployment() {
        WebArchive webArchive = ShrinkWrap.create(WebArchive.class, "asyncjms.war")
                .addClasses(PayloadCheck.class)
                .addAsWebInfResource(
                        new File("src/test/resources-glassfish-managed/glassfish-resources.xml"),
                        "glassfish-resources.xml")
                .addAsWebInfResource(
                        EmptyAsset.INSTANCE, "beans.xml");

        System.out.println(webArchive.toString(true));
        return webArchive;
    }

    private List<String> messages = new ArrayList<>();

    private CompletionListener completionListener = new CompletionListener() {
        @Override
        public void onCompletion(Message msg) {
            TextMessage textMsg = (TextMessage)msg;
            try {
                System.out.printf("%s.onCompletion(%s) Thread: %s\n",
                        getClass().getSimpleName(), textMsg.getText(), Thread.currentThread());
            } catch (JMSException e) {
                e.printStackTrace(System.err);
            }
        }

        @Override
        public void onException(Message msg, Exception ex) {
            ex.printStackTrace(System.err);
        }
    };

    @Test
    @RunAsClient
    public void shouldFire() throws JMSException, InterruptedException, NamingException {
        Properties properties = new Properties();
//        properties.put("com.sun.appserv.iiop.endpoints", "localhost:7676");
//        properties.put("org.omg.CORBA.ORBInitialHost", "localhost");
//        properties.put("org.omg.CORBA.ORBInitialPort", "3700");
//        properties.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.enterprise.naming.SerialInitContextFactory");
//        properties.put(Context.PROVIDER_URL, "mq://localhost:7676/");
//        properties.put("java.naming.factory.url.pkgs", "com.sun.enterprise.naming");
//        properties.put("java.naming.factory.state", "com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl");

        properties.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.enterprise.naming.SerialInitContextFactory");
        properties.put(Context.URL_PKG_PREFIXES, "com.sun.enterprise.naming");
        properties.put(Context.STATE_FACTORIES, "com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl");
//        properties.put("org.omg.CORBA.ORBInitialHost", "localhost");
//        properties.put("org.omg.CORBA.ORBInitialPort", "3700");
        properties.put(Context.PROVIDER_URL, "mq://localhost:7676"); // vm://localhost:
//        properties.put(Context.PROVIDER_URL, "iiop://localhost:7676"); // vm://localhost:

        InitialContext jndiContext = new InitialContext(properties);
        System.out.printf("\t jndiContext=%s\n", jndiContext);

        ConnectionFactory connectionFactory =
                (ConnectionFactory)jndiContext.lookup("jms/demoConnectionFactory");

        Queue queue = (Queue)jndiContext.lookup("jms/demoQueue");

        assertNotNull(connectionFactory);
        assertNotNull(queue);

        Connection connection = connectionFactory.createConnection();
        JMSContext context = connectionFactory.createContext(
                Session.AUTO_ACKNOWLEDGE );
        JMSProducer producer = context.createProducer();

        messages.clear();

        producer.setAsync(completionListener);

        producer.send(queue, "hello");
        producer.send(queue, "world");
        producer.send(queue, "asynchronously");

        Thread.sleep(2000); // Delay before shutdown

        System.out.println("Done");

    }
}

The evidence is in the code and you can review commented out lines, because every which way and some has been tried.

The reason is that certain calls such as setAsync are forbidden in a Java EE and web container. Therefore if you want an asynchronous JMS reader or writer in EE you can forget about it.

The glassfish resource configuration file is:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE resources PUBLIC "-//GlassFish.org//DTD GlassFish Application Server 3.1 Resource Definitions//EN" "http://glassfish.org/dtds/glassfish-resources_1_5.dtd">
<resources>
    <admin-object-resource enabled="true" jndi-name="jms/demoQueue" object-type="user" res-adapter="jmsra" res-type="javax.jms.Queue">
        <description/>
        <property name="Name" value="PhysicalQueue"/>
    </admin-object-resource>
    <admin-object-resource enabled="true" jndi-name="jms/demoTopic" object-type="user" res-adapter="jmsra" res-type="javax.jms.Topic">
        <description/>
        <property name="Name" value="PhysicalTopic"/>
    </admin-object-resource>
    <connector-connection-pool name="jms/demoDestinationFactoryPool"
                               connection-definition-name="javax.jms.QueueConnectionFactory"
                               resource-adapter-name="jmsra" />
    <connector-resource enabled="true"
                        jndi-name="jms/demoConnectionFactory"
                        pool-name="jms/demoDestinationFactoryPool"
                        object-type="system-all" />
</resources>

In fact, it is such an embarrassing state of affairs, I would recommend not look at GlassFish for a standalone JMS client, but maybe to wait for WildFly or Tom EE. Clearly, using JMS 2.0 outside of EE container is very unamusing, and I think this has be bloody easier for new developers, otherwise they want touch Java EE with a barge pole. If the technical expert cannot develop a simple example of outside-of-container JMS use then what is the point? The official JMS 2.0 page is also unhelpful.

Part of the problem is that there is no standard client side JMS API for Java SE, JAX RS 2.0 now has a client-side API. Another is that some of the GlassFish Maven artifacts have huge dependencies, which cause the download of the entire application server’s modules (I pointing a finger at gf-client:4.0-SNAPSHOT). Finally, this hardshell problem is not really documented and sadly, Java EE 7 tutorial sample code is only accessible as part of a bundle and not independently for quick access.

So my plan, is to leave this JMS async project as part of the book’s code distribution. I am sorry that the code does not work at all. This code should work as a single integration test in the reference implementation GlassFish and Arquillian. I have no more time to devote it, but I will exclude building it (because the test fails) in the new Gradle dynamic task sub-project enhancements, which I am currently writing now.

:-| +PP+

Tutorial: WordPress as distributed microservices on Kubernetes.

Topics:

Published at DZone with permission of Peter Pilgrim, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}