Wednesday November 30, 2005 Web service client in EJB module in NetBeans 5.0 I'm working on one J2EE application that has web service client in EJB module. However, NetBeans 5.0 doesn't support web service client for EJB. Since NetBeans uses Ant as build tool is very easy to add this missing feature in NetBeans. We should changes build.properties and add new target in build.xml file. Let's to add support for web service client in NetBeans. These steps create Static generated web service client (JSR-101) in your EJB module:
<?xml version="1.0" encoding="UTF-8"?>
<configuration xmlns="http://java.sun.com/xml/ns/jax-rpc/ri/config">
<wsdl location="http://localhost:8080/credit/CreditCardService?WSDL"
packageName="creditsystem.client"/>
</configuration>
Where location attribute represents location of the WSDL file and package is package where stubs will be generated.
wscompile.classpath=${wscompile.tools.classpath}:${j2ee.platform.wscompile.classpath}
wscompile.client.CreditCardService.features=strict,wsi
wscompile.client.CreditCardService.package=creditsystem.client
wscompile.tools.classpath=${java.home}\\..\\lib\\tools.jar
First line setups classpath for wscompile, second one is wscompile options.
<target name="-pre-compile">
<taskdef name="wscompile"
classname="com.sun.xml.rpc.tools.ant.Wscompile"
classpath="${wscompile.classpath}"/>
<copy file="src/conf/CreditCardService-config.xml"
tofile="${build.classes.dir}/META-INF/wsdl/CreditCardService-config.xml"/>
<wscompile gen="true" base="${build.classes.dir}" keep="true" debug="true"
config="${build.classes.dir}/META-INF/wsdl/CreditCardService-config.xml"
classpath="${wscompile.classpath}"/>
<wscompile gen="true" base="${build.dir}/ear-module" keep="true" debug="true"
config="${build.classes.dir}/META-INF/wsdl/CreditCardService-config.xml"
classpath="${wscompile.classpath}"/>
</target>
Here is one issue. You can see that similar task is invoked twice. The hack solves issue that EJB module can
be included in J2EE application or can be standalone. When you build J2EE application with this EJB module then classes are built in different directory then for standalone module. I don't know how to resolve this issue in build.xml. Therefore, I call these two tasks.
Transactions and JMS I started to talk about JMS thence I might write a few sentences about transactions. Very often use case is that you deliver message and then this message is stored in database. How we can solve this. Should we use JTA for this?
I hope that reader knows that you mustn't use global transaction for consumer and producers. Why? Because, having all producers and all consumers participate in one global transaction would defeat the purpose of using a loosely coupled asynchronous messaging environment. JMS transactions follow the convention os separating the send operations from the receive operations. Which ways do we have for transactions with JMS?
UserTransaction txt = (UserTransaction) ctx.lookup("UserTransaction");
txt.begin();
// make JDBC stuff and send message
txt.commit();
public void onMessage(Message aMessage) {
try{
if (aMessage instanceof ObjectMessage){
// process message
Order order = (Order)((ObjectMessage) aMessage).getObject();
Connection conn = getDS().getConnection();
// insert Order in DB
...................
}else{
logger.log(Level.SEVERE,"Only object messages are supported.");
}
}catch(SQLException ex){
context.setRollbackOnly();
}
}
I encountered one issue with this approach in Sun Aplication server. Messages are redelivered again and again. It means that you can flood your server with many messages. BTW, it's good test of Sun App server for DOS attack :-). I know that Jboss allows to setup of number of redelivering but I can't find it for Sun App server. Therefore, I suggest to use a little bit approach, throw EJB exception. What's happened when the database will be offline? Under container-managed transaction demarcation, upon receiving a runtime exception (EJBException extends Runtime exception) from a MDB the container roll-backs the container-started transaction and the message is delivered in dead queue. Below is same sample that throws EJBException.
public void onMessage(Message aMessage) {
try{
if (aMessage instanceof ObjectMessage){
// process message
Order order = (Order)((ObjectMessage) aMessage).getObject();
Connection conn = getDS().getConnection();
// insert Order in DB
...................
}else{
logger.log(Level.SEVERE,"Only object messages are supported.");
}
}catch(SQLException ex){
throw new EJBException(ex);
}
}
Add other JMS subscriber in topic On of the big advance of the topic is that other subscriber can be added very easy. For instance, we have existing order application that have one ProcessOrder subscriber and we would like to add other one. In this post I will show how you can add new subscriber in NetBeans 5.0, which changes should be done:
<ejb>
<ejb-name>AccountBean</ejb-name>
<jndi-name>jms/ProcessOrderBean</jndi-name>
<mdb-connection-factory>
<jndi-name>jms/ProcessOrderDestinationFactory</jndi-name>
</mdb-connection-factory>
</ejb>
<message-destination>
<message-destination-name>AccountDestination</message-destination-name>
<jndi-name>jms/ProcessOrderBean</jndi-name>
</message-destination>
How to develop JMS client in NetBeans I will describe developing of a client application that send JMS message with order. The order will be processed in application tier. Since, I would like to conform patterns, I will use business pattern that separates presentations from business logic. I would like to describe this pattern in one of the next posts. Specifically, a business delegate is a helper class that handles the details of connecting and sending JMS message. GUI invokes methods in business delegate class and isn't interested in low-level stuff. :-) Let's start to create J2SE client:
public class DelegateImpl implements OrderDelegate{
private static String JMS_FACTORY_NAME = "jms/ProcessOrderDestinationFactory";
private static String QUEUE_NAME = "jms/ProcessOrderBean";
public DelegateImpl() throws ApplicationException{
try{
ctx = new InitialContext();
connFactory = (TopicConnectionFactory) ctx.lookup(JMS_FACTORY_NAME);
destination = (Topic) ctx.lookup(QUEUE_NAME);
}catch(NamingException ex){
throw new ApplicationException(ex.getMessage());
}
}
public void createOrder(Order order) throws ApplicationException{
Connection conn = null;
MessageProducer producer;
try {
conn = connFactory.createConnection();
Session session = conn.createSession(false,
Session.AUTO_ACKNOWLEDGE);
producer = session.createProducer(destination);
ObjectMessage objMsg = session.createObjectMessage();
objMsg.setObject(order);
producer.send(objMsg);
if(conn != null){
conn.close();
}
} catch (JMSException ex) {
throw new ApplicationException(ex.getMessage());
}
}
JMS message browser Last post I started develop JMS application that receives order messages. I encountered some problems with the MDB bean during testing this bean. Therefore, these messages weren't delivered and processed. The main advance of the JMS is that no message is lost and JMS mechanisms guarants delivery of messages between clients. However, there are cases where guaranteed delivery, acknowledgements, and transactional are just not enough. Many conditions can cause a message to be undeliverable. Messages may expire before they reach customer or they are viewed as undeliverable due to some reason. What's hapenned with these messages?
They are delivered in some special queue, 'Dead Message Queue'. Messaging server that is bundled in Sun Application server has this admin queue. The name of this queue is mq.sys.dmq. How we can browse the messages that are in the dead queue?
Very simple, you can use QueueBrowser example that is in imq/demo/applications/qbrowser directory in Sun App server. Start the application with this option:
java -cp $J2EE_HOME/imq/lib/jms.jar:$J2EE_HOME/imq/lib/imq.jar:. QBrowser
In text field specify name of your or dead queue and click Browse. Then, you can select a message and click Browse, in new dilog all information about message are displayed. There you can check message body, reason of undelivery, JMS delivery count, ...This tool is very helpful when you need to analyze messages that are in appropriate queue. After analyzing these messages you want to purge them. Messages can be deleted from admin console that was described two days ago. Undar Actions menu is Purge Messages item.
Developing Message Driven beans in NetBeans Today, I would like to start develop application that uses MDB bean in application tier. I hope that everyone knows Message Driven beans. If not, I shortly describe it. MDB is an enetrprise bean that enables J2EE applications to process messages asynchronously. JMS API provides two different approach for messaging:
Point-to-point messaging: Each message is addressed to a specific queue, and receiving clients extract messages from the queues established to hold their messages. Queues retain all messages sent to them until the messages are consumed or until the messages expire.
Publish/Subscribe: Clients address messages to a topic, which functions somewhat like a bulletin board. Publishers and subscribers are generally anonymous and can dynamically publish or subscribe to the content hierarchy. The system takes care of distributing the messages arriving from a topic's multiple publishers to its multiple subscribers. Topics retain messages only as long as it takes to distribute them to current subscribers.
Now, we know basic approach and I will describe other terminology. We need connection factory and destination for sending/receiving messages. A connection factory is the object a client uses to create a connection to a provider. A connection factory encapsulates a set of connection configuration parameters that has been defined by an administrator JMS server. A destination is the object a client uses to specify the target of messages it produces and the source of messages it consumes. In the PTP messaging domain, destinations are called queues. In the pub/sub messaging domain, destinations are called topics.
This application will send orders from J2SE client in application tier. Order's parameters are encapsulated in Order class. The class is shared between client and EJB module, therefore creation of library module with this class is helpfulness.
public void onMessage(Message aMessage) {
try{
if (aMessage instanceof ObjectMessage){
// process message
Order order = (Order)((ObjectMessage) aMessage).getObject();
logger.log(Level.SEVERE,order.toString());
}else{
logger.log(Level.SEVERE,
"Get message that isn't supported, only ObjectMessage is supported");
}
}catch(JMSException ex){
logger.log(Level.SEVERE, ex.getMessage());
}
}
We support only Object messages in this MDB. JMS API defines many types of messages, e.g. Text, Map, Stream and Byte messages. Different between bytes and stream messages is that stream messages are a stream of primitive values
in Java. BytesMessage allows data to be read using any type. Thus even if your payload contains a long value, you can invoke a method to read a short and it will return you something. It will not give you a semantically correct data but the call will succeed in reading the first two bytes of data. In the code above message is typed to ObjectMessage that Order object is obtained and then printed in log.
JMS monitoring tool in Sun Application server I would like to write a few posts about developing JMS (Java Message Service) components in NetBeans. About developing
Message driven beans and JMS clients I will write in next posts. However, today I would like to introduce very useful
tool Java System Message Queue Administration console, you can run imqadmin in $SUN_APPSERV/imq/lib directory. Now, you
can connect to local broker, click on Destinations node and in table are listed all destinations that are avalaible in JMS server. When you select the destination and click Actions -> Properties new dialog with other info is displayed. There you can specify many options for queue, e.g. max number of messages, max number of producers, ... or you can find number of messeges, producers or consumers or number of messages that are not delivered for durable subscriptions. This tool is very valuable when you want to monitor your queue or topic.
Do you know java2db mode for deployment in Sun App server? One my colleague from doc team sent me one EJB module that was very strange for him. The module includes
some CMP beans but mapping file sin-cmp-mappings.xml nether dbschema ar missing in this module. First question from him was: How you can run this module without mappings info? How does a container know which CMP fields should be mapped in appropriate table columns? I should disclose that I couldn't answer his questions. I asked Rochelle Raccah who works in team that works on mapping framework in Sun Application server. She answered, this module uses java2db mode for deployment in Sun Application server.
What does it mean? It means that you can't write sun-cmp-mappings.xml file for this module. This file is created during module deployment.
How does container know which CMP fields should be mapped in appropriate table column? Since the container creates tables too. If you already has these tables, you shouldn't use this mode.
How can I enable it in NetBeans? Very simple add folowing elements in sun-ejb-jar.xml:
<cmp-resource>
<jndi-name>jdbc/cmpcustomer</jndi-name>
<create-tables-at-deploy>true</create-tables-at-deploy>
<drop-tables-at-undeploy>true</drop-tables-at-undeploy>
<database-vendor-name>oracle</database-vendor-name>
</cmp-resource>
and delete sun-cmp-mappings.xml file and dbschema from project. Option create-tables-at-deploy should be set to true. Option database-vendor-name specifies the name of the database vendor for which tables can be created. Allowed values are db2, mssql, oracle, pointbase, and sybase.
Better practice in EJB handling exception Sometimes I get user's source code. Recently, I had a chance to study one J2EE application.
I was interested in one business method that creates new entity bean or finds existing one. This
method was implmented very disconsolately and threfore I decided to analyze this method and suggest
better solution.
The user has EJB module with many entity beans and one session bean. The session bean conducts as
session facade. Web clients communicate with this bean. This is common pattern in J2EE application when you have session facade in application tier and business delegate in web tier.
Session bean has one business method that has a paramater that represents composed transfer object
(AccountDTO has references to UserDTO and MestoDTO). The methods checks wheter entity bean exists and creates new one if not, see code:
public void createAccount(AccountDTO account) throws EJBException{
try {
MestoLocal mesto;
MestoDTO mestoTO = account.getMesto();
if(mestoHome.cityExists(account.getMesto().getId())){
mesto = mestoHome.findByPrimaryKey(account.getMesto().getId());
}else{
mesto = mestoHome.create(mestoTO.getId(),mestoTO.getDescription());
}
UzivatelLocal uzivatel = uzivatelHome.findByPrimaryKey(account.getUzivatel().getId());
accountHome.create(account.getIdAccount(),account.getAmount(),uzivatel,mesto);
In this snapshot cityExists home method of Mesto entity bean is invoked. The home methods return true if appropriate bean exists and false if not. This home methods invokes select method that has folowing EJB-QL query:
SELECT COUNT(o) FROM Mesto o WHERE o.id = ?1
I think that implementation is very ugly, home methods are not intended for this purpose. They should be used for business logic that is not specific to an entity bean instance. I guess that using home method for this is uselessly.
try{
mesto = mestoHome.findByPrimaryKey(account.getMesto().getId());
}catch(ObjectNotFoundException ex){
mesto = mestoHome.create(mestoTO.getId(),mestoTO.getDescription());
}
The home and select methods are not needed in this case. What's your opinion for the originall method?
Posted by pblaha
( Nov 16 2005, 05:22:05 PM CET )
Permalink
Comments [0]
Remote Web tier on Tomcat Today's post describes how to setup web tier that communicates with ejb tier that is deployed on different server. This scenario is very often since App server is in local network behind firewall and Web server is located in DMZ (demilitarized zone) or in Internet. I used Tomcat 5.0.28 as web server and App server 8.1. I hope that the configuration could be simple adopted for other Tomcat's version as well.
I assuming that you have existing application that consists of web module and EJB module. Of course, all facade beans should have remote interfaces. Deploy these modules on appropriate servers.
Copy j2ee.jar and appserv-rt.jar to $TOMCAT_DIR/common/lib. Note, I should modify appserv-rt.jar, the App server's jar includes org.catalina, org.commons, org.coyote, .... packages. Tomcat doesn't start with these packages. Delete packages org.* from the jar. Don't modify original library.
Change catalina50.sh or catalina50.bat startup scripts, add the line that sets up name for EJBs lookup
export JAVA_OPTS="-Dorg.omg.CORBA.ORBInitialHost=hostName -Dorg.omg.CORBA.ORBInitialPort=3700"
Posted by pblaha
( Nov 15 2005, 07:52:30 PM CET )
Permalink
Comments [0]
Developing J2EE clients for Sun Application server In last post I wrote about EJB client for JBoss, today I would like to write introduction about J2EE clients for Sun Application server. You have two ways for devloping the client: using ACC or without it.
I guess that many users asks what this acronym stands for? ACC is Application Client Container. What is it? The Application client container includes a set of java classes, libraries and others files that are required for and distributed with Java clients programs that are executed in their JVM. The ACC manages the execution of J2EE app clients according to security, ... For instance, authentication techniques are provided by the client container and are note under control of the application client component. These security constraints are defined in deployment descriptor. I would like to develop this type of the client in next post.
Today, I will create simpler client that access EJB on remote server. This client doesn't use ACC. To access and EJB perform these steps:
InitialContext ctx = new InitialContext();
Object obj = ctx.lookup("beanName");
BeanHome home = (BeanHome)PortableRemoteObject.narrow(obj, BeanHome.class);
You can find beanName in server specific DD sun-ejb-jar.xml, the element jndi-name.
-Dorg.omg.CORBA.ORBInitialHost=ORBHostname -Dorg.omg.CORBA.ORBInitialPort=ORBPort
ORBHostname is the Application server hostname and ORBPort is port for ORB port, default 3700.
#!/bin/sh
JAVA_HOME="/usr/java/jdk1.5.0_02"
J2EE_LIB="/lib"
export JAVA_HOME
CLASS_PATH="$J2EE_LIB/j2ee.jar:$J2EE_LIB/appserv-rt.jar:MyClient.jar"
ARGS="-Dorg.omg.CORBA.ORBInitialHost=Hostname -Dorg.omg.CORBA.ORBInitialPort=3700"
$JAVA_HOME/bin/java $ARGS -cp $CLASS_PATH pkg.Main
exit 0
Bean's client Today I would like to finish guide that I started yesterday. We have application tier in issue tracking application. Now, we will develop J2SE client that invokes methods in EJB tier.
java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
java.naming.provider.url=localhost
InitialContext ctx = new InitialContext();
Object obj = ctx.lookup("IZFacadeBean");
IZFacadeRemote izFacade = ((IZFacadeRemoteHome)PortableRemoteObject.narrow(obj,
IZFacadeRemoteHome.class)).create();
// print issue ID 1
IssueDTO issue = izFacade.getIssueById(1);
System.out.println("Issue id: " + issue.getId() + ", summary: " + issue.getSummary());
// create new issue
izFacade.createNewIssue(new IssueDTO(new Long(10),"D", new Integer(1), "PETR", "Test fails"));
How to develop CMP beans for JBoss in NetBeans I have recently read one question about developing CMP beans for Jboss in NetBeans. The user asked for some details that are related to CMP beans for JBoss, e.g. setup database in Jboss, server specific deployment descriptors, ... I decided to write simple tutorial about developing CMP beans for JBoss.
Let's start to develop simple application that manages issues for your product. The issues are persisted in MySQL database, application tier has two beans, one is CMP bean that represents issue and stateless session bean with remote and local interface. This bean represents facade for business logic. The client is simple J2SE client that invokes business methods in session bean. We will develop application tier today and client tomorrow. Eneterpise module sources are avalaible here.
CREATE TABLE ISSUE (
ID SERIAL,
TYPE CHAR(1),
PRIORITY SMALLINT,
OWNER VARCHAR(20),
SUMMARY VARCHAR(30),
PRIMARY KEY(ID));
If you don't want to creat the table manually, you can download sources and in a directory setup is file setup.sql that creates table and inserts values into table. You can the command mysql -u your_user -p < setup.sql.
Bound EJB LocalHome 'IssueBean' to jndi 'local/IssueBean@17546680' Bound EJB LocalHome 'IZFacadeBean' to jndi 'local/IZFacadeBean@17637582' Bound EJB Home 'IZFacadeBean' to jndi 'IZFacadeBean' Deployed: file:/home.local/blaha/servers/jboss/server/default/deploy/Issues.jar
FindBugs module for NetBeans I'm trying to improve quality of Netbeans code and therefore I was looking for some tool
that can check sources of NetBeans modules. I found FindBugs tool
that looks for instances of "bug patterns" - code instances that are likely errors. Radim Kubacki suggested me his Findbugs NetBeans module but this module doesn't work for NetBeans module project. I added to Radim's module support for NetBeans Module projects. It means that you can run Findbugs on your NetBeans modules and check their code quality. It's better catch a bug before spending a hour with debugging. :-)

Apply code changes for Web and EJB module I have read recently in Roumen's blog about Apply code changes feature. I was fascinated by this functionality since you can change something in your code, apply code changes and then debug new code in one devug session. Roumen showed this feature for NetBeans sources. I was interested whether similar feature can be used for servlets and beans as well. Before this, I should deploy web module debug, change the code finish debug session and deploy again.
I tried this with servlet and it's working for me. I changed some code in my servlet, applied code changes and then debug new code. I thought, that this feature should work for EJB as well. But, I found a new issue. When this issue will be fixed debuging of EJB will be pleasure.
Roumen, thanks for your tip.
Posted by pblaha
( Nov 08 2005, 05:01:36 PM CET )
Permalink
Comments [1]