Administrator Administrator [
http://community.jboss.org/people/admin] modified the
document:
"How to use an application client in JBoss-5"
To view the document, visit:
http://community.jboss.org/docs/DOC-12835
--------------------------------------------------------------
This wiki tries to explain the usage of application client container in JBoss. It consists
of two parts: first an EJB is injected, the second part shows how to inject a
MessageDrivenBean Queue.
h1. Injection of EJBs
In this example, we are trying to inject an EJB into an application-client and then invoke
a method on that EJB in the client. +This has been tested on JBoss-5 GA. The attached
example is compiled with Java5.+ So let's get started:
h6. *Step-1:Deploy th**e application*
Deploy the enterprise application which contains the EJB as well as the
application-client, onto the JBoss-5 GA server. Here's what the Stateless.ear
contains:
META-INF/MANIFEST.MF
StatelessEJB.jar
StatelessClient.jar
a) The StatelessEJB.jar is the jar which contains the EJB. The EJB is simple and has a
couple of methods:
import javax.ejb.Stateless;
@Stateless
public class GeometricModelBean
implements GeometricModelRemote, GeometricModelLocal
{
public double computeCuboidVolume(double a, double b, double c)
{
// some code here
}
public double computeCuboidSurface(double a, double b, double c)
{
// some code here
}
}
b) The StatelessClient.jar is the application client which uses the EJB (through
injection). Here's the class which has the main function:
import javax.ejb.EJB;
public class GeometricModelApplicationClient
{
*@EJB
public static GeometricModelRemote geometricModel;*
public static void main(String[] args)
{
double dblVolume;
try
{
dblVolume = geometricModel.computeCuboidVolume(10.0D, 5.0D, 7.0D);
double dblSurface = geometricModel.computeCuboidSurface(10.0D, 5.0D, 7.0D);
System.out.println("Calculated volume: " + dblVolume + ", surface:
" + dblSurface);
}
catch (Exception ex)
{
ex.printStackTrace();
}
}
}
As you can see, the EJB is being injected in the client and later on used to invoke a
method. The StatelessClient.jar should contain a application-client.xml and a
jboss-client.xml (optional) to be identified as a application client. Here are the
contents of these files:
+StatelessClient.jar /META-INF/application-client.xml+
<?xml version="1.0" encoding="UTF-8"?>
<application-client id="Application-client_ID" version="5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/application-client_5.xsd">
<display-name>StatelessClient</display-name>
</application-client>
+StatelessClient.jar/META-INF/jboss-client.xml+:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE jboss-client PUBLIC
"-//JBoss//DTD Application Client 5.0//EN"
"http://www.jboss.org/j2ee/dtd/jboss-client_5_0.dtd">
<jboss-client>
<jndi-name>StatelessClient</jndi-name>
</jboss-client>
And then the StatelessClient.jar/META-INF/MANIFEST.MF should point to the application
client class which has the main function.
+StatelessClient.jar/META-INF/MANIFEST.MF+:
Manifest-Version: 1.0
Class-Path: StatelessEJB.jar
Main-Class:
de.fhw.komponentenarchitekturen.knauf.stateless.GeometricModelApplicationClient
Note that this ear does not have an application.xml. But if required, you can have one.
When this EAR is successfully deployed on the JBoss-5 GA server, you will see the
following log output on the console:
13:55:57,734 INFO [JBossASKernel] Created KernelDeployment for: StatelessClient.jar
13:55:57,734 INFO [JBossASKernel] installing bean:
jboss.j2ee:ear=Stateless.ear,jar=StatelessClient.jar,name=StatelessClient,service=EJB3
13:55:57,734 INFO [JBossASKernel] with dependencies:
13:55:57,734 INFO [JBossASKernel] and demands:
13:55:57,734 INFO [JBossASKernel] and supplies:
13:55:57,734 INFO [JBossASKernel] Added
bean(jboss.j2ee:ear=Stateless.ear,jar=StatelessClient.jar,name=StatelessClient,service=EJB3)
to KernelDeployment of: StatelessClient.jar
13:56:00,156 INFO [JBossASKernel] Created KernelDeployment for: StatelessEJB.jar
13:56:00,156 INFO [JBossASKernel] installing bean:
jboss.j2ee:ear=Stateless_BrokenAppClient2.ear,jar=StatelessEJB.jar,name=GeometricModelBean,service=EJB3
13:56:00,156 INFO [JBossASKernel] with dependencies:
13:56:00,156 INFO [JBossASKernel] and demands:
13:56:00,156 INFO [JBossASKernel] jboss.ejb:service=EJBTimerService
13:56:00,156 INFO [JBossASKernel] and supplies:
13:56:00,156 INFO [JBossASKernel]
jndi:Stateless/GeometricModelBean/local-de.fhw.komponentenarchitekturen.knauf.stateless.GeometricModelLocal
13:56:00,156 INFO [JBossASKernel]
jndi:Stateless/GeometricModelBean/remote-de.fhw.komponentenarchitekturen.knauf.stateless.GeometricModelRemote
13:56:00,156 INFO [JBossASKernel]
Class:de.fhw.komponentenarchitekturen.knauf.stateless.GeometricModelRemote
13:56:00,156 INFO [JBossASKernel] jndi:Stateless/GeometricModelBean/local
13:56:00,156 INFO [JBossASKernel]
Class:de.fhw.komponentenarchitekturen.knauf.stateless.GeometricModelLocal
13:56:00,171 INFO [JBossASKernel] jndi:Stateless/GeometricModelBean/remote
13:56:00,171 INFO [JBossASKernel] Added
bean(jboss.j2ee:ear=Stateless.ear,jar=StatelessEJB.jar,name=GeometricModelBean,service=EJB3)
to KernelDeployment of: StatelessEJB.jar
13:56:00,437 INFO [ClientENCInjectionContainer] STARTED CLIENT ENC CONTAINER:
StatelessClient
13:56:01,171 INFO [SessionSpecContainer] Starting
jboss.j2ee:ear=Stateless_BrokenAppClient2.ear,jar=StatelessEJB.jar,name=GeometricModelBean,service=EJB3
13:56:01,187 INFO [EJBContainer] STARTED EJB:
de.fhw.komponentenarchitekturen.knauf.stateless.GeometricModelBean ejbName:
GeometricModelBean
13:56:01,203 WARN [SessionSpecContainer] Populating JBoss-specific annotation metadata
manually until done by deployers:
jboss.j2ee:ear=Stateless.ear,jar=StatelessEJB.jar,name=GeometricModelBean,service=EJB3
....
13:56:01,656 INFO [ServerImpl] JBoss (Microcontainer) [5.0.0.GA (build:
SVNTag=JBoss_5_0_0_GA date=200809171046)] Started in 1m:8s:299ms
In your JNDIView you can now see that the application client has been bound to the JNDI:
java:comp namespace of the component
jboss.j2ee:ear=Stateless.ear,jar=StatelessEJB.jar,name=GeometricModelBean,service=EJB3 :
+- EJBContext (class: javax.ejb.EJBContext)
+- TransactionSynchronizationRegistry[link ->
java:TransactionSynchronizationRegistry] (class: javax.naming.LinkRef)
+- UserTransaction (class: org.jboss.ejb3.tx.UserTransactionImpl)
+- env (class: org.jnp.interfaces.NamingContext)
+- ORB[link -> java:/JBossCorbaORB] (class: javax.naming.LinkRef)
Global JNDI Namespace
+- StatelessClient (class: org.jnp.interfaces.NamingContext)
| +- UserTransaction[link -> UserTransaction] (class: javax.naming.LinkRef)
| +- metaData (class: org.jboss.metadata.client.jboss.JBossClientMetaData)
| +- env (class: org.jnp.interfaces.NamingContext)
| | +- geometricModel[link ->
Stateless/GeometricModelBean/remote-de.fhw.komponentenarchitekturen.knauf.stateless.GeometricModelRemote]
(class: javax.naming.LinkRef)
| +- classPathEntries (class: java.util.ArrayList)
h6. *Step-2: Use the* *appclient-launcher to launch the application client container.*
Now that the EAR containing the bean and the application client has been deployed, the
next step is to launch the application client container. Note: Just running the
application client class through a java command will not get the injection working. You
need the launcher to provide the application server functionalities.
From the command prompt, 'cd' to %JBOSS_HOME%\client folder. I
have JBoss installed in D:\jboss-5.0.0.GA so from my command prompt, i will cd to
D:\jboss-5.0.0.GA\client folder:
D:\jboss-5.0.0.GA\client>set JBOSS_HOME=d:\jboss-5.0.0.GA
D:\jboss-5.0.0.GA\client>set JAVA_HOME=c:\jdk1.6.0_10
D:\jboss-5.0.0.GA\client>set PATH=%JAVA_HOME%\bin;%PATH%
Now use the following command to launch the application client container:
D:\jboss-5.0.0.GA\client>%JAVA_HOME%\bin\java
-Djava.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
-Djava.naming.provider.url=jnp://localhost:1099 -classpath
"%JBOSS_HOME%\client\jbossall-client.jar;%JBOSS_HOME%\client\jboss-metadata.jar;%JBOSS_HOME%\lib\jboss-classloader.jar;%JBOSS_HOME%\lib\jboss-classloading-spi.jar;%JBOSS_HOME%\lib\jboss-classloading-vfs.jar;%JBOSS_HOME%\lib\jboss-classloading.jar;%JBOSS_HOME%\lib\jboss-dependency.jar;%JBOSS_HOME%\lib\jboss-reflect.jar;%JBOSS_HOME%\lib\jboss-kernel.jar;%JBOSS_HOME%\lib\jboss-xml-binding.jar;%JBOSS_HOME%\lib\jboss-xml-binding.jar;%JBOSS_HOME%\lib\jboss-vfs.jar;%JBOSS_HOME%\lib\jboss-reflect.jar;%JBOSS_HOME%\common\lib\jboss-ejb3-core.jar"
org.jboss.client.AppClientMain -jbossclient
de.fhw.komponentenarchitekturen.knauf.stateless.GeometricModelApplicationClient -launchers
org.jboss.ejb3.client.ClientLauncher -j2ee.clientName StatelessClient
The entire command should be in one single line. The important things to note in this
command (other than the classpath stuff) is that:
a) We are passing the JNDI related properties:
-Djava.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
-Djava.naming.provider.url=jnp://localhost:1099
The -Djava.naming.provider.url should point to the server's Naming port.
*+Where is the "-Djava.naming.factory.url.pkgs" argument?+*
This argument is required, if the client app performs a JNDI lookup itself, and it's
value has to be "org.jboss.naming.client".
But this one is not used by the Injection framework. jaikirans investigations found that
the environment property Context.URL_PKG_PREFIXES does not come into picture when using
injection because of the way org.jboss.ejb3.client.JNDIDependencyItem is working. It does
not look into the java:comp/env namespace but just looks up and adds a dependency on
StatelessClient/metaData jndiname. Later on when the actual lookup for java:comp/env
namespace is done on the jndi *server*, the properties that are on the server are used.
b) We are calling the org.jboss.client.AppClientMain which is the application client
container's entry point
c) We are passing -jbossclient parameter and its corresponding value
de.fhw.komponentenarchitekturen.knauf.stateless.GeometricModelApplicationClient to
org.jboss.client.AppClientMain. This is your application client main class which uses the
EJB
d) We are also passing the -j2ee.clientName which is the name of your application client
to org.jboss.client.AppClientMain. In this case, its StatelessClient.
e) We are passing the -launchers org.jboss.ejb3.client.ClientLauncher to
org.jboss.client.AppClientMain. This one is important. The -launchers accepts a comma
separate list of fully qualified implementations of org.jboss.client.AppClientLauncher
interface. The org.jboss.ejb3.client.ClientLauncher is one such implementation (provided
by JBoss) which is responsible for injecting EJB (and some other things) in the
application client.
h6. *Step-3: See th**e output.*
When you run the command mentioned in Step-2, the application client container will invoke
the main method of your application client. In our example, the main method uses the
injected EJB and invokes a method on the EJB and finally prints the following output on
the client side:
Calculated volume: 350.0, surface: 310.0
Note, on the server side you might see the EJB related logs (if you have any logging
messages).
That's it!
*P.S: The application attached here is provided by Wolfgang Knauf*
http://www.jboss.com/index.html?module=bb&op=viewtopic&t=143595
http://www.jboss.com/index.html?module=bb&op=viewtopic&t=143595
h5. Why don't i see logs on the application client side?
By default, with the command used in Step-2, you will not see the log message. The log
messages are really useful when debugging any issue. You have to do 2 things to see logs
on the client side:
1) Add log4j.jar to the client classpath
2) Add a log4j properties or xml file to the classpath or pass -Dlog4j.configuration=[path
to log4j config file] JVM option.
On my setup, i created a log4j.properties file with the following settings:
log4j.rootLogger=DEBUG, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%t][%c] - <%m>%n
And then placed this file under %JBOSS_HOME%\client folder. Finally i changed the java
command (in Step-2) to include the log4j.jar and also pass this log4j configuration file
path as a JVM option. Here's the updated command:
D:\jboss-5.0.0.GA\client>%JAVA_HOME%\bin\java
-Djava.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
-Djava.naming.provider.url=jnp://localhost:1099
-Dlog4j.configuration=%JBOSS_HOME%\client\log4j.properties -classpath
"%JBOSS_HOME%\client\jbossall-client.jar;%JBOSS_HOME%\client\jboss-metadata.jar;%JBOSS_HOME%\client\log4j.jar;%JBOSS_HOME%\lib\jboss-classloader.jar;%JBOSS_HOME%\lib\jboss-classloading-spi.jar;%JBOSS_HOME%\lib\jboss-classloading-vfs.jar;%JBOSS_HOME%\lib\jboss-classloading.jar;%JBOSS_HOME%\lib\jboss-dependency.jar;%JBOSS_HOME%\lib\jboss-reflect.jar;%JBOSS_HOME%\lib\jboss-kernel.jar;%JBOSS_HOME%\lib\jboss-xml-binding.jar;%JBOSS_HOME%\lib\jboss-vfs.jar;%JBOSS_HOME%\lib\jboss-reflect.jar;%JBOSS_HOME%\common\lib\jboss-ejb3-core.jar"
org.jboss.client.AppClientMain -jbossclient
de.fhw.komponentenarchitekturen.knauf.stateless.GeometricModelApplicationClient -launchers
org.jboss.ejb3.client.ClientLauncher -j2ee.clientName StatelessClient
If Log4j does not show the expected results, add "-Dlog4j.debug=true" to the
startup parameters, which will print Log4j debugging output and hopefully point you to the
reason why e.g. the config file could not be found.
h5.
h1. Injection of a Queue
(credits for this chapter go to jaikiran, I (Wolfgang) just documented his findings here,
see
http://www.jboss.org/index.html?module=bb&op=viewtopic&t=149330
http://www.jboss.org/index.html?module=bb&op=viewtopic&t=149330 ).
Assume a client that wants to send data to a queue (e.g. a Message Driven Bean).
You need a javax.jms.QueueConnectionFactory and a javax.jms.Queue, which will be injected
by the container. As they are injected, they must be static variables in the class
containing the "main" method (annotations will be added later):
private static QueueConnectionFactory queueConnectionFactory;
private static Queue queue;
This is the code to send the message (one more "Hello World" sample ;-) ):
QueueConnection queueConnection = queueConnectionFactory.createQueueConnection();
QueueSession queueSession = queueConnection.createQueueSession(false,
Session.AUTO_ACKNOWLEDGE);
QueueSender queueSender = queueSession.createSender(queue);
//Send a text message:
TextMessage textMessage = queueSession.createTextMessage();
textMessage.setText("Hello World");
queueSender.send(textMessage);
There are two possibilities to inject the Queue and QueueConnectionFactory.
We assume that our Queue (which points to a MDB) is bound to the global JNDI name
"queue/MessageBeanQueue". The QueueConnectionFactory is provided by JBoss (you
can find it in the JMXConsole as ObjectName
"jboss.messaging.connectionfactory").
h5. 1) From global JNDI
This one is easy: the "mappedName" attribute of the @Resource annotation points
to the global JNDI names:
@Resource(mappedName="ConnectionFactory")
private static QueueConnectionFactory queueConnectionFactory;
@Resource(mappedName="queue/MessageBeanQueue")
private static Queue queue;
h5. 2) From Environment Naming Context (ENC)
The "name" attribute of the @Resource annotation points to ENC names:
@Resource(name="jms/MBConnectionFactory")
private static QueueConnectionFactory queueConnectionFactory;
@Resource(name="jms/MBQueueRef")
private static Queue queue;
Here you need two config files:
*application-client.xml* looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<application-client id="Application-client_ID" version="5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/application-client_5.xsd">
...
<resource-ref>
<res-ref-name>jms/MBConnectionFactory</res-ref-name>
<res-type>javax.jms.QueueConnectionFactory</res-type>
<res-auth>Container</res-auth>
</resource-ref>
<message-destination-ref>
<message-destination-ref-name>jms/MBQueueRef</message-destination-ref-name>
<message-destination-type>javax.jms.Queue</message-destination-type>
</message-destination-ref>
</application-client>
The QueueConnectionFactory as declared as a resource-ref, while the Queue is declared as a
message-destination-ref !
*jboss-client.xml* handles the binding of the ENC entries to JBoss JNDI names:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE jboss-client PUBLIC
"-//JBoss//DTD Application Client 5.0//EN"
"http://www.jboss.org/j2ee/dtd/jboss-client_5_0.dtd">
<jboss-client>
<jndi-name>...</jndi-name>
<resource-ref>
<res-ref-name>jms/MBConnectionFactory</res-ref-name>
<jndi-name>ConnectionFactory</jndi-name>
</resource-ref>
<message-destination-ref>
<message-destination-ref-name>jms/MBQueueRef</message-destination-ref-name>
<jndi-name>queue/MessageBeanQueue</jndi-name>
</message-destination-ref>
</jboss-client>
Same as in application-client.xml: The Queue must be declared as a
message-destination-ref
A full sample can be found here:
http://www.informatik.fh-wiesbaden.de/~knauf/KomponentenArchitekturen2008...
http://www.informatik.fh-wiesbaden.de/~knauf/KomponentenArchitekturen2008...
(compiled with Java 1.6, will not run with 1.5)
It contains an EJB module with a MDB, and an application client module (simple swing
client with a JTextField whose content is sent to the server). The queue is declared in
the module with a -service.xml file in the EJB module. Simply deploy it to the server. To
run the client: extract "MessageClient.jar" from the EAR to some other
directory, and start the client using the ClientLauncher (see step 2 above).
The code is commented in German, but hopefully you will understand it anyway ;-)
--------------------------------------------------------------
Comment by going to Community
[
http://community.jboss.org/docs/DOC-12835]
Create a new document in EJB3 at Community
[
http://community.jboss.org/choose-container!input.jspa?contentType=102&am...]