segunda-feira, 3 de dezembro de 2012

Some hints about Assignment #3 - 2012/13

I'm afraid that web services are not working properly with version 4.11 server. Please try 4.10, but don't delete 4.11, as it has useful examples. The following are only suggestions, if you think of a simpler solution you are allowed (and encouraged) to use it:

1 - Unmarshall XML: use smooks.
2 - Splitter and Aggregator. You may write your own splitter. Check the streaming_aggregator example, the java class IncomingComposer (version 4.11). The difference as I explained in the class is that there is no final message to count the previous ones. Each message carries the total number of messages.
3 - Process details: check bpm_orchestrator4 (and the easier ones 1,2 and 3 before).
4 - Make the process reply: use <property name="reply-to-originator" value="true" /> in the action <action class="org.jboss.soa.esb.services.jbpm.actions.BpmProcessor" name="..."> of jboss-esb.xml. This requires that the process also uses <action class="org.jboss.soa.esb.services.jbpm.actionhandlers.EsbNotifier"> at some point (typically in the end). Again, this is done in the aforementioned examples (bpm_orchestrator4).
5 - Creation of web services and utilization as wrappers of the EJBs: in this blog message.
6 - Invoke web services: see example webservice_consumer1 (we may also see the others and use their approaches). You may also want to take a look at webservice_producer.

Don't forget to download the Programmers guide, from here.

segunda-feira, 19 de novembro de 2012

The HelloWorld in the JBoss Enterprise Service Bus

INSTALLING JBOSS ESB

Let's start by istalling JBoss ESB. First the bad news: we can't use JBoss AS 7. We have two options, both of them with their own problems. Either we install (the full blown) JBoss ESB server version 4.11 or we need to revert to JBoss AS 6 and install the ESB (non-server) 4.11 on top of it.

(Option 1) It is easier to download and install the standalone server JBoss ESB distribution. However, it uses a pretty old JBoss distribution, the 4.2.3, at the time I write this document. This means that many of the code you have in Java EE may not run there.

(Option 2) If you go for the other option, JBoss AS 6 is available here. Pick the last one (6.1.0.Final). You can find the JBoss ESB server distributions here. Pick the one that is not server: jbossesb-4.11.zip. The documentation, which you can find here, explains how to install JBoss ESB into the JBoss AS 6 you downloaded. I found it simple and it the installation worked pretty well to me. Unfortunately, I never managed to run the bpm_orchestration3 example that comes with the code (the web interface crashes), something you will need to do in EAI. So, if this example do not work for you either, you should go for Option 1.

INSTALLING JBOSS DEVELOPER STUDIO

Next, we need to install the JBoss Developer Studio (JDS) IDE enriched with the SOA tooling. This may not be entirely trivial to do. For me it was hard to find a location from where to download the SOA tooling. Moreover, you must register on the RedHat site to download JDS.

At least in theory you may do similar steps to use plain Eclipse plus some plug-ins. Nevertheless, it is certainly easier to install JDS and SOA Tooling. Check these sites:
Jboss Developer Studio 5.x
SOA Tooling

This latter web page didn't work well for me. I had to download a zip to my local disk and use the Help->Install New Software menu of the JDS and point it to the location of the contents I downloaded to get the following image:


THE HELLOWORLD ESB PROJECT

Now, if everything went smoothly, we should be able to create an ESB project. Take a look at the jbossesb-server-4.11/samples directory and to the "helloworld" project. We will make a copy of it using JDS. Go to the File menu, pick "New" and look for ESB. You should get to this point:


You may want to set up the JBoss ESB for the project as well (by clicking next and next again):

The samples/helloworld example contains three java source files. Copy the MyJMSListenerAction.java to your JDS project.

You will also need the "jobss-esb.xml" file. Copy it into the "esbcontent/META-INF" folder. Don't be afraid to overwrite the file with the same name that was there before. Two more files:
deployment.xml, which contains a list of JMS queues required, and jam-queue-service.xml (Option 1 above) or hornetq-jms.xml (Option 2), which instructs JBOSS to create those queues. The "deployment.xml" goes to the "esbcontent/META-INF" directory, while the latter goes to the "esbcontent" directory. The organization of the files should look like this:

(Option 1)

or
(Option 2)

In Option 2, the file deployment.xml must change to look as follows, otherwise do not touch it:

<?xml version="1.0" encoding="UTF-8"?>
<jbossesb-deployment>
 <depends>org.hornetq:module=JMS,type=Queue,name="quickstart_helloworld_Request_esb"</depends>
 <depends>org.hornetq:module=JMS,type=Queue,name="quickstart_helloworld_Request_gw"</depends>
</jbossesb-deployment>


So, let's deploy the project, by taking the following steps:

Then:

 And finally (pick your own directory):

Check the URL http://localhost:8080/contract/ to see whether the service is running, as you can see in the lowest box of the following figure:

THE CLIENT PROJECT - USING JMS

Everything that follows was tried only for Option 1 above. For Option 2 slight changes may apply. Let us just use a standard Java Project. Go to File-->New and then you may either see the option to create a Java Project, or you may need to pick "Other":

You may call it the HelloWorldClient. To work on this project, you should change the perspective on the right upper corner to Java (this is not mandatory). Copy the two files SendJMSMessage.java and SendEsbMessage.java to the "src" folder of the project. Again, these files are in the samples/quickstarts/helloworld example. After you move everything to the appropriate package, you should still see library problems:

You need a lot of external jar files and a library to solve the JMS related problems. Include all the jar files in the following directories (this will be necessary for directly sending an ESB message):

$JBOSS_HOME/server/default/deploy/jboss-aop-jdk50.deployer
$JBOSS_HOME/server/default/lib/
$JBOSS_HOME/client/

I should say that at some point I had to make sure to include the jboss-messaging.jar before the jbossall-client.jar. But you should not need to do this.

To add the Library just press the "Add Library..." button, when you are managing the build path:


You may either find the following window or you may have to push the "Manage ESB Runtimes". In the latter case you should point to the home of your jboss, $JBOSS_HOME, to come back to this window with an option to select:

All project errors should go, once you finish this step. Now, let us start by firing the service via the JMS gateway queue. You need to set the parameters of SendJMSMessage, as follows:

Let us say "Hello":

And the result on the console of JBoss should be the following:



THE CLIENT PROJECT - USING ESB ASYNCHRONOUS DELIVERY

Now, let us invoke the ESB service directly, without resorting to JMS. This can be tricky, due to configuration problems. 

First, we need to create a folder name META-INF with the uddi.xml file inside. This file is in the samples/quickstarts/conf/registry/META-INF. You also need the jbossesb-properties.xml, which is in the helloworld directory. The tree should look as follows:


Check your source folders, to ensure that JDS did not exclude the META-INF folder. The next figure shows that no folder is excluded:



We will now run the SendEsbMessage class. Look at the arguments:



They match the service category and name that we defined in the server project, in the file jboss-esb.xml. You can also find them here: http://localhost:8080/contract/.


Once you run this, the JBoss console should display signs of your activity displaying a friendly "HelloESBWorld".

sexta-feira, 26 de outubro de 2012

Using a Message-Driven Bean in JBoss 7

Let me describe the environment where this example runs: I assume that we will deploy a EJB in JBoss 7, and this JBoss includes an implementation of a queueing system accessible via Java Message Service. Additionally, I assumes that we already configured a queue named queue/PlayQueue. Refer to my other message about the Java Message Service for details on how to configure such queue. Again, we need to start JBoss in the following way, to start the messaging system:


./standalone.sh --server-config=standalone-full.xml



We now can write the code of the Message Bean. It is actually quite simple. Pick the Java EE perspective on the upper right corner of Eclipse. Then, create a new EJB Project (File-->New menu). Here I only show the source code of the bean in a Java package named message. The most important and not-so-obvious details concern the annotation @MessageDriven:



package message;

import javax.ejb.ActivationConfigProperty;
import javax.ejb.MessageDriven;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;

/**
 * Message-Driven Bean implementation class for: MyBean
 *
 */
@MessageDriven(
activationConfig = {
@ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
@ActivationConfigProperty(propertyName = "destination", propertyValue = "queue/PlayQueue")
},
mappedName = "queue/PlayQueue")
public class MyBean implements MessageListener {

    /**
     * Default constructor. 
     */
    public MyBean() {
    }
/**
     * @see MessageListener#onMessage(Message)
     */
    public void onMessage(Message message) {
    try {
System.out.println("Recebi: " + ((TextMessage) message).getText());
} catch (JMSException e) {
e.printStackTrace();
}
    }

}

To export the project to JBoss we do as usual:

The project in the form of a .jar file goes to standalone/deployments directory of JBoss:

You can now check the output of JBoss to see if everything went smoothly.

And now we need a program to send a message:


import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.naming.NamingException;


import org.hornetq.api.core.TransportConfiguration;
import org.hornetq.api.jms.HornetQJMSClient;
import org.hornetq.api.jms.JMSFactoryType;
import org.hornetq.core.remoting.impl.netty.NettyConnectorFactory;


public class Sender {
private ConnectionFactory cf;
private Connection c;
private Session s;
private Destination d;
private MessageProducer mp;

public Sender() throws NamingException, JMSException {
TransportConfiguration transportConfiguration =
new TransportConfiguration(NettyConnectorFactory.class.getName());              
cf = (ConnectionFactory) HornetQJMSClient.createConnectionFactoryWithoutHA(JMSFactoryType.CF,transportConfiguration);
c = cf.createConnection("joao", "pedro");
d = HornetQJMSClient.createQueue("PlayQueue");

this.s = this.c.createSession(false, Session.AUTO_ACKNOWLEDGE);
this.c.start();
this.mp = this.s.createProducer(this.d);
}

public void send(String contents) throws JMSException {
TextMessage m = this.s.createTextMessage();
m.setText(contents);
this.mp.send(m);
}

public void close() throws JMSException {
this.c.close();
}
public static void main(String[] args) throws NamingException, JMSException {
Sender s = new Sender();
s.send("Ola");
}

}

Once you execute this code you should get the following view or similar in JBoss' console:

quarta-feira, 26 de setembro de 2012

A few variations over JMS

PREVIOUS NOTE: Although not deprecated, as this example should work just fine with Java EE 7, I would consider the asynchronous receiver example in this message to be obsolete. I would advise the reader to consider this message instead.

In this message, I will provide a few examples that slightly change a sender-receiver synchronous interaction. In the basic example, the sender just sends a simple message, "OH OH OH", and the receiver just prints it. You should notice that the message goes through the JBoss Message Provider. For these examples to run you need to register a user, set up the queue and start the provider, just as I showed in "Java Message Service with JBoss AS 7". We will change this basic example to create:

The Basic Case

To get a sender look here (and a synchronous receiver): Java Message Service with JBoss AS 7.

The Asynchronous Receiver

Let us now change the Receiver to get messages asynchronously. One should notice that the main thread needs to be put on halt, or otherwise it will leave and kill the daemon thread of the session that is waiting for the message. The main difference is that the Receiver class now implements the MessageListener interface. When you run this receiver you should press enter in the console to finish it. The sender goes unchanged.


import java.io.IOException;

import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.MessageListener;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.naming.InitialContext;
import javax.naming.NamingException;


public class Receiver2 implements MessageListener {
private ConnectionFactory cf;
private Connection c;
private Session s;
private Destination d;
private MessageConsumer mc;

public Receiver2() throws NamingException, JMSException {
InitialContext init = new InitialContext();
this.cf = (ConnectionFactory) init.lookup("jms/RemoteConnectionFactory");
this.d = (Destination) init.lookup("jms/queue/PlayQueue");
this.c = (Connection) this.cf.createConnection("joao", "pedro");
this.c.start();
this.s = this.c.createSession(false, Session.AUTO_ACKNOWLEDGE);
mc = s.createConsumer(d);
mc.setMessageListener(this);
}

@Override
public void onMessage(Message msg) {
TextMessage tmsg = (TextMessage) msg;
try {
System.out.println(tmsg.getText());
} catch (JMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

private void close() throws JMSException {
this.c.close();
}


/**
* @param args
* @throws JMSException 
* @throws NamingException 
* @throws IOException 
*/
public static void main(String[] args) throws NamingException, JMSException, IOException {
Receiver2 r = new Receiver2();
System.in.read();
r.close();
}


}


ReplyTo and Temporary Destinations

Let us now play with the replyTo plus a temporary destination. The sender creates a queue where the receiver should send its reply to. I include only the code of the sender and the receiver that changes, starting from the sender.



Session s = c.createSession(false, Session.AUTO_ACKNOWLEDGE);
MessageProducer mp = s.createProducer(d);
TextMessage msg = s.createTextMessage();
Destination replyto = s.createTemporaryQueue();
msg.setJMSReplyTo(replyto);
msg.setText("OH OH OH");
mp.send(msg);
MessageConsumer mc = s.createConsumer(replyto);
TextMessage reply = (TextMessage) mc.receive();
System.out.println("Sender got back: " + reply.getText());
c.close();

The receiver:


Session s = c.createSession(false, Session.AUTO_ACKNOWLEDGE);
MessageConsumer mc = s.createConsumer(d);
TextMessage msg = (TextMessage) mc.receive();
System.out.println(msg.getText());
TextMessage reply = s.createTextMessage(msg.getText() + " to you too my friend!");
MessageProducer mp = s.createProducer(msg.getJMSReplyTo());
mp.send(reply);

c.close();



Durable Subscriptions


You need to do a few changes to make a durable subscription. First, you need to give an id to the connection, as follows (only the second line is new):


c = cf.createConnection("joao""pedro");
c.setClientID("joao");

To create an appropriate message consumer you need to do as follows. This is pretty much the same as you used to do with a regular message consumer, except that you need to add a subscriptionid (a regular string):

MessageConsumer mconsumer = s.createDurableSubscriber(topic, subscriptionid);
This means that the clientid is independent of the identifier of the subscription (presumably, the client can have multiple durable subscriptions, although I didn't explicitly tried).

We also need to allow the role "guest" to make durable subscriptions. For this we edit the standalone-full.xml file (see my previous post). Note the lines with the "durable" word in it:

                <security-settings>
                    <security-setting match="#">
                        <permission type="send" roles="guest"/>
                        <permission type="consume" roles="guest"/>
                        <permission type="createNonDurableQueue" roles="guest"/>
                        <permission type="deleteNonDurableQueue" roles="guest"/>
                        <permission type="createDurableQueue" roles="guest"/>
                        <permission type="deleteDurableQueue" roles="guest"/>
                    </security-setting>
                </security-settings>

Now, just restart the JBoss AS 7.



Filtering


Let us again consider sending a message. The server can add a set*Property to the message to provide additional hints for the receiver to filter. Hence, just add a single line to the original sender:

TextMessage msg = s.createTextMessage();
msg.setText("OH OH OH");
msg.setLongProperty("Idade", 15);
mp.send(msg);

The receiver needs to add a filter like this, at the time it creates the consumer:

MessageConsumer mc = s.createConsumer(d, "Idade < 80");

You can now play with the ages on the sender and receiver sides. One obvious question is: when the receiver filters out the message, does the message provider keep it? Or should we lose the message for ever? E.g., assume that we don't care for any age above 45, but the sender sends a 46. Will we get this 46, once we change the receiving filter to 50?


Transactions


Finally the transactions, starting again from the server (go back to the original example, once again):


Session s = c.createSession(true, 0);
MessageProducer mp = s.createProducer(d);
TextMessage msg = s.createTextMessage();
msg.setText("OH OH OH");
mp.send(msg);
s.commit();
c.close();


The receiver:


Session s = c.createSession(true, 0); 
MessageConsumer mc = s.createConsumer(d);
TextMessage msg = (TextMessage) mc.receive();
System.out.println(msg.getText());
s.commit();
c.close();

To fully explore this example, you may want to do the following: delete the commit of the receiver and send one message. Run the receiver over and over again. It will always get the message. Restore the commit on the receiver and delete the commit on the server side. Now, you will see that the message never gets to the receiver.


sexta-feira, 11 de maio de 2012

Java Message Service with JBoss AS 7

PREVIOUS NOTE: Although not deprecated, as this example should work just fine with Java EE 7, I would consider this message to be obsolete. I would advise the reader to consider this message instead.

In this message, I will guide the reader through the process of writing a simple sender-receiver application that uses a Java Message Service queue for the JBoss Application Server 7.1. It may be my fault, but as the time of writing of this message, I failed to find good documentation on how to run the most basic example of JMS in JBoss AS 7. This is what I show here. I will assume that the reader is familiar with JMS. There are plenty of resources out there on the web covering this topic, and it is not the goal of this blog to do the same.

I tried all this on Mac OS X Lion with the Brontes version of JBoss.

The first thing to know is that by default JBoss doesn't start with messaging. Therefore, you must explicitly use a different configuration that enables messaging. In the standalone case, you can do as follows, but you may want to defer starting the server to a later stage, after performing all necessary changes I describe:

./standalone.sh --server-config=standalone-full.xml

In other words, you need to specify the configuration file standalone-full.xml. The bad news is that we will need to change this configuration file, but this is not particularly difficult.

But before going into the server details, let us focus on the client applications. I will create one sender and one receiver application. They are pretty basic, in the sense that they only exchange one message and finish. I present them here. You can create your own standard Java project in Eclipse (or NetBeans) and add these two classes to the default package:


import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.naming.InitialContext;
import javax.naming.NamingException;


public class Sender {
private ConnectionFactory cf;
private Connection c;
private Session s;
private Destination d;
private MessageProducer mp;

public Sender() throws NamingException, JMSException {
InitialContext init = new InitialContext();
this.cf = (ConnectionFactory) init.lookup("jms/RemoteConnectionFactory");
this.d = (Destination) init.lookup("jms/queue/PlayQueue");
this.c = (Connection) this.cf.createConnection("joao", "pedro");
this.c.start();
this.s = this.c.createSession(false, Session.AUTO_ACKNOWLEDGE);
this.mp = this.s.createProducer(this.d);
}

private void send(String string) throws JMSException {
TextMessage tm = this.s.createTextMessage(string);
this.mp.send(tm);
}

private void close() throws JMSException {
this.c.close();
}

/**
* @param args
* @throws JMSException 
* @throws NamingException 
*/
public static void main(String[] args) throws NamingException, JMSException {
Sender s = new Sender();
s.send("Ola ca estou eu!");
s.close();
}


}

The Receiver:


import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.MessageConsumer;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.naming.InitialContext;
import javax.naming.NamingException;


public class Receiver {
private ConnectionFactory cf;
private Connection c;
private Session s;
private Destination d;
private MessageConsumer mc;

public Receiver() throws NamingException, JMSException {
InitialContext init = new InitialContext();
this.cf = (ConnectionFactory) init.lookup("jms/RemoteConnectionFactory");
this.d = (Destination) init.lookup("jms/queue/PlayQueue");
this.c = (Connection) this.cf.createConnection("joao", "pedro");
this.c.start();
this.s = this.c.createSession(false, Session.AUTO_ACKNOWLEDGE);
mc = s.createConsumer(d);
}

private String receive() throws JMSException {
TextMessage msg = (TextMessage) mc.receive();
return msg.getText();
}

private void close() throws JMSException {
this.c.close();
}

/**
* @param args
* @throws JMSException 
* @throws NamingException 
*/
public static void main(String[] args) throws NamingException, JMSException {
Receiver r = new Receiver();

String msg = r.receive();
System.out.println("Mensagem: " + msg);
r.close();
}

}


In this source code, what I found really problematic was to initialize the destination (the queue) and the ConnectionFactory. Eventually, I managed to use JNDI, as I should. I summarize the process in following lines:


InitialContext init = new InitialContext();
this.cf = (QueueConnectionFactory) init.lookup("jms/RemoteConnectionFactory");
this.d = (Destination) init.lookup("jms/queue/PlayQueue");
this.c = (Connection) this.cf.createConnection("joao""pedro");

We need the extra "jms" before the name of the resource. For this to work, we also need an extra file, the jndi.properties. Place this file in the src folder of your project (this will not work for WildFly. Check the new version in this message):


java.naming.factory.initial=org.jboss.naming.remote.client.InitialContextFactory
java.naming.provider.url=remote://localhost:4447
jboss.naming.client.ejb.context=true
#username
java.naming.security.principal=joao
#password
java.naming.security.credentials=pedro




To use the JMS libraries (and other JBoss client libraries by the way) you need to add the following jar file: (jboss-home)/bin/client/jboss-client.jar.



Note that we are providing the (very weak) user credentials of "joao" with password "pedro" to create the connection. For this to work, we need to add this user in the server running the add-user.sh (or .bat) available in the bin directory. The script will let us know in exactly which files did it do the modifications, but this is for the sake of curiosity only. I show this process in the next figure.


For this example to work we also need to add the queue to the standallone-full.xml file (refer to the command line in the top).



                <jms-destinations>
                    <jms-queue name="testQueue">
                        <entry name="queue/test"/>
                        <entry name="java:jboss/exported/jms/queue/test"/>
                    </jms-queue>
                    <jms-queue name="PlayQueue">
                        <entry name="queue/PlayQueue"/>
                        <entry name="java:jboss/exported/jms/queue/PlayQueue"/>
                    </jms-queue>
                    <jms-topic name="testTopic">
                        <entry name="topic/test"/>
                        <entry name="java:jboss/exported/jms/topic/test"/>
                    </jms-topic>
                </jms-destinations>



Now, you should be able to start the server first and then run the receiver and the sender in any order. Good luck!