Author Archive
August 27th, 2008 by Simon Zambrovski
The vacation time of most people is over, so it is time to meet and discuss a little. A good opportunity to do this will be given on September 1st
in Roxie, Hamburg during the
Eclipse Stammtisch. The event name translates into regular’s table and indicates a regularity of the happening. Even if the upcoming event is only the
second in series I expect to meet many people after the
great
feedback after the last one.
Details:
See you next Monday.
Posted in announce, eclipse, technology | 1 Comment »
August 22nd, 2008 by Simon Zambrovski
The
Java User Group Hamburg (JUG-HH)
organizes
another event at
Lehmanns Bookstore in Hamburg. This time the subject of the talk is build management and project automation with help of an open-source tool called Maven. Maven is a software project management and comprehension tool. Based on the concept of a project object model (POM), Maven can manage a project’s build, reporting and documentation from a central piece of information.
Posted in announce, java, technology, tools | 1 Comment »
May 20th, 2008 by Simon Zambrovski
Yesterday, as
reported earlier a great session on Java EE 5 featured by
Adam Bien took place in
Lehmanns Buchhandlung in Hamburg. It was a full success, having approx. 100 developers taking part. Adam asked for the experiences with Java EE and it seemed to be a bunch of professionals. The session slides contained only headings, the rest of the story has been done in NetBeans 6.1 and Glassfish. The entire session has been executed on pretty high speed – to be honest, Adam spoke that quick I just could understand. The session took place in the bookstore, that basically sells two types of books: computer and medical. Adam noticed that the shelf to the right of him contained books on psychiatry, and pointed each time he wanted to express that the antipattern leads to…

Regarding the content, Adam focused on two main directions: the basic enterprise patterns and enterprise anti-patterns (this could be a good book title, btw.). General ideas, like support of DRY principle, convention over configuration and IoC, that are on my opinion the greatest achievements of Java EE 5 has been explained in a very plastic way. Especially, Adam really showed, that the bad-artifacts that made J2EE development boring disappeared in Java EE (or may be better to say: can be avoided). The last part of the talk was attended to the nonfunctional activities around the developed software. Adam focused on testing, management, monitoring, performance, etc… It was pretty interesting to see that Java EE community listens to the developer voices and push the technology towards modern, pragmatic and efficient programming platform.
During and after the session one could ask questions around the topics. Adam told a lot during the answers and proved again his excellent expertise in the Java in general and Java EE in particular. I really enjoyed the session and hope that the next one will not let us wait for several years again. Adam spoke about possible JavaFX session – this would be also very interesting.
(
more photos in my photostream)
Posted in announce, enterprise systems, java | 3 Comments »
May 20th, 2008 by Simon Zambrovski
As announced in a
previous post,
Egon Boerger introduced his current work on Semantical Model of BPMN. The computer scientist, known by most of us through his work on Abstract Sate Machines (ASM), focused in his talk on the try to improve the BPMN with a unambigious and clear meaning. Especially, he showed in a very plastic way, how a formal specification can foster the understanding of a standard like BPMN. In doing so he reveal several weak points of BPMN concerning the meaning of splits/merges. Especially, those become a real problem if you use BPMN like a workflow language.
The main message of Egon was the need of formal specification and separation of specification from implementation. He showed how this can help in order to define the semantics. I was glad, that he confirmed some statements I’m discussing in my
thesis.
Another positive message was that he is in touch with the OMG and SAP guys and his propositions are not only know in academia, but also in the standardization organization like OMG. He reported about some positive feedback from them, and spoke about some contributions to the BPMN 2.0.
I really enjoyed the session, because I like this old-school-style computer scientists. They spread their meta-thinking of a very high level and precision, that sometimes drives us progmatic guyes crazy. In the same time, they establish a natural meaning of quality and foster the reasoning about the topic, we are dealing with everyday…
(
more photos in my photo stream)
Posted in announce, computer science | No Comments »
May 14th, 2008 by Simon Zambrovski
May 19th, 2008 seems to become an important day for the computer science in Hamburg.
Modelling BPEL Using Abstract State Machines
May 19th, 15:30 – 16:30
Ditze Hörsaal, Schwarzenbergstr. 95, 016 (AudiMax I building), 21073 Hamburg
by
Prof. Egon Börger from the University of Pisa, Italy. (
original announcement)
It starts with an invited talk of a
Prof. Dr. Egon Börger, famous computer science researcher, applying the concepts of
Abstract State Mashines to the software and hardware design at Hamburg University of Technology.
Pragmatic Java EE 5 Hacking – Rethinking Best Practices
May 19th, 20:00 – 22:00
Lehmanns Fachbuchhandlung (am Hauptbahnhof)
Kurze Mühren 6, 20095 Hamburg
by
Adam Bien (
original announcement)

On the same day the meeting of the
Java User Group Hamburg takes place at Lehmanns Fachbuchhandlung. This time an invited talk on “Progmatic Java EE 5 Hacking” by Adam Bien. Java Champion Adam Bien is a self-employed consultant, lecturer, software architect, developer, and author in the enterprise Java sector in Germany who implements Java technology on a large scale. He is also the author of several books and articles on Java and J2EE technology, as well as distributed Java programming. His books include J2EE Patterns, J2EE HotSpots, Java EE 5 Architectures, Enterprise Architectures, Enterprise Java Frameworks, SOA Expert Knowledge, and Struts, all published in German.
Java EE 5 is a revolution, not an evolution. Perhaps it goes not far enough – however some best-practices and patterns need to be pimped up, re-thought or pruned. After a short introduction into Java EE 5 / Java EE 6 (with a from scratch creation of a simple application with all “enterprise features”). The talk will provide the concept, patterns, best practices and discuss the context, advantages as well as shortcomings and provide suggestions / solutions for Java EE 5/6. This session will be interactive / openspace like. I’m really open for constructive criticism and will try to answer all questions with …code and real world context. Some upcoming Java EE 6 features will be presented as well.
So, see you there…
Posted in announce, computer science, enterprise systems | 2 Comments »
May 6th, 2008 by Simon Zambrovski
Yesterday, the first “Eclipse Stammtisch Hamburg” took place in Bolero in Ottensen. It was a full success, about 50 people were there. I was glad to see people I known from
Eclipse Democamp again. I liked the location, having a separated room, big enough for another 50 people. I spoke with Ralph on the intended frequency of the event – it could be good to have it four times a year.
The rest of the pictures can be seen in my
FlickR gallery.

Posted in announce | 2 Comments »
February 26th, 2008 by Simon Zambrovski
The specification part
We continued the search for the reason of error described in the
previous post. After some search in HTTP Specification executed by
Prof. Turau: “… Multiple message-header fields with the same field-name MAY be present in a message if and only if the entire field-value for that header field is defined as a comma-separated list [i.e., #(values)]…”
For example Accept Header:
Accept = “Accept” “:” #( media-range [ accept-params ] )
But not Content-Type Header:
Content-Type = “Content-Type” “:” media-type
The server-side implementation
Besides Nokia Bug, putting
multiple Content-Type headers in one request, there is an additional error server-side. I followed the JBoss call hierarchy which is:
org.jboss.ws.server.StandardEndpointServlet#doPost(HttpServletRequest req, HttpServletResponse res);
org.jboss.ws.server.ServiceEndpointManager#processSOAPRequest();
new org.jboss.ws.server.ServletHeaderSource(HttpServletRequest req, HttpServletResponse res);
org.jboss.ws.server.ServiceEndpoint#handleRequest(HeaderSource headerSource, ServletEndpointContext context, InputStream inputStream);
org.jboss.ws.server.ServletHeaderSource#getMimeHeaders();
During the whole processing, the headers are retrieved from the HttpServletRequest by the ServletHeaderSource which is the only implementation of HeaderSource:
public MimeHeaders getMimeHeaders()
{
Enumeration e = req.getHeaderNames();
if(e == null)
return null;
MimeHeaders headers = new MimeHeaders();
String name = null;
for(; e.hasMoreElements(); headers.addHeader(name, req.getHeader(name)))
name = (String)e.nextElement();
return headers;
}
Afterwards, if you call getHeader on the MimeHeaders object the string array is constructed from the existing data and returned:
public String[] getHeader(String name)
{
ArrayList tmp = new ArrayList();
for(int n = 0; n < headers.size(); n++)
{
MimeHeader mh = (MimeHeader)headers.get(n);
if(mh.getName().equalsIgnoreCase(name))
tmp.add(mh.getValue());
}
String values[] = null;
if(tmp.size() > 0)
{
values = new String[tmp.size()];
tmp.toArray(values);
}
return values;
}
This means, that the implementation of the HttpServletRequest returns concatinated list of values for the duplicate headers.
Specifications again
Now, I looked in Java Servlet Specifications about the getHeader method:
Servlet 2.1
Returns the value of the requested header. The match between the given name and the request header is case-insensitive. If the header requested does not exist, this method returns null.
Servlet 2.2
The getHeader method allows access to the value of a header given the name of the header. Multiple headers, such as the Cache-Control header, can be present in an HTTP request. If there are multiple headers with the same name in a request, the getHeader method returns the first header contained in the request.
Servlet 2.3 and 2.4
The getHeader method returns a header given the name of the header. There can be multiple headers with the same name, e.g. Cache-Control headers, in an HTTP request. If there are multiple headers with the same name, the getHeader method returns the first head in the request.
Results
So it seems to be a Tomcat Bug, as long as Tomcat provides the implementation for the HttpServletRequest… This bug is integrated in JBoss, because they use Tomcat implementation. Never the less, JBoss use the getHeader method relies on the correct implementation.
Posted in enterprise systems, java, jboss | No Comments »
February 25th, 2008 by Simon Zambrovski
Introduction
During some work executed for the proposal to the
NFC Congress 2008, we introduced a scenario for using the NFC-enabled Nokia 6131 in the industrial environment. The selected use case records some NFC data and uses the Internet to transmit it to the cental server. During the prototype construction, we decided to use Google Maps as a framework for location-based display of gathered information. The server has been constructed based on J2EE EJBs and exposes its
functionality using SOAP-based document-literal Web Serives, as described in one of the privious posts.
Nokia 6131 NFC
The
Nokia 6131 NFC is first NFC-enabled mobile phone. NFC stands for
Near-Field-Communication – a new evolving wireless technology to interact with RFID tags. It is strongly supported and pushed by several big players. This results in several conferences around this subject all around the world.
The NFC in Java is specified in
JSR 257. In addition to that, 6131 seems to support
several other JSRs, also including
JSR 172 for Web Services. After having a closer look on the offered API, it cames out, that only the XML-parser part of JSR 172 is supported.
Sending SOAP Requests without JSR 172
In order to set the requests to a Web Service from a mobile phone, that does not supprt Web Service JSR 172, a manual creation of request is needed. This results in something like:
public abstract class SoapHandler extends DefaultHandler {
public static final String SOAP_BEGIN = "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:q0=\"http://www.techjava.de/2008/nfc/visualizer/types\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"><soapenv:Body>";
public static final String SOAP_END = "</soapenv:Body></soapenv:Envelope>";
private StringBuffer reqBuf = new StringBuffer(); // Buffer that holds the request message
...
public SoapHandler(String message) {
reqBuf.append(message);
}
public int doHttpRequest(String url, String soapAction) throws IOException {
reqBuf.insert(0, SOAP_BEGIN);
reqBuf.append(SOAP_END);
HttpConnection httpConn = (HttpConnection) Connector.open(url);
httpConn.setRequestMethod(HttpConnection.POST);
httpConn.setRequestProperty("SOAPAction", soapAction);
httpConn.setRequestProperty("Content-Length", Integer.toString(reqBuf.length()));
OutputStream os = httpConn.openOutputStream();
os.write(reqBuf.toString().getBytes());
os.close(); // Request is sent when output-stream is closed
return httpConn.getResponseCode();
}
...
}
If you execute the code above, the 6131 device send a HTTP request using Content-Type plain/text, that is automatically inserted and changes the case of “SOAPAction” to lower. As long as JBoss 4.0.5 GA used in this experiment supports only Content-Types application/soap+xml and text/xml (as it should according to the specification), it throws a SOAP Exception:
javax.xml.soap.SOAPException: Unsupported content type: text/plain
at org.jboss.ws.soap.MessageFactoryImpl.createMessageInternal(MessageFactoryImpl.java:138)
at org.jboss.ws.soap.MessageFactoryImpl.createMessage(MessageFactoryImpl.java:87)
at org.jboss.ws.server.ServiceEndpoint.handleRequest(ServiceEndpoint.java:190)
at org.jboss.ws.server.ServiceEndpointManager.processSOAPRequest(ServiceEndpointManager.java:355)
at org.jboss.ws.server.StandardEndpointServlet.doPost(StandardEndpointServlet.java:115)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
at org.jboss.ws.server.StandardEndpointServlet.service(StandardEndpointServlet.java:76)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:810)
...
The MIME Content-Type can easily be set on any HTTP connection:
httpConn.setRequestProperty("Content-Type", "application/soap+xml");
This works well in the NFC Nokia simulator, part of the Nokia SDK, but breaks down executed from the device. It seems to be a bug in the implementation, or an intended feature of Nokia limiting the usage of the phone for business applications, but the HTTP-Request contains a duplicate Content-Type entry valued by the “application/soap+xml”. Playing around with the implementation, we found that it put any Content-Type header twice into the request. Decompiling and analyzing of simulator code does not helped at all. Since we don’t know how to get and patch sources of J2ME port to Nokia 6131, I decided to apply a workaround.
Server tolerance
JBoss reacts to this fact of a duplicate Content-Type header by throwing a SOAPFaultException.
javax.xml.rpc.soap.SOAPFaultException: Could not parse content type:javax.mail.internet.ParseException: Expected ';', got ","
at org.jboss.ws.jaxrpc.SOAPFaultExceptionHelper.exceptionToFaultMessage(SOAPFaultExceptionHelper.java:194)
at org.jboss.ws.server.ServiceEndpoint.handleRequest(ServiceEndpoint.java:223)
at org.jboss.ws.server.ServiceEndpointManager.processSOAPRequest(ServiceEndpointManager.java:355)
at org.jboss.ws.server.StandardEndpointServlet.doPost(StandardEndpointServlet.java:115)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
at org.jboss.ws.server.StandardEndpointServlet.service(StandardEndpointServlet.java:76)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:810)
...
We followed the stacktrace, and identified the class that causes the Execption. It is org.jboss.ws.soap.MessageFactoryImpl located in JBOSS_DEPLOY /jbossws14.sar/jbossws14-core.jar. After some source code alanysis, we found several problems in the implementation:
private static ContentType getContentType(MimeHeaders headers) throws SOAPException
{
ContentType contentType = null;
try
{
String type[] = headers.getHeader("Content-Type");
if (type != null)
{
contentType = new ContentType(type[0]);
} else
{
contentType = new ContentType("text/xml");
}
return contentType;
} catch (ParseException e)
{
String message = (new JBossStringBuilder()).append("Could not parse content type:").append(e).toString();
throw new SOAPException(message);
}
}
First of all, we would expect that the array length is proven, before the first element is accessed. Secondly, if multiple same headers are present in the request, their values are combined using a comma resulting in:
application/soap+xml; charset=utf-8, application/soap+xml; charset=utf-8
This combination could make sence if you put multiple Content-Lang headers in your request, but not for Content-Type. So we fixed the implementation by following code, taking only the first Content-Type value from the list, if present:
...
String type[] = headers.getHeader("Content-Type");
if (type != null && type.length != 0)
{
int index = type[0].indexOf(',');
String correctedType = (index != -1) ? type[0].substring(0, index) : type[0];
contentType = new ContentType(correctedType);
} else
{
contentType = new ContentType("text/xml");
}
return contentType;
...
Summary
Even if Nokia 6131 NFC offers some functionality for the developer, it does not provide the best platform for use case try-outs. Especially, the lack of supported standard (like full JSR 172) and a low-end OS (Symbian 40-Series), and some bugs / features in implementation of connectivity will lead to problems in prototype implementations of use cases…
Posted in java, technology | No Comments »
February 19th, 2008 by Simon Zambrovski
Abstract
In this article we describe how to implement a simple Web Service using old fashioned Java EE 1.4. The dummy functionality is implemented in Session Beans and exposed via document-literal Web Service following the recommendations of W3C and WS-I.
Introduction
Before we get in to technical details about the implementation a short overview of planned is helpful. The main idea of this article is to show how a web service can be implemented using Java Enterprise Edition. Especially, this article tries to achieve two goals: show how existing EJB functionality can be exposed using Web Service technology and how Web Service technology can be linked to something stable, most of us have experience with. Many people follow the new trend of saying that EJB is ineffective and heavyweight – we don’t want to argue about this thesis. In this article we show a progmatic EJB development approach using “code-by-convention” combined with
Generative-Programming techniques. We develop the EJB functionality and Web Service definition independent from each other and link them later together – we are sure that this is the only approach to keep both parts simple, clean and reusable. During the WSDL design we follow a certain style of type and element selection, that results from some experiences of using generators and integration with non-Java environments. Our use case is a little synthetic in order to show the variety of types and seems to introduce structural complexity, which can be avoided. We implement the examples using open source products only.
The article starts with a short introduction which could look a little lyrical for some technicians of you. Then the requirements to the selected software are listed, followed by the practical use case. Then we jumpstart the EJB development cycle, design the Web Service and finally put both implementations together. In the outline, we discuss the testing possibilities…
Requirements
In order to develop, generate, package and finally deploy and run the component, exposing its functionality we need special software. Following selections has been made:
- Sun’s JDK (> 1.4.2)
- Apache Ant (> 1.6.5)
- XDoclet (1.2.3)
- Sun’s Java Web Service Developer Pack (1.6)
- JBoss AS (4.0.5 GA)
- Eclipse IDE (> 3.3), recommended WTP installation
First of all we need to setup our environment. In order to make development under MS Windows convenient, we used to setup the entire environment variables in a single shell script:
@echo off
echo ----------------------------------------
echo Project Environment
echo ----------------------------------------
set DEVEL=c:\environment
set ANT_HOME=%DEVEL%\libraries\ant\1.6.5
set JAVA_HOME=%DEVEL%\compiler\j2sdk1.5.0_01
set JAVAC_EXEC=%DEVEL%\compiler\j2sdk1.5.0_01\bin\javac.exe
set JWSDP_HOME=%DEVEL%\compiler\jwsdp-1.6
set PATH=%JAVA_HOME%\bin;%ANT_HOME%\bin;%PATH%;%DEVEL%\bin;%JWSDP_HOME%\jaxrpc\bin
echo Environment variables:
echo ANT home : %ANT_HOME%
echo JAVA home : %JAVA_HOME%
echo PATH set to : echo %PATH%
echo ----------------------------------------
echo CLASSPATH set to : echo %CLASSPATH%
echo ----------------------------------------
cmd
For usage under Linux/MacOS the script should be adjusted correspondingly.
Eclipse is used as IDE for the whole development. In order to avoid any dependency to certain Eclipse functionalities we use Apache Ant as a build tool. In order to use the build tools these should be configured. In Preferences of Eclipse we set up Apache Ant and XDoclet. In Window -> Preferences -> Ant -> Runtime set up the Ant Home pointing to the Ant installation directory. In Window -> Preferences -> XDoclet set up XDoclet Home to XDoclet installation directory and set the version to 1.2.3.
Project Setup
Even if we don’t want to rely on the build and shortcommings of Eclipse in the area of EJB development, we want to use maximum of support if possible.
Create a new EJB Project and select the following Project Facets: EJB Module 2.1, XDoclet 1.2.3 and Java 1.4. We use the following project structure: all hand-written Java files go to /java/src directory, all Doclet-generated goes to /java/generated, the compiled files go to /java/class and the resulting archives (jars and ears) go to /java/build. The additional /metadata directory contains source and descriptor files needed for the project. To set all this up go to Project Properties -> Java Build Path. As long as we control XDoclet from an Ant script, we deactivate the XDoclet Builder in Project Preferencies -> XDoclet and in Project Preferences -> Builders. Before we begin with the implementation we have to set up the Ant script, that will build and package our project. The script unifies different tools we use to a single toolchain and contains several targets. These are EJB-Doclet generation target, WS-Compile target, Web-Doclet target, target for compilation of the Java classes and, finally, creation of a JAR and EAR files. In order to hold the build file project independent we use properties files that contain project specific settings. In order to access XDoclet and WSCompile from Ant the corresponding task definitions must be included and the libraries must be put to directories in classpath. For this purpose we used to create a library project in the same workspace, containing the libraries (called general).
...
<path id="class.path.local">
<fileset dir="../general/lib">
<include name="**/*.jar"></include>
<include name="**/*.zip"></include>
</fileset>
</path>
<path id="class.path.jwsdp">
<path refid="class.path.local"></path>
</path>
<path id="class.path.doclet">
<path refid="class.path.ant"></path>
</path>
<taskdef name="wscompile" classname="com.sun.xml.rpc.tools.ant.Wscompile" classpathref="class.path.jwsdp"></taskdef>
<taskdef name="xdoclet" classname="xdoclet.DocletTask" classpathref="class.path.doclet"></taskdef>
<taskdef name="ejbdoclet" classname="xdoclet.modules.ejb.EjbDocletTask" classpathref="class.path.doclet"></taskdef>
<taskdef name="wseedoclet" classname="xdoclet.modules.wsee.WseeDocletTask" classpathref="class.path.doclet"></taskdef>
...
In order to demonstrate the implementation we introduce a use case. This is sonstructed for the demonstration purposes and shows the usage of different types.
Use Case
The constructed system is capable of providing the measurements of some sensors. The sensors are identified by numers and can be queried by the user by providing the timespan of measurements. As a result, the systems delivers the set of measurements for the given timespan with one measurement per minute but at most sixty measurements. Every measurement contain the id of sensor from which it has been recorded, the timestamp, the value as a byte array, the measurement unit and finally the flag if the measurement exceeds the expectation and has alarming values.
We start with typical EJB implementation and then adopt the resulting types to those, that should be used in a Web Service.
First Session Bean powered by XDoclet
Following the EJB 2.1 specification the stateless session bean class must implement the javax.ejb.SessionBean interface. We follow the
Class Adapter design pattern and create an abstract session bean that serves as a super class of all session beans.
public abstract class AbstractSessionBean implements SessionBean
{
/** Logging facility */
protected static Logger LOG = Logger.getLogger(AbstractSessionBean.class);
/** Session context */
protected SessionContext sessionContext;
/**
* @see javax.ejb.SessionBean#ejbActivate()
*/
public void ejbActivate() throws EJBException, RemoteException
{
}
/**
* @see javax.ejb.SessionBean#ejbPassivate()
*/
public void ejbPassivate() throws EJBException, RemoteException
{
}
/**
* @see javax.ejb.SessionBean#ejbRemove()
*/
public void ejbRemove() throws EJBException, RemoteException
{
}
/**
* @see javax.ejb.SessionBean#setSessionContext(javax.ejb.SessionContext)
*/
public void setSessionContext(SessionContext sessionContext) throws EJBException, RemoteException
{
this.sessionContext = sessionContext;
}
}
Using such an adapter we can avoid code repetition in functional session beans. It could be also a good idea to put the logging facility into this abstract class. Any functional bean extends AbstractSessionBean and overwrites the ejbCreate() method which is used to setup the working copy of a Bean. Mostly, references to other beans are initialized in this method. Due to the usage of XDoclet, we follow the Factory pattern implemented in the EJB-Util class, which simplifies access to other EJBs.
In our example we flatten the exception handling to the minimum and introduce one exception class for every functional bean, which is thrown by any error during processing. Therefore, any functional methods throw this exception. Usually, exceptions should be topic-related instead of being bean-related.
Information needed for XDoclet generation is stored in the corresponding XDoclet tags inside of the JavaDoc comments. For the full list of XDoclet tag please refer to the
XDoclet site. We only explain the tags, we use. The ejb.bean tag indicates that a class is an EJB, providing a name, display-name, description as well as JNDI-Names of LocalHome interface and of the bean itself. The visibility is controlled over the view-type tag, the transactionality over transaction-type tag. Every business method we want to be included to business interfaces (Remote or Local) should be tagged with ejb.interface-method with corresponding view-type. Using this simple rule set we can easily implement business logic layer based on the stateless session beans:
/**
* ...
* @ejb.bean name="SensorManager"
* description="A Bean responsible for sensor operations"
* display-name="SensorManagerBean"
* jndi-name="techjava/SensorManagerrBean"
* local-jndi-name="techjava/SensorManagerLocalHome"
* type="Stateless"
* transaction-type="Container"
* view-type="both"
* ...
*/
public class SensorManagerBean extends AbstractSessionBean
{
/**
* Max number of returned values
*/
private static final long MAX_DURATION = 60;
/**
* Retrieves data from sensors
* @param sensorId id of sensor to query
* @param timespanStart start of the time period
* @param timespanEnd end of the time period
* @return a collection of Measurement POJOs or an empty collection
* @throws SensorManagerException if something goes wrong
* @ejb.interface-method view-type="both"
*/
public Collection getSensorData(Long sensorId, Date timespanStart, Date timespanEnd)
throws SensorManagerException
{
Collection ret = new Vector();
LOG.debug("Entering getSensorData()");
if (sensorId == null || timespanStart == null || timespanEnd == null)
{
throw new SensorManagerException("Missing a mandatory parameter, that was null (not set)");
} else if (!timespanStart.before(timespanEnd)) {
throw new SensorManagerException("The timespan is defined by the start that should be before end");
}
for (long i = 0; i < getNumberOfElements(timespanStart, timespanEnd); i++)
{
Date date = new Date(timespanStart.getTime() + i*1000*60);
if (date.after(timespanEnd))
{
break;
}
Measurement measurement = createMeasurement(sensorId, date, i);
ret.add(measurement);
}
LOG.debug("Leaving getSensorData(). Returning " + ret.size() +" values");
return ret;
}
/**
* retrieves the number of measurements in timespan
* @param timespanStart
* @param timespanEnd
* @return
*/
public long getNumberOfElements(Date timespanStart, Date timespanEnd) { ... }
/**
* Creates a measurement instance
* @param sensorId
* @param timestamp
* @param number
* @return
*/
public Measurement createMeasurement(Long sensorId, Date timestamp, long number) { ... }
}
In order to generate the artifacts required by the specification from the written bean, we need to call a corresponding EJBDoclet task. The task itself is configuring only main generation options, during the subtasks are invoked for artifact generation. We used to separate classes of different purpose by packages and massively use the packageSubstitution subtask for this purpose. Remote, local, local home and remote home interfaces, util factory class and both EJB and a vendor-specific descriptors are generated using corresponding tasks.
<ejbdoclet destdir="${ejb.distdir}" verbose="true" ejbspec="2.1">
<fileset dir="${ejb.srcdir}">
<include name="${ejb.include}" />
</fileset>
<fileset dir="${ejb.distdir}">
<include name="${ejb.include}" />
</fileset>
<packageSubstitution packages="ejb.entity" substituteWith="interfaces.entity" />
<packageSubstitution packages="ejb.session" substituteWith="interfaces.session" />
<packageSubstitution packages="ejb.facade" substituteWith="interfaces.facade" />
<remoteinterface pattern="{0}Remote" />
<localinterface pattern="{0}Local" />
<homeinterface pattern="{0}Home" />
<localhomeinterface pattern="{0}LocalHome" />
<utilobject kind="physical">
<packageSubstitution packages="ejb.session" substituteWith="util.session" />
<packageSubstitution packages="ejb.facade" substituteWith="util.facade" />
</utilobject>
<deploymentdescriptor
destdir="${ejb.descriptor.distdir}"
displayname="${ejb.modulename}"
description="EJB Module ${ejb.modulename}"
/>
<jboss
destdir="${ejb.descriptor.distdir}"
version="4.0"
mergedir="metadata/merge"
/>
</ejbdoclet>
After generation of the classes and descriptors, which will be executed in a separate directory, it is a good idea to copy the descriptors back to the primary source folder, in order to allow for Eclipse to work with generated descriptors. Now we can compile the hand written code, together with generated code, put the results in a Java archive and assembly it to an enterprise archive, which can be deployed on an application server.
Hands on the Web Service Definition
The design of the interface definition is in general one of the most important steps in the component development life cycle. Depending on the quality of the interface design the component becomes reuseable or remains in usage only in the application it was initially built for. Therefore, we rely on a human engineering instead of generation.
For the definition of our Web Service, we use a standard language for this purpose, the WSDL. A WSDL file has a following structure:
- Types
- Messages
- Operations
- Port Type
- Bindings
- Services
As long as we intend to use document-literal, SOAP-style Web Services, the Binding and the Service parts are straight forward. The only thing we should pay attention is the Fault definition. We start from the Port Type definition, which is the equivalence of the business interface. A Port Type has a name and a collection of operation definitions, containing references to incoming, outgoing and fault messages. The Message part defines how XML Schema Types are used in the operations. This means that the most important parts of the WSDL file are the introduced Types, which are defined using XML Schema and the Port Types, which defines Operations, which use the Types.
The main purpose of a WSDL file is to define an interface. In order to distinguish it from the others, the interface is named. As long as WSDL defines a web-accessible resource, we use full qualified names, similar to XML target namespace.
<wsdl:definitions name="MeasurementProvider"
targetNamespace="http://www.techjava.de/2008/ws4j2ee14/measurement/"
xmlns:tns="http://www.techjava.de/2008/ws4j2ee14/measurement/"
xmlns:types="http://www.techjava.de/2008/ws4j2ee14/measurement/types/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<wsdl:types>
<xsd:schema
targetNamespace="http://www.techjava.de/2008/ws4j2ee14/measurement/types/"
xmlns:types="http://www.techjava.de/2008/ws4j2ee14/measurement/types/"
elementFormDefault="qualified"
>
<!--
ID element for sensor
-->
<xsd:simpleType name="sensor-id">
<xsd:restriction base="xsd:long" />
</xsd:simpleType>
<!--
Measurement complex type
-->
<xsd:complexType name="Measurement">
<xsd:sequence>
<xsd:element name="sensorid" type="types:sensor-id" />
<xsd:element name="timestamp" type="xsd:dateTime" />
<xsd:element name="critical" type="xsd:boolean" />
<xsd:element name="value" type="xsd:base64Binary" />
<xsd:element name="unit" type="xsd:string" />
</xsd:sequence>
</xsd:complexType>
<!--
Timespan complex type
-->
<xsd:complexType name="Timespan">
<xsd:sequence>
<xsd:element name="start" type="xsd:dateTime"
minOccurs="1" maxOccurs="1" />
<xsd:element name="end" type="xsd:dateTime"
minOccurs="1" maxOccurs="1" />
</xsd:sequence>
</xsd:complexType>
<!--
Operation Types
-->
<xsd:element name="GetSensorData">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="sensorid" type="types:sensor-id"
minOccurs="1" maxOccurs="1" />
<xsd:element name="timespan" type="types:Timespan"
minOccurs="1" maxOccurs="1" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="GetSensorDataResponse">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="measurements" type="types:Measurement"
maxOccurs="unbounded" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="GetSensorDataFault">
<xsd:complexType>
<xsd:sequence minOccurs="1" maxOccurs="1">
<xsd:element name="reason" type="xsd:string"
minOccurs="0" maxOccurs="1" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
</wsdl:types>
...
<!--
Port Type (interface declaration)
-->
<wsdl:portType name="MeasurementProviderPortType">
<wsdl:operation name="GetSensorData">
<wsdl:input message="tns:GetSensorDataRequest" />
<wsdl:output message="tns:GetSensorDataResponse" />
<wsdl:fault message="tns:GetSensorDataFaultMessage"
name="GetSensorDataFault" />
</wsdl:operation>
</wsdl:portType>
...
</wsdl:definitions>
Web Service Implementation
The created WSDL file is used for further Java code generation. For this purpose we use WSCompile, a tool supplied with Sun’s Java Web Service Developer Pack. The tool need a configuration file (wsdl-config.xml) storing the location of the WSDL file and namespace-to-package mappings. As a result of its execution, the tool generate Java classes for every custom type defined in XML Schema and the descriptor for JAX-RPC mapping required by the container for serialization and deserialization. In addition, it creates a Service interface, that is a interface to the factory of generated Port Type interfaces. The tool also generate implementation stubs for every Port Type, which can be ignored.
<configuration xmlns="http://java.sun.com/xml/ns/jax-rpc/ri/config">
<wsdl
location="./metadata/MeasurementProviderService.wsdl"
packageName="de.techjava.sensor.interfaces.stubs"
>
<namespaceMappingRegistry>
<namespaceMapping
namespace="http://www.techjava.de/2008/ws4j2ee14/measurement/types/"
packageName="de.techjava.sensor.valueobjects"
/>
</namespaceMappingRegistry>
</wsdl>
</configuration>
The WS Compile is usually called from the command line, but we use the Ant Task for this. Important are the features passed to the generator: documentliteral, wsi, searchschema, serializeinterfaces and explicitcontext. The path to the generated JAX-RPC mapping file is provided by the mapping attribute. Pay attention on the tool call, because depending on parameters given it generates Java classes from WSDL or vice versa.
<wscompile fork="true" import="true" base="java/class"
sourceBase="java/generated" verbose="true"
features="documentliteral, wsi, searchschema, serializeinterfaces, explicitcontext"
mapping="java/generated/META-INF/jaxrpc-mapping.xml"
config="metadata/wsdl-config.xml"
xSerializable="true"
>
<classpath>
<path refid="class.path.local" />
<path refid="class.path.ant" />
<pathelement path="${java.class.path}" />
</classpath>
</wscompile>
After we generated the Java representation of the Web Service interface, we can integrate it with our EJB implementation. In order to do this, we used to create a
Facade session bean, that implements the Port Type interface. The methods of the facade bean provide some parameter validation, form the values needed for the calculations, invoke the corresponding EJBs, receive results or exceptions and, finally, form the response object or fault. The XDoclet annotation of the facade bean follows the one discussed above, but differs from it slightly. The view-type attribute of the ejb.bean tag should hold the value remote-service-endpoint. In addition, the ejb.interface tag provide information about the Java Port Type interface and about the special Endpoint interface, that is required for the container. In order to generate the Endpoint interface, we add the service-endpoint subtask to the ejbdoclet task.
...
/**
* @ejb.interface
* service-endpoint-class="de.techjava.sensor.interfaces.session.MeasurementProviderFacadeConnectorEndpoint"
* service-endpoint-extends="de.techjava.sensor.interfaces.stubs.MeasurementProviderPortType"
* @wsee.port-component
* name="MeasurementProviderService"
* local-part="MeasurementProviderService"
* display-name="MeasurementProviderService"
* description="MeasurementProvider Bean exposed as a web service"
*/
public class MeasurementProviderFacadeBean
extends AbstractSessionBean
implements MeasurementProviderPortType
{
private SensorManagerLocal sensorManagerLocal = null;
/**
* Creates a link to SensorManager
* @see de.techjava.sensor.ejb.session.AbstractSessionBean#ejbCreate()
*/
public void ejbCreate()
throws EJBException
{
try
{
sensorManagerLocal = SensorManagerUtil.getLocalHome().create();
} catch (CreateException e)
{
throw new EJBException("Error creating new Session Manager instance");
} catch (NamingException e)
{
throw new EJBException("Session Manager Local Home could not be found in JNDI");
}
}
/**
* Method called on web service message receipt
* @ejb.interface-method view-type="remote-service-endpoint"
*/
public GetSensorDataResponse getSensorData(GetSensorData parameters)
throws GetSensorDataFault
{
LOG.debug("Received a web service request getSensorData()");
if (parameters == null
|| parameters.getTimespan() == null
|| parameters.getTimespan().getEnd() == null
|| parameters.getTimespan().getStart() == null)
{
LOG.debug("Leaving getSensorData() with error");
throw new GetSensorDataFault("Wrong request, check mandatory parameters");
}
if (sensorManagerLocal == null)
{
LOG.debug("Leaving getSensorData() with error");
throw new GetSensorDataFault("Sensor Manager is not available");
}
Long sensorId = new Long(parameters.getSensorid());
Date timespanStart = parameters.getTimespan().getStart().getTime();
Date timespanEnd = parameters.getTimespan().getEnd().getTime();
try
{
Collection simpleMeasurements = sensorManagerLocal.getSensorData(sensorId, timespanStart, timespanEnd);
Vector measurements = new Vector(simpleMeasurements.size());
Iterator simpleMeasurementI = simpleMeasurements.iterator();
// convert types from EJB to generated XSD representations
while(simpleMeasurementI.hasNext())
{
SimpleMeasurement sm = (SimpleMeasurement) simpleMeasurementI.next();
Measurement measurement = convertMeasurement(sm);
measurements.add(measurement);
}
GetSensorDataResponse response = new GetSensorDataResponse();
response.setMeasurements((Measurement[]) measurements.toArray(new Measurement[measurements.size()]));
LOG.debug("Leaving getSensorData().");
return response;
} catch (SensorManagerException e)
{
LOG.debug("Leaving getSensorData() with error");
throw new GetSensorDataFault(e.getMessage());
}
}
}
In addition, the special J2EE Web Service descriptor webservices.xml needs to be created. For this purpose we use WSEE-Doclet, that introduces its own tags. The wsee-port-component provides display-name, web-service-description-name and port-component-name in the attributes name, local-part and display-name. The WSEE-Doclet is started from an Ant task and has one subtask wsee-deploymentdescriptor which is used to generate the required webservice.xml file.
...
<wseedoclet destDir="${ejb.descriptor.distdir}" jaxrpcMappingFile="jaxrpc-mapping.xml" wseeSpec="1.1" force="true" verbose="true">
<fileset dir="${ejb.srcdir}">
<include name="**/*.java" />
</fileset>
<wsee-deploymentdescriptor />
</wseedoclet>
...
Outline
For testing of Web Services is an important step of development. Especially, the resulting SOAP messages should be reviewed at least once, to ensure that the description is completed correctly, and no malformed XML structures are used. In order to play around with fresh-deployed Web Service open a browser of you choice and enter the URL of the web service overview of your application server. If JBoss (>4.0.5) runs locally, this will be http://localhost:8080/jbossws/. You should see a list of deployed web services. By clicking on a wsdl-button you can retrieve the version of WSDL after deployment (containing the target URL of the endpoint interface). Using this WSDL you can run tests of your web service. We use Eclipse’s Web Service Explorer to run developer tests (WTP installation needed). You can access it under Run -> Launch the Web Service Explorer. Switsch to WSDL-Page by clicking on the second button from right, in the upper right corner, enter the URL and hit Go. Fill the form generated for each method, send the request and analsye the response. If you want to create more advanced tests (and test suites) please refer to
SOAP-UI Project.

Resources
You can download the zip file (
de.techjava.ws4j2ee14.sensor_20080219_src.zip) containing the example above.
References
-
S. Microsystems, "The Java Web Services Tutorial," 2004.
@techreport{SUN_2004_JWSTUTORIAL,
author = {Sun Microsystems},
title = {The Java Web Services Tutorial},
month = Jun, year = {2004},
url = {http://java.sun.com/webservices/docs/1.4/tutorial/doc/index.html}
}
-
O. Ihns, S. M. Heldt, R. Wirdemann, and H. Zuzmann, Enterprise JavaBeans komplett, publisher Oldenburg, , 2003.
@Book{IHNS_2003,
author = {Oliver Ihns and Stefan M. Heldt and Ralf Wirdemann and Henning Zuzmann},
title = {Enterprise JavaBeans komplett},
publisher {Oldenburg},
year = {2003},
month = {Oct},
url = {http://www.ejbkomplett.de/}
}
-
K. Czarnecki and U. W. Eisenecker, Generative Programming, publisher Addison-Wesley, , 2000.
@Book{CZARNECKI_2003,
author = {Krzysztof Czarnecki and Ulrich W. Eisenecker},
title = {Generative Programming},
publisher {Addison-Wesley},
year = {2000},
month = {May},
}
-
E. Gamma, R. Helm, R. Johnson, and J. Vlissides, Design Patterns: Elements of Reusable Object-Oriented Software, , 1994.
@Book{GAMMA_1994,
author = {Erich Gamma and Richard Helm and Ralph Johnson and John Vlissides},
title = {Design Patterns: Elements of Reusable Object-Oriented Software},
year = {1994}
}
-
"XDoclet Project,".
@techreport{XDOCLET,
author = {},
title = {XDoclet Project},
url = {http://xdoclet.sourceforge.net/xdoclet/index.html}
}
Posted in enterprise systems, java, jboss, technology | 1 Comment »
February 11th, 2008 by Simon Zambrovski
We are currently reasoning about usage of
Apache’s Ivy for library dependency. This should solve the problem for library acquisition and is a step towards
continuous integration by providing an own repository. As long we use Eclipse for development, we also need a good integration in to the IDE. The
Ive Eclipse plugin is very poor, but I found
a post in Swapfile of my brain with similar ideas… It’s time to put everything together.
Posted in java, tools | No Comments »