Use the following to install the sun java developers kit on ubuntu gutsy:
sudo apt-get install sun-java6-jdk sun-java6-plugin sun-java6-fonts
sudo update-java-alternatives –set java-6-sun
Use the following to install the sun java developers kit on ubuntu gutsy:
sudo apt-get install sun-java6-jdk sun-java6-plugin sun-java6-fonts
sudo update-java-alternatives –set java-6-sun
Let’s use the previous JPA sample in an EJB. We start creating a datasource on the OC4J container. Then we create the entities again. After this we use the entities in a Stateless EJB which we will deploy to OC4J 11g. Finally we create a stand-alone client which calls the EJB.
We start with the creation of the datasource. We need a ConnectionPool.
java -jar $OC4J_ADMIN/j2ee/home/admin_client.jar deployer:oc4j:localhost oc4jadmin welcome -CreateJDBCConnectionPool -applicationName default -name HrConnectionPool -factoryClass oracle.jdbc.pool.OracleDataSource -user hr -password hr -url jdbc:oracle:thin:@localhost:1521:orcl
Test the connectionpool:
java -jar $OC4J_ADMIN/j2ee/home/admin_client.jar deployer:oc4j:localhost oc4jadmin welcome
-testConnectionPool -connectionPoolName HrConnectionPool -sqlStatement “select
* from dual” And the datasource:
java -jar $OC4J_ADMIN/j2ee/home/admin_client.jar deployer:oc4j:localhost oc4jadmin welcome -createManagedDataSource -applicationName default -dataSourceName HrDataSource -jndiLocation jdbc/HrDataSource -connectionPoolName HrConnectionPool
After this we create the entities:
/home/broersa/work/CountryApp/CountryJPAEJB/src/com/bekijkhet/entity/Country.java:
package com.bekijkhet.entity;
import java.io.Serializable;
import javax.persistence.*;
@Entity
@Table(name="COUNTRIES")
public class Country implements Serializable {
private String id;
private String name;
private Region region;
@Id
@Column(name="COUNTRY_ID")
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
@Column(name="COUNTRY_NAME")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@ManyToOne(cascade={CascadeType.ALL})
@JoinColumn(name="REGION_ID",nullable=false)
public Region getRegion() {
return region;
}
public void setRegion(Region region) {
this.region = region;
}
}
/home/broersa/work/CountryApp/CountryJPAEJB/src/com/bekijkhet/entity/Region.java
package com.bekijkhet.entity;
import java.io.Serializable;
import javax.persistence.*;
import static javax.persistence.CascadeType.*;
import static javax.persistence.FetchType.*;
import java.util.List;
import java.util.ArrayList;
@Entity
@Table(name="REGIONS")
public class Region implements Serializable {
private int id;
private String name;
private List<Country> countries = new ArrayList<Country>();;
@Id
@Column(name="REGION_ID")
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Column(name="REGION_NAME")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@OneToMany(fetch=FetchType.EAGER, cascade={CascadeType.ALL}, mappedBy="region")
public List<Country> getCountries() {
return countries;
}
public void setCountries(List<Country> newValue) {
this.countries = newValue;
}
}
The EJB:/home/broersa/work/CountryApp/CountryJPAEJB/src/com/bekijkhet/country/CountryEJBLocal.java:
package com.bekijkhet.country;
import com.bekijkhet.entity.*;
import java.util.List;
public interface CountryEJBLocal {
public List<Country> getCountriesByRegion(String region);
public Region getRegionByCountry(String country);
}
/home/broersa/work/CountryApp/CountryJPAEJB/src/com/bekijkhet/country/CountryEJB.java:
package com.bekijkhet.country;
import java.util.List;
import com.bekijkhet.entity.*;
public interface CountryEJB {
public List<Country> getCountriesByRegion(String region);
public Region getRegionByCountry(String country);
public void addorchangeCountry(Country country) ;
public void addorchangeRegion(Region region) ;
public void removeCountry(Country country) ;
public void removeRegion(Region region) ;
public List<Region> getAllRegions() ;
public List<Country> getAllCountries();
}
/home/broersa/work/CountryApp/CountryJPAEJB/src/com/bekijkhet/country/CountryEJBBean.java
package com.bekijkhet.country;
import javax.ejb.Stateless;
import javax.ejb.Remote;
import javax.ejb.Local;
import java.util.List;
import com.bekijkhet.entity.*;
import javax.persistence.*;
@Stateless
@Remote(CountryEJB.class)
@Local(CountryEJBLocal.class)
public class CountryEJBBean implements CountryEJB,CountryEJBLocal {
@PersistenceContext
EntityManager em;
public List<Country> getCountriesByRegion(String region) {
Query q = em.createQuery("select r from Region r where r.name = :name");
q.setParameter("name",region);
Region r = (Region) q.getSingleResult();
// r.getCountries().size(); // get the LAZY relation
return r.getCountries();
}
public Region getRegionByCountry(String country) {
Query q = em.createQuery("select c from Country c where c.name = :name");
q.setParameter("name",country);
Country c = (Country) q.getSingleResult();
return c.getRegion();
}
public void addorchangeCountry(Country country) {
em.persist(country);
}
public void addorchangeRegion(Region region) {
em.persist(region);
}
public void removeCountry(Country country) {
Country c = em.merge(country);
em.remove(c);
}
public void removeRegion(Region region) {
Region r = em.merge(region);
em.remove(r);
}
public List<Region> getAllRegions() {
Query q = em.createQuery("select r from Region r");
List<Region> l = q.getResultList();
return l;
}
public List<Country> getAllCountries() {
Query q = em.createQuery("select c from Country c");
List<Country> l = q.getResultList();
return l;
}
}
We need a persistence descriptor : /home/broersa/work/CountryApp/CountryJPAEJB/src/META-INF/persistence.xml:
<persistence>
<persistence-unit name="MyPU">
<jta-data-source>jdbc/HrDataSource</jta-data-source>
</persistence-unit>
</persistence>
We need the build file:/home/broersa/work/CountryApp/CountryJPAEJB/build.xml:
<project name="CountryJPAEJB" default="dist" basedir=".">
<description>
simple example build file
</description>
<!-- set global properties for this build -->
<property name="src" location="src"/>
<property name="build" location="build"/>
<property name="dist" location="dist"/>
<path id="files-classpath">
<!--fileset dir="$HOME/oc4j_client_11110_preview/j2ee/home/lib" >
<include name="persistence.jar"/>
</fileset-->
<pathelement location="/home/broersa/oc4j_client_11110_preview/j2ee/home/lib/persistence.jar"/>
<pathelement location="/home/broersa/oc4j_client_11110_preview/j2ee/home/lib/ejb.jar"/>
</path>
<target name="init">
<!-- Create the time stamp -->
<tstamp/>
<!-- Create the build directory structure used by compile -->
<mkdir dir="${build}"/>
</target>
<target name="compile" depends="init"
description="compile the source " >
<!-- Compile the java code from ${src} into ${build} -->
<javac srcdir="${src}" destdir="${build}">
<classpath refid="files-classpath" />
</javac>
</target>
<target name="dist" depends="compile"
description="generate the distribution" >
<!-- Create the distribution directory -->
<mkdir dir="${dist}"/>
<copy todir="${build}/META-INF">
<fileset dir="src/META-INF">
<include name="*" />
</fileset>
</copy>
<!-- Put everything in ${build} into the MyProject-${DSTAMP}.jar file -->
<jar jarfile="${dist}/CountryBean.jar" basedir="${build}"/>
</target>
<target name="clean"
description="clean up" >
<!-- Delete the ${build} and ${dist} directory trees -->
<delete dir="${build}"/>
<delete dir="${dist}"/>
</target>
</project>
We can build and deploy the EJB:type “ant” to build the EJB.use the next command to deploy the ejb:
java -jar $OC4J_ADMIN/j2ee/home/admin_client.jar deployer:oc4j:localhost oc4jadmin welcome -deploy -file $HOME/work/CountryApp/CountryJPAEJB/dist/CountryBean.jar -deploymentName CountryBean
Now this is done we can create the client:
/home/broersa/work/CountryApp/CountryClient/com/bekijkhet/CountryClient.java:
package com.bekijkhet;
import javax.naming.*;
import com.bekijkhet.country.CountryEJB;
import com.bekijkhet.entity.*;
import java.util.Properties;
import java.util.List;
public class CountryClient {
public static void main(String[] args) {
try {
Properties props = new Properties();
props.put("java.naming.factory.initial","com.evermind.server.ApplicationClientInitialContextFactory");
props.put("java.naming.provider.url","ormi://localhost/CountryBean");
props.put("java.naming.security.principal","oc4jadmin");
props.put("java.naming.security.credentials","welcome");
InitialContext ctx = new InitialContext(props);
CountryEJB h = (CountryEJB)ctx.lookup("CountryEJBBean");
System.out.println("The Netherlands has region: " + h.getRegionByCountry("Netherlands").getName());
List<Country> l1 = h.getCountriesByRegion("Europe");
System.out.println("Europe has the following countries:");
for (Country c : l1) {
System.out.println(" " + c.getName());
}
System.out.println("All regions:");
List<Region> l2 = h.getAllRegions();
for (Region r : l2) {
System.out.println(" " + r.getName());
}
System.out.println("All countries:");
List<Country> l3 = h.getAllCountries();
for (Country c2 : l3) {
System.out.println(" " + c2.getName() + " - " + c2.getRegion().getName());
}
Region r3 = new Region();
r3.setName("MyRegion1");
r3.setId(1001);
Country c3 = new Country();
c3.setName("MyCountry1");
c3.setId("31");
c3.setRegion(r3);
r3.getCountries().add(c3);
h.addorchangeCountry(c3);
Region r4 = new Region();
r4.setName("MyRegion2");
r4.setId(1002);
Country c4 = new Country();
c4.setName("MyCountry2");
c4.setId("32");
c4.setRegion(r4);
r4.getCountries().add(c4);
h.addorchangeRegion(r4);
System.out.println("All regions:");
List<Region> l5 = h.getAllRegions();
for (Region r5 : l5) {
System.out.println(" " + r5.getName());
}
System.out.println("All countries:");
List<Country> l6 = h.getAllCountries();
for (Country c6 : l6) {
System.out.println(" " + c6.getName() + " - " + c6.getRegion().getName());
}
}
catch (Exception e) {
System.out.println(e);
e.printStackTrace();
}
}
}
/home/broersa/work/CountryApp/CountryClient/com/bekijkhet/META-INF/application-client.xml:
<?xml version="1.0" encoding="UTF-8"?>
<application-client version="1.4" xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/application-client_1_4.xsd">
<display-name>CountryClient</display-name>
<description>test</description>
</application-client>
Compile the client:javac -cp $OC4J_HOME/j2ee/home/oc4jclient.jar:/home/broersa/work/CountryApp/CountryJPAEJB/dist/CountryBean.jar:. -d . CountryClient.javaAnd test the client:java -cp $OC4J_HOME/j2ee/home/oc4jclient.jar:/home/broersa/work/CountryApp/CountryJPAEJB/dist/CountryBean.jar:. com.bekijkhet.CountryClient
The Netherlands has region: Europe
Europe has the following countries:
Belgium
Switzerland
Germany
Denmark
France
Italy
Netherlands
United Kingdom
All regions:
Europe
Americas
Asia
Middle East and Africa
All countries:
Argentina – Americas
Australia – Asia
Belgium – Europe
Brazil – Americas
Canada – Americas
Switzerland – Europe
China – Asia
Germany – Europe
Denmark – Europe
Egypt – Middle East and Africa
France – Europe
HongKong – Asia
Israel – Middle East and Africa
India – Asia
Italy – Europe
Japan – Asia
Kuwait – Middle East and Africa
Mexico – Americas
Nigeria – Middle East and Africa
Netherlands – Europe
Singapore – Asia
United Kingdom – Europe
United States of America – Americas
Zambia – Middle East and Africa
Zimbabwe – Middle East and Africa
All regions:
Europe
Americas
Asia
Middle East and Africa
MyRegion1
MyRegion2
All countries:
MyCountry1 – MyRegion1
MyCountry2 – MyRegion2
Argentina – Americas
Australia – Asia
Belgium – Europe
Brazil – Americas
Canada – Americas
Switzerland – Europe
China – Asia
Germany – Europe
Denmark – Europe
Egypt – Middle East and Africa
France – Europe
HongKong – Asia
Israel – Middle East and Africa
India – Asia
Italy – Europe
Japan – Asia
Kuwait – Middle East and Africa
Mexico – Americas
Nigeria – Middle East and Africa
Netherlands – Europe
Singapore – Asia
United Kingdom – Europe
United States of America – Americas
Zambia – Middle East and Africa
Zimbabwe – Middle East and Africa
In this sample we will create a stand alone java app which uses the JPA (Toplink) api to connect to the HR sample schema in a Oracle database.
The hr schema must be unlocked and database must be accessible via the network.
We will start with the persistence.xml file.
/home/broersa/work/CountryApp/CountryJPA/build/META-INF/persistence.xml
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0"> <persistence-unit name="default"> <provider> oracle.toplink.essentials.PersistenceProvider </provider> <exclude-unlisted-classes>false</exclude-unlisted-classes> <properties> <property name="toplink.logging.level" value="INFO"/> <property name="toplink.jdbc.driver" value="oracle.jdbc.OracleDriver"/> <property name="toplink.jdbc.url" value="jdbc:oracle:thin:centos.bekijkhet.com:l521:orcl"/> <property name="toplink.jdbc.password" value="hr"/> <property name="toplink.jdbc.user" value="hr"/> </properties> </persistence-unit> </persistence>
After this the entities which represent the database objects. I choose the regions and countries tables.
/home/broersa/work/CountryApp/CountryJPA/src/com/bekijkhet/entity/Region.java
package com.bekijkhet.entity;
import java.io.Serializable;
import javax.persistence.*;
import static javax.persistence.CascadeType.*;
import java.util.List;
import java.util.ArrayList;
@Entity
@Table(name="REGIONS")
public class Region implements Serializable {
private int id;
private String name;
private List<Country> countries = new ArrayList<Country>();;
@Id
@Column(name="REGION_ID")
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Column(name="REGION_NAME")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@OneToMany(cascade={CascadeType.ALL}, mappedBy="region")
public List<Country> getCountries() {
return countries;
}
public void setCountries(List<Country> newValue) {
this.countries = newValue;
}
}
/home/broersa/work/CountryApp/CountryJPA/src/com/bekijkhet/entity/Country.java
package com.bekijkhet.entity;
import java.io.Serializable;
import javax.persistence.*;
@Entity
@Table(name="COUNTRIES")
public class Country implements Serializable {
private String id;
private String name;
private Region region;
@Id
@Column(name="COUNTRY_ID")
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
@Column(name="COUNTRY_NAME")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@ManyToOne()
@JoinColumn(name="REGION_ID",nullable=false)
public Region getRegion() {
return region;
}
public void setRegion(Region region) {
this.region = region;
}
}
Compile the entities:
cd /home/broersa/work/CountryApp/CountryJPA
javac -cp /home/broersa/oc4j_client_11110_preview/j2ee/home/lib/persistence.jar:build -d build src/com/bekijkhet/entity/*.java
After this the client app:
/home/broersa/work/CountryApp/CountryJPA/src/com/bekijkhet/client/Client.java:
package com.bekijkhet.client;
import javax.persistence.EntityManager;
import javax.persistence.Persistence;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Query;
import java.util.List;
import com.bekijkhet.entity.*;
public class Client {
private static EntityManagerFactory emf;
private static EntityManager em;
public static void main(String[] args) {
emf = Persistence.createEntityManagerFactory("default");
em = emf.createEntityManager();
// Find a country with region
Query q1 = em.createQuery("select c from Country c where c.id = :id");
q1.setParameter("id","NL");
Country c1 = (Country) q1.getSingleResult();
System.out.println(c1.getName() + " - " + c1.getRegion().getName());
// Find a region with countries
Query q2 = em.createQuery("select r from Region r where r.id = :id");
q2.setParameter("id",1);
Region r2 = (Region) q2.getSingleResult();
System.out.println(r2.getName());
List<Country> l2 = r2.getCountries();
for (Country c2 : l2) {
System.out.println(" " + c2.getName());
}
// Add a region with two countries
em.getTransaction().begin();
Region r3 = new Region();
r3.setId(1001);
r3.setName("MyRegion1");
Country c31 = new Country();
c31.setId("31");
c31.setName("MyCountry31");
c31.setRegion(r3);
r3.getCountries().add(c31);
Country c32 = new Country();
c32.setId("32");
c32.setName("MyCountry32");
c32.setRegion(r3);
r3.getCountries().add(c32);
em.persist(r3);
em.getTransaction().commit();
// List the added region with countries
Query q4 = em.createQuery("select r from Region r where r.id = :id");
q4.setParameter("id",1001);
Region r4 = (Region) q4.getSingleResult();
System.out.println(r4.getName());
List<Country> l4 = r4.getCountries();
for (Country c4 : l4) {
System.out.println(" " + c4.getName());
}
// Change the country names
em.getTransaction().begin();
Query q5 = em.createQuery("select r from Region r where r.id = :id");
q5.setParameter("id",1001);
Region r5 = (Region) q5.getSingleResult();
List<Country> l5 = r5.getCountries();
for (Country c5 : l5) {
c5.setName(c5.getName()+"-changed");
}
em.getTransaction().commit();
// List the added region with countries
Query q6 = em.createQuery("select r from Region r where r.id = :id");
q6.setParameter("id",1001);
Region r6 = (Region) q6.getSingleResult();
System.out.println(r6.getName());
List<Country> l6 = r6.getCountries();
for (Country c6 : l6) {
System.out.println(" " + c6.getName());
}
// Remove samples
// Remove a single detail
em.getTransaction().begin();
Query q7 = em.createQuery("select r from Region r where r.id = :id");
q7.setParameter("id",1001);
Region r7 = (Region) q7.getSingleResult();
System.out.println(r7.getName());
List<Country> l7 = r7.getCountries();
em.remove(l7.get(1));
em.getTransaction().commit();
// Remove samples
// Remove the whole region
em.getTransaction().begin();
Query q8 = em.createQuery("select r from Region r where r.id = :id");
q8.setParameter("id",1001);
Region r8 = (Region) q8.getSingleResult();
System.out.println(r8.getName());
em.remove(r8);
em.getTransaction().commit();
em.close();
}
}
compile and run:
cd /home/broersa/work/CountryApp/CountryJPA
javac -cp /home/broersa/oc4j_client_11110_preview/j2ee/home/lib/persistence.jar:build -d build src/com/bekijkhet/client/*.java
java -cp /home/broersa/oc4j_client_11110_preview/j2ee/home/lib/persistence.jar:/home/broersa/toplink_11.1.1.0_071214_preview-3/lib/java/api/toplink.jar:/home/broersa/myclasses/ojdbc6.jar:build -javaagent:/home/broersa/toplink_11.1.1.0_071214_preview-3/lib/java/internal/toplink-essentials-agent.jar com.bekijkhet.client.Client
[TopLink Info]: 2008.01.28 08:09:38.718–ServerSession(9519074)–TopLink, version: Oracle TopLink Essentials – 2.0 (Build SNAPSHOT (06/04/2007))
[TopLink Info]: 2008.01.28 08:09:41.744–ServerSession(9519074)–file:/home/broersa/work/CountryApp/CountryJPA/build/-default login successful
Netherlands – Europe
Europe
Belgium
Switzerland
Germany
Denmark
France
Italy
Netherlands
United Kingdom
MyRegion1
MyCountry31
MyCountry32
MyRegion1
MyCountry31-changed
MyCountry32-changed
MyRegion1
MyRegion1
In this example I create a Counter MBean which I will install in the Glassfish server. This bean has three methods getCounter, incrementCounter and resetCounter. After this I create an EJB which will increment the counter each time sayHello is called. We can then monitor the counter with the jconsole app. After reading a lot of different implementations I think this is in my opinion the best way to implement this. The problem I have with this implementation is that I can call the increment function from jconsole with which I can influence the counter.
Let’s start with the MBean:
/home/broersa/work/HelloApp/MyCounterMBean/src/com/bekijkhet/MyCounterMBean.java
package com.bekijkhet;
public interface MyCounterMBean {
public int getCounter();
public void incrementCounter();
public void resetCounter();
}
/home/broersa/work/HelloApp/MyCounterMBean/src/com/bekijkhet/MyCounter.java
package com.bekijkhet;
public class MyCounter implements MyCounterMBean {
public int counter = 0;
public int getCounter() {
return counter;
}
public void incrementCounter() {
counter++;
}
public void resetCounter() {
counter = 0;
}
}
/home/broersa/work/HelloApp/MyCounterMBean/build.xml
<project name="MyCounterMBean" default="compile" basedir=".">
<description>
simple example build file
</description>
<!-- set global properties for this build -->
<property name="src" location="src"/>
<property name="build" location="build"/>
<target name="init">
<!-- Create the time stamp -->
<tstamp/>
<!-- Create the build directory structure used by compile -->
<mkdir dir="${build}"/>
</target>
<target name="compile" depends="init"
description="compile the source " >
<!-- Compile the java code from ${src} into ${build} -->
<javac srcdir="${src}" destdir="${build}"/>
</target>
<target name="clean"
description="clean up" >
<!-- Delete the ${build} and ${dist} directory trees -->
<delete dir="${build}"/>
</target>
</project>
type:asant compileto compile the MBean.cd build
cp -r com /home/broersa/glassfish/domains/domain1/applications/mbeans
asadmin create-mbean com.bekijkhet.MyCounter
to deploy the managed bean.
Now it is time to create the statefull EJB which increments the counter in the MBean.
/home/broersa/work/HelloApp/MyCounterEJB/src/com/bekijkhet/MyCounterEJB.java
package com.bekijkhet;
public interface MyCounterEJB {
public String sayHello();
}
/home/broersa/work/HelloApp/MyCounterEJB/src/com/bekijkhet/MyCounterEJB.java
package com.bekijkhet;
import javax.ejb.Stateless;
import javax.ejb.EJB;
import javax.ejb.Remote;
import java.util.Properties;
import java.net.URL;
import javax.naming.*;
import javax.management.*;
import java.lang.management.*;
@Stateless
@Remote(MyCounterEJB.class)
public class MyCounterEJBBean implements MyCounterEJB {
private MyCounterMBean mbean = null;
public MyCounterEJBBean() {
try {
// Get the platform MBeanServer
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
ObjectName name = new ObjectName("user:impl-class-name=com.bekijkhet.MyCounter,name=com.bekijkhet.MyCounter,server=server");
mbean = (MyCounterMBean) MBeanServerInvocationHandler.newProxyInstance(mbs, name, MyCounterMBean.class, false);
} catch(Exception e) {
e.printStackTrace();
}
}
public String sayHello() {
mbean.incrementCounter();
return "Hello From Glassfish!!!! ";
}
}
/home/broersa/work/HelloApp/MyCounterEJB/build.xml
<project name="MyCounterEJB" default="dist" basedir=".">
<description>
simple example build file
</description>
<!-- set global properties for this build -->
<property name="src" location="src"/>
<property name="build" location="build"/>
<property name="dist" location="dist"/>
<target name="init">
<!-- Create the time stamp -->
<tstamp/>
<!-- Create the build directory structure used by compile -->
<mkdir dir="${build}"/>
</target>
<target name="compile" depends="init"
description="compile the source " >
<!-- Compile the java code from ${src} into ${build} -->
<javac srcdir="/home/broersa/work/HelloApp/MyCounterMBean/src" destdir="${build}"/>
<javac srcdir="${src}" destdir="${build}"/>
</target>
<target name="dist" depends="compile"
description="generate the distribution" >
<!-- Create the distribution directory -->
<mkdir dir="${dist}"/>
<!-- Put everything in ${build} into the MyProject-${DSTAMP}.jar file -->
<jar jarfile="${dist}/MyCounterEJB.jar" basedir="${build}"/>
</target>
<target name="clean"
description="clean up" >
<!-- Delete the ${build} and ${dist} directory trees -->
<delete dir="${build}"/>
<delete dir="${dist}"/>
</target>
</project>
In this build.xml I included a second javac rule that includes the MBean classes in this ejb.Now we build and deploy the ejb:
asant dist
asadmin deploy dist/MyCounterEJB.jar
Now it is time to create the client that calls the ejb sayhello method that increments our counter in the mbean.
package com.bekijkhet.helloclient;
import javax.naming.*;
import com.bekijkhet.MyCounterEJB;
public class HelloClient {
public static void main(String[] args) {
try {
InitialContext ctx = new InitialContext();
MyCounterEJB m = (MyCounterEJB)ctx.lookup("com.bekijkhet.MyCounterEJB");
System.out.println(m.sayHello());
}
catch (Exception e) {
System.out.println(e);
e.printStackTrace();
}
}
}
compile the code:javac -cp $GLASSFISH_HOME/lib/appserv-rt.jar:$GLASSFISH_HOME/lib/javaee.jar:$HOME/work/HelloApp/MyCounterEJB/dist/MyCounterEJB.jar:. -d . HelloClient.java
open a jconsole to monitor our Mbean. connect to localhost:8686 (which is the default portnumber) and connect with admin pwd: adminadmin

See the counter which has the value 0.
Now we run our client:
java -cp $GLASSFISH_HOME/lib/appserv-rt.jar:$GLASSFISH_HOME/lib/javaee.jar:$HOME/work/HelloApp/MyCounterEJB/dist/MyCounterEJB.jar:. com.bekijkhet.helloclient.HelloClient
And the counter is incremented by one:

In this example I created a counter that gets updated from multiple instances. All examples I found on internet are using a single agent instance. The crux is to create a static MBean object that is available to all instances of the agent class. Let’s get to the code:
/home/broersa/work/mbean/mypack/MyCounterMBean.java
package mypack;
public interface MyCounterMBean {
public int getCounter();
public void sayCounter();
}
/home/broersa/work/mbean/mypack/MyCounter.java
package mypack;
public class MyCounter implements MyCounterMBean {
private int counter = 0;
public MyCounter() {
counter = 0;
}
public int getCounter() {
return counter;
}
public void incCounter() {
counter++;
}
public void sayCounter() {
System.out.println(counter);
}
}
/home/broersa/work/mbean/mypack/SimpleAgent.java
package mypack;
import javax.management.*;
import java.lang.management.*;
public class SimpleAgent {
private static MyCounter counterBean = new MyCounter();
private MBeanServer mbs = null;
public SimpleAgent() {
// Get the platform MBeanServer
mbs = ManagementFactory.getPlatformMBeanServer();
// Unique identification of MBeans
// replaced by static var. Hello helloBean = new Hello();
ObjectName myCounterName = null;
try {
// Uniquely identify the MBeans and register them with the platform MBeanServer
myCounterName = new ObjectName("SimpleAgent:name=MyCounter");
mbs.registerMBean(counterBean, myCounterName);
} catch (InstanceAlreadyExistsException e) {
System.out.println("Instance Already Exists");
} catch(Exception e) {
e.printStackTrace();
}
counterBean.incCounter();
}
// Utility method: so that the application continues to run
private static void waitForEnterPressed() {
try {
System.out.println("Press to continue...");
System.in.read();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String argv[]) {
SimpleAgent agent1 = new SimpleAgent();
SimpleAgent agent2 = new SimpleAgent();
System.out.println("SimpleAgent is running...");
SimpleAgent.waitForEnterPressed();
}
}
goto the directory mbean and compile the code:
javac -d . mypack/MyCounter.java
javac -d . mypack/SimpleAgent.java
run the code:
java -Dcom.sun.management.jmxremote mypack.SimpleAgent
Instance Already Exists
SimpleAgent is running…
Press to continue…
When we connect to the MBeanServer using the jconsole utility we see the counter has the value 2:
In part 1 we created a sessionbean with authorization on the methods. In this exemple we get the same sessionbean but we add some progammatic logic in the method the make the authorization a bit more controllable. We add two functions to get the group info and one to get the current username.
For this example we use the same code from part 1. The only file we change is the one below:
/home/broersa/work/HelloApp/HelloSecurity/src/com/bekijkhet/HelloBean.java
package com.bekijkhet;
import javax.ejb.Stateless;
import javax.ejb.Remote;
import javax.annotation.security.RolesAllowed;
import javax.annotation.security.DenyAll;
import javax.annotation.security.PermitAll;
import javax.annotation.security.DeclareRoles;
import javax.annotation.Resource;
import java.security.Principal;
import javax.ejb.SessionContext;
@Stateless
@Remote(Hello.class)
@DeclareRoles({"superuser","user"})
public class HelloBean implements Hello {
@Resource SessionContext ctx;
@RolesAllowed("superuser")
public String sayHellosuperuser() {
return "sayHellosuperuser";
}
@RolesAllowed({"user","superuser"})
public String sayHellousersuperuser() {
return "sayHellousersuperuser";
}
@RolesAllowed("user")
public String sayHellouser() {
return "sayHellouser";
}
@PermitAll
public String sayHelloPermitAll() {
Principal callerPrincipal = ctx.getCallerPrincipal();
if (ctx.isCallerInRole("superuser")) {
return "sayHelloPermitAll as role superuser by "+callerPrincipal.getName();
}
if (ctx.isCallerInRole("user")) {
return "sayHelloPermitAll as role user by "+callerPrincipal.getName();
}
return "sayHelloPermitAll as role <unknown> by "+callerPrincipal.getName();
}
@DenyAll
public String sayHelloDenyAll() {
return "sayHelloDenyAll";
}
}
use asant dist to recreate the jar.
redeploy the jar with asadmin deploy dist/HelloSecurity.jar
rerun the client with the myadmin account:
java -cp $GLASSFISH_HOME/lib/appserv-rt.jar:$GLASSFISH_HOME/lib/appserv-admin.jar:$GLASSFISH_HOME/lib/javaee.jar:$HOME/work/HelloApp/HelloSecurity/dist/HelloSecurity.jar:. -Djava.security.auth.login.config=$GLASSFISH_HOME/lib/appclient/appclientlogin.conf com.bekijkhet.helloclient.HelloClient myadmin myadmin
1
2
3
sayHellosuperuser: sayHellosuperuser
sayHellousersuperuser: sayHellousersuperuser
sayHellouser: No Permission
sayHelloPermitAll: sayHelloPermitAll as role superuser by myadmin
sayHelloDenyAll: No Permission
We see that we get the role and the username. You can do the same with the myuser1 and myuser2 accounts and discover that they are in the user role.
Security is hot these days, so let’s start with a sample to implement it in the EJB session beans.
First thing to do is create three users in Glassfish:
asadmin create-file-user –groups myusergrp myuser1
asadmin create-file-user –groups myusergrp myuser2
asadmin create-file-user myadmin
We now created two users that have the group myusergrp and a myadmin user with no group.
After this we can create the secure bean:
/home/broersa/work/HelloApp/HelloSecurity/src/com/bekijkhet/Hello.java
package com.bekijkhet;
public interface Hello {
public String sayHellosuperuser();
public String sayHellousersuperuser();
public String sayHellouser();
public String sayHelloPermitAll();
public String sayHelloDenyAll();
}
/home/broersa/work/HelloApp/HelloSecurity/src/com/bekijkhet/HelloBean.java
package com.bekijkhet;
import javax.ejb.Stateless;
import javax.ejb.Remote;
import javax.annotation.security.RolesAllowed;
import javax.annotation.security.DenyAll;
import javax.annotation.security.PermitAll;
@Stateless
@Remote(Hello.class)
public class HelloBean implements Hello {
@RolesAllowed("superuser")
public String sayHellosuperuser() {
return "sayHellosuperuser";
}
@RolesAllowed({"user","superuser"})
public String sayHellousersuperuser() {
return "sayHellousersuperuser";
}
@RolesAllowed("user")
public String sayHellouser() {
return "sayHellouser";
}
@PermitAll
public String sayHelloPermitAll() {
return "sayHelloPermitAll";
}
@DenyAll
public String sayHelloDenyAll() {
return "sayHelloDenyAll";
}
}
Next we create the mapping wherein we map the application roles to the applicationserver users and groups./home/broersa/work/HelloApp/HelloSecurity/META-INF/sun-ejb-jar.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sun-ejb-jar PUBLIC "-//Sun Microsystems, Inc.//DTD Application Server 9.0 EJB 3.0//EN" "http://www.sun.com/software/appserver/dtds/sun-ejb-jar_3_0-0.dtd">
<sun-ejb-jar>
<security-role-mapping>
<role-name>user</role-name>
<group-name>myusergrp</group-name>
</security-role-mapping>
<security-role-mapping>
<role-name>superuser</role-name>
<principal-name>myadmin</principal-name>
</security-role-mapping>
</sun-ejb-jar>
and the buil.xml file/home/broersa/work/HelloApp/HelloSecurity/build.xml
<project name="HelloSecurity" default="dist" basedir=".">
<description>
simple example build file
</description>
<!-- set global properties for this build -->
<property name="src" location="src"/>
<property name="build" location="build"/>
<property name="dist" location="dist"/>
<target name="init">
<!-- Create the time stamp -->
<tstamp/>
<!-- Create the build directory structure used by compile -->
<mkdir dir="${build}"/>
</target>
<target name="compile" depends="init"
description="compile the source " >
<!-- Compile the java code from ${src} into ${build} -->
<javac classpath="$GLASSFISH_HOME/lib/javaee.jar" srcdir="${src}" destdir="${build}"/>
</target>
<target name="dist" depends="compile"
description="generate the distribution" >
<!-- Create the distribution directory -->
<mkdir dir="${dist}"/>
<copy todir="${build}/META-INF">
<fileset dir="META-INF">
<include name="*" />
</fileset>
</copy>
<!-- Put everything in ${build} into the MyProject-${DSTAMP}.jar file -->
<jar jarfile="${dist}/HelloSecurity.jar" basedir="${build}"/>
</target>
<target name="clean"
description="clean up" >
<!-- Delete the ${build} and ${dist} directory trees -->
<delete dir="${build}"/>
<delete dir="${dist}"/>
</target>
</project>
build the ejb with:asant distdeploy:asadmin deploy dist/HelloSecurity.jar
Now we must create the client:
/home/broersa/work/HelloApp/HelloClient/src/com/bekijkhet/helloclient/HelloClient.java
package com.bekijkhet.helloclient;
import javax.naming.*;
import com.bekijkhet.Hello;
import com.sun.appserv.security.ProgrammaticLogin;
public class HelloClient {
public static void main(String[] args) {
try {
ProgrammaticLogin login = new ProgrammaticLogin();
login.login(args[0],args[1]);
System.out.println("1");
InitialContext ctx = new InitialContext();
System.out.println("2");
Hello n = (Hello)ctx.lookup("com.bekijkhet.Hello");
System.out.println("3");
try {
System.out.print("sayHellosuperuser: ");
System.out.println(n.sayHellosuperuser());
} catch (javax.ejb.EJBException t) { System.out.println("No Permission"); }
try {
System.out.print("sayHellousersuperuser: ");
System.out.println(n.sayHellousersuperuser());
} catch (javax.ejb.EJBException t) { System.out.println("No Permission"); }
try {
System.out.print("sayHellouser: ");
System.out.println(n.sayHellouser());
} catch (javax.ejb.EJBException t) { System.out.println("No Permission"); }
try {
System.out.print("sayHelloPermitAll: ");
System.out.println(n.sayHelloPermitAll());
} catch (javax.ejb.EJBException t) { System.out.println("No Permission"); }
try {
System.out.print("sayHelloDenyAll: ");
System.out.println(n.sayHelloDenyAll());
} catch (javax.ejb.EJBException t) { System.out.println("No Permission"); }
}
catch (Exception x) {
System.out.println("Invalid Username Password");
}
}
}
Compile the code:javac -cp $GLASSFISH_HOME/lib/appserv-rt.jar:$GLASSFISH_HOME/lib/appserv-admin.jar:$GLASSFISH_HOME/lib/javaee.jar:$HOME/work/HelloApp/HelloSecurity/dist/HelloSecurity.jar:. -d . HelloClient.java
Run the code with different users:
as myadmin which is in the superuser role:
java -cp $GLASSFISH_HOME/lib/appserv-rt.jar:$GLASSFISH_HOME/lib/appserv-admin.jar:$GLASSFISH_HOME/lib/javaee.jar:$HOME/work/HelloApp/HelloSecurity/dist/HelloSecurity.jar:. -Djava.security.auth.login.config=$GLASSFISH_HOME/lib/appclient/appclientlogin.conf com.bekijkhet.helloclient.HelloClient myadmin myadmin
1
2
3
sayHellosuperuser: sayHellosuperuser
sayHellousersuperuser: sayHellousersuperuser
sayHellouser: No Permission
sayHelloPermitAll: sayHelloPermitAll
sayHelloDenyAll: No Permission
as myuser1 which is in the myusergrp which has the user role:
java -cp $GLASSFISH_HOME/lib/appserv-rt.jar:$GLASSFISH_HOME/lib/appserv-admin.jar:$GLASSFISH_HOME/lib/javaee.jar:$HOME/work/HelloApp/HelloSecurity/dist/HelloSecurity.jar:. -Djava.security.auth.login.config=$GLASSFISH_HOME/lib/appclient/appclientlogin.conf com.bekijkhet.helloclient.HelloClient myuser1 myuser1
1
2
3
sayHellosuperuser: No Permission
sayHellousersuperuser: sayHellousersuperuser
sayHellouser: sayHellouser
sayHelloPermitAll: sayHelloPermitAll
sayHelloDenyAll: No Permission
as myuser2 which is also in the myusergrp which has the user role:
java -cp $GLASSFISH_HOME/lib/appserv-rt.jar:$GLASSFISH_HOME/lib/appserv-admin.jar:$GLASSFISH_HOME/lib/javaee.jar:$HOME/work/HelloApp/HelloSecurity/dist/HelloSecurity.jar:. -Djava.security.auth.login.config=$GLASSFISH_HOME/lib/appclient/appclientlogin.conf com.bekijkhet.helloclient.HelloClient myuser2 myuser2
1
2
3
sayHellosuperuser: No Permission
sayHellousersuperuser: sayHellousersuperuser
sayHellouser: sayHellouser
sayHelloPermitAll: sayHelloPermitAll
sayHelloDenyAll: No Permission
When you call the client with an invalid username password combination you get an exception on the call to the Lookup of the bean. This is catched in the last catch in the client main method:
java -cp $GLASSFISH_HOME/lib/appserv-rt.jar:$GLASSFISH_HOME/lib/appserv-admin.jar:$GLASSFISH_HOME/lib/javaee.jar:$HOME/work/HelloApp/HelloSecurity/dist/HelloSecurity.jar:. -Djava.security.auth.login.config=$GLASSFISH_HOME/lib/appclient/appclientlogin.conf com.bekijkhet.helloclient.HelloClient myuser1 myuser
1
2
Invalid Username Password
In this sample we create an EJB that calls the MDB from previous blog.
Lets start with the EJB code (don’t look at the method names, I copied from a previous example
)
broersa@debian1:~/work/HelloApp/HelloMDBEJB/src/com/bekijkhet$ cat HelloMDBEJBLocal.java
package com.bekijkhet;
public interface HelloMDBEJBLocal {
public String sayHelloStateless();
public String sayHelloStatelessLocal();
public void setMember(String member);
}
broersa@debian1:~/work/HelloApp/HelloMDBEJB/src/com/bekijkhet$ cat HelloMDBEJB.java
package com.bekijkhet;
public interface HelloMDBEJB {
public String sayHelloStateless();
public String sayHelloStatelessRemote();
public void setMember(String member);
}
broersa@debian1:~/work/HelloApp/HelloMDBEJB/src/com/bekijkhet$ cat HelloMDBEJBBean.java
package com.bekijkhet;
import javax.ejb.Stateless;
import javax.ejb.Remote;
import javax.ejb.Local;
import javax.jms.*;
import javax.naming.*;
@Stateless
@Remote(HelloMDBEJB.class)
@Local(HelloMDBEJBLocal.class)
public class HelloMDBEJBBean implements HelloMDBEJB,HelloMDBEJBLocal {
private String member = "Not set!";
public String sayHelloStateless() {
try {
Context ctx = new InitialContext();
ConnectionFactory connectionFactory = (ConnectionFactory)ctx.lookup("jms/ConnectionFactory");
Queue queue = (Queue)ctx.lookup("jms/SampleQueue");
javax.jms.Connection connection = connectionFactory.createConnection();
javax.jms.Session session = connection.createSession(false,Session.AUTO_ACKNOWLEDGE);
MessageProducer messageProducer = session.createProducer(queue);
TextMessage message = session.createTextMessage();
message.setText("my test message");
System.out.println( "MDBEJB:"+ message.getText());
messageProducer.send(message);
connection.close();
} catch (Exception e) {System.out.println(e.toString());}
return "Hello Stateless "+member;
}
public String sayHelloStatelessLocal() {
return "Hello Local Stateless "+member;
}
public String sayHelloStatelessRemote() {
return "Hello Remote Stateless "+member;
}
public void setMember(String member) {
this.member=member;
}
}
broersa@debian1:~/work/HelloApp/HelloMDBEJB$ cat build.xml
<project name="HelloEJB" default="dist" basedir=".">
<description>
simple example build file
</description>
<!-- set global properties for this build -->
<property name="src" location="src"/>
<property name="build" location="build"/>
<property name="dist" location="dist"/>
<target name="init">
<!-- Create the time stamp -->
<tstamp/>
<!-- Create the build directory structure used by compile -->
<mkdir dir="${build}"/>
</target>
<target name="compile" depends="init"
description="compile the source " >
<!-- Compile the java code from ${src} into ${build} -->
<javac srcdir="${src}" destdir="${build}"/>
</target>
<target name="dist" depends="compile"
description="generate the distribution" >
<!-- Create the distribution directory -->
<mkdir dir="${dist}"/>
<!-- Put everything in ${build} into the MyProject-${DSTAMP}.jar file -->
<jar jarfile="${dist}/HelloMDBEJB.jar" basedir="${build}"/>
</target>
<target name="clean"
description="clean up" >
<!-- Delete the ${build} and ${dist} directory trees -->
<delete dir="${build}"/>
<delete dir="${dist}"/>
</target>
</project>
after this build with
asant dist
and deploy
asadmin deploy dist/HelloMDBEJB.jar
than the client to call the EJB which is similar to the client in the previous samples:
broersa@debian1:~/work/HelloApp/HelloClient/src/com/bekijkhet/helloclient$ cat HelloMDBEJBClient.java
package com.bekijkhet.helloclient;
import javax.naming.*;
import com.bekijkhet.HelloMDBEJB;
public class HelloMDBEJBClient {
public static void main(String[] args) {
try {
InitialContext ctx = new InitialContext();
HelloMDBEJB h = (HelloMDBEJB)ctx.lookup("com.bekijkhet.HelloMDBEJB");
System.out.println(h.sayHelloStateless());
}
catch (Exception e) {
System.out.println(e);
e.printStackTrace();
}
}
}
compile:
javac -cp $GLASSFISH_HOME/lib/appserv-rt.jar:$GLASSFISH_HOME/lib/javaee.jar:$HOME/work/HelloApp/HelloMDBEJB/dist/HelloMDBEJB.jar:. -d . HelloMDBEJBClient.java
run:
java -cp $GLASSFISH_HOME/lib/appserv-rt.jar:$GLASSFISH_HOME/lib/javaee.jar:$HOME/work/HelloApp/HelloMDBEJB/dist/HelloMDBEJB.jar:. com.bekijkhet.helloclient.HelloMDBEJBClient
Hello Stateless Not set!
and the output in the $GLASSFISH_HOME/domains/domain1/logs/server.log
[#|2007-11-23T13:49:49.076+0100|INFO|sun-appserver9.1|javax.enterprise.system.stream.out|_ThreadID=26;_ThreadName=p: thread-pool-1; w: 61;|
MDBEJB:my test message|#]
[#|2007-11-23T13:49:49.091+0100|INFO|sun-appserver9.1|javax.enterprise.system.stream.out|_ThreadID=26;_ThreadName=p: thread-pool-1; w: 61;|
Got message: my test message|#]
Next example is a message driven bean deployed on glassfish that gets called by a stand alone client. Let start with creating the JMS Connection Factory and the JMS Queue on glassfish.
Issue the following statement to create the connection factory:
asadmin create-jms-resource –restype javax.jms.ConnectionFactory jms/ConnectionFactory
After this create the resource destination:
asadmin create-jmsdest -T queue sampleQueue
Create the JMS destination:
asadmin create-jms-resource –restype javax.jms.Queue –property Name=sampleQueue jms/SampleQueue
Now we can create the Message Driven Bean:
broersa@debian1:~/work/HelloApp/HelloMDB/src/com/bekijkhet$ cat HelloMDB.java
package com.bekijkhet;
import javax.ejb.MessageDriven;
import javax.jms.MessageListener;
import javax.jms.Message;
import javax.jms.TextMessage;
@MessageDriven(mappedName="jms/SampleQueue")
public class HelloMDB implements MessageListener {
public void onMessage(Message msg) {
try {
if (msg instanceof TextMessage) {
TextMessage txtmsg = (TextMessage) msg;
System.out.println("Got message: "+txtmsg.getText());
}
} catch (Exception e) { System.out.println(e.toString()); }
}
}
broersa@debian1:~/work/HelloApp/HelloMDB$ cat build.xml
<project name="HelloMDB" default="dist" basedir=".">
<description>
simple example build file
</description>
<!-- set global properties for this build -->
<property name="src" location="src"/>
<property name="build" location="build"/>
<property name="dist" location="dist"/>
<target name="init">
<!-- Create the time stamp -->
<tstamp/>
<!-- Create the build directory structure used by compile -->
<mkdir dir="${build}"/>
</target>
<target name="compile" depends="init"
description="compile the source " >
<!-- Compile the java code from ${src} into ${build} -->
<javac srcdir="${src}" destdir="${build}"/>
</target>
<target name="dist" depends="compile"
description="generate the distribution" >
<!-- Create the distribution directory -->
<mkdir dir="${dist}"/>
<!-- Put everything in ${build} into the MyProject-${DSTAMP}.jar file -->
<jar jarfile="${dist}/HelloMDB.jar" basedir="${build}"/>
</target>
<target name="clean"
description="clean up" >
<!-- Delete the ${build} and ${dist} directory trees -->
<delete dir="${build}"/>
<delete dir="${dist}"/>
</target>
</project>
Build and deploy the MDB:asant dist
asadmin deploy dist/HelloMDB.jar
Let’s go on creating the stand alone client to call the MDB.
broersa@debian1:~/work/HelloApp/HelloClient/src/com/bekijkhet/helloclient$ cat HelloMDBClient.java
package com.bekijkhet.helloclient;
import javax.naming.*;
import javax.jms.*;
public class HelloMDBClient {
public static void main(String args[]) {
try {
// will get the local default context from appserv-rt.jar
Context ctx = new InitialContext();
ConnectionFactory connectionFactory = (ConnectionFactory)ctx.lookup("jms/ConnectionFactory");
Queue queue = (Queue)ctx.lookup("jms/SampleQueue");
javax.jms.Connection connection = connectionFactory.createConnection();
javax.jms.Session session = connection.createSession(false,Session.AUTO_ACKNOWLEDGE);
MessageProducer messageProducer = session.createProducer(queue);
TextMessage message = session.createTextMessage();
message.setText("my own text message");
System.out.println( "Send: "+ message.getText());
messageProducer.send(message);
connection.close();
} catch (Exception e) {System.out.println(e.toString());}
}
}
Compile and run:
javac -cp $GLASSFISH_HOME/lib/appserv-rt.jar:$GLASSFISH_HOME/lib/javaee.jar:. -d . HelloMDBClient.java
java -cp $GLASSFISH_HOME/lib/appserv-rt.jar:$GLASSFISH_HOME/lib/javaee.jar:$GLASSFISH_HOME/lib/install/applications/jmsra/imqjmsra.jar:$GLASSFISH_HOME/lib/appserv-admin.jar:. com.bekijkhet.helloclient.HelloMDBClient
<snipped a lot of initialisation output..>
Send: my own text message
When we look at the server log file ($GLASSFISH_HOME/domains/domain1/logs/server.log) we can see the MDB got fired:
[#|2007-11-23T12:17:45.309+0100|INFO|sun-appserver9.1|javax.enterprise.system.stream.out|_ThreadID=23;_ThreadName=p: thread-pool-1; w: 34;|
Got message: my own text message|#]
After this my client app (HelloMDBClient) hangs….. Press ctrl-c to end the process. I can’t find a solution to get the program exit normally… It looks like another thread got starten to listen for incomming messages??
In the next sample I create an EJB to send messages which will be run from inside the container. This seams to work without hanging. Maybe someone can explain?
In this example I show the difference between Stateful en Stateless EJB’s. First I create and deploy the stateful bean.
broersa@debian1:~/work/HelloApp/HelloStateful/src/com/bekijkhet$ cat HelloStateful.java
package com.bekijkhet;
public interface HelloStateful {
public String sayHelloStateful();
public String sayHelloStatefulRemote();
public void setMember(String member);
}
broersa@debian1:~/work/HelloApp/HelloStateful/src/com/bekijkhet$ cat HelloStatefulLocal.java
package com.bekijkhet;
public interface HelloStatefulLocal {
public String sayHelloStateful();
public String sayHelloStatefulLocal();
public void setMember(String member);
}
broersa@debian1:~/work/HelloApp/HelloStateful/src/com/bekijkhet$ cat HelloStatefulBean.java
package com.bekijkhet;
import javax.ejb.Stateful;
import javax.ejb.Remote;
import javax.ejb.Local;
@Stateful
@Remote(HelloStateful.class)
@Local(HelloStatefulLocal.class)
public class HelloStatefulBean implements HelloStateful,HelloStatefulLocal {
private String member = "Not set!";
public String sayHelloStateful() {
return "Hello Stateful "+member;
}
public String sayHelloStatefulLocal() {
return "Hello Local Stateful "+member;
}
public String sayHelloStatefulRemote() {
return "Hello Remote Stateful "+member;
}
public void setMember(String member) {
this.member=member;
}
}
broersa@debian1:~/work/HelloApp/HelloStateful$ cat build.xml
<project name="HelloEJB" default="dist" basedir=".">
<description>
simple example build file
</description>
<!-- set global properties for this build -->
<property name="src" location="src"/>
<property name="build" location="build"/>
<property name="dist" location="dist"/>
<target name="init">
<!-- Create the time stamp -->
<tstamp/>
<!-- Create the build directory structure used by compile -->
<mkdir dir="${build}"/>
</target>
<target name="compile" depends="init"
description="compile the source " >
<!-- Compile the java code from ${src} into ${build} -->
<javac srcdir="${src}" destdir="${build}"/>
</target>
<target name="dist" depends="compile"
description="generate the distribution" >
<!-- Create the distribution directory -->
<mkdir dir="${dist}"/>
<!-- Put everything in ${build} into the MyProject-${DSTAMP}.jar file -->
<jar jarfile="${dist}/HelloStateful.jar" basedir="${build}"/>
</target>
<target name="clean"
description="clean up" >
<!-- Delete the ${build} and ${dist} directory trees -->
<delete dir="${build}"/>
<delete dir="${dist}"/>
</target>
</project>
Then build: asant distThen deploy: asadmin deploy dist/HelloStateful.jarNow the stateless bean:
broersa@debian1:~/work/HelloApp/HelloStateless/src/com/bekijkhet$ cat HelloStateless.java
package com.bekijkhet;
public interface HelloStateless {
public String sayHelloStateless();
public String sayHelloStatelessRemote();
public void setMember(String member);
}
broersa@debian1:~/work/HelloApp/HelloStateless/src/com/bekijkhet$ cat HelloStatelessLocal.java
package com.bekijkhet;
public interface HelloStatelessLocal {
public String sayHelloStateless();
public String sayHelloStatelessLocal();
public void setMember(String member);
}
broersa@debian1:~/work/HelloApp/HelloStateless/src/com/bekijkhet$ cat HelloStatelessBean.java
package com.bekijkhet;
import javax.ejb.Stateless;
import javax.ejb.Remote;
import javax.ejb.Local;
@Stateless
@Remote(HelloStateless.class)
@Local(HelloStatelessLocal.class)
public class HelloStatelessBean implements HelloStateless,HelloStatelessLocal {
private String member = "Not set!";
public String sayHelloStateless() {
return "Hello Stateless "+member;
}
public String sayHelloStatelessLocal() {
return "Hello Local Stateless "+member;
}
public String sayHelloStatelessRemote() {
return "Hello Remote Stateless "+member;
}
public void setMember(String member) {
this.member=member;
}
}
broersa@debian1:~/work/HelloApp/HelloStateless$ cat build.xml
<project name="HelloEJB" default="dist" basedir=".">
<description>
simple example build file
</description>
<!-- set global properties for this build -->
<property name="src" location="src"/>
<property name="build" location="build"/>
<property name="dist" location="dist"/>
<target name="init">
<!-- Create the time stamp -->
<tstamp/>
<!-- Create the build directory structure used by compile -->
<mkdir dir="${build}"/>
</target>
<target name="compile" depends="init"
description="compile the source " >
<!-- Compile the java code from ${src} into ${build} -->
<javac srcdir="${src}" destdir="${build}"/>
</target>
<target name="dist" depends="compile"
description="generate the distribution" >
<!-- Create the distribution directory -->
<mkdir dir="${dist}"/>
<!-- Put everything in ${build} into the MyProject-${DSTAMP}.jar file -->
<jar jarfile="${dist}/HelloStateless.jar" basedir="${build}"/>
</target>
<target name="clean"
description="clean up" >
<!-- Delete the ${build} and ${dist} directory trees -->
<delete dir="${build}"/>
<delete dir="${dist}"/>
</target>
</project>
And finally the client:broersa@debian1:~/work/HelloApp/HelloClient/src/com/bekijkhet/helloclient$ cat HelloStatefulClient.java
package com.bekijkhet.helloclient;
import javax.naming.*;
import com.bekijkhet.HelloStateful;
import com.bekijkhet.HelloStateless;
public class HelloStatefulClient {
public static void main(String[] args) {
try {
InitialContext ctx = new InitialContext();
HelloStateful h = (HelloStateful)ctx.lookup("com.bekijkhet.HelloStateful");
HelloStateful i = (HelloStateful)ctx.lookup("com.bekijkhet.HelloStateful");
System.out.println(h.sayHelloStateful());
h.setMember("Initialized!");
System.out.println(h.sayHelloStateful());
System.out.println(i.sayHelloStateful());
}
catch (Exception e) {
System.out.println(e);
e.printStackTrace();
}
try {
InitialContext ctx = new InitialContext();
HelloStateless j = (HelloStateless)ctx.lookup("com.bekijkhet.HelloStateless");
HelloStateless k = (HelloStateless)ctx.lookup("com.bekijkhet.HelloStateless");
System.out.println(j.sayHelloStateless());
j.setMember("Init!");
System.out.println(j.sayHelloStateless());
System.out.println(k.sayHelloStateless());
}
catch (Exception e) {
System.out.println(e);
e.printStackTrace();
}
}
}
broersa@debian1:~/work/HelloApp/HelloClient/src/com/bekijkhet/helloclient$ javac -cp $GLASSFISH_HOME/lib/appserv-rt.jar:$GLASSFISH_HOME/lib/javaee.jar:$HOME/work/HelloApp/HelloStateful/dist/HelloStateful.jar:$HOME/work/HelloApp/HelloStateless/dist/HelloStateless.jar:. -d . HelloStatefulClient.javaRun for the first time:
broersa@debian1:~/work/HelloApp/HelloClient/src/com/bekijkhet/helloclient$ java -cp $GLASSFISH_HOME/lib/appserv-rt.jar:$GLASSFISH_HOME/lib/javaee.jar:$HOME/work/HelloApp/HelloStateful/dist/HelloStateful.jar:$HOME/work/HelloApp/HelloStateless/dist/HelloStateless.jar:. com.bekijkhet.helloclient.HelloStatefulClient
Hello Stateful Not set!
Hello Stateful Initialized!
Hello Stateful Not set!
Hello Stateless Not set!
Hello Stateless Init!
Hello Stateless Init!
Run for the second time:
broersa@debian1:~/work/HelloApp/HelloClient/src/com/bekijkhet/helloclient$ java -cp $GLASSFISH_HOME/lib/appserv-rt.jar:$GLASSFISH_HOME/lib/javaee.jar:$HOME/work/HelloApp/HelloStateful/dist/HelloStateful.jar:$HOME/work/HelloApp/HelloStateless/dist/HelloStateless.jar:. com.bekijkhet.helloclient.HelloStatefulClient
Hello Stateful Not set!
Hello Stateful Initialized!
Hello Stateful Not set!
Hello Stateless Init!
Hello Stateless Init!
Hello Stateless Init!
Notice that everytime you create a new stateful session bean you get a new fresh instance. But when you set it it keeps its state during the client session.
When a stateless session bean is created you always get the same instance (from out of a pool). It looks like the state is kept, but this is server independant and can never been garenteed. When we call the client again after +/- half an hour we get a fresh stateless bean, so it gets cleaned up. This clean up process can happen all the time, even between two calls of the same instance in the same client session.