Você está na página 1de 141

Programming

ANDREAS MANESSINGER ON SOFTWARE AND HOW TO MAKE IT


 About
 Contact
  Tutorials
o
Search
 
 Eclipse / GlassFish / Java EE 6 Tutorial

An Eclipse / GlassFish / Java EE 6 Tutorial


Add comments

Version 1.3, last updated August 21, 2010 – 12:00

[-- hide table of contents --]


1. Applicability
2. How to use the tutorial
3. Typographical conventions
4. Tools
5. Preparing the workspace
6. Preparing the database
7. The container project (EAR project)
1. Purpose
2. Steps in Eclipse
8. The core logic (EJB project)
1. Purpose
2. Abstraction of data access (Entity Access Objects)
3. Services guard the entrance
4. Instantiation of Enterprise Java Beans
i. EJB annotation
ii. Lookup via JNDI
iii. Calling the bean as a SOAP web service
5. Scope of EJBs
6. Accessing an EJB application from outside
9. The EJB Project
1. Creating the project in Eclipse
2. Creating a service bean
3. Manual testing via GlassFish web service tester
4. Testing with soapUI
5. Prepare for persistence
6. Creating entity classes
7. Allocation sizes for sequences – a deviation
8. A simple Entity Access Object (EAO)
9. Using the EAO and looking for an error
10. Specifying the database, testing, SQL log
i. Creating connection pools and JDBC resources in the Administration
Console
ii. Creating connection pools and JDBC resources using asadmin
iii. Referencing the JDBC resource from the application
11. Data Transfer Objects (DTO)
i. Where to convert?
ii. Implementation
iii. Updating definition in soapUI and testing
10. Accessing EJBs from a servlet
1. Creating a Dynamic Web Projects for servlets
2. Creating a servlet
3. Accessing the EJB
11. Unit tests
1. In-container testing
i. Project setup
ii. EJB lookup
iii. Testing and a NotSerializableException
iv. Testing internal interfaces
v. Testsuite
2. Out-of-container testing
i. Project setup
ii. Persistence unit and entity manager
iii. Simulating injection and testing
iv. Testsuite
12. Insert and Update
1. Extending the Database
2. Exceptions
3. Implementing storeZip()
4. If it does not work
i. java.sql.SQLSyntaxErrorException: Table/View ‘SEQUENCE’ does not exist
ii. Result has no id
13. Validation
1. ValidationException
2. Specifying constraints
3. Validation using interceptors
4. Testing the validator
14. Other uses of interceptors
1. A hypothetical security interceptor
2. Handling transaction rollbacks
i. The problem
ii. Towards a solution
iii. A solution using an interceptor
15. Adding extra libraries
16. Syndication Feeds
1. Realizing a feed with ROME
2. A bug in Eclipse
17. Configuration via JNDI Custom Resources
18. Access via REST
1. The REST servlet
2. The REST delegator
3. Examples of HTTP traffic
i. add()
ii. countryCount()
iii. dumpCountries()
iv. storeZip()
v. inputStream()
19. PostgreSQL as database backend
1. Installing PostgreSQL and creating a database user
2. Creating the database
3. PostgreSQL connection pool in GlassFish
4. Definition of the datasource in Eclipse
5. Entities
6. Access to PostgreSQL via SSL
20. Conclusion

In “4 – Equipment” I have committed myself to using Eclipse and the Java Enterprise Edition as my
tools, while in “5 – Patterns And Languages” I’ve declared my high-level goals for implementing a
next step of design pattern-based tools. Now, for a deeper understanding of design patterns, you
first have to use them. This post in the form of a tutorial shows some very basic project setups using
Eclipse and GlassFish.

I am no expert in this field, some important things may be missing, so just take the following
as a set of things that work for me.
As I am not immune to learning, and as I am going the use these things a lot, it is inevitable that my
understanding of certain aspects will change. I suppose that means, I will have to make changes to
this post whenever it happens. If I ever do so, I will post a short notice.

Applicability
[back to top]
This is a tutorial about using Eclipse and the GlassFish v3 Java application server to implement Java
EE 6 applications. I will show how to use different Eclipse project types for different purposes, will
show how to do manual tests and how to implement automatic unit tests. We will not create a
complete application, but more a vertical slice through an application. The idea is to just touch all
relevant areas, not to finish a project.

The tutorial assumes the existence of a relational database, and it concentrates on the Java
application used as a backend. Using JSF or another server-based GUI framework is definitely out
of scope.

How to use the tutorial


[back to top]
For your convenience and for reference I have zipped the workspace that I have used in these
examples (all but the .metadata directory) and uploaded it to my server. You can download it
fromhttp://manessinger.com/data/playground.zip. These files reflect exactly what you are going to
have, when you have completed this tutorial. No intermediate steps are contained in the archive. For
the best learning effect I suggest that you don’t use these sources, but just follow the tutorial step by
step. Eventually you will get to exactly that result.
Source listings in this tutorial can normally be taken by cut and paste. There is only one instance of
an XML file, where you can’t do it, but in that instance I explicitly say so.

If you don’t type the program texts, but instead copy them by cut and paste, it is possible to complete
the tutorial in six to eight hours. Depending upon your familiarity with the topics covered, it may be
shorter or considerably longer.

Typographical conventions
[back to top]
I’m trying to use a little bit of semantic markup here. At the moment I use the following conventions:

TERM Used for terms, normally only when they are introduced
UI Element Used for user interface elements, everything that refers to GUI elements
text Used for names, texts that you type in or that you get as feedback from the GUI

Tools
[back to top]
I use the GlassFish Tools Bundle for Eclipse, and at the time of this writing, it is version 1.2, released
December 17, 2009. This package bundles the Java EE 6 reference implementation with Eclipse
3.5.1 and JDK 1.6. I have installed it on Windows 7 in the default location  C:\GlassFish-Tools-Bundle-
For-Eclipse-1.2
While Eclipse 3.6 “Helios” has been released and is already supported by a new version of the
GlassFish plugin for Eclise, there is still an annoying bug, and I currently suggest that, unless you
really, really need Helios, you just use the bundle until the bug gets fixed. See “7 – Eclipse 3.6
“Helios” and GlassFish 3.01” for details.
The database is Apache Derby. This comes as part of the tools bundle. It has all the features of
“real” databases like Oracle or PostgreSQL, but it has a very small memory footprint.
For manual testing, I will use the Open Source edition of soapUI. Automatic testing will be done
using JUnit, which conveniently comes bundled with Eclipse. No further software is needed and I
have neither installed updates to GlassFish nor plugins.
I myself currently use an Eclipse workspace called playground. Every workspace will do, that’s just
what I use and what I may refer to.

Preparing the workspace


[back to top]

Eclipse has the notion of a WORKSPACE. Whenever you have an open instance of Eclipse, it
is open with a particular workspace. A workspace contains projects, where the notion
of PROJECT does not necessarily correspond to what we may regard as project in classic project
management.
Eclipse workspaces are just a collection of settings like how Eclipse itself is configured, which
servers are running, which databases you connect to, how the sub-windows (the VIEWS) and the
toolbars are arranged, which projects are part of the workspace, which files are open, etc.
A PROJECT is normally a collection of source files that compile and package to an ARTIFACT, for
instance a JAR or a WAR or an EAR file. The type of artifact depends on the type of project, for
instance a JAR is the artifact of a normal JAVA PROJECT, a WAR is the artifact of a DYNAMIC WEB
PROJECT, while an EAR is the artifact of anENTERPRISE APPLICATION PROJECT, basically a container
project that bundles collections of sub-projects into a single artifact.
Every time you open Eclipse, it asks you for the workspace to use, and when you open Eclipse for
the first time, or when you open Eclipse with a new workspace name, i.e. a workspace that does not
yet exist (for instance playground), you arrive at the welcome screen. Not much to do there, only
some documentation links, what you really want to do is go on to the workbench.
If it’s a new workspace, you’ll be in the RESOURCE PERSPECTIVE.
The PERSPECTIVE is another important concept in Eclipse. There are different perspectives for
different kinds of work. There is a JAVA EE PERSPECTIVE for working with Java in an Enterprise
Edition environment, aDATABASE DEVELOPMENT PERSPECTIVE for working with databases, and so on.
Each perspective is an arrangement of Views. A VIEW shows a particular aspect in a perspective.
You have a tree-like PROJECT EXPLORER view (normally along the left edge of the Eclipse window),
an EDITOR VIEW on an open file, a CONSOLE VIEW showing console output like in a passive terminal,
a SERVERS VIEW listing the running servers and giving access to server commands
like Start and Stop. Views can be tabbed together in groups. If something important happens in a
view, Eclipse automatically makes it the top tab in a tabbed group.
The Resource perspective is a general perspective for accessing project resources. We need two
other perspectives, Java EE and Database Development.
Use Window / Open Perspective / Java EE to change to the Java EE perspective. Now you will have
two buttons in the upper right toolbar, one labeled Java EE and the other Resource. Each of these
has a context menu (mouse right) and you can drag one button upon the other to change positions.
Try that and then choose Close from the context menu of the Resource perspective. We don’t need
it any more. In the same way you should open the Database Development perspective. Then switch
back to the Java EE perspective.

You may or may not have a server definition in the Servers view, and you may not even see
a Servers view at all. It should be in the tabbed pane at the bottom. If not, use Window / Show View /
Servers, or if it’s not directly in the menu, use Window / Show View / Other / Servers to show it.
If there is no server definition for the Bundled GlassFish v3 JEE 6 server, create a new one from the
context menu of the Servers view using New / Server. Just follow the screenshots. If you don’t use
the GlassFish Tools Bundle for Eclipse, you may have to define a new server runtime first, either
from the link on the first page of the New Server wizard, or from the menu bar via Window /
Preferences / Server / Runtime Environments / Add.
Now that we have a server, we need one more view that we’ll use frequently, and that is not visible
by default.

We use JUnit for unit tests. JUnit comes bundled with Eclipse and of course there is a JUnit view for
starting tests and viewing results. In the JEE perspective its default location is a tad awkward, thus
we will change it. If it is visible at all, it is in the bottom pane where you also find the  Servers view. If
you don’t see it, open it withWindow / Show View / Other / Java / JUnit.
Now take the tab and drag it onto the tab of the Project Explorer in the left part of Eclipse. Again you
can change orders by dragging the tabs onto each other. Make sure the Project Explorer is visible,
that’s what we use most of the time.

Preparing the database


[back to top]
This is neither about object-relational mapping nor is it a meaningful sample application. I still want
at least two or three classes with foreign key relationships, thus we will use a classic master/detail
relation: a table of countries and a second table of cities, with cities being located in countries. One
more table will be added later.

The GlassFish Tools Bundle for Eclipse already comes with a pre-defined JDBC datasource for a
pre-designed Sample JavaDB Database. JavaDB is Sun’s name for Apache Derby.
We open Eclipse and first make sure that Derby is running. From the menu bar select  Window /
Preferences, and in the Preferences dialog GlassFish Preferences. Make sure Start the JavaDB
database process when Starting GlassFish Server is ticked.
Next make sure that the Java EE perspective is active. In the lower part of the window there is a
tab Servers. Activate it, select Bundled GlassFish v3 Java EE 6 and start it, either with the green
arrow or from its context menu.
This will take a few seconds, maybe half a minute. In case GlassFish does not start and you get a
message box complaining about a wrong user name or password, have a look at “4 – Equipment“. You
may have run into the same problem as I did. Normally all should be well, the server running and
Derby ready for use.
Select the Database Development perspective. In the tree to the left, under Database Connections,
you will see Sample JavaDB Database. I don’t want to pollute the sample database that comes with
GlassFish. It is used in Sun’s tutorials and I recommend leaving it alone.

Let’s create a new database. From the context menu of Database Connections, we
select New and first have to select name and database type (Derby).
We click Next and now have to specify the new connection’s properties. I usecookbookdb as
database name (the name on the previous page was for display), and specify a
user cookbookuser with password cookbook. Use whatever you like. We will use this database a lot,
there won’t ever be anything of value in it, thus we can safely tick Save password. If you don’t feel
comfortable saving passwords in a development tool, you have my respect, just don’t do it, but in
any case try the Test Connection button once. You will be confirmed with a message box that Ping
succeeded. Click Finish and we’re done.

Derby is modeled after the big guys, thus we have not only databases, we have schema as
well. Looks like Oracle, huh?
Now that we have a database, we create the tables. Derby has automatically created a schema for
our user cookbookuser (though you can’t yet see it). In that schema we create two
tables, COUNTRY and CITY, the primary keys and the constraints.
In order to do this, select the new database and from its context menu choose  Open SQL
Scrapbook. Make sure that our Cookbook Database is selected and connected. Now copy the
following text and paste it into the SQL window. Then right-click in the window and choose  Execute
All.

--
-- Set up database schema
--
CREATE TABLE COUNTRY (
ID INTEGER GENERATED ALWAYS AS IDENTITY NOT NULL,
NAME VARCHAR(50)
);
ALTER TABLE COUNTRY ADD CONSTRAINT COUNTRY_PRIMARY_KEY PRIMARY KEY (ID);
CREATE UNIQUE INDEX COUNTRY_NAME_IDX ON COUNTRY(NAME);
 
CREATE TABLE CITY (
ID INTEGER GENERATED ALWAYS AS IDENTITY NOT NULL,
COUNTRY_ID INTEGER NOT NULL,
NAME VARCHAR(50)
);
ALTER TABLE CITY ADD CONSTRAINT CITY_PRIMARY_KEY PRIMARY KEY (ID);
ALTER TABLE CITY ADD CONSTRAINT CITY_FOREIGNKEY_COUNTRY_ID FOREIGN KEY (COUNTRY_ID)
REFERENCES COUNTRY (ID);
CREATE UNIQUE INDEX CITY_NAME_IDX ON CITY(NAME);
 
--
-- Initialize with some values
--
INSERT INTO COUNTRY (NAME) VALUES ('Austria');
INSERT INTO COUNTRY (NAME) VALUES ('Italy');
INSERT INTO COUNTRY (NAME) VALUES ('USA');
 
INSERT INTO CITY (COUNTRY_ID, NAME)
VALUES ((SELECT ID FROM COUNTRY WHERE NAME = 'Austria'), 'Graz');
INSERT INTO CITY (COUNTRY_ID, NAME)
VALUES ((SELECT ID FROM COUNTRY WHERE NAME = 'Austria'), 'Linz');
INSERT INTO CITY (COUNTRY_ID, NAME)
VALUES ((SELECT ID FROM COUNTRY WHERE NAME = 'Austria'), 'Salzburg');
INSERT INTO CITY (COUNTRY_ID, NAME)
VALUES ((SELECT ID FROM COUNTRY WHERE NAME = 'Austria'), 'Wien');
 
INSERT INTO CITY (COUNTRY_ID, NAME)
VALUES ((SELECT ID FROM COUNTRY WHERE NAME = 'Italy'), 'Bologna');
INSERT INTO CITY (COUNTRY_ID, NAME)
VALUES ((SELECT ID FROM COUNTRY WHERE NAME = 'Italy'), 'Firenze');
INSERT INTO CITY (COUNTRY_ID, NAME)
VALUES ((SELECT ID FROM COUNTRY WHERE NAME = 'Italy'), 'Roma');
INSERT INTO CITY (COUNTRY_ID, NAME)
VALUES ((SELECT ID FROM COUNTRY WHERE NAME = 'Italy'), 'Venezia');
 
INSERT INTO CITY (COUNTRY_ID, NAME)
VALUES ((SELECT ID FROM COUNTRY WHERE NAME = 'USA'), 'Atlanta');
INSERT INTO CITY (COUNTRY_ID, NAME)
VALUES ((SELECT ID FROM COUNTRY WHERE NAME = 'USA'), 'Los Angeles');
INSERT INTO CITY (COUNTRY_ID, NAME)
VALUES ((SELECT ID FROM COUNTRY WHERE NAME = 'USA'), 'New York');
INSERT INTO CITY (COUNTRY_ID, NAME)
VALUES ((SELECT ID FROM COUNTRY WHERE NAME = 'USA'), 'Washington');

This is the data we’ll work with. Now you can choose from the context menu of Database
Connections / Cookbook Database / cookbookdb / Schemas, and when you drill down, you see a
new schemaCOOKBOOKUSER with the two tables that we’ve just created.
When you look at the table definitions, you see that primary keys are declared as

ID INTEGER GENERATED ALWAYS AS IDENTITY NOT NULL;

This is Derby’s way of declaring automatically generated keys. In other databases you would use
sequences. Sequence support is already in the current version 10.6 of Derby, but the GlassFish
Tools Bundle for Eclipsestill comes with 10.5. In reality this is not important here. We are only going
to use this as a playground.

The container project (EAR project)


[back to top]

Purpose
[back to top]
There are different Eclipse project types that can be used with the JEE 6. In the most flexible setup,
you use a so-called ENTERPRISE APPLICATION PROJECT, also called an EAR PROJECT, after the
artifact it produces, anENTERPRISE ARCHIVE or EAR.
An EAR project is nothing but a container, intended to bundle the artifacts of the contained projects,
along with any libraries that they use and that are not already part of the Java Enterprise Edition. We
always begin with an EAR project, and then we create those projects, where we do the actual work,
adding each of them to the EAR. Later, for deployment, we can export the EAR project as one single
EAR file that contains all JARs from the contained projects.

Today an EAR would not be strictly needed. Today Dynamic Web Projects, the project type that
compiles to a WAR (Web Application Archive), also run under the control of an enterprise container,
thus you can use them to create Enterprise Java Beans, something that used to need an EJB
project. Still, I prefer to have my EJBs in an EJB project, and that wrapped up in an EAR. Only this
way do I get the client library that I need, when I want to access my beans via Corba/IIOP, and that’s
the protocol of choice when you want to be able to let beans participate in distributed transactions.

Steps in Eclipse
[back to top]
From now on, if not explicitly stated otherwise, we always assume that Eclipse is started, the
Database exists, GlassFish server and Derby database are started and the JEE perspective is
active.

In the JEE perspective you have the Project Explorer on the left side. If you have a fresh
workspace, then the Project Explorer will be empty. Either from the File menu or from the Project
Explorer context menu choose New / Enterprise Application Project. This opens the New EAR
Application Project dialog.
It is not so important what specific naming convention you have, but it is useful to have one. Mine is,
to have a name for the overall application, here cookbook, and then to suffix the projects with
something that tells about their type. Thus the EAR project is suffixed with EAR.

The core logic (EJB project)


[back to top]

Purpose
[back to top]
ENTERPRISE JAVA BEANS (EJB) are really just normal Java classes. Create one with new MyBean(),
and you get just a plain old Java object (POJO). It is when EJBs are instantiated under the control of
an EJB CONTAINER, that all sorts of interesting things begin to happen automatically.
For instance you can leave field variables in your beans uninitialized, and as long as they have the
right annotations, the container injects proper instances, and for performance reasons it can do that
from a pool of pre-allocated, momentarily idle instances. In a multi-threaded server this can give you
an enormous performance boost.
One of the most important aspects of EJB containers is, that they can inject datasources (for
instance JDBC datasources) and other resources, that the program only references by name, and
that are really defined in the application server.

Not only does the container manage datasources for accessing databases, it also handles
transactions, and it can do not only the simple case of handling local transactions, it also handles
and/or coordinates distributed transactions.

But again, in order for all this to work, you have to run your beans under the control of an EJB
container.

EJBs come in three flavors: STATELESS SESSION BEANS, STATEFUL SESSION BEANS and SINGLETON


BEANS. In the context of this sample application we will look at only one of them, stateless session
beans.
In the Java Enterprise Edition before version 5, entity persistence was handled by the Enterprise
Edition Container as well. This was called CONTAINER MANAGED PERSISTENCE (CMP), and although
you can still do it that way (in fact for compatibility you can still do all that tedious and verbose XML
configuration stuff), the new and much simpler way is to use the JAVA PERSISTENCE API (JPA).
When you use JPA, an Entity is again a simple Java class with getters and setters for its fields, a
POJO. You make it an entity by doing two things: annotating it with JPA annotations, and letting
an EntityManager fetch it from or persist it to the database. You get such
an EntityManager again via injection, when you get it, it is already associated with a persistence
context that manages transactions and caches entities, thus using JPA is again easy, how easy it is,
I’ll show you after some more definitions.

Abstraction of data access (Entity Access Objects)


[back to top]
Mapping relational databases to objects is a well-understood task by now, thus there are plenty of
supporting tools, and normally those tools generate code. Eclipse itself comes with a tool to create
entities from tables, so do other IDEs and of course the major UML tools can do that as well. Upon
re-generating a mapping after database changes, some of these tools can handle user-modified
entity classes, some can not. In general it is a good idea to leave generated code alone.
On the other hand, when you access the database via JPA, you either ask the  EntityManager for
entities that you have an id for, or you create query objects, execute them and get lists of objects as
results. If you use queries (which you will do a lot), you express them in the  JAVA PERSISTENCE
QUERY LANGUAGE. This is very much like SQL, and if you know SQL, you already know most of
what’s to learn.
Still, relational databases are not the only possible way to store data (although a good one), and
SQL is not the only way to get at data. The core logic of your application is not about getting or
storing data, it is about manipulating it. Thus it makes sense to encapsulate data access.

Traditionally Java has done a good job encapsulating data access, just think of the Data Access
Object(DAO) pattern or Java Data Objects (JDO). Here I propose a similar layer, and we will call
it ENTITY ACCESS OBJECTS (EAO). Basically I could as well have used DAO, but this name is so
burdened with reminiscences to the dark J2EE past, I don’t want to use it.
You can have one EAO per entity class, one per use case, a hierarchy of EAOs, a single one for the
whole application, it does not matter. The only thing that I recommend is, that all database access
goes through an EAO.

EAOs need database access and database access in JEE is via datasources injected by the EJB
container, thus EAOs need to be EJBs themselves. We will use Stateless Session Beans for that
purpose.

Services guard the entrance


[back to top]
J2EE, the dreaded version that gave the Java Enterprise Edition its bad reputation, required that
EJBs haveBUSINESS INTERFACES. I’ve never worked with J2EE, but I suppose that had some kind of
technical reason. As long as you stay within one Enterprise Application (EAR), this is not strictly
needed any more. EJBs that don’t implement an interface, can now be called via their so-called NO-
INTERFACE VIEW, which essentially means an implicit interface containing all public methods, and that
means you can call any of their public methods you like.
On the other hand, using interfaces for publishing the functionality that you commit to deliver, is still
considered good practice. Eclipse makes creating interfaces and keeping them in sync with their
implementation effortless, thus it won’t bog us down and instead give us a great deal more flexibility
down the road.
In other words, we design our application as a set of interfaces, and we implement these interfaces
as Stateless Session Beans. EJBs that we don’t expose, like our Entity Access Objects, neither
need nor get an interface.

Just to make sure that we know what we are talking about, we call such EJBs with public business
interfacesSERVICE BEANS.

Instantiation of Enterprise Java Beans


[back to top]
We already saw that EJBs are simple objects. They don’t do any magic, the magic is done by the
EJB container. The container holds pools of EJB instances and it controls the lifecycle of an EJB. An
EJB is an EJB only when it is instantiated by the container. Do it yourself and all you get is a POJO.

Generally there are three ways to get access to an EJB.

EJB annotation

[back to top]
The first kind is the EJB annotation. Inside of one EJB you can declare a field of the type of another
EJB class, but instead of initializing it, you annotate it.

@EJB MyBean mybean;

or

@EJB MyBusinessInterface mybean;

This is called DEPENDENCY INJECTION, because the EJB container injects a bean that we depend on.
Obviously this can only be done, when the referring object is an EJB itself, also running under the
control of the container. References can only be injected into field variables, and the injection is
done at every top-level invocation.
A top-level invocation is a call from outside of a container, into an EJB running inside of a container.
Clearly injection alone would not help us ever making top-level calls.
Although we may get a new chain of container-managed EJBs for every top-level invocation (at least
as long as we look at Stateless Session Beans), the injection mechanism is static insofar as the
container can already check for availability of all referenced types at deployment time. Thus if you try
to inject a variable of a type that is not defined at the application server (but may have been defined
in your development environment), the Enterprise Application won’t even start.

Lookup via JNDI

[back to top]
Sometimes you need more flexibility. For instance you could have different beans implementing the
same interface, and at runtime you may want to decide yourself, which type of implementation you
really want. In such a case you would decide (based on input, some calculations or an event) upon
the name of the bean type you are interested in, and then you would look it up via JNDI, the JAVA
NAMING AND DIRECTORY INTERFACE.
You do this by going through an InitialContext, just like

MyInterface myBean =
(MyInterface) InitialContext.doLookup(
"java:global/MyEAR/MyBeans/MyBean"
);

This is a shortcut for

MyInterface myBean =
(MyInterface) new InitialContext().lookup(
"java:global/MyEAR/MyBeans/MyBean"
);

The parameter of lookup() is a so-called JNDI name, and since JEE 6, there is a standard for
JNDI names. The name used here is a GLOBAL JNDI NAME. It is prefixed
by "java:global" followed by a path consisting of the name of the EAR, the name of a JAR within
the EAR (both without extension), followed by the name of the bean class.
If you need to lookup a bean that implements more than one interface, you need to specify an
interface as well. Given MyBean implements an interface com.mycompany.MyInterface, the
lookup via the fully qualified global JNDI name would be

MyInterface myBean =
(MyInterface) InitialContext.doLookup(
"java:global/MyEAR/MyBeans/MyBean!com.mycompany.MyInterface"
);

It gets even more complicated, when we want to call into a bean on another machine. In such a case
we have to use the longer form, instantiate the InitialContext ourselves, and pass a set of
properties into its constructor, thereby telling the context on which machine to begin the search. You
will see an example of that later.
Apart from looking up EJBs dynamically from within an EJB container, there is another, even more
important use of JNDI lookups, and that is the lookup from outside of the container. In fact, given
that it has access to all necessary libraries, any Java class can look up an EJB via JNDI, and the
bean instance that is returned, will have been instantiated by the EJB container. Therfore JNDI
lookup is a way to access EJBs from outside of the container, thus allowing us to make top-level
calls.

Calling the bean as a SOAP web service

[back to top]
While JNDI lookups are not exactly complicated, there is another easy way to access Service
Beans: we can simply annotate their class as web service. If we don’t care about the exact schema
of the WDSL that gets generated, it is enough to use one simple annotation like this:

@Stateless
@WebService
public class MyBean {
...
}

You see two annotations here. @Stateless marks this bean as a STATELESS SESSION BEAN,
and @WebServicecauses the application server to make all public methods of this bean accessible
as web service calls. Any such method can be called from a SOAP service test application
like soapUI. In fact this is the method we’ll use in our initial manual tests.

Scope of EJBs
[back to top]
We’ve already covered the NO-INTERFACE VIEW and BUSINESS INTERFACES, only that there is one
further distinction between business interfaces: they come as local and as remote interfaces.
There is no substantial difference between the No-Interface view and a LOCAL INTERFACE. Both are
called via normal Java method calls, it’s only that with a local interface, like always when you shield
implementations, an EJB is more resilient, better able to absorb change. Calls via the local interface
and the No-Interface view are equally efficient. For tightly coupled beans, that have no use outside
the application, local interfaces or the No-Interface view are adequate choices.
Remote interfaces can be called across applications, from everywhere within the application server
as well as from outside, even from other hosts. There is more than one way to declare a business
interface, but today the normal way is, to annotate the interface with either @Local or @Remote, for
instance like this:

@Remote
public interface MyInterface {
public long numberOfObjects();
}

From within the EJB container, business interfaces are normally accessed via injection. You declare
a field of such an interface type, and the container automatically injects a matching instance.

@EJB MyInterface mybean;

An EJB can implement more than one interface, Remote and Local mixed as you like. Thus it is
possible to provide a high-performance local variant for local callers, and another, probably restricted
remote interface.

While remote interfaces won’t strictly be necessary in many cases, it is good practice to provide
them anyway, at least for EJBs that are to be called from outside of the application, even if you
initially plan to access the bean only via SOAP. It may turn out that you want to re-use it from
another application and then you may need the bean to take part in a distributed transaction,
necessitating access via Corba/IIOP.

Accessing an EJB application from outside


[back to top]
Basically there are three ways to communicate with an EJB application:
1. Referencing an EJB from a servlet (an therefore from a Dynamic Web Project), bundled
within the same EAR. From Java EE 6, the servlet is instantiated by the EJB container, therefore
the EJB can be injected.
2. Referencing an EJB from externally via its remote interface. Access is
viaInitialContext.doLookup(). Should an access via Corba/IIOP cross machine
boundaries, make sure that the relevat port (3700 per default) is not blocked by a firewall.
3. Directly calling an EJB as web service. This is the simplest way. The EJB is instantiated by
the EJB container, thus injection just works.

The EJB Project


[back to top]

Creating the project in Eclipse


[back to top]

We assume that the EAR project cookbookEAR already exists. We now create a new


project for our Enterprise Java Beans, the Entities, the Entity Access Objects, any parameter types,
in other words, our whole business logic. As project type we choose EJB Project.
Let’s call the project cookbookEJB. On the first page of the wizard, right in the middle
under Configuration, we initially see Default Configuration for GlassFish v3 Java EE 6. The default
configuration does not have the project facet for persistence, thus we press Modify and add theJava
Persistence facet. OK brings us back to the first page.

Please make sure that Add project to an EAR is checked. Also please verify
thatcookbookEAR is selected. Eclipse will always pre-select the EAR that you created last, thus if you

don’t check, you could add your project to the wrong EAR. It has happened to me 

Page two of the wizard is OK as it is. On Page three it could be that it’s impossible to
check Create an EJB Client JAR Module to hold the client interfaces and classes. If so, then you
forgot to check Add project to an EAR on page one.

The last page configures the database connection. UnderConnection we choose Cookbook


Database and add the database driver to the build path.
After closing the dialog, we see that not one but two projects have been created. As expected one
is cookbookEJB, and there is a second project calledcookbookEJBClient. When we create EJBs with
business interfaces, Eclipse is going to create the interfaces in this client project.
Those two projects are linked. cookbookEJB depends on cookbookEJBClient, that means each class
incookbookEJB can access every class or interface in cookbookEJBClient. From now on we will always
have to ask ourselves into which project a new class belongs. Basically what belongs in the client
project are:
 client interfaces of EJBs (automatically done by Eclipse)
 classes that are used as parameters in interface methods
 exceptions that are thrown by interface methods

Creating a service bean


[back to top]
The next thing we want to do is to create a service bean with a preliminary interface for our
application, and then to test that manually. We will use a remote interface for the bean, and we will
also allow access via the No-Interface view. Depending on size and complexity of the application, it
may be reasonable to use one service bean for the whole application, one for each use case, or
whatever makes sense to you, but we will always use at least one.

In Java we structure our classes by organizing them in PACKAGES, each package


corresponding to a directory. This is not the most sophisticated implementation of namespaces, but
it’s easy and it gets the job done. Package names are hierarchically structured, normally consisting
of a reversed domain name as prefix, then a project name and finally whatever structure you use
within your project.
From the context menu of the EJB project I choose New / Package. I accept the default source
folder and use as full package name com.manessinger.cookbook.service. And then, now from the
context menu of the new package, I use New / Session Bean (Java EE 6). I call it CookbookBean,
choose to give access to it by the No-interface view and via a remote interface. As name of the
remote interface I use CookbookInterface. The default would have been CookbookBeanRemote, but
I don’t like to have the name of the interface reveal its locality. Remote of local, what I want to name
is functionality.
The result is the following file (reformatted and comments stripped):

package com.manessinger.cookbook.service;
 
import javax.ejb.LocalBean;
import javax.ejb.Stateless;
 
@LocalBean
@Stateless
public class CookbookBean implements CookbookInterface {
 
public CookbookBean() { }
}

This bean has two annotations: @LocalBean means that we can access it via the No-Interface view,
while@Stateless declares it a STATELESS SESSION BEAN.
Upon inspection we find out that CookbookInterface has not been created in the EJB project but
in the client project instead. It is in the same package though, and the package has also been
created automatically in the client project. Thus no import of the interface is necessary.

package com.manessinger.cookbook.service;
 
import javax.ejb.Remote;
 
@Remote
public interface CookbookInterface {
 
}

Now we have a service bean but no functionality at all. Let’s add a method, for instance one that
returns the number of countries in the database. It’s just for testing, but we may even end up
needing it in a real application. This method will be called from outside, thus it has to be defined in
the interface. Let’s add the following method to the interface:

public long countryCount();

As soon as we store the interface, we notice that Eclipse shows an error in CookbookBean. The class
name is underlined with a red, wavy line, and when we move the mouse over the red mark, we see a
popup with the message The type CookbookBean must implement the inherited abstract method
CookbookInterface.countryCount().
The popup offers two so-called QUICK FIXES. They are possible changes that Eclipse offers to do
automatically and that have the potential to fix the problem. In this case they are
1. Add unimplemented methods
2. Make type CookbookBean abstract
Syntactically both solve the problem, but of course what we want is to add the method.
In this popup Eclipes offers the quick fixes as links, but you could also set the text curser on an error
marker and press Ctrl-1. This would have the same effect, only there would not be a popup with
links, but a drop-down menu instead.
Quick fixes are extremely powerful in Eclipse and you can use them in many situations when there’s
not even an error. Consider for instance the following situation: You want to
call System.getenv(), a library method that returns a Map<String, String>. How do you do
that? You could simply write

Map<String, String> env = System.getenv();

Doing so, you would probably see the word Map underlined as error, and by pressing Ctrl-1 you
would be offered the quick fix to import java.util.Map. Not bad, but the smart way to do it is to
write only the right-hand side

System.getenv();

This is a valid but useless statement, thus no error will be indicated. When you now press Ctrl-1,
Eclipse offers the quick fix Assign statement to new local variable. If we choose that, Eclipse not only
generates the map declaration on the left-hand side, it also imports java.util.Map for us.

Sorry for the long digression, but to know this is so incredibly useful, I just had to mention it 

Let’s get on with our method. In CookbookBean.java Eclipse has inserted a method stub

@Override
public long countryCount() {
// TODO Auto-generated method stub
return 0;
}

and we change it to

@Override
public long countryCount() {
return 17; // FIXME call EAO method
}
There are two “magic” kewords for comments. Eclipse generated TODO, and I have changed it
to FIXME. Eclipse provides markers where these keywords occur, and this way it is easy to find the
places where you have preliminary code that needs to be changed later.  FIXME is the stronger of
the two.
The generated method result value of zero is an unlucky choice, because it is also the default value
for an uninitialized long. I like to see something more distinctive, thus the value 17. You may also

use 42 or 666 if you like 

Manual testing via GlassFish web service tester


[back to top]
At this moment we have a service bean with a callable method, but we have no way yet to actually
call it. First we have to make the application run. Two things have to be done:

In the lower part of the Eclipse window, we choose the Servers view. Here should be a
server entry with the label GlassFish v3 Java EE 6 at localhost [Stopped]. From the context menu of
the server we choose Add and Remove.
We get a window with two boxes, on the left side the applications available for deployment on the
server, on the right side those that are currently deployed. In the list of available applications you see
our EAR. With Add > or Add All >> you can move it to the right and then press Finish.
Next, if we had not already done so, we would have to start the server. You do that in
the Servers view, either from the context menu of the server, or with the green start button on the
right side. Starting the server may take up to a minute.
Btw, currently there seems to be a problem with restarting the servers. It eventually succeeds, but
only after a long and annoying timeout. Thus please don’t restart, always stop/start.

From this moment on the EJB could be called. It’s only that the call would have to come from a Java
client using the client project on its CLASS_PATH. This is much too much effort needed, thus we
just make our bean a web service, and then we can call it via SOAP. Doing so takes only one
additional annotation @WebServiceon the class.

package com.manessinger.cookbook.service;
 
import javax.ejb.LocalBean;
import javax.ejb.Stateless;
import javax.jws.WebService;
 
@LocalBean
@Stateless
@WebService
public class CookbookBean implements CookbookInterface {
 
public CookbookBean() { }
 
@Override
public long countryCount() {
return 17; // FIXME call EAO method
}
}

If you store that change, the application running in GlassFish is automatically updated. This
automatic re-deployment works most of the time, it may fail though after major refactorings. If so, just
stop the server and start it again (did I caution you against restarting?).

GlassFish comes with a web application for administration. It’s called the ADMINISTRATION CONSOLE.
It has its own port number, and which port that is, this is our next job to find out.
There can be more than one GlassFish domain on one machine, a domain actually being an
instance of the server with its own set of port numbers. To find out what port numbers our installation
uses, we choose Openfrom the context menu of the server and come to an overview of the server
configuration. On my current instance I see 4860 as Admin Server Port Number. Thus the URL of
the console is
http://localhost:4860/
Let’s open this URL in a browser. We get to a login page. In the base development configuration the
username is admin, the password is empty.
Testing of the web service is easy now. In the tree on the left side of the browser window we
locateApplications. We click cookbookEAR and get to an Edit Application view. On the right side of
the table at the bottom, there is a link View Endpoint, and that leads to the Web Service Endpoint
Information view. Here we have three links:
 Application Name takes us back to the previous page
 Tester opens a Web Service Tester in a new browser window
 WSDL opens a new browser window showing the WSDL
We choose Tester and get a window with a form an a button for each method of the service. If a
method has parameters, we are presented with an input box per parameter. In our case we have
only one parameter-less method, therefore we see only a single button countryCount(). We press
the button, see the SOAP XML data, and indeed, the result is 17. Just as expected.
Note: should you instead get an internal error in the tester window, and in the console log in Eclipse
a stack trace with something like the following text in the middle,

Caused by: com.sun.xml.ws.util.ServiceConfigurationError:


com.sun.xml.ws.api.pipe.TransportPipeFactory:
Provider
com.sun.enterprise.jbi.serviceengine.bridge.transport.JBITransportPipeFactory
is specified in
bundle://245.0:0/META-INF/services/com.sun.xml.ws.api.pipe.TransportPipeFactory
but not found

then you’ve probably updated GlassFish via the UPDATE TOOL in the administration console. Don’t do
that. It currently breaks the web service tester. There is no need to update, everything I do here
works perfectly with the original release of the GlassFish Tools Bundle for Eclipse from December
12, 2009. Uninstall the Tools Bundle, reinstall, open the workspace again and it will work.

Testing with soapUI


[back to top]
In cases where you have non-scalar parameter types, the tester application built into GlassFish does
not suffice, because it only gives you one input text field per parameter. In such cases soapUI is the
much better tool. soapUI also has a workspace metaphor and also has projects.

On the left side there is again a tree with projects, that you can open, add WSDLs to, create sample
requests for, edit requests and finally run them.

When you create a soapUI project, you are asked for a project name (I’ve used cookbookEAR and an
initial WSDL (taken from the Endpoint View in GlassFish’s administration console. In our case this is

http://localhost:8084/CookbookBeanService/CookbookBean?wsdl

With soapUI you can control and view all aspects of your SOAP requests and responses. You can
define additional HTTP headers, send and receive attachments and much more. For us it’s only
important, that the requests that soapUI generates, are simple XML texts that we can edit and that
way fill out complex parameter types. You send a request by clicking the small green triangle in the
upper left corner of a request window.

For now we leave it at that, but we’ll come back to soapUI later, when we treat the validation of
complex parameter types.

Prepare for persistence


[back to top]
So far we have a Stateless Session Bean that can act as a web service, but the only service method
currently returns a hardcoded dummy number 17. Now it’s time to replace that with actual results
from the database.

As regards entity classes and tables, there are two possible strategies:

 generating a database schema from Java entity classes


 generating Java entity classes from a database schema
Here we assume the database that we’ve already introduced. Before we actually generate entities,
we want to make some preparations.

The code generator included with Eclipse allows us to let the generated entities inherit from a class
or implement any number of interfaces. Of course it’s clear that methods declared in those interfaces
will have to be implemented. Concerning interfaces, we have the following options:

1. let the entities implement marker interfaces (without methods)


2. insert any method declared in an interface into the generated entities
3. implement the interface methods in a base class and let the entities inherit from that base
class
Option #1 is perfectly possible, but only not very useful. Option #2 is ruled out, because we
absolutely want to avoid changing generated code. This leaves us with option #3, but when we
already have to extend a class that has to implement all of the interface’s methods, why do we need
an interface at all? Thus we won’t let our entities implement interfaces, but a base class might be
useful.
We use New / Project / Java EE / Utility Project to create a new JAVA EE UTILITY PROJECT. Let’s call
itjee_utilities, and whenever we happen to create a reusable class, we’ll put it there.

We add the new project to the EAR. Of course, being a standalone project, it could be added to any
other EAR, and therefore it is reusable.

Any classes in this utility project must be visible from the EJB project, thus we insert it
into cookbookEJB‘s build path by choosing Build Path / Configure Build Path / Projects / Add from
the context menu.
Now the classes are visible in Eclipse at compile time, but in order to make them accessible when
running in GlassFish, we need to put the JAR file of the utility project into the lib directory of the
EAR. We do that in theProperties dialog of the EAR project.
Then we create a package com.manessinger.util.jpa in the utility project, and there we add a
classEntity, the base class for our entities:

package com.manessinger.util.jpa;
 
public abstract class Entity {
 
public static boolean isId(Integer id) {
return (id != null && id > 0);
}
 
public boolean hasId() {
return isId(getId());
}
 
public abstract Integer getId();
}

OK, that’s how we do it, but why do we do it at all? We gain two things:

 The base class bundles all entities, and whether a class is an entity or not, that can be
checked at compile and run time. So far this could have
been achieved with marker interfaces as well
 We put a thin abstration layer around the fact that we will generate Integer as primary key
type, and that null is not a valid key value but instead the value of an uninitialized key variable.
We could as well have decided to generate keys of type int, taken from a sequence, and then
the value 0 would have been the value of an uninitialized key variable. Thus we basically
encapsulate the magic value nulland create an API to check if some object has a valid ID and
can possibly have been read from the database.
We’ll see the use of this base class later, for now just create it. And even if you see no value in this
exact base class, there are definitely other uses where a base class for our entities may be useful.
This is how to create it.

Creating entity classes


[back to top]
Our entities need a place to live in, thus we first create a package in the EJB project, and we call
itcom.manessinger.cookbook.entity. We won’t expose entities via business interfaces, thus the entities
clearly belong into cookbookEJB, not into the client project.
The fastest way to add a package to an existing hierarchy, is to call New / Package not from the
context menu of the project, but from the context menu of another package, because then the name
will already be initialized with the existing package. Here we just have to replace service with entity.
Now let’s generate code. In the context menu of the EJB project (and only there) you’ll find  JPA
Tools / Generate Entities from Tables. That’s what we need, and it takes us to the Generate Custom
Entities-Dialog.

When the dialog opens, it can be that Eclipse has no connection to the database yet. In that case
you can connect with a click on the connection icon directly below the Connection drop-down menu.
When you are connected, you can see a list of tables in the connected schema. Check all tables that
you want to generate entities for and press Next.
In the following step you see the associations that Eclipse was able to detect. Eclipse is fairly good
at it, but of course this will only work for reasonably crafted database schemas. If you don’t use
foreign key constraints and not even name your fields in a meaningful way, then you’ll have to do the
mapping yourself. In my experience, what you need to change most often, are the property names,
i.e. the names that refer to the associations in Java. In this trivial case Eclipse has detected all there
was.

The next step is the definition of mapping defaults. Normally you will have only one strategy of
generating IDs and that will apply to all tables. In Oracle you will probably use sequences, and all the
sequences will probably be named systematically. I name mine after table and id field, and then add
a suffix _seq. For such a naming system you would enter $table_$pk_seq in the Sequence
name input field.
In our case we don’t need that. We use the value identity as Key generator, because that’s how we
have defined the keys in Derby.
In the last step we can change the defaults for tables and even down to each field. We can rename,
change datatypes, etc. Here we change the types of the generated primary keys (id)
from int to Integer. Remember to do that for both tables.
Here is the generated code, reformatted to make it more compact:

package com.manessinger.cookbook.entity;
 
import java.io.Serializable;
import javax.persistence.*;
import java.util.Set;
 
@Entity
public class Country extends com.manessinger.util.jpa.Entity implements Serializable {
private static final long serialVersionUID = 1L;
 
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
private String name;
 
//bi-directional many-to-one association to City
@OneToMany(mappedBy="country")
private Set<City> cities;
 
public Country() { }
 
public Integer getId() { return this.id; }
public void setId(Integer id) { this.id = id; }
public String getName() { return this.name; }
public void setName(String name) { this.name = name; }
 
public Set<City> getCities() { return this.cities; }
public void setCities(Set<City> cities) { this.cities = cities; }
}

package com.manessinger.cookbook.entity;
 
import java.io.Serializable;
import javax.persistence.*;
 
@Entity
public class City extends com.manessinger.util.jpa.Entity implements Serializable {
private static final long serialVersionUID = 1L;
 
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
private String name;
 
//bi-directional many-to-one association to Country
@ManyToOne
private Country country;
 
public City() { }
 
public Integer getId() { return this.id; }
public void setId(Integer id) { this.id = id; }
public String getName() { return this.name; }
public void setName(String name) { this.name = name; }
 
public Country getCountry() { return this.country; }
public void setCountry(Country country) { this.country = country; }
}}

The generated entities are normal classes, plain old Java objects or POJOs, sparingly annotated
with mapping information. During code generation you can also choose to generate the annotations
for those things that otherwise are defaulted. I wouldn’t do that though. It does not help when your
code is riddled with annotations.

Allocation sizes for sequences – a deviation


[back to top]
Let’s have a short look over the fence here. What if you use sequences for primary key generation?
You may not use Derby but Oracle, and with Oracle, sequences are the natural choice for that job.
Furthermore you may not be free to make any changes to your database, especially not to the
sequence value allocation policy. If so, you may run into a problem. Let me explain:

A sequence is a database object that you can draw numbers from. In the normal case you get
numbers beginning with 1, and each time you draw a number, the sequence increments. Two callers
never get the same value (at least not until the sequence overflows, but that is another problem) and
you never get the same value twice. The value by which the sequence is incremented after a draw
defaults to 1, but it can be set when the sequence is created using INCREMENT BY.
While it is most natural to let the sequence increment by 1, it actually makes sense to use a higher
value. Imagine a sequence incrementing by 50. Then you essentially get not one but 50 exclusive
values with one single draw. Thus the program drawing the values does not have to make 50 trips to
the database but only one. This increases performance.

GlassFish defaults to an increment fo 50, but what if your database has already been created with
an increment of 1 (or any other value but 50)? You can’t simply change the increment, because
existing database clients depend on the current value. Thus you have to tell JPA what your
increment value is.

Here is the City entity once again, but this time we use an Oracle databases with sequences:

package com.manessinger.cookbook.entity;
 
import java.io.Serializable;
import javax.persistence.*;
 
@Entity
public class City extends com.manessinger.util.jpa.Entity implements Serializable {
private static final long serialVersionUID = 1L;
 
@Id
@SequenceGenerator(name="CITY_ID_GENERATOR", sequenceName="CITY_ID_SEQ")
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="CITY_ID_GENERATOR")
private Long id;
 
private String name;
 
//bi-directional many-to-one association to Country
@ManyToOne
@JoinColumn(name="COUNTRYID")
private Country country;
 
public City() { }
 
public Long getId() { return this.id; }
public void setId(Long id) { this.id = id; }
public String getName() { return this.name; }
public void setName(String name) { this.name = name; }
 
public Country getCountry() { return this.country; }
public void setCountry(Country country) { this.country = country; }
}

We can specify the allocation size of the underlying sequence (here CITY_ID_SEQ) by specifying
the attributeallocationSize to the @SequenceGenerator annotation, for instance like this:

@Id
@SequenceGenerator(name="CITY_ID_GENERATOR", sequenceName="CITY_ID_SEQ",
allocationSize=1)
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="CITY_ID_GENERATOR")
private Long id;

The problem is, that we would have to change the generated entity, but this is something that we
don’t want to do. Ideally the code generator would have created the attribute in the first place, but
this did not happen. Fortunately there is an alternative to editing generated code.
Like everywhere in the Java Enterprise Edition, annotations are only one way to specify things. The
other way are the good old XML configuration files, and when a Java EE server sees both, the XML
configuaration wins. This is good, because you can override annotated specifications at runtime,
without having to re-compile the application. That way an administrator can make configuration
changes and does not rely on a developer.

In our case we have to create a file ejbModule/META-INF/eclipselink-orm.xml in the EJB


project. We do that by calling New / XML from the context menu of the directory META-INF in
the Project Explorer.

<entity-mappings version="1.0"
xmlns="http://java.sun.com/xml/ns/persistence/orm"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm
http://java.sun.com/xml/ns/persistence/orm_1_0.xsd">
<sequence-generator
name="COUNTRY_ID_GENERATOR"
sequence-name="COUNTRY_ID_SEQ"
initial-value="1"
allocation-size="1"
/>
<sequence-generator
name="CITY_ID_GENERATOR"
sequence-name="CITY_ID_SEQ"
initial-value="1"
allocation-size="1"
/>
</entity-mappings>

Be careful though: Whenever we add a new table (or actually a new sequence), we have to change
this XML configuaration!

This concludes our diversion to Oracle, let’s carry on with the regular tutorial.

A simple Entity Access Object (EAO)


[back to top]
Like already said, we encapsulate database internals in ENTITY ACCESS OBJECTS, and although we’ll
only have a single one here, we still put it in a new package com.manessinger.cookbook.eao.
EAOs are STATELESS SESSION BEANS, so we create one of those and call it CookbookEao. So far we
only need a method to determine the number of coutries. Let’s create it like this:

package com.manessinger.cookbook.eao;
 
import javax.ejb.LocalBean;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
 
@LocalBean
@Stateless
public class CookbookEao {
 
@PersistenceContext
EntityManager em;
 
public CookbookEao() { }
 
public long countCountries() {
long result;
Query q = em.createQuery("select count(co) from Country co");
result = (Long)q.getSingleResult();
return result;
}
}

We use a field variable of type ENTITYMANAGER, attributed with @PersistenceContext, and we


don’t initialize this variable. It is automatically injected by the EJB container.
The method countCountries() uses this entity manager to create a QUERY, executes the query
(that’s what happens in getSingleResult() and finally returns the result.
We could have written that much more compact as

return (Long)em.createQuery("select count(co) from Country co").getSingleResult();

but the longer variant has the advantage, that it is easier to understand, self-documenting, and you
can set a breakpoint in the debugger.

Using the EAO and looking for an error


[back to top]
Now that we have an EAO, we want to get back to our TODO item and replace the constant 17 with
the result of a call to countCountries().

package com.manessinger.cookbook.service;
 
import javax.ejb.EJB;
import javax.ejb.LocalBean;
import javax.ejb.Stateless;
import javax.jws.WebService;
 
import com.manessinger.cookbook.eao.CookbookEao;
 
@LocalBean
@Stateless
@WebService
public class CookbookBean implements CookbookInterface {
 
@EJB CookbookEao eao;
 
public CookbookBean() { }
 
@Override
public long countryCount() {
return eao.countCountries();
}
}

We have added a field variable eao, have attibuted it and expect an EAO instance to be injected
upon each call of the top-level method countryCount(). This actually happens, but then we get
an error.
When we call countryCount() from the GlassFish Web Service tester, instead of the expected
result 3, we get the following error:

Service invocation threw an exception with message : null;


Refer to the server log for more details
 
Exceptions details : java.lang.reflect.InvocationTargetException
javax.servlet.ServletException: java.lang.reflect.InvocationTargetException at
...
... many lines omitted
...
org.apache.derby.client.am.SqlException: Table/View 'COUNTRY' does not exist.
at org.apache.derby.client.am.Statement.completeSqlca(Unknown Source) at
...
... many more line omitted
...

This is weird. We know there is a table COUNTRY. We have created it, we have filled it, we have
used it to create an entity. We remember that we have connected to the database when we created
entities, so this just should not happen, right?
Wrong. Yes, we have connected to the database, but the connection was made in Eclipse, not in
GlassFish. Remember how we configured Eclipse to always start JavaDB when starting GlassFish?
JavaDB is a seperate process, so is GlassFish. It does not mean a thing to GlassFish, when Eclipse
is connected to a database.
And when we talk about being connected to a database: how should GlassFish know what database
to use? We have defined our schema in the Cookbook Database, but how do we communicate that?
When we created the EJB project, we have added a Java Persistence project facet, and due to that,
we were asked for a database connection. Later, when creating entities, Eclipse used that very
same connection to discover tables and their associations. Eclipse has done nothing though, to tell
GlassFish about it.
Before we come to the solution, please allow me a short digression: Let’s look at what we would
have got in Oracle.

The error message would have begun identically, only in the stack trace we would have seen a
weird series of exceptions:

The DatabaseSession has an external transaction controller defined by something


other than the ServerPlatform. EclipseLink will permit the override of the
external transaction controller, but we recommend you consider the alternative
of subclassing org.eclipse.persistence.platform.server.ServerPlatformBase and
override getExternalTransactionControllerClass().

Funny, huh? Chronologically the next exception is

Unexpected exception while creating resource for pool DerbyPool.


Exception : javax.resource.spi.ResourceAllocationException: Connection could
not be allocated because:
java.net.ConnectException : Error connecting to server localhost on port 1527
with message Connection refused.

and then

Failed to obtain/create connection from connection pool [ DerbyPool ].


Reason : com.sun.appserv.connectors.internal.api.PoolingException:
Connection could not be allocated because:
java.net.ConnectException : Error connecting to server localhost on port 1527
with message Connection refused.

This is followed by more consecutive faults. What’s happening here? We use Oracle, but GlassFish
looks for our tables in Derby?
It turns out that GlassFish can’t know about our Oracle database, for all the reasons that we have
already explained, but Derby is GlassFish’s fallback, and the sample database that comes with
GlassFish is configured as the default database. No wonder that GlassFish couldn’t find a
table COUNTRY, even when we really used Derby. GlassFish was never told about a cookbookdb,
all it knew was the sample database.

Specifying the database, testing, SQL log


[back to top]
Whatever the database, it is clear that GlassFish has to be told about it. Let’s do that. We need to do
two things:

First we have to create a reference in GlassFish that points to the database. Second, we have to
change the application in a way that it tells GlassFish, which one of possibly several databases
defined in GlassFish we want to use. Let’s begin with creating the reference.

Such a reference consists of two parts, a JDBC connection pool and a JNDI name definition refering
to the pool. This JNDI name finally is, what we will use in the application to point to the database.

Creating connection pools and JDBC resources in the Administration Console

[back to top]
We open the administration console and go to Resources / JDBC / Connection Pools. There we see
a list of the currently defined connection pools.

Step 1 of the New JDBC Connection Pool wizard requires us to use a Resource Type. The help
page of the wizard tells us that
Available resource types are javax.sql.XADataSource (global
transactions),java.sql.ConnectionPoolDataSource (local transactions, possible performance
improvements), javax.sql.DataSource (local transactions only), and java.sql.Driver

. For the purpose of our tutorial, javax.sql.DataSource is OK, but if we create EJBs that may
eventually partake in distributed transactions, we have to choose the most general
variant javax.sql.XADataSource. They are a little more expensive, consuming more memory,
but that’s the price for the added flexibility. There will be a separate post about multi-database
scenarios shortly.
Here we enter a name for the new pool, choose Derby as database vendor and go on to the next
screen. On the top part of the page, we can leave everything as it is. The important things have to be
defined as properties. Scroll down, remove all unnecessary attributes and fill the rest with the values
that we already used when we defined the database. Before you click Finish, make sure that Ping is
enabled. This way GlassFish will test the database definition.

The next step is to define a JNDI name. Go to Resources / JDBC / JDBC Resources, add a new one
and connect it to the new pool.
Creating connection pools and JDBC resources using asadmin
[back to top]
We can do that in GlassFish’s Administration Console web application as we just did, and we can
also do it using the asadmin commandline utility. Whatever you can do in the Administration Console,
you can do inasadmin as well, and then supposedly some things more. Here is a session in Windows
where I have created the same resources as in the web application.

C:\Users\Andreas>asadmin --port 4860 --user admin \


create-jdbc-connection-pool \
--datasourceclassname org.apache.derby.jdbc.ClientDataSource \
--restype javax.sql.DataSource \
--property
portNumber=1527:password=cookbook:user=cookbookuser:serverName=localhost:databaseName=
cookbookdb:connectionAttributes=;create\=true CookbookPool
 
Command create-jdbc-connection-pool executed successfully.

Backslashes at line end are not to be typed, they mean the command continues on the next line. So
far we have a connection pool. Next we list connection pools and look if it’s there.

C:\Users\Andreas>asadmin --port 4860 --user admin list-jdbc-connection-pools


__TimerPool
DerbyPool
CookbookPool

Yup, it is. Let’s try to ping it, i.e. test it by making a connection.

C:\Users\Andreas>asadmin --port 4860 --user admin ping-connection-pool CookbookPool


 
Command ping-connection-pool executed successfully.
The connection works. Now we create the JDBC resource definition.

C:\Users\Andreas>asadmin --port 4860 --user admin create-jdbc-resource


--connectionpoolid CookbookPool jdbc/cookbookdb
 
Command create-jdbc-resource executed successfully.

List JDBC resources and look if it worked.

C:\Users\Andreas>asadmin --port 4860 --user admin list-jdbc-resources


jdbc/__TimerPool
jdbc/__default
jdbc/cookbookdb

In order to make this work, I had to put two directories on the path (environment variable  Path in
Windows 7): the directory that contains java.exe (C:\Program Files
(x86)\Java\jre6\bin) and the GlassFish admin binary directory (C:\GlassFish-Tools-
Bundle-For-Eclipse-1.2\glassfishv3\glassfish\bin).
I had to specify the port number 4860, because GlassFish defaults to 4848, but in my particular
workspace it is on 4860. Here I have explicitly specified port number and admin user with each
command. I could also have set environment
variables AS_ADMIN_PORT and AS_ADMIN_USER instead.
I could also have started asadmin in interactive mode once by typing

C:\Users\Andreas>asadmin --port 4860 --user admin

and then I would have been able to type the sub-commands like create-jdbc-connection-pool directly
one after the other. In the end I would have left asadmin by typing exit

Referencing the JDBC resource from the application

[back to top]
At this point GlassFish knows about a database that can be referenced as jdbc/cookbookdb, but we
still don’t reference it from the application. Let’s do that now:
In the Project Explorer we locate the file persistence.xml, open it, go to the Connection tab, add the
JNDI name as JTA data source and save the file. Now try to call countryCount() from the
GlassFish Web Service tester again, and this time you’ll get the expected result 3.

If you want to see the database statements in Eclipse’s Console view, go to the Logging tab, set


theLogging level to Fine and try the call again. If you don’t see the server log, then you have to
switch between consoles. Find the button that I’ve marked red on the right side of the  Console view
and use it to switch to the server log. Now you should see the statement.

FINE: SELECT COUNT(ID) FROM COUNTRY

If you look at persistence.xml in the Source tab, you see the following XML code (some namespace
definitions omitted, don’t copy/paste this!):

<?xml version="1.0" encoding="UTF-8"?>


<persistence version="1.0" ...>
<persistence-unit name="cookbookEJB">
<jta-data-source>jdbc/cookbookdb</jta-data-source>
<class>com.manessinger.cookbook.entity.City</class>
<class>com.manessinger.cookbook.entity.Country</class>
<properties>
<property name="eclipselink.logging.level" value="FINE"/>
</properties>
</persistence-unit>
</persistence>

Obviously most of what you can set from the various tabs of persistence.xml is optional.

Data Transfer Objects (DTO)


[back to top]
To illustrate the next point, we will add another method to the business interface. The method is to
be calleddumpCountries(), and we want it to yield a representation of all data in the database.
Let’s begin with thinking about the interface: We could simply define it as

public Country[] dumpCountries();

but when we try to add this method to the Remote Interface, we see that Eclipse flags an
error. Country is not defined in the client project. What now?
We could create the entities in cookbookEJBClient instead of the EJB project cookbookEJB, but that
won’t work. The context menu of the client project does not give us the option to create entities from
tables. Another option would be, to move the generated entities from the EJB project to the client
project. This would work, but it is tedious and it would have to be repeated every time we need to
generate anew.
Seemingly the tool doesn’t want to do it our way, and whenever something like that happens, it’s a
good idea to think twice if what we want to achieve is really what we need to do.

Indeed that’s not the case here. Entities directly reflect the inner structure of the database, and that
is something that we should avoid to expose. When we send entities over the interface, then we
actually send them over the network. They become part of the contract, if they change, because the
database has changed, clients have to be changed as well. Not a good idea. We will want to insert
an abstraction layer comprising all datatypes used as parameters to business interface methods.

We call such objects DATA TRANSFER OBJECTS (DTO). Their only purpose is to represent


datastructures. We didn’t add any business methods to entities, and we won’t add them to DTOs
either.
The drawback of using DTOs is, that we have to create them, and that information has to be copied
between entities and DTOs. This will cost a little performance and memory, but it is greatly
outweighed by the better maintainability and greater flexibility. Additionally, as long as we keep
DTOs free of business logic, they would be easy to automatically generate, if we only had a meta-
model of the application. In the long run we will have such a thing, and then the pattern will be even
less costly.

Thus a possible method would be (1)

public List<CountryDump> dumpCountries();

with CountryDump holding the information about a country. Alternatively we could write it as (2)

public CountryDump[] dumpCountries();

or even (3)

public DumpResponse dumpCountries();


where DumpResponse would hold an array of CountryDump. Java serializes all three versions to
more or less

<?xml version="1.0" encoding="UTF-8"?>


<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Body>
<ns2:dumpResponse xmlns:ns2="http://service.cookbook.manessinger.com/">
<return>
<cities>Wien</cities>
<cities>Linz</cities>
<cities>Graz</cities>
<cities>Salzburg</cities>
<name>Austria</name>
</return>
<return>
<cities>Roma</cities>
<cities>Bologna</cities>
<cities>Firenze</cities>
<cities>Venezia</cities>
<name>Italy</name>
</return>
<return>
<cities>New York</cities>
<cities>Los Angeles</cities>
<cities>Atlanta</cities>
<cities>Washington</cities>
<name>USA</name>
</return>
</ns2:dumpResponse>
</S:Body>
</S:Envelope>

or a veriant thereof with slightly different element names. Microsoft .NET would deserialize all three
into something like #3. Variant (1) relies on SOAP implementations for Java serializing collections in
that form. Variant (2) only relies on array results being serialized like that, and variant (3) finally does
not rely on anything.

Variant (3) is obviously portable and maintains interoperability, regardless of the Java SOAP
implementation being used. This was a point to worry about in the past, but nowadays (1) and (2)
are portable as well, and that is, because such a serialization is the standard behaviour of the JAVA
ARCHITECTURE FOR XML BINDING(JAXB), and JAXB is the basis of all modern SOAP
implementations for Java.
Why is this important at all? Well, again, we define a protocol here, a network protocol between two
programs, a server and a client. As long as all communication is between a Java server and a Java
client via EJB client libraries, interoperability is not really a question. It get’s more interesting though,
as soon as we have different languages on client and server. Obviously both sides have to rely on
interface stability and it must be ruled out, that the XML on the wire changes, only because some
version of some SOAP implementation library has changed.

JAXB is exactly about that. It has a standardized behavior and it will shield the client from changes in
the server. We have to rely on the client to do something similar. A Java client would use the same
technology and per definition do so, .NET does as well. Therefore we don’t have to restrict ourselves
to arrays. We are free to choose what is easiest for us and that is (1), the list of DTOs.

Where to convert?

[back to top]
We have two types of objects that, apart from getters/setters and constructors don’t have any
methods:

 Entities, because they are generated that way


 DTOs, because we choose them to be parameter objects only
In many cases, especially in the initial program version, there will be a close one-to-one
correspondence between entities and DTOs, the DTOs carrying most of the information contained in
their corresponding entities. It may not necessarily stay that way, the business interfaces may over
time become facades that hide the then current implementation, but normally we start out very close.

There will have to be one place where we do the conversions, where we move information from
entities into DTOs and vice versa. The following options apply:

1. We do everything in entities. We add to them a constructor with a DTO as a parameter, and


we add a method toDto(), that returns a DTO
2. We do everything in DTOs. Same system, a constructor with entity parameter and a
methodtoEntiy(), that returns an entity
3. A mixed approach with constructors only
4. A mixed approach with toDto() and toEntiy() methods
5. A separate class Conversion with methods public static EntityType
fromDto(DtoType dto)and public static DtoType fromEntity(EntityType
entity)
#1 has the problem that we would have to modify generated entity classes, thus we drop it. #2 can’t
be done, because the DTOs have to go into the client project, therefore they have no access to
entity types. #3 and #4 fail for both reasons, and that leaves us with the unelegant but practical #5.

Should we ever manage to generate DTOs from an application model, the conversion methods
would be obvious and simple targets for code generation as well. Thus we add a
packagecom.manessinger.cookbook.dto to the client project and a
packagecom.manessinger.cookbook.util to the EJB project. The latter is for our Conversion class.

Implementation

[back to top]
We end up with the following code in the DTO

package com.manessinger.cookbook.dto;
 
import java.util.List;
 
public class CountryDump {
 
private String name;
private List<String> cities;
 
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public List<String> getCities() { return cities; }
public void setCities(List<String> cities) { this.cities = cities; }
}

in the interface

package com.manessinger.cookbook.service;
 
import java.util.List;
import javax.ejb.Remote;
import com.manessinger.cookbook.dto.CountryDump;
 
@Remote
public interface CookbookInterface {
public long countryCount();
public List<CountryDump> dumpCountries();
}

in the service bean


package com.manessinger.cookbook.service;
 
import java.util.ArrayList;
import java.util.List;
import javax.ejb.EJB;
import javax.ejb.LocalBean;
import javax.ejb.Stateless;
import javax.jws.WebService;
import com.manessinger.cookbook.dto.CountryDump;
import com.manessinger.cookbook.eao.CookbookEao;
import com.manessinger.cookbook.entity.Country;
import com.manessinger.cookbook.util.Conversion;
 
@LocalBean
@Stateless
@WebService
public class CookbookBean implements CookbookInterface {
 
@EJB CookbookEao eao;
@EJB Conversion conv;
 
public CookbookBean() { }
 
@Override
public long countryCount() {
return eao.countCountries();
}
 
@Override
public List<CountryDump> dumpCountries() {
List<CountryDump> result = new ArrayList<CountryDump>();
List<Country> allCountries = eao.allCountries();
for (Country c : allCountries) {
CountryDump ci = conv.fromEntity(c);
result.add(ci);
}
return result;
}
}

in the EAO

package com.manessinger.cookbook.eao;
 
import java.util.List;
import javax.ejb.LocalBean;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import com.manessinger.cookbook.entity.Country;
 
@LocalBean
@Stateless
public class CookbookEao {
 
@PersistenceContext
EntityManager em;
 
public CookbookEao() { }
 
public long countCountries() {
long result;
Query q = em.createQuery("select count(co) from Country co");
result = (Long)q.getSingleResult();
return result;
}
 
@SuppressWarnings("unchecked")
public List<Country> allCountries() {
List<Country> result;
Query q = em.createQuery("select co from Country co");
result = (List<Country>) q.getResultList();
return result;
}
}

and finally in the converter

package com.manessinger.cookbook.util;
 
import java.util.ArrayList;
import java.util.List;
import javax.ejb.EJB;
import javax.ejb.Stateless;
import com.manessinger.cookbook.dto.CountryDump;
import com.manessinger.cookbook.eao.CookbookEao;
import com.manessinger.cookbook.entity.City;
import com.manessinger.cookbook.entity.Country;
 
@Stateless
public class Conversion {
 
@EJB CookbookEao eao;
 
public Conversion() { }
 
public CountryDump fromEntity(Country e) {
CountryDump result = new CountryDump();
result.setName(e.getName());
List<String> cities = new ArrayList<String>();
for (City city : e.getCities()) {
cities.add(city.getName());
}
result.setCities(cities);
return result;
}
}

After such major changes involving new classes, you may need to restart the server. Normally
changes are automatically deployed, but if too much structure is changed, then a server restart can’t
be avoided. This is such a point. Just remember to actually stop/start the server, because restarting
has a bug right now.

Updating definition in soapUI and testing

[back to top]

We can test dumpCountries() in the GlassFish web service tester (Appplications /


projectxEAR / Modules and Components / View Endpoint / Tester), or we can do it in soapUI. In
order to do the latter, we have to make it update its definition. We do that from the context menu
of CookbookBeanPortBinding with Update Definition.
When we finally make the call, we see the expected result:

<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Body>
<ns2:dumpResponse xmlns:ns2="http://service.cookbook.manessinger.com/">
<return>
<cities>Linz</cities>
<cities>Graz</cities>
<cities>Wien</cities>
<cities>Salzburg</cities>
<name>Austria</name>
</return>
<return>
<cities>Venezia</cities>
<cities>Roma</cities>
<cities>Bologna</cities>
<cities>Firenze</cities>
<name>Italy</name>
</return>
<return>
<cities>Los Angeles</cities>
<cities>Washington</cities>
<cities>New York</cities>
<cities>Atlanta</cities>
<name>USA</name>
</return>
</ns2:dumpResponse>
</S:Body>
</S:Envelope>

We have done nothing to maintain a particular sort order, thus the order may vary from call to call.

Accessing EJBs from a servlet


[back to top]
Not always does it suffice to access Enterprise Java Beans via SOAP. Sometimes we will need to
access them from a servlet. Here we look at a simple example where a servlet presents a tabular
representation of the database content.

Beginning from Java EE 6 it is possible to access EJBs from a servlet. Servlets are instantiated by
the EJB container, and therefore they have access to EJBs via injection.

In order to create servlets in Eclipse, we need a DYNAMIC WEB PROJECT. This is a project type that
we actually could use to create EJBs as well, but we wouldn’t get client projects that way. Thus, for
maximum flexibility, we work with an EAR and with separate projects of different types for the
different kinds of access.
Now the strategy is clear: we need a Dynamic Web Project and we define it as dependent on the
EJB project. We get access to the beans via dependency injection, and we inject the bean classes
directly via their No-Interface view.

Instead of letting the Dynamic Web Project depend on the EJB project, we could use the client
project as well, but then we would have to add a @Local business interface, or else we could use
the existing but slower remote interface. This could make sense if we had a need for very loose
coupling between servlet and EJB.

Creating a Dynamic Web Projects for servlets


[back to top]
We begin with creating the project. Either from the context menu of the Project Explorer (tree on the
left side in Eclipse) or from the File menu we choose New / Dynamic Web Project.

From the context menu of the new project we select Build Path / Configure Build Path and add the
EJB project to the build path. Now we have access to all types in the EJB project as well as the
client project.

The Dynamic Web Project has a source folder src, and from its context menu we choose New /
Package. We see the servlet as a kind of service, thus we use again the package
namecom.manessinger.cookbook.service.

Creating a servlet
[back to top]
From the context menu of the package we choose New / Web Servlet (Java EE 6).

We call the servlet class CountryList and accept the defaults. The result is this class (comments
omitted):

package com.manessinger.cookbook.service;
 
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
@WebServlet(name = "CountryList", urlPatterns = { "/CountryList" })
public class CountryList extends HttpServlet {
private static final long serialVersionUID = 1L;
 
public CountryList() { super(); }
 
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
 
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
 
protected void processRequest(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
try {
out.println("<html>");
out.println("<head>");
out.println("<title>Servlet CountryList</title>");
out.println("</head>");
out.println("<body>");
out.println("<h1>Servlet CountryList at "
+ request.getContextPath() + "</h1>");
out.println("</body>");
out.println("</html>");
} finally {
out.close();
}
}
 
@Override
public String getServletInfo() { return "Short description"; }
}
You may need to stop/start the server again, and then you can already call the servlet under the
following URL (portnumber may be different, check with the server):

http://localhost:8084/cookbookServlets/CountryList

Accessing the EJB


[back to top]
Now we change the servlet code and add an EJB as uninitialized field, annotated with @EJB. We
call thedumpCountries() method and print the result into an HTML definition list inside of a DIV
element. Here is the code:

package com.manessinger.cookbook.service;
 
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
import javax.ejb.EJB;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.manessinger.cookbook.dto.CountryDump;
 
@WebServlet(name = "CountryList", urlPatterns = { "/CountryList" })
public class CountryList extends HttpServlet {
private static final long serialVersionUID = 1L;
 
@EJB CookbookBean cbBean;
 
public CountryList() { super(); }
 
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
 
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
 
protected void processRequest(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
try {
out.println("<html>");
out.println("<head>");
out.println("<title>Country list</title>");
out.println("</head>");
out.println("<body>");
out.println("<h1>Country list</h1>");
 
List<CountryDump> countries = cbBean.dumpCountries();
if (countries.size() > 0) {
out.println("<div class=\"cookbook-country-list\">");
out.println("<dl>");
for (CountryDump co : countries) {
out.println("<di>"+co.getName()+"</di>");
out.println("<dd>");
List<String> cities = co.getCities();
if (cities.size() > 0) {
out.println("<ul>");
for (String ci : cities) {
out.println("<li>"+ci+"</li>");
}
out.println("</ul>");
}
out.println("</dd>");
}
out.println("</dl>");
out.println("</div>");
}
 
out.println("</body>");
out.println("</html>");
} finally {
out.close();
}
}
 
@Override
public String getServletInfo() {
return "Displays a list of countries and some of their cities";
}
}

This is it. We get a list.

Unit tests
[back to top]
Unit tests are a means to make sure, that by adding new code or modifying existing one, you don’t
inadvertently break what already works. Unit tests are just small test programs that verify the
contracts of the units of code that they test. Programmers always have done that, it’s just
that Extreme Programming made their use mandatory, and that Kent Beck and Erich Gamma
devised a clever but simple framework called JUnit.
Unit tests can be executed from within Eclipse (or any of the other popular Java IDEs), they can be
run via Ant, and they are run by so-callen continuous integration servers like Hudson. In many
organizations and projects a successful run of the unit test suite is even precondition for a checkin
into the version control system.
In times of J2EE, unit testing EJBs was notoriously hard, mostly because the beans were not
POJOs. They completely depended on the container, and testing them independently was not
possible.

We are going to try two strategies here, in-container testing as it could have been done earlier as
well, and out-of-container testing, which has been greatly simplified with JEE 5 respectively EJB 3.

In-container testing
[back to top]
In order for in-container testing to be possible, the application must be deployed to a server. That
may have been an obstacle in the past, when servers were big, slow to start and consumed a lot of
memory, but now it’s something we hardly notice. I always run a server anyway, started from
Eclipse, and I let Eclipse automatically deploy all changes. In a time of much faster machines, plenty

of memory and lean, optimized server code (hard to tell what’s the dominant factor here   ),
there’s no reason not to do so. When the server is already running, we can use it to run the
interactively started unit tests as well, and when we start the tests automatically as part of a nightly
build in an integration server or after changes in a source repository have been detected, having
them run in a server is no matter either.

Basically we have two options to call into the server from the test program. We could call via SOAP,
restricting ourselves to testing what we publish. The other option is to call “EJB style”, i.e. calling via
Corba/IIOP to a Remote Interface. This is what we do here.

The test program is a normal Java program, not a JEE application (though it would be possible to
conceive of a JUnit runner to be one), and we can only test what has exposed itself via a  REMOTE
INTERFACE. If we properly set up the test project, there is no need for the remote interface to be part
of the client project, but the beans that we test must still register with the server for remote access,
and they will continue to do so in production. If that troubles you and you don’t want to expose
internal interfaces, even in the rather opaque way of not having them included in the client libraries,
in other words, if you care about making it impossible to call them, then, well, then you should
probably not use Java at all. A language that is not as easy to de-compile would suit you better. In
this context I assume that this is a non-issue.
Project setup

[back to top]
We begin setting up the test project, an ordinary Java project called cookbookJUnitInServer.

In order to have access to all beans in the server, exposed via client libraries or not, we don’t put the
client project on the build path but the EJB project cookbookEJB instead. We need to add Junit
libraries to the project, and we do this via Libraries / Add Library / JUnit / JUnit 4. Similarly we need
the client library for access to GlassFish. Note though, that you don’t get that via  Libraries / Add
Library / Server Runtime / GlassFish v3 JEE 6. The library we need is called gf-client.jar and it is
located in the GlassFish modules directory. On my standard Windows 7 installation of the GlassFish
Tools Bundle For Eclipse this is located inC:\GlassFish-Tools-Bundle-For-Eclipse-
1.2\glassfishv3\glassfish\modules. You have to add the file via Libraries / Add External JARs, and when
you do that, Eclipse pulls in a host of referenced files as well. You don’t see that in the Build
Path dialog, but you’ll see it in the Project Explorer.

EJB lookup

[back to top]
The way to get access to an EJB from outside of the EJB container is via JNDI lookup, i.e. by calling
thelookup() method of an InitialContext, but in this case we have to go a little
further. InitialContextcomes with normal Java SE and it does not know about JEE or
GlassFish. We have to provide some hints when constructing the InitialContext. These hints
are given to the constructor as a set of properties. We want one place where these properties are
defined, thus we create a package in the test project calledcom.manessinger.junit. Here we create a
class Util with a static method Properties getInitProperties().

package com.manessinger.junit;
 
import java.util.Properties;
 
public class Util {
 
public static Properties getInitProperties() {
Properties result = new Properties();
 
// We need to tell the context where and how to look
result.setProperty("java.naming.factory.initial",
"com.sun.enterprise.naming.SerialInitContextFactory");
result.setProperty("java.naming.factory.url.pkgs",
"com.sun.enterprise.naming");
result.setProperty("java.naming.factory.state",
"com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl");
 
// Should not be necessary for local test (default values), but
// currently is
result.setProperty("org.omg.CORBA.ORBInitialHost", "localhost");
result.setProperty("org.omg.CORBA.ORBInitialPort", "3700");
 
return result;
}
}

The first block of three properties causes JNDI to use GlassFish-specific libraries for the lookup. The
second block
with org.omg.CORBA.ORBInitialHost and org.omg.CORBA.ORBInitialPort is interesting
though. The values specified should be default values, but fact is, that they currently are not. On the
other hand, we can use exactly these properties to access EJBs running on any host. We only have
to make sure that the calls are not blocked by a firewall. This way it is also possible to run the unit
tests on another host than the actual beans under test.
Should you ever do that, you have to make sure that GlassFish on the target machine does not only
register for localhost but for the external interface. In order to do that, you open the Administration
Console in a browser and change Configuration / ORB / IIOP Listeners / orb-listener-1 / Network
address from127.0.0.1 to either the external IP address or, better, the DNS name of the server host.
Again, you have to make sure that no firewall blocks the accesses.
Even if you don’t plan on calling to other hosts, it’s still a good idea to check Configuration / ORB /
IIOP Listeners / orb-listener-1 / Network address in the Administration Console. On Linux I have a
default of127.0.0.1 (which is OK), but on Windows I had 0.0.0.0. No idea if this is the default for
Windows (why should it be?) or if it was the result of me tinkering with the installation, but it does not
hurt to have a look.

Testing and a NotSerializableException

[back to top]
No we can write a simple test class for our EJB. Note that we always put our test classes into
packages with the same names (as packages are namespaces, essentially meaning they are in the
same package) as the classes under test. Thus we first create a
package com.manessinger.cookbook.service in the test project, and then we create the test class:

package com.manessinger.cookbook.service;
 
import static org.junit.Assert.assertEquals;
import java.util.List;
import javax.naming.InitialContext;
import org.junit.Before;
import org.junit.Test;
import com.manessinger.cookbook.dto.CountryDump;
import com.manessinger.junit.Util;
 
public class TestCookbookBean {
 
private CookbookInterface serviceBean;
 
@Before
public void setUp() throws Exception {
serviceBean =
(CookbookInterface) new InitialContext(Util.getInitProperties())
.lookup("java:global/cookbookEAR/cookbookEJB/CookbookBean"
+"!com.manessinger.cookbook.service.CookbookInterface");
}
 
@Test
public void countryCountTest() {
long n = serviceBean.countryCount();
assertEquals(3, n);
}
 
@Test
public void dumpTest() {
List<CountryDump> countries = serviceBean.dumpCountries();
assertEquals(3, countries.size());
for (CountryDump co : countries) {
assertEquals(4, co.getCities().size());
}
}
}

We run a unit test by right-clicking in the file and calling Run As / JUnit Test from the context menu.
This pops up the JUnit view, but when you are in the Java EE perspective, it may still be down
where the Server viewand Console view are. Just take the tab and drag it onto the Project
Explorer tab on the left side or the Eclipse window. That’s where it is in the normal Java perspective,
and this is a much better place.
When you run the test like that, you will see that countryCountTest() succeeds,
but dumpTest() fails with

javax.ejb.EJBException:
java.rmi.MarshalException: CORBA BAD_PARAM 1330446342 Maybe;
nested exception is:
java.io.NotSerializableException:
----------BEGIN server-side stack trace----------
org.omg.CORBA.BAD_PARAM: vmcid:
OMG minor code: 6 completed: Maybe
at com.sun.corba.ee.impl.logging.OMGSystemException.notSerializable
and so on and so on. What’s wrong? Obviously something should be serializable and is not, but
what exactly is it. You see the solution in the server log:

WARNUNG: "IOP00100006: (BAD_PARAM)


Class com.manessinger.cookbook.dto.CountryDump is not Serializable"

Is it not? Yup, GlassFish is right, it isn’t. In Java you make a class serializable by letting it implement
the marker interface java.io.Serializable. This is called a marker interface, because it does
not contain any method signatures. I think for orthogonality modern Java should provide an
annotation @Serializable, but until it does, we need to change CountryDump (in the client
project) like this:

package com.manessinger.cookbook.dto;
 
import java.io.Serializable;
import java.util.List;
 
public class CountryDump implements Serializable {
 
private static final long serialVersionUID = 1L;
 
private String name;
private List<String> cities;
 
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public List<String> getCities() { return cities; }
public void setCities(List<String> cities) { this.cities = cities; }
}

We didn’t get the error before, because so far we had called dumpCountries() only via SOAP,
and the SOAP serializer code obviously dose not need parameter classes to explicitly
implement Serializable.

Testing internal interfaces

[back to top]

When we look back at the test class, we see an annotation @Before on the


methodsetup(). This is a JUnit 4 annotation, and it means that the setup method is called before
each test method. There is another annotation @BeforeClass, and when we use that on a static
method, it is called before the first test method, and finally there is another pair of
annotations, @After and @AfterClass. They are obviously called after each method, respectively
after the last test method.
If we want to test the EAO (which is the only other bean at the moment anyway), we need it to
implement aREMOTE INTERFACE. We don’t want to have this interface in the client project, instead we
put it into the EJB project into the package com.manessinger.cookbook.eao, where the EAO itself is. We
do that by usingRefactor / Extract Interface from either the context menu of CookbookEao.java in
the Project Explorer or from the context menu of the class name within the file.
Extracting the interface is not enough though. We need to make it a REMOTE INTERFACE by adding
the @Remoteannotation:

package com.manessinger.cookbook.eao;
 
import java.util.List;
import javax.ejb.Remote;
import com.manessinger.cookbook.entity.Country;
 
@Remote
public interface CookbookEaoInterface {
 
public long countCountries();
public List<Country> allCountries();
}

When we extracted the interface, the EAO has automatically been changed to implement it:

package com.manessinger.cookbook.eao;
 
import java.util.List;
import javax.ejb.LocalBean;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import com.manessinger.cookbook.entity.Country;
 
@LocalBean
@Stateless
public class CookbookEao implements CookbookEaoInterface {
 
@PersistenceContext
EntityManager em;
 
public CookbookEao() { }
 
public long countCountries() {
long result;
Query q = em.createQuery("select count(co) from Country co");
result = (Long)q.getSingleResult();
return result;
}
 
@SuppressWarnings("unchecked")
public List<Country> allCountries() {
List<Country> result;
Query q = em.createQuery("select co from Country co");
result = (List<Country>) q.getResultList();
return result;
}
}

Now we can do just the same as for the service bean and create a test class. Of course we could as
well add the tests to our existing test class, but that scales only to a certain point. Add more beans
and it becomes quickly confusing, so why not do it right from the beginning? Again we create a
packagecom.manessinger.cookbook.eao in the test project, and here’s the test class:

package com.manessinger.cookbook.eao;
 
import static org.junit.Assert.assertEquals;
import javax.naming.InitialContext;
import org.junit.Before;
import org.junit.Test;
import com.manessinger.junit.Util;
 
public class TestCookbookEao {
 
private CookbookEaoInterface eao;
 
@Before
public void setUp() throws Exception {
eao = (CookbookEaoInterface) new InitialContext(Util.getInitProperties())
.lookup("java:global/cookbookEAR/cookbookEJB/CookbookEao"
+ "!com.manessinger.cookbook.eao.CookbookEaoInterface");
}
 
@Test
public void countryCountTest() {
long n = eao.countCountries();
assertEquals(3, n);
}
}

Testsuite

[back to top]
Now we have one test class per class tested, both in the test project, but in the same packages as
the classes that they test. We can run each of them separately with Run As / JUnit Test, but we also
want the option to run the whole suite of tests. That’s what a JUnit test suite is for. Here is another
class that can be Run As / JUnit Test, and this class will run all the individual test classes:

package com.manessinger.cookbook;
 
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
 
@RunWith(Suite.class)
@Suite.SuiteClasses({
com.manessinger.cookbook.service.TestCookbookBean.class,
com.manessinger.cookbook.eao.TestCookbookEao.class,
})
public class AllTests {
// Any global setup would go here
}

Out-of-container testing
[back to top]
We already know to run unit tests on beans running in a server. In order to make this possible, the
beans must expose the methods that we test over a Remote Interface. This is not the only way of
testing though. In the next step we will look at testing without a container.

The idea is, to do in setup what the container would do normally, thus we need to simulate injection
of EJBs and entity managers.

Project setup

[back to top]
Just like with in-server testing, we create a new project, and again this project is a normal Java
project. We call it cookbookJUnitOutOfServer.

Just like with the in-server test project, we add the EJB project, the JUnit 4 libraries (Add Library /
JUnit / JUnit 4) and the GlassFish server runtime (Add Library / Server Runtime / GlassFish v3 Java
EE6). When I did the same at work with Oracle, I also needed to add the Oracle JDBC driver JAR
file, but here with Derby it is not necessary. It comes with the GlassFish runtime anyway.

Persistence unit and entity manager

[back to top]
We work with JPA for database access. JPA needs a file META-INF/persistence.xml in its class path.
We can simply copy cookbookEJB/ejbModule/META-INF and paste it to cookbookJUnitOutOfServer/src.
Then we edit the file like this:

<?xml version="1.0" encoding="UTF-8"?>


<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
<persistence-unit name="cookbookEJB_junit">
<jta-data-source>jdbc/cookbookdb</jta-data-source>
<class>com.manessinger.cookbook.entity.City</class>
<class>com.manessinger.cookbook.entity.Country</class>
<properties>
<property name="javax.persistence.jdbc.driver"
value="org.apache.derby.jdbc.ClientDriver" />
<property name="javax.persistence.jdbc.url"
value="jdbc:derby://localhost:1527/cookbookdb;create=true" />
<property name="javax.persistence.jdbc.user"
value="cookbookuser" />
<property name="javax.persistence.jdbc.password"
value="cookbook" />
 
<property name="eclipselink.logging.level"
value="FINE" />
<property name="eclipselink.target-server"
value="com.manessinger.junit.JTATransactionController"/>
</properties>
</persistence-unit>
</persistence>

The name of the persistence unit was cookbookEJB, we change it to cookbookEJB_junit. This is


important, because our test project has the EJB project (and therefore the original META-
INF/persistence.xml) on the build path. We need to make sure that our name is unique, because
otherwise we would depend on which persistence.xml is found first on the path.
Apart from changing the name of the persistence unit, we have to add some properties for specifying
the database connection. In the EJB project (and also when testing in-server) the connection had
been supplied by the server in form of a JDBC data source, referenced by a JNDI name. Now we
have no server, thus we have to specify it here. This is also the way how you can use JPA without a
JEE environment.

In this sample project we use the same database for testing as we use in the EJB project. Normally
you will not do that. Interactive tests tend to change the database, but for testing you want a
database with a well-known set of records. Only then can you do such things as test for a number of
countries, etc.

Again we use a property to set the logging level to FINE, but the last property is something
new.eclipselink.target-server refers to a class that we will have to implement. When you use JPA with
the libraries supplied with GlassFish, the default for this property would refer to a GlassFish-internal
class. That’s why we normally don’t have to define this property. Here we have no GlassFish, that’s
why we need a workaround, and again we put this workaround into a
package com.manessinger.junit in the test project.

package com.manessinger.junit;
 
import javax.transaction.TransactionManager;
 
public class JTATransactionController extends
org.eclipse.persistence.transaction.JTATransactionController {
 
public static final String JNDI_TRANSACTION_MANAGER_NAME =
"java:comp/TransactionManager";
 
public JTATransactionController() { super(); }
 
@Override
protected TransactionManager acquireTransactionManager() throws Exception {
return (TransactionManager) jndiLookup(JNDI_TRANSACTION_MANAGER_NAME);
}
}

Basically we inherit from the GlassFish-internal JTATransactionController, and we provide a way for


JPA to get a transaction manager. Finally we provide a class Util in the same package, and this
time it contains a static method that returns an EntityManager.

package com.manessinger.junit;
 
import javax.persistence.EntityManager;
import javax.persistence.Persistence;
 
public class Util {
 
public static EntityManager getEntityManager() {
return Persistence.createEntityManagerFactory("cookbookEJB_junit")
.createEntityManager();
}
}

Simulating injection and testing

[back to top]
Now that we have prepared the environment, it’s easy to instrument the beans under test and to
write the test classes. Remember, we have no running container that could inject EJBs or entity
managers, thus we add constructors. Here is the changed EAO with a constructor taking
an EntityManager:

package com.manessinger.cookbook.eao;
 
import java.util.List;
import javax.ejb.LocalBean;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
 
import com.manessinger.cookbook.entity.Country;
 
@LocalBean
@Stateless
public class CookbookEao implements CookbookEaoInterface {
 
@PersistenceContext
EntityManager em;
 
public CookbookEao() { }
 
public CookbookEao(EntityManager em) { this.em = em; } // for unit test
 
public long countCountries() {
long result;
Query q = em.createQuery("select count(co) from Country co");
result = (Long)q.getSingleResult();
return result;
}
 
@SuppressWarnings("unchecked")
public List<Country> allCountries() {
List<Country> result;
Query q = em.createQuery("select co from Country co");
result = (List<Country>) q.getResultList();
return result;
}
}

This version of the EAO can be used for both kinds of testing. Of course if you had no in-server
tests, you would not need CookbookEao to implement a remote interface.
In the test class (package com.manessinger.cookbook.eao in the test project) we use
the setUp()method to construct the necessary beans. Other than that, the code of the test methods
is exactly as it was in the in-server test.

package com.manessinger.cookbook.eao;
 
import static org.junit.Assert.assertEquals;
import javax.persistence.EntityManager;
import org.junit.Before;
import org.junit.Test;
import com.manessinger.junit.Util;
 
public class TestCookbookEao {
 
private EntityManager _em;
 
private CookbookEao eao;
 
@Before
public void setUp() throws Exception {
_em = Util.getEntityManager();
eao = new CookbookEao(_em);
}
 
@Test
public void countryCountTest() {
long n = eao.countCountries();
assertEquals(3, n);
}
}

Again we start the test with Run As / JUnit Test.


After the same pattern we add another constructor to CookbookBean

package com.manessinger.cookbook.service;
 
import java.util.ArrayList;
import java.util.List;
import javax.ejb.EJB;
import javax.ejb.LocalBean;
import javax.ejb.Stateless;
import javax.jws.WebService;
import com.manessinger.cookbook.dto.CountryDump;
import com.manessinger.cookbook.eao.CookbookEao;
import com.manessinger.cookbook.entity.Country;
import com.manessinger.cookbook.util.Conversion;
 
@LocalBean
@Stateless
@WebService
public class CookbookBean implements CookbookInterface {
 
@EJB CookbookEao eao;
@EJB Conversion conv;
 
public CookbookBean() { }
 
public CookbookBean(CookbookEao eao, Conversion conv) {
// for unit test
this.eao = eao;
this.conv = conv;
}
 
@Override
public long countryCount() {
return eao.countCountries();
}
 
@Override
public List<CountryDump> dumpCountries() {
List<CountryDump> result = new ArrayList<CountryDump>();
List<Country> allCountries = eao.allCountries();
for (Country c : allCountries) {
CountryDump ci = conv.fromEntity(c);
result.add(ci);
}
return result;
}
}

and the converter

package com.manessinger.cookbook.util;
 
import java.util.ArrayList;
import java.util.List;
import javax.ejb.EJB;
import javax.ejb.Stateless;
import com.manessinger.cookbook.dto.CountryDump;
import com.manessinger.cookbook.eao.CookbookEao;
import com.manessinger.cookbook.entity.City;
import com.manessinger.cookbook.entity.Country;
 
@Stateless
public class Conversion {
 
@EJB CookbookEao eao;
 
public Conversion() { }
 
public Conversion(CookbookEao eao) { this.eao = eao; } // for Unit test
 
public CountryDump fromEntity(Country e) {
CountryDump result = new CountryDump();
result.setName(e.getName());
List<String> cities = new ArrayList<String>();
for (City city : e.getCities()) {
cities.add(city.getName());
}
result.setCities(cities);
return result;
}
}

and finally test the service bean with a test class in package com.manessinger.cookbook.service in the
test project.

package com.manessinger.cookbook.service;
 
import static org.junit.Assert.assertEquals;
import java.util.List;
import javax.persistence.EntityManager;
import org.junit.Before;
import org.junit.Test;
import com.manessinger.cookbook.dto.CountryDump;
import com.manessinger.cookbook.eao.CookbookEao;
import com.manessinger.cookbook.util.Conversion;
import com.manessinger.junit.Util;
 
public class TestCookbookBean {
 
private EntityManager _em;
private CookbookEao _eao;
private Conversion _conv;
 
private CookbookBean serviceBean;
 
@Before
public void setUp() throws Exception {
_em = Util.getEntityManager();
_eao = new CookbookEao(_em);
_conv = new Conversion(_eao);
serviceBean = new CookbookBean(_eao, _conv);
}
 
@Test
public void countryCountTest() {
long n = serviceBean.countryCount();
assertEquals(3, n);
}
 
@Test
public void dumpTest() {
List<CountryDump> countries = serviceBean.dumpCountries();
assertEquals(3, countries.size());
for (CountryDump co : countries) {
assertEquals(4, co.getCities().size());
}
}
}

Testsuite

[back to top]
Again we have one test class per class under test, and we want to have a suite that runs all tests:

package com.manessinger.cookbook;
 
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
 
@RunWith(Suite.class)
@Suite.SuiteClasses({
com.manessinger.cookbook.service.TestCookbookBean.class,
com.manessinger.cookbook.eao.TestCookbookEao.class,
})
public class AllTests {
// Any global setup would go here
}

Insert and Update


[back to top]
So far we have an extremely minimal database schema with only two tables and no insert/update
operations. This is not overly simplified, in fact it reflects the common request to construct a
reporting add-on for some existing database and application. Let’s see what we have to change,
when we need to insert/update data. What we will insert/update are ZIP codes. In the end we want
to have one more operation in the service bean:

public ZipDto storeZip(ZipDto in) throws EntityNotFoundException;

We want it to cover both inserting and updating in one single operation. When the object exists, its
attributes are updated, when not, it is created. In any case we return the object. An exception is
thrown when we get an object complete with identity (primary key set, i.e. should be in the
database), but the object is not found.

Extending the Database


[back to top]
We begin with a new table storing ZIP codes. We have ZIP codes all over the world, but there is no
common format. There could be, e.g. some twelve-digit number would certainly suffice, but it never
came to complete standardization. Instead of a common numeric format, we have country codes,
and within each country one specific system. Many countries have numbers only, for instance the
UK uses alphabetic characters as well. We will look at only Austria, Italy and the United States here.
All three have numbers only, Austria with four digits, Italy with five, and the United States use a five
digit main code, followed by a dash and a four digit sub-code. Here’s the DDL part, that can be
executed in the Database Development perspective by copying it into a SQL Scrapbook and running
it there:

--
-- Set up database schema
--
CREATE TABLE ZIP (
ID INTEGER GENERATED ALWAYS AS IDENTITY NOT NULL,
COUNTRY_ID INTEGER NOT NULL,
CODE VARCHAR(20),
NAME VARCHAR(50)
);
 
ALTER TABLE ZIP ADD CONSTRAINT ZIP_PRIMARY_KEY PRIMARY KEY (ID);
ALTER TABLE ZIP ADD CONSTRAINT ZIP_FOREIGNKEY_COUNTRY_ID FOREIGN KEY (COUNTRY_ID)
REFERENCES COUNTRY (ID);
CREATE UNIQUE INDEX ZIP_CODE_IDX ON ZIP(CODE);
 
--
-- Initialize with some values
--
INSERT INTO ZIP (COUNTRY_ID, CODE, NAME)
VALUES ((SELECT ID FROM COUNTRY WHERE NAME = 'Austria'),
'8054', 'Graz-Webling');
INSERT INTO ZIP (COUNTRY_ID, CODE, NAME)
VALUES ((SELECT ID FROM COUNTRY WHERE NAME = 'Italy'),
'30124', 'Venezia');
INSERT INTO ZIP (COUNTRY_ID, CODE, NAME)
VALUES ((SELECT ID FROM COUNTRY WHERE NAME = 'USA'),
'20001-6000', 'Metropolitan Washington Airports Authority');

The new table has been created by executing SQL statements, thus in a way “behind the scenes”.
Eclipse’s database interface has not yet recognized it, and when we immediately try to generate the
entity for the new table, we will see, that the code generator does not know about it. One way to
refresh Eclipse’s information about database metadata, is to go to the Database
Development perspective, drill down to the tables, and to choose Refresh from the context menu
of Tables. You should see all three tables now, and so will the code generator.
Now that we have the new table in the database, we create the missing entity Zip by again
calling JPA Tools / Generate Entities from Tables from the EJB project’s context menu. We see that
the tables CITY andCOUNTRY are still selected, just as we left them the last time.
We select ZIP as well, and when we go on to the Table Associations page, we see that the foreign
key relation between Zip and Country has again been mapped automatically and correctly. The
only change from the defaults is again in the last step, where we change the primary key type
from int to Integer.
When we press Finish, we are asked if we really want to overwrite the classes already generated
before. We never change generated code, thus we can safely confirm with Yes To All.
Here is the generated code:

package com.manessinger.cookbook.entity;
 
import java.io.Serializable;
import javax.persistence.*;
 
@Entity
public class Zip extends com.manessinger.util.jpa.Entity implements Serializable {
private static final long serialVersionUID = 1L;
 
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
 
private String code;
private String name;
 
//bi-directional many-to-one association to Country
@ManyToOne
private Country country;
 
public Zip() { }
 
public Integer getId() { return this.id; }
public void setId(Integer id) { this.id = id; }
public String getCode() { return this.code; }
public void setCode(String code) { this.code = code; }
public String getName() { return this.name; }
public void setName(String name) { this.name = name; }
 
public Country getCountry() { return this.country; }
public void setCountry(Country country) { this.country = country; }
}

You may remember that Synchronize classes listed in persistence.xml was selected on the first page
of theGenerate Custom Entities wizard. Indeed Eclipse has automatically added the
class Zip topersistence.xml. What it couldn’t do though, was updating the copy that we made
inprojectxJUnitOutOfServer/src/META-INF/persistence.xml. It’s a cool idea to do that
now.
If we were using Oracle, and if we had created a file ejbModule/META-INF/eclipselink-
orm.xml in the EJB project, in order to maintain sequence allocation sizes, we would have to
update that as well.

Exceptions
[back to top]
So far we have completely ignored exceptions, but now is a good time to think about a strategy for
what exceptions to throw and when to throw them.

Our proposed method storeZip() is a method of a service bean, intended to be called by external


clients, either via the client library and Corba/IIOP, or as web service method via SOAP. As a matter
of principle we will only throw exceptions over the wire, that are meaningful in context of the interface
and explainable in all details, without needing to know the internal implementation of the service. We
will indeed hide even the fact that the service is implemented in Java, and therefore we will not throw
any Java- or GlassFish-specific exceptions. Thus, although JPA already has
an EntityNotFoundException, we won’t use it and instead define our own. We also don’t wrap
any original exceptions.
In general, exceptions are a controversial topic. Some people love them, some hate them, some use
them to the advantage of their project, some abuse them. A good strategy is, to treat exceptions as,
well, exceptional. A design shouldn’t rely on exceptions being throuwn and caught in normal
operation. It is a terrible anti-pattern to use them as kind of if statement with the else branch
realized in a catch clause. This not only hurts performance, it also makes control flow much harder
to comprehend.
A good use for exceptions is the server-side parameter checking. We need to make sure that
parameters are not only of the correct type (this is guaranteed by the protocol), but also are within
the expected value ranges. If we have a precise specification of the interface and a correct
implementation, this will always be the case. The check will always succeed, except … when it does
not. Mistakes happen, special cases don’t get anticipated, unit tests only cover what we have
thought of testing, thus even if we could be sure to always get called by a known client that we have
written ourselves (and we can’t even expect that), it would be sensible to check anyway. A server
has to protect itself from clients gone wild.

What exactly are the options that we have when we are called with invalid input data? There is no
meaningful way to go on and the whole thing won’t happen in regular use. Look at storeZip(). Its
intended semantics is to use a supplied primary key for fetching an object for update. We can fully
expect the client to only supply an id that has been read from the database. Of course this is the
classic case for an exception.
When exceptions are part of the interface, it means two things:

 The server should only throw checked exceptions.


 The exception classes need to be created in the client project.
Thus we create a package com.manessinger.cookbook.exception in cookbookEJBClient,
and there we create EntityNotFoundException.

package com.manessinger.cookbook.exception;
 
public class EntityNotFoundException extends Exception {
 
private static final long serialVersionUID = 1L;
 
private String className;
private Integer id;
 
public EntityNotFoundException(Class< ? > clazz, Integer id) {
super("Entity of class "+clazz.getSimpleName()+" with id "+id+" not found");
this.className = clazz.getSimpleName();
this.id = id;
}
 
public String getClassName() { return className; }
public Integer getId() { return id; }
}

We don’t give away that we use JPA for accessing the database. For a SOAP client it wouldn’t even
be obvious that the server is written in Java. We only offer a simple default message and the detail
information for clients that need to construct their own localized message.
Implementing storeZip()
[back to top]
We want storeZip() to look roughly like this:

public ZipDto storeZip(ZipDto in) {


Zip zip = conv.fromDto(in);
eao.persist(zip);
return conv.fromEntity(zip);
}

We convert a DTO to an entity, store the entity, convert back and return the result. But, what exactly
is aZipDto?
Up to now we had only a single DTO, CountryDump. It was used to transfer information about a
country and all its cities. Within one object we had the name of a country and a list of strings
containing city names. We could as well have defined a CountryDto containing a list of CityDto.
Both are legitimate. The former is OK when the client does not need to know about key values of
dependent objects.
Now let’s think about typical interactions in a CRUD (Create, Retrieve, Update, Delete) client. We
would certainly have an “Add ZIP” use case. A user would have to select the ZIP’s country from a list
of already defined countries. Thus in order to define a new ZIP code, the list of countries must
already have been retrieved by the client. On the other hand, each country selectable by the user
must already exist at the server, thus it is unnecessary to send the whole country along with a new
ZIP to be inserted. We only want to insert a ZIP, not to change a country. Thus a ZipDto won’t
contain a CountryDto or even a CountryDump, but it will contain a countryId. This also means,
that we have to worry about countries that don’t exist.
When we want to stay with the proposed structure of storeZip(), the check for existence of the
country must happen in the converter within fromDto().
Here is the DTO
package com.manessinger.cookbook.dto;
 
import java.io.Serializable;
 
public class ZipDto implements Serializable {
 
private static final long serialVersionUID = 1L;
 
private Integer id;
private String name;
private String code;
private Integer countryId;
 
public void setId(Integer id) { this.id = id; }
public Integer getId() { return id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getCode() { return code; }
public void setCode(String code) { this.code = code; }
 
public Integer getCountryId() { return countryId; }
public void setCountryId(Integer countryId) { this.countryId = countryId; }
}

and that’s the extended version of the converter:

package com.manessinger.cookbook.util;
 
import java.util.ArrayList;
import java.util.List;
 
import javax.ejb.EJB;
import javax.ejb.LocalBean;
import javax.ejb.Stateless;
 
import com.manessinger.cookbook.dto.CountryDump;
import com.manessinger.cookbook.dto.ZipDto;
import com.manessinger.cookbook.eao.CookbookEao;
import com.manessinger.cookbook.entity.City;
import com.manessinger.cookbook.entity.Country;
import com.manessinger.cookbook.entity.Zip;
import com.manessinger.cookbook.exception.EntityNotFoundException;
import com.manessinger.util.jpa.Entity;
 
@LocalBean
@Stateless
public class Conversion {
 
@EJB CookbookEao eao;
 
public Conversion() { }
 
public Conversion(CookbookEao eao) { this.eao = eao; }
 
public CountryDump fromEntity(Country e) {
CountryDump result = new CountryDump();
result.setName(e.getName());
List<String> cities = new ArrayList<String>();
for (City city : e.getCities()) {
cities.add(city.getName());
}
result.setCities(cities);
return result;
}
 
public ZipDto fromEntity(Zip e) {
ZipDto result = new ZipDto();
result.setId(e.getId());
result.setName(e.getName());
result.setCode(e.getCode());
result.setCountryId(e.getCountry().getId());
return result;
}
 
public Zip fromDto(ZipDto d) throws EntityNotFoundException {
Zip result;
Integer id = d.getId();
if (Entity.isId(id)) {
result = eao.findOrFail(Zip.class, id);
} else {
result = new Zip();
}
result.setName(d.getName());
result.setCode(d.getCode());
result.setCountry(eao.findOrFail(Country.class, d.getCountryId()));
return result;
}
}

fromEntity() is trivial, we only copy values, but fromDto() is more interesting. For the first time
we use the static method isId from the Entity base class. When the DTO comes with a key
value, we try to fetch the corresponding object from the database for update, otherwise we create a
new one. Then we fetch the referenced country from the database and finally copy values.
When accessing objects by primary key, we don’t use the JPA method find(), but instead a
wrapper with more explicit semantics: While JPA’s find() returns null in case no result is found,
we use ourfindOrFail() instead. If no object is found, it throws
our EntityNotFoundException.
This is the updated version of the EAO remote interface, that we introduced for in-server testing:

package com.manessinger.cookbook.eao;
 
import java.util.List;
import javax.ejb.Remote;
import com.manessinger.cookbook.entity.Country;
import com.manessinger.cookbook.exception.EntityNotFoundException;
import com.manessinger.util.jpa.Entity;
 
@Remote
public interface CookbookEaoInterface {
 
public long countCountries();
public List<Country> allCountries();
public <T extends Entity> T findOrFail(Class<T> clazz, Integer id) throws
EntityNotFoundException;
public <T extends Entity> void persist(T entity);
public Country countryByName(String name);
}

That’s the updated EAO:

package com.manessinger.cookbook.eao;
 
import java.util.List;
import javax.ejb.LocalBean;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
 
import com.manessinger.cookbook.entity.Country;
import com.manessinger.cookbook.exception.EntityNotFoundException;
import com.manessinger.util.jpa.Entity;
 
@LocalBean
@Stateless
public class CookbookEao implements CookbookEaoInterface {
 
@PersistenceContext
EntityManager em;
 
public CookbookEao() { }
 
public CookbookEao(EntityManager em) { this.em = em; } // for unit test
 
@Override
public <T extends Entity> T findOrFail(Class<T> clazz, Integer id) throws
EntityNotFoundException {
T e = em.find(clazz, id);
if (e == null) {
throw new EntityNotFoundException(clazz.getClass(), id);
}
return e;
}
 
@Override
public <T extends Entity> void persist(T entity) {
if (entity.hasId()) {
em.merge(entity);
} else {
em.persist(entity);
if (entity.getId() == null) {
em.flush();
}
}
}
 
public long countCountries() {
long result;
Query q = em.createQuery("select count(co) from Country co");
result = (Long)q.getSingleResult();
return result;
}
 
@SuppressWarnings("unchecked")
public List<Country> allCountries() {
List<Country> result;
Query q = em.createQuery("select co from Country co");
result = (List<Country>) q.getResultList();
return result;
}
 
@Override
public Country countryByName(String name) {
Country result;
Query q = em.createQuery("select co from Country co where co.name = :name");
q.setParameter("name", name);
result = (Country) q.getSingleResult();
return result;
}
}

There are two additional methods in this code. eao.persist() calls


either em.persist() or em.merge(). The former causes an INSERT statement to be issued, the
latter an UPDATE.
Note that I check if the entity has its id set after the call to em.persist(). With an underlying
Oracle database this would have been the case, with Derby we need to flush the entity manager at
this point. Obviously that’s a good reason to also offer a variant of eao.persist() that takes a
collection of entities as parameter. Flushing only once for a bunch of entities would be more efficient.
countryByName() is used nowhere so far, but it illustrates how you can set parameters in queries.
Here is the updated remote interface

package com.manessinger.cookbook.service;
 
import java.util.List;
import javax.ejb.Remote;
import com.manessinger.cookbook.dto.CountryDump;
import com.manessinger.cookbook.dto.ZipDto;
import com.manessinger.cookbook.exception.EntityNotFoundException;
 
@Remote
public interface CookbookInterface {
public long countryCount();
public List<CountryDump> dumpCountries();
public ZipDto storeZip(ZipDto in) throws EntityNotFoundException;
}

amd that’s the service bean:

package com.manessinger.cookbook.service;
 
import java.util.ArrayList;
import java.util.List;
import javax.ejb.EJB;
import javax.ejb.LocalBean;
import javax.ejb.Stateless;
import javax.jws.WebService;
import com.manessinger.cookbook.dto.CountryDump;
import com.manessinger.cookbook.dto.ZipDto;
import com.manessinger.cookbook.eao.CookbookEao;
import com.manessinger.cookbook.entity.Country;
import com.manessinger.cookbook.entity.Zip;
import com.manessinger.cookbook.exception.EntityNotFoundException;
import com.manessinger.cookbook.util.Conversion;
 
@LocalBean
@Stateless
@WebService
public class CookbookBean implements CookbookInterface {
 
@EJB CookbookEao eao;
@EJB Conversion conv;
 
public CookbookBean() { }
 
public CookbookBean(CookbookEao eao, Conversion conv) {
// for unit test
this.eao = eao;
this.conv = conv;
}
 
@Override
public long countryCount() {
return eao.countCountries();
}
 
@Override
public List<CountryDump> dumpCountries() {
List<CountryDump> result = new ArrayList<CountryDump>();
List<Country> allCountries = eao.allCountries();
for (Country c : allCountries) {
CountryDump ci = conv.fromEntity(c);
result.add(ci);
}
return result;
}
 
@Override
public ZipDto storeZip(ZipDto in) throws EntityNotFoundException {
Zip zip = conv.fromDto(in);
eao.persist(zip);
return conv.fromEntity(zip);
}
}

Now we want to test this. Let’s try to enter a new ZIP for Klagenfurt, the city in Austria where I was
born. Klagenfurt has a ZIP code of 9020, and Austria’s country id in my database instance is 1. If
you took my SQL statements to initialize the database, Austria was the first country inserted, thus it
should have the id 1, but look it up to be sure.

In SoapUI, in order to make it recognize the new method, we have to update the definition
of the interface by reloading the WSDL. From the context menu
ofCookbookBeanPortBinding select Update Definition. Make sure you opt for re-creating optional
content, otherwise you’ll only get an empty parameter. See the image.
Now you should have a sample request for storeZip(). Change it like this (empty id)

<soapenv:Envelope
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ser="http://service.cookbook.manessinger.com/">
<soapenv:Header/>
<soapenv:Body>
<ser:storeZip>
<arg0>
<code>9020</code>
<countryId>1</countryId>
<id></id>
<name>Klagenfurt</name>
</arg0>
</ser:storeZip>
</soapenv:Body>
</soapenv:Envelope>

and when you run the request, you’ll get that result:

<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Body>
<ns2:storeZipResponse xmlns:ns2="http://service.cookbook.manessinger.com/">
<return>
<code>9020</code>
<countryId>1</countryId>
<id>4</id>
<name>Klagenfurt</name>
</return>
</ns2:storeZipResponse>
</S:Body>
</S:Envelope>

If it does not work


[back to top]
Normally this should work just fine, but in case you get an error, here are some possible traps.

java.sql.SQLSyntaxErrorException: Table/View ‘SEQUENCE’ does not exist

[back to top]
I got this error when I first tried to call storeZip() via SOAP. It had perfectly worked with Oracle,
but with Derby I got this weird problem. It turned out that I had defined the keys in the database  AS
IDENTITY, thus we have to
specify @GeneratedValue(strategy=GenerationType.IDENTITY) in the entity class, or
because the entity class is generated, we have to use the Key Generator: identiy in the Generate
Custom Entitieswizard. I didn’t do that though, instead I left it at the default of auto, which is
supposed to let JPA figure out what to use. Well, JPA decided on a table called SEQUENCE. It would
even work if we left it at auto and created such a table, by the way.

Result has no id

[back to top]
That’s how I found out that with Derby the call to em.persist() does not flush to the database.
Callem.flush() after em.persist() and it works.

Validation
[back to top]
Programming languages support only a handful of standard data types like numeric types of different
precisions, strings, etc, and when we need more, we can always define custom types, in Java in the
form of classes. Frequently a standard type is sufficient, but the range of meaningful values is
normally smaller than the range of values that can be represented by the type. Think of Integer.
Maybe you can’t accept just any positive or negative value, maybe the only meaningful values lie in
the range from 1 to 100. In other cases you may want to restrict the range of possible string values
to those beginning with an upper-case “X” and having a length between 3 and 7. No way a language
could ever cover this for you.
When you call a method, the parameters of the method are implicitly guaranteed to be of the
corresponding type, or if not, and if a standard conversion between the actual parameter’s type and
the parameter type as declared exists, the parameters are guaranteed to be converted to the
corresponding type in a loss-less way. Any further narrowing-down has to be performed in the
method itself.

Java has some nice capabilities, that help making validation on parameters easier. Of course there
are plenty of alternatives, some even more powerful, but what I want to talk about, is what you get
with standard JEE 6, and that’s not shabby either.

I’m talking about BEAN VALIDATION (JSR 303) and JEE 6 @INTERCEPTORS. Interceptors have been in
the Java Enterprise Edition for a long time. What’s new is, you guess it, that you can specify them
with annotations. Bean Validation is a new standard for how to validate the values of fields,
parameters, etc. I won’t go into every detail, I’ll just present one very useful application.
The idea is, to have a generic validator, that can be associated with any method of any service bean.
This validator would check all constraints put on parameters of the method, or the fields of those
parameters. This looks like a lot of introspection, and of course that’s exactly what goes on, but
although it has the potential to slow things down, it is also eminently useful. Let’s just see how it
works.

ValidationException
[back to top]
In the client project, in the package com.manessinger.cookbook.exception, we create three
classes, basically a ValidationException and some stuff to contain its details.

package com.manessinger.cookbook.exception;
 
import java.io.Serializable;
 
public class ConstraintProperty implements Serializable {
 
private static final long serialVersionUID = 1L;
 
private String name;
private String value;
 
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getValue() { return value; }
public void setValue(String value) { this.value = value; }
}
We will put constraints on parameters, and those constraints have properties. For instance we may
want to associate a constraint upon the minimum of an Integer value, and then we would have a
property with name of value and a … hmmm … value of 1. Makes a fine constraint for a primary
key value. Another property could be a regular expression that is matched against a string. When a
caller’s specified values violate a constraint, we want to report not only that a value is wrong, it is
also necessary to report what the constraint was. If that does not make sense yet, stay with me a
little longer, it will all be clear when you see the result.

package com.manessinger.cookbook.exception;
 
import java.io.Serializable;
import java.util.List;
 
public class ViolationDetail implements Serializable {
private static final long serialVersionUID = 1L;
 
private String attributedItem;
private String invalidItemValue;
private String constraintName;
private List<ConstraintProperty> constraintProperties;
 
public ViolationDetail() { }
 
public String getAttributedItem() {
return attributedItem;
}
public void setAttributedItem(String attributedItem) {
this.attributedItem = attributedItem;
}
public String getInvalidItemValue() {
return invalidItemValue;
}
public void setInvalidItemValue(String invalidItemValue) {
this.invalidItemValue = invalidItemValue;
}
public String getConstraintName() {
return constraintName;
}
public void setConstraintName(String constraintName) {
this.constraintName = constraintName;
}
public void setConstraintProperties(List<ConstraintProperty> constraintProperties)
{
this.constraintProperties = constraintProperties;
}
public List<ConstraintProperty> getConstraintProperties() {
return constraintProperties;
}
}

In case some constraint is violated, we want to return all detail that we have, and we want to do it in
a way that the client can use the information to construct a meaningful message. Simply returning a
text is not enough. Clients may want to present the details in a language different from what the
server uses. We will report the attributed item, that’s the item, attributed with a constraint, the actual
value supplied, the name of the constraint and any properties associated with that constraint.

package com.manessinger.cookbook.exception;
 
import java.util.ArrayList;
import java.util.List;
 
public class ValidationException extends Exception {
 
private static final long serialVersionUID = 1L;
 
private List<ViolationDetail> details = new ArrayList<ViolationDetail>();
 
public ValidationException(List<ViolationDetail> details) { this.details =
details; }
 
public List<ViolationDetail> getViolationDetail() { return details; }
}

The exception itself is trivial, it just takes a list of violation details. It’s a list, because in complex
parameters more than one field could be in violation of its constraints.

Specifying constraints
[back to top]
BEAN VALIDATION (JSR 303) uses annotations to specify constraints. The
packagejavax.validation.constraints (part of Java EE 6) provides a lot of useful constraints. Three of
them will be used here.

package com.manessinger.cookbook.dto;
 
import java.io.Serializable;
 
import javax.validation.constraints.Min;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;
 
public class ZipDto implements Serializable {
 
private static final long serialVersionUID = 1L;
 
private Integer id;
 
@Size(min=1, max=50)
private String name;
 
@Pattern(regexp="^(\\d{4,5}|\\d{5}-\\d{4})$")
private String code;
 
@Min(1)
private Integer countryId;
 
public void setId(Integer id) { this.id = id; }
public Integer getId() { return id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getCode() { return code; }
public void setCode(String code) { this.code = code; }
 
public Integer getCountryId() { return countryId; }
public void setCountryId(Integer countryId) { this.countryId = countryId; }
}

We have placed three constraints upon fields of ZipDto. The size restrictions of the name reflect
the limits specified in the database definition. The regular expression says that the code is either a
number with four or five digits, or it is a five-digit number followed by a dash and another four-digit
number. countryId is supposed to be the primary key of a Country record in the database, thus it
can’t possibly be zero or negative.
Note that I have placed no constraint on the value of id, because we don’t even require an id to be
present. If it is null, we insert a new ZIP. So far that’s easy, the hard part was to figure out how
exactly the validator should work, in order to give us all the details we want. Fortunately you can
simply take it as it is. We put it into the EJB project, into the same package as the converter class.

Validation using interceptors


[back to top]
Interceptors are not a new idea in the Java Enterprise Edition. An INTERCEPTOR is a class, that is
declared as such (via annotation), and that provides specific interceptor methods, that are annotated
as well. This interceptor class is, where the real work is done.

package com.manessinger.cookbook.util;
 
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
 
import javax.interceptor.AroundInvoke;
import javax.interceptor.Interceptor;
import javax.interceptor.InvocationContext;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import javax.validation.groups.Default;
 
import com.manessinger.cookbook.exception.ConstraintProperty;
import com.manessinger.cookbook.exception.ValidationException;
import com.manessinger.cookbook.exception.ViolationDetail;
 
@Interceptor
public class ValidationInterceptor {
 
// the factory is expensive but thread-safe
private static ValidatorFactory factory =
Validation.buildDefaultValidatorFactory();
 
@AroundInvoke
public Object intercept(InvocationContext ctx) throws Exception {
Validator v = factory.getValidator();
// for all parameters
for (Object p : ctx.getParameters()) {
// validate parameter
Set<ConstraintViolation<Object>> violations = v.validate(p,
Default.class);
if (!violations.isEmpty()) {
// validation failed, gather details and throw an exception
List<ViolationDetail> details = new ArrayList<ViolationDetail>();
for (ConstraintViolation<Object> violation : violations) {
ViolationDetail d = new ViolationDetail();
// path to violated constraint
d.setAttributedItem(violation.getPropertyPath().toString());
// what type of constraint, e.g. "Min" or "Pattern"
d.setConstraintName(
violation.getConstraintDescriptor()
.getAnnotation().annotationType().getSimpleName()
);
// construct list of constraint properties
Map<String, Object> violationAttributes
= violation.getConstraintDescriptor().getAttributes();
List<ConstraintProperty> properties = new
ArrayList<ConstraintProperty>();
for (String propertyName : violationAttributes.keySet()) {
if (propertyName.matches("^(message|payload|groups|flags)$"))
{
// skip unwanted property
continue;
}
ConstraintProperty a = new ConstraintProperty();
a.setName(propertyName);
a.setValue(violationAttributes.get(propertyName).toString());
properties.add(a);
}
d.setConstraintProperties(properties);
// the value that violated the constraint
Object invalidValue = violation.getInvalidValue();
d.setInvalidItemValue((invalidValue != null ?
invalidValue.toString() : "null"));
 
details.add(d);
}
throw new ValidationException(details);
}
}
return ctx.proceed();
}
}
OK, that’s a big one. Let me explain just two things:

The bean validator would also give us a message for each validation. In case of  @Min, it would be
something like “must be greater or equal to 1″. We could get that message
with violation.getMessage(), but unfortunately, being a message, it must be in a certain
language. In my Linux installation at work I have set the locale to en_US as I hate localized
operating systems, but on my private Windows 7 computers, I use de_DE. Please don’t ask me why,
it is just that way. The problem is, that I can’t get my GlassFish on Windows 7 to produce anything
but German messages, and that although the Administration Console is in perfect English. This
seems to be a GlassFish bug, and it seems to have been fixed already, but only not in the released
version. But even if the bug were not present, what good would a message in English be for a
German or French client application? That’s the reason why I don’t transfer the message to the client
at all.
The second thing is, that I don’t report some optional constraint properties that make no sense to a
client. Take for instance groups. You can associate groups with a constraint, and when checking,
you can specify, that only constraints in certain groups should be validated. This is clearly aimed at
something like debugversus production, but in our context it does not make sense. A server has
to protect itself always, not only in debug mode.
Now that we have a validator in place, we can associate it with the service bean
method storeZip(), and we do it like this:

@Override
@Interceptors(ValidationInterceptor.class)
public ZipDto storeZip(ZipDto in) throws EntityNotFoundException, ValidationException
{
Zip zip = conv.fromDto(in);
eao.persist(zip);
return conv.fromEntity(zip);
}

We don’t need the @Interceptors annotation at the remote interface, but we do need to add the
additional exception to it.

package com.manessinger.cookbook.service;
 
import java.util.List;
import javax.ejb.Remote;
import com.manessinger.cookbook.dto.CountryDump;
import com.manessinger.cookbook.dto.ZipDto;
import com.manessinger.cookbook.exception.EntityNotFoundException;
import com.manessinger.cookbook.exception.ValidationException;
 
@Remote
public interface CookbookInterface {
public long countryCount();
public List<CountryDump> dumpCountries();
public ZipDto storeZip(ZipDto in) throws EntityNotFoundException,
ValidationException;
}

Here is the complete service bean:

package com.manessinger.cookbook.service;
 
import java.util.ArrayList;
import java.util.List;
import javax.ejb.EJB;
import javax.ejb.LocalBean;
import javax.ejb.Stateless;
import javax.interceptor.Interceptors;
import javax.jws.WebService;
import com.manessinger.cookbook.dto.CountryDump;
import com.manessinger.cookbook.dto.ZipDto;
import com.manessinger.cookbook.eao.CookbookEao;
import com.manessinger.cookbook.entity.Country;
import com.manessinger.cookbook.entity.Zip;
import com.manessinger.cookbook.exception.EntityNotFoundException;
import com.manessinger.cookbook.exception.ValidationException;
import com.manessinger.cookbook.util.Conversion;
import com.manessinger.cookbook.util.ValidationInterceptor;
 
@LocalBean
@Stateless
@WebService
public class CookbookBean implements CookbookInterface {
 
@EJB CookbookEao eao;
@EJB Conversion conv;
 
public CookbookBean() { }
 
public CookbookBean(CookbookEao eao, Conversion conv) {
// for unit test
this.eao = eao;
this.conv = conv;
}
 
@Override
public long countryCount() {
return eao.countCountries();
}
 
@Override
public List<CountryDump> dumpCountries() {
List<CountryDump> result = new ArrayList<CountryDump>();
List<Country> allCountries = eao.allCountries();
for (Country c : allCountries) {
CountryDump ci = conv.fromEntity(c);
result.add(ci);
}
return result;
}
 
@Override
@Interceptors(ValidationInterceptor.class)
public ZipDto storeZip(ZipDto in) throws EntityNotFoundException,
ValidationException {
Zip zip = conv.fromDto(in);
eao.persist(zip);
return conv.fromEntity(zip);
}
}

Please note, that the ValidationInterceptor throws Exception and not only


the ValidationExceptionthat we explicitly throw. This is due to the fact that it is a wrapper
method executed around the service method. See the annotation @AroundInvoke on public
Object intercept(InvocationContext ctx)? That’s what it means. We do our validation
before the parameters are supplied to the actual method and before it is called. The call happens at
the end, in ctx.proceed(), and because the interceptor signature is generic, it can’t know about
our custom exception.
We still need to explicitly mark storeZip() as throwing ValidationException, because that’s
the way to get the class into the interface. Otherwise we would get
an UndeclaredThrowableException, and only deeply buried within its stack trace we would see
our custom exception.

Testing the validator


[back to top]
Now let’s try and call storeZip() again, but this time with deliberately wrong input. The “x” in front
of the code violates the regular expression of the pattern constraint, and the name has 51
characters, that’s more than would fit into the database field.

<soapenv:Envelope
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ser="http://service.cookbook.manessinger.com/">
<soapenv:Header/>
<soapenv:Body>
<ser:storeZip>
<arg0>
<code>x9020</code>
<countryId>1</countryId>
<id></id>
<name>Klagenfurt, also known as "Klagenfurt am Wörthersee"</name>
</arg0>
</ser:storeZip>
</soapenv:Body>
</soapenv:Envelope>

The result of the request is a SOAP fault that contains everything we want to know about what went
wrong.

<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Body>
<S:Fault xmlns:ns4="http://www.w3.org/2003/05/soap-envelope">
<faultcode>S:Server</faultcode>

<faultstring>com.manessinger.cookbook.exception.ValidationException</faultstring>
<detail>
<ns2:ValidationException
xmlns:ns2="http://service.cookbook.manessinger.com/">
<violationDetail>
<attributedItem>code</attributedItem>
<constraintName>Pattern</constraintName>
<constraintProperties>
<name>regexp</name>
<value>^(\d{4,5}|\d{5}-\d{4})$</value>
</constraintProperties>
<invalidItemValue>x9020</invalidItemValue>
</violationDetail>
<violationDetail>
<attributedItem>name</attributedItem>
<constraintName>Size</constraintName>
<constraintProperties>
<name>min</name>
<value>1</value>
</constraintProperties>
<constraintProperties>
<name>max</name>
<value>50</value>
</constraintProperties>
<invalidItemValue>
Klagenfurt, also known as "Klagenfurt am Wörthersee"
</invalidItemValue>
</violationDetail>
</ns2:ValidationException>
</detail>
</S:Fault>
</S:Body>
</S:Envelope>

My validation interceptor is generic. It has no application-specific knowledge about the parameters


that it validates. You can use it to validate whatever constraints can be expressed with standard JSR
303 annotations, but that’s it. No database accesses are made, no objects fetched from foreign keys
given. All that would need application-specific knowledge.
Other uses of interceptors
[back to top]

A hypothetical security interceptor


[back to top]
Unlike what we’ve seen with the ValidationInterceptor, an interceptor is not necessarily a
normal class, it can be a Stateless Session Bean as well, and if so, it can use other beans and also
access the database. For a general-purpose validator this didn’t make sense, but think of that
parameter InvocationContext ctx of the interceptor method. We only used it to extract the
actual parameters of the service method. This invocation context can give us access to
a Map<String, Object> contextData, a map that, among other things, contains HTTP
headers (at least as long as we were called via SOAP/HTTP).
Imagine an authenticating portal/gateway, that would pass along some session/security identifier as
HTTP header. A security interceptor could look that value up in a database, and depending on the
result grant or deny access to the a specific method. Such an interceptor could look like this:

@Interceptor
@Stateless
public class SecurityInterceptor {
 
@EJB SecurityEao sec;
@EJB SecurityGuard guard;
 
@SuppressWarnings("unchecked")
@AroundInvoke
public Object intercept(InvocationContext ctx) throws Exception {
 
Map<String, Object> contextData = ctx.getContextData();
Map<String, List<String>> headers
= (Map<String, List<String>>)
contextData.get("javax.xml.ws.http.request.headers");
 
List<String> secCredentials = headers.get("X-Portal-Credentials");
if (secCredentials == null || secCredentials.isEmpty()) {
throw new SecurityNoCredentialsException();
}
SecInfo secInfo = sec.secInfoBySecCredentials(secCredentials);
Method invokedMethod = ctx.getMethod();
if (!guard.isInvocationAllowed(invokedMethod, secInfo)) {
throw new SecurityViolationException();
}
return ctx.proceed();
}
}

The two interceptors could even be combined:


@Interceptors({ValidationInterceptor.class, SecurityInterceptor.class})
public OutputDto someSecuredAndValidatedMethod(InputDto in)
throws SecurityNoKeyException, SecurityViolationException, ValidationException
{
OutputDto result = new OutputDto();
...
return result;
}

Handling transaction rollbacks


[back to top]
While the security interceptor was completely hypothetical (though you generally would implement
security in form of some interceptor), there is another very useful application of interceptors.

The problem

[back to top]
Let’s make an experiment. We will try to insert a ZIP into the database, and then we will simply
repeat it with the same input. Here it is.

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ser="http://service.projectx.advman.adv.magwien/">
<soapenv:Header/>
<soapenv:Body>
<ser1:storeZip xmlns:ser1="http://service.cookbook.manessinger.com/">
<arg0>
<code>9020</code>
<countryId>1</countryId>
<id></id>
<name>Klagenfurt</name>
</arg0>
</ser1:storeZip>
</soapenv:Body>
</soapenv:Envelope>

If you have simply followed this tutorial, then you will already have sent that input once and will have
got the expected result. Upon the second time though, you must get an error. We have
left id empty, thus the call toeao.persist() will call em.persist(), and that causes a
SQL INSERT to be issued. Remember though, that we have a unique index on NAME. You can’t
insert a record for Klagenfurt twice. Thus we can expect an exception, but when it happens, we don’t
get much useful information:

<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Body>
<S:Fault xmlns:ns4="http://www.w3.org/2003/05/soap-envelope">
<faultcode>S:Server</faultcode>
<faultstring>javax.ejb.EJBTransactionRolledbackException</faultstring>
</S:Fault>
</S:Body>
</S:Envelope>

Well you could also get a much, much longer version of that, just like this:

<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Body>
<S:Fault xmlns:ns4="http://www.w3.org/2003/05/soap-envelope">
<faultcode>S:Server</faultcode>
<faultstring>javax.ejb.EJBTransactionRolledbackException</faultstring>
<detail>
<ns2:exception
class="javax.ejb.EJBTransactionRolledbackException"
note="To disable this feature, set
com.sun.xml.ws.fault.SOAPFaultBuilder.disableCaptureStackTrace
system property to false"
xmlns:ns2="http://jax-ws.dev.java.net/">
<ns2:stackTrace>
<ns2:frame class="com.sun.ejb.containers.BaseContainer"
file="BaseContainer.java" line="2204"
method="mapLocal3xException"/>
<ns2:frame class="com.sun.ejb.containers.BaseContainer"
file="BaseContainer.java" line="2004"
method="postInvoke"/>
...
... many, many more lines
...
</ns2:exception>
</detail>
</S:Fault>
</S:Body>
</S:Envelope>

If so, you need to follow the advice given in the SOAP fault, open the Administration console and set
GlassFish’s com.sun.xml.ws.fault.SOAPFaultBuilder.disableCaptureStackTrace system property to false.
You do that in the Administration Console via Enterprise Server / System Properties / Add Property.
You have to stop/start the server bevore the new property gets effective, but then you should get the
short response. This is much better, because why should we expose internal details over the
network? The same information is in the server log as well, and that is a much more appropriate
place.
OK, now that we have that out of our way, let’s look at what we’ve got:
A javax.ejb.EJBTransactionRolledbackException. Obviously the transaction was aborted,
that’s right, but what we got was just the generic exception that occurs, when an undeclared
exception has been caught by the container. Looking at the server log, we find

java.sql.SQLIntegrityConstraintViolationException:
The statement was aborted because it would have caused a duplicate key value
in a unique or primary key constraint or unique index identified by
'ZIP_CODE_IDX' defined on 'ZIP'.

Cool. It’s probably still not what we would want to show to the user of a client application, but it is
information that we may want to transport to the client. Btw, in Oracle we would have got

java.sql.SQLIntegrityConstraintViolationException:
ORA-00001: unique constraint (COOKBOOK_ADMIN.ZIP_CODE_IDX) violated

Only the message is different, but the exception is the same. It is independent of the underlying
database.

Towards a solution

[back to top]
So we want to deliver an exception that is meaningful to the client. Let’s try to catch exceptions in
the service method, analyze them, and finally throw our own TransactionRollbackException.
Just like so:

@Override
@Interceptors(ValidationInterceptor.class)
public ZipDto storeZip(ZipDto in)
throws EntityNotFoundException, TransactionRollbackException, ValidationException
{
try {
Zip zip = conv.fromDto(in);
eao.persist(zip);
return conv.fromEntity(zip);
} catch (Throwable t) {
throw new TransactionRollbackException(t);
}
}

The TransactionRollbackException could look like this:

package com.manessinger.cookbook.exception;
 
public class TransactionRollbackException extends Exception {
 
private static final long serialVersionUID = 1L;
 
private String type;
private String message;
 
public TransactionRollbackException(Throwable t) {
Throwable current = t;
 
do {
if (current.getCause() == null) {
type = current.getClass().getSimpleName();
message = current.getMessage();
}
current = current.getCause();
} while (current != null);
}
 
public String getType() { return type; }
public String getMessage() { return message; }
}

What it does is, it goes along the chains of causes until it reaches the ultimate cause, and in our
case that would be the SQLIntegrityConstraintViolationException. We store type and
message of the most inner exception, and due to the two getters, these will show up in the SOAP
message. The only problem is: it does not always work.
Well, actually it does work with Derby, but it does not work in Oracle. Remember how we had to
flush theEntityManager in eao.persist(), in order to immediately get ids back after
calling em.persist()? We flush early in Derby, we don’t do so in Oracle.
Let’s make another experiment: Let’s add a method eao.flush, that simply delegates
to em.flush(). Now we can write the service method as

@Override
@Interceptors(ValidationInterceptor.class)
public ZipDto storeZip(ZipDto in)
throws EntityNotFoundException, TransactionRollbackException, ValidationException
{
try {
Zip zip = conv.fromDto(in);
eao.persist(zip);
eao.flush();
return conv.fromEntity(zip);
} catch (Throwable t) {
throw new TransactionRollbackException(t);
}
}

As I said, it won’t make a difference in Derby. There you will already have seen the response
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Body>
<S:Fault xmlns:ns4="http://www.w3.org/2003/05/soap-envelope">
<faultcode>S:Server</faultcode>
<faultstring>
The statement was aborted because it would have caused
a duplicate key value in a unique or primary key constraint
or unique index identified by 'ZIP_CODE_IDX'
defined on 'ZIP'.
</faultstring>
<detail>
<ns2:TransactionRollbackException
xmlns:ns2="http://service.cookbook.manessinger.com/">
<message>
The statement was aborted because it would have caused
a duplicate key value in a unique or primary key constraint
or unique index identified by 'ZIP_CODE_IDX'
defined on 'ZIP'.
</message>
<type>SqlException</type>
</ns2:TransactionRollbackException>
</detail>
</S:Fault>
</S:Body>
</S:Envelope>

but now, with flusing inside of the service method, we also get a similar response in Oracle:

<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Body>
<S:Fault xmlns:ns4="http://www.w3.org/2003/05/soap-envelope">
<faultcode>S:Server</faultcode>
<faultstring>
ORA-00001: unique constraint (ADVMAN_ADMIN.ZIP_CODE_IDX) violated
</faultstring>
<detail>
<ns2:TransactionRollbackException
xmlns:ns2="http://service.projectx.advman.adv.magwien/">
<message>
ORA-00001: unique constraint (ADVMAN_ADMIN.ZIP_CODE_IDX) violated
</message>
<type>SQLIntegrityConstraintViolationException</type>
</ns2:TransactionRollbackException>
</detail>
</S:Fault>
</S:Body>
</S:Envelope>

Mission accomplished, right? The SOAP response contains the name of the innermost exception
and its message, thus we deliver the best information that we have.
There is only one problem: We have to do that in every service method. Each method needs
a try/catchblock, and at least in all methods that write to the database, we need to flush within
the try block. Finally, within each catch block we need to throw
a TransactionRollbackException. In big applications this is quite some effort for something
that ideally would happen automatically.

A solution using an interceptor

[back to top]
Again this is a case where we want something to be handled behind the scenes, automatically for all
service methods and for all invocations. This calls for an interceptor.

Remember that an interceptor gets a context parameter (ctx) and that it has to call the
methodctx.proceed(). This is the pivot point, this is where interceptors are chained, and at the
end of this chain the actual service method is called.
In the ValidationInterceptor we had to validate before the service method was called, thus we
did our checks first, and then called ctx.proceed(). Here the opposite is true. We first
call ctx.proceed(), and then we flush the EntityManager. Here is the result:

package com.manessinger.cookbook.util;
 
import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.interceptor.AroundInvoke;
import javax.interceptor.Interceptor;
import javax.interceptor.InvocationContext;
 
import com.manessinger.cookbook.eao.CookbookEao;
import com.manessinger.cookbook.exception.TransactionRollbackException;
 
@Interceptor
@Stateless
public class TransactionRollbackHandler {
 
@EJB CookbookEao eao;
 
@AroundInvoke
public Object handleException(InvocationContext ctx) throws Exception {
try {
Object result = ctx.proceed();
eao.flush();
return result;
} catch (javax.ejb.EJBTransactionRolledbackException etrbe) {
throw new TransactionRollbackException(etrbe);
}
}
}
Please note that we only catch the exception that we actually expect, namely the default exception,
that is thrown when the container catches an exception, that has not been declared by the service
method. It would be completely wrong to catch Throwable, because then this interceptor would
interfere with the ValidationInterceptor. We actually want ValidationException to get
thrown to the client.

We’ve already seen the TransactionRollbackException, so for the sake of completeness,


here is the current EAO interface

package com.manessinger.cookbook.eao;
 
import java.util.List;
import javax.ejb.Remote;
import com.manessinger.cookbook.entity.Country;
import com.manessinger.cookbook.exception.EntityNotFoundException;
import com.manessinger.util.jpa.Entity;
 
@Remote
public interface CookbookEaoInterface {
 
public long countCountries();
public List<Country> allCountries();
public <T extends Entity> T findOrFail(Class<T> clazz, Integer id)
throws EntityNotFoundException;
public <T extends Entity> void persist(T entity);
public Country countryByName(String name);
public void flush();
}

the EAO itself

package com.manessinger.cookbook.eao;
 
import java.util.List;
import javax.ejb.LocalBean;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
 
import com.manessinger.cookbook.entity.Country;
import com.manessinger.cookbook.exception.EntityNotFoundException;
import com.manessinger.util.jpa.Entity;
 
@LocalBean
@Stateless
public class CookbookEao implements CookbookEaoInterface {
 
@PersistenceContext
EntityManager em;
 
public CookbookEao() { }
 
public CookbookEao(EntityManager em) { this.em = em; } // for unit test
 
@Override
public void flush() {
em.flush();
}
 
@Override
public <T extends Entity> T findOrFail(Class<T> clazz, Integer id)
throws EntityNotFoundException
{
T e = em.find(clazz, id);
if (e == null) {
throw new EntityNotFoundException(clazz.getClass(), id);
}
return e;
}
 
@Override
public <T extends Entity> void persist(T entity) {
if (entity.hasId()) {
em.merge(entity);
} else {
em.persist(entity);
if (entity.getId() == null) {
em.flush();
}
}
}
 
public long countCountries() {
long result;
Query q = em.createQuery("select count(co) from Country co");
result = (Long)q.getSingleResult();
return result;
}
 
@SuppressWarnings("unchecked")
public List<Country> allCountries() {
List<Country> result;
Query q = em.createQuery("select co from Country co");
result = (List<Country>) q.getResultList();
return result;
}
 
@Override
public Country countryByName(String name) {
Country result;
Query q = em.createQuery("select co from Country co where co.name = :name");
q.setParameter("name", name);
result = (Country) q.getSingleResult();
return result;
}
}

the remote interface


package com.manessinger.cookbook.service;
 
import java.util.List;
import javax.ejb.Remote;
import com.manessinger.cookbook.dto.CountryDump;
import com.manessinger.cookbook.dto.ZipDto;
import com.manessinger.cookbook.exception.EntityNotFoundException;
import com.manessinger.cookbook.exception.TransactionRollbackException;
import com.manessinger.cookbook.exception.ValidationException;
 
@Remote
public interface CookbookInterface {
public long countryCount() throws TransactionRollbackException;
public List<CountryDump> dumpCountries() throws TransactionRollbackException;
public ZipDto storeZip(ZipDto in)
throws TransactionRollbackException, EntityNotFoundException,
ValidationException;
}

and finally the service bean itself.

package com.manessinger.cookbook.service;
 
import java.util.ArrayList;
import java.util.List;
import javax.ejb.EJB;
import javax.ejb.LocalBean;
import javax.ejb.Stateless;
import javax.interceptor.Interceptors;
import javax.jws.WebService;
import com.manessinger.cookbook.dto.CountryDump;
import com.manessinger.cookbook.dto.ZipDto;
import com.manessinger.cookbook.eao.CookbookEao;
import com.manessinger.cookbook.entity.Country;
import com.manessinger.cookbook.entity.Zip;
import com.manessinger.cookbook.exception.EntityNotFoundException;
import com.manessinger.cookbook.exception.TransactionRollbackException;
import com.manessinger.cookbook.exception.ValidationException;
import com.manessinger.cookbook.util.Conversion;
import com.manessinger.cookbook.util.TransactionRollbackHandler;
import com.manessinger.cookbook.util.ValidationInterceptor;
 
@LocalBean
@Stateless
@WebService
@Interceptors(TransactionRollbackHandler.class)
public class CookbookBean implements CookbookInterface {
 
@EJB CookbookEao eao;
@EJB Conversion conv;
 
public CookbookBean() { }
 
public CookbookBean(CookbookEao eao, Conversion conv) {
// for unit test
this.eao = eao;
this.conv = conv;
}
 
@Override
public long countryCount() throws TransactionRollbackException {
return eao.countCountries();
}
 
@Override
public List<CountryDump> dumpCountries() throws TransactionRollbackException {
List<CountryDump> result = new ArrayList<CountryDump>();
List<Country> allCountries = eao.allCountries();
for (Country c : allCountries) {
CountryDump ci = conv.fromEntity(c);
result.add(ci);
}
return result;
}
 
@Override
@Interceptors(ValidationInterceptor.class)
public ZipDto storeZip(ZipDto in)
throws TransactionRollbackException, EntityNotFoundException, ValidationException
{
Zip zip = conv.fromDto(in);
eao.persist(zip);
eao.flush();
return conv.fromEntity(zip);
}
}

Please note that we add the @Interceptors annotation to the class, and that means, that it will
intercept each method. Therefore we have to add a throws
TransactionRollbackException to each method. If we fail to do so, we end up with
ajava.lang.reflect.UndeclaredThrowableException.

Adding the exception to the signatures of the service methods will make the two test projects and the
Dynamic Web Project cookbookServlets go red because of the unhandled exceptions. In the test
projects you can simply throw them on, in the CountryList servlet you’d normally catch it and
return something meaningful.
In order to reach our goal of having generic exceptions replaced by our own kind of exception, that is
more specific about what really happened, we had to give a little, take a little, and although the result
is less elaborate than our naive first approach, it is still kind of a burden. There may be better
solutions, this is just what I came up with, and you or I may find something more elegant. But that’s
not the point. The point is, that this is the kind of things that you can do with interceptors, this is the
sort of tradeoffs that you have to expect.
Adding extra libraries
[back to top]
The Java Enterprise Edition is real big, but there will always be things that are not included. Basically
we can break down the choice of libraries into
1. included standardized APIs
2. included non-standardized APIs
3. non-included standardized APIs
4. non-included, non-standardized APIs
If we care about portability between application servers, we should try to stick to #1. If we need
anything else, it is not a good idea to just use #2. Those libraries may be there, but if so, it’s because
the standardized APIs happen to be implemented on top of them. Another application server may
implement its functionality on top of a set of different libraries. JPA comes to mind. In GlassFish it is
built on top of EclipseLink, code originally contributed from Oracle’s TopLink object/relational
mapping tool, while in JBoss Application Server it is of course built on top of their Hibernate family of
object relational mapping libraries. As long as we stick to JPA (i.e. libraries
in javax.persistence), we can expect our code to run in any Java EE 6 application server.
If #1 is not enough, it is usually the most portable solution, to package the non-standard and/or non-
included libraries with the application. There are two ways to do it.

1. If we need a some libraries only inside of one specific DYNAMIC WEB PROJECT, there is
nothing wrong with putting them into that project’s WebContent/WEB-INF/lib directory. It will
be packaged into the project’s WAR, the WAR will be packaged inside the EAR, and that way
the libraries are deployed and found at runtime.
2. If we need to access the libraries throughout the application, i.e. from more than one project,
or from an EJB project, it is better to package them into an auxilliary project, add that project to
the EAR, and to make sure that the libraries show up in the EAR’s lib directory at runtime.
Suppose we want to use two extra libraries, jdom.jar and rome.jar. We’ll need them for the next
chapter anyway.

With New / Project / General / Project from the context menu of the Project Explorer, we create a
plain project called cookbookExtraLibs. Neither will we be asked to add it to the EAR nor can we do
so. Basically the project will be a simple directory, and into that directory we just copy the two JARs.
When we then open the Properties for cookbookEAR dialog and go to Java EE Module
Dependencies, we can press Add JARs, select the two JARs from the new project, and they will
automatically be packaged with the EAR and deployed into the EAR’s lib directory.
Additionally, in order to make the libraries available in the development environment as well, we
have to add them to the Build Path of the projects that need them.

Syndication Feeds
[back to top]
A SYNDICATION FEED (RSS or Atom in their various incarnations) is a good method to make data
accessible on the web. So-called FEED READERS (built into all major browsers, or like Google
Reader available as web applications) make it possible to SUBSCRIBE to feeds.
A feed is just an XML document under a specific URL, the feed’s address. The contents of the
document changes. A feed is a sequence of feed entries. The number of entries is finite and
normally low. Typical are the blog posts of a month or the last 30 records in a sequence of data. A
feed reader basically polls the URLs of the subscribed feeds, and whenever a new entry turns up,
the user is notified, either visually or via a popup window. Syndication feeds are most prevalent in
the world of blogs, but they can be of use for any kind of data distribution.

Of the various XML formats used for content syndication, RSS 1.0, RSS 2.0 and Atom 1.0 are the
most important.

The Java Enterprise Edition currently does not include APIs for creating or digesting feeds. If for
instance we want to supply the list of countries as syndication feed (basically an XML variant of
what CountryListdelivers as HTML), we can of course simply copy and modify the servlet that we
have. On the other hand,ROME is a project that is dedicated specifically to creating and consuming
syndication feeds in Java, thus we will use that.

Realizing a feed with ROME


[back to top]
In order to use ROME, we have to download the two libraries jdom.jar and rome.jar and put
them into an extra libraries project as described in the last chapter. As we will need the libraries only
in the Dynamic Web Project cookbookServlets, you could as well put them
into cookbookServlets/WebContent/WEB-INF/libdirectory. If you choose to use the extra
project, don’t forget to put the two libraries onto the Build Path ofcookbookServlets.
The central data structure in ROME is the SYNDICATION FEED (SyndFeed). A feed has entries
(SyndEntry) and the entries have metadata and CONTENT (SyndContent). In the feed we deliver a
representation similar to what we produced in CountryList, here with a country per entry and the
list of cities as HTML content.

package com.manessinger.cookbook.service;
 
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.ejb.EJB;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.manessinger.cookbook.dto.CountryDump;
import com.sun.syndication.feed.synd.SyndContent;
import com.sun.syndication.feed.synd.SyndContentImpl;
import com.sun.syndication.feed.synd.SyndEntry;
import com.sun.syndication.feed.synd.SyndEntryImpl;
import com.sun.syndication.feed.synd.SyndFeed;
import com.sun.syndication.feed.synd.SyndFeedImpl;
import com.sun.syndication.io.SyndFeedOutput;
 
@WebServlet(name = "Feed", urlPatterns = { "/Feed" })
public class Feed extends HttpServlet {
 
private static final long serialVersionUID = 1L;
 
@EJB CookbookBean cbBean;
 
public Feed() { super(); }
 
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
processRequest(request, response);
}
 
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
processRequest(request, response);
}
 
protected void processRequest(HttpServletRequest request, HttpServletResponse
response)
throws ServletException, IOException
{
PrintWriter out = response.getWriter();
try {
SyndFeed feed = new SyndFeedImpl();
 
feed.setTitle("Cookbook Sample Feed");
feed.setLink("http://localhost:8084/cookbookServlets/Feed");
feed.setDescription("This is a feed of available countries");
 
List<SyndEntry> entries = new ArrayList<SyndEntry>();
SyndEntry entry;
SyndContent description;
 
for (CountryDump cd : cbBean.dumpCountries()) {
entry = new SyndEntryImpl();
entry.setTitle(cd.getName());
entry.setUri(String.format("http://maps.google.com/maps?q=%s",
cd.getName()));
entry.setPublishedDate(new Date());
description = new SyndContentImpl();
description.setType("text/html");
StringBuilder sb = new StringBuilder();
sb.append("<ul>\n");
for (String city : cd.getCities()) {
sb.append("<li>");
sb.append(city);
sb.append("</li>\n");
}
sb.append("</ul>\n");
description.setValue(sb.toString());
entry.setDescription(description);
entries.add(entry);
}
feed.setEntries(entries);
feed.setFeedType("rss_2.0");
response.setContentType("application/xml;charset=UTF-8");
SyndFeedOutput output = new SyndFeedOutput();
output.output(feed, response.getWriter());
} catch (Exception e) {
e.printStackTrace();
String msg = "Could not generate feed of countries";
log(msg, e);
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, msg);
} finally {
out.close();
}
}
 
@Override
public String getServletInfo() { return "Feed of countries"; }
}

As to the feed type, ROME supports all variants of RSS and Atom, here I have simply set it to RSS
2.0. This is an ordinary servlet, thus we could either use different URLs for differnet types, or we
could use a URL parameter to select the feed type.

We would expect the feed now to be available under the URL (port number may differ)
http://localhost:8084/cookbookServlets/Feed

A bug in Eclipse
[back to top]
Surprisingly at this point neither of the two servlets may run, and in fact if we find in the server log
the following messages,

SEVERE: Class [ com/sun/syndication/feed/synd/SyndFeed ] not found.


Error while loading [ class com.manessinger.cookbook.service.Feed ]
WARNING: Error in annotation processing:
java.lang.NoClassDefFoundError: com/sun/syndication/feed/synd/SyndFeed

somewhere in the vicinity of where we would expect a message about successful


deployment, we know that GlassFish does not know about the libraries. In fact it should, because in
the last step of setting up the extra libs directory (see last chapter), we have added them to the
EAR’s lib directory. When we check now under Properties for cookbookEAR / Java EE Module
Dependencies, we may see that the libraries are not there. When we try to export the EAR project to
an EAR file cookbookEAR.ear, rename the EAR file to cookbookEAR.zip and look inside, we
may find the two libraries in the top-level directory or the EAR, but not in the lib directory below.
Even worse, we can’t simply add the libraries again. We can try to Add JARs one more time, select
the libraries, add them, but they will still not show up, nor will the servlets be deployed.
This is obviously a bug in Eclipse. I expect it to be fixed in a future version (maybe it is already fixed
in current code), but at the moment there is a workaround:

We can open the Properties for cookbookServlets dialog, go to Java EE Module Dependencies,


press Add JARs and add the two jars. Now it should work. I’m pretty sure this is not always
necessary. Somehow I must have damaged my project setup or whatever.
If you got really bitten by this bug and if nothing works at all, you can always throw in the towel until
the bug is fixed, and simply put the libraries into cookbookServices/WebContent/WEB-
INF/lib. This smells a little bit like defeat, but at the moment I have no better idea. Let’s check it
again with the next release.
Oh, and one more thing: If you happen to have followed my advice to use an extra project for the
libraries, if you ran into the bug and if even the workaround did not work (it did for me one time,
another time it did not), and if you finally moved the libraries
tocookbookServices/WebContent/WEB-INF/lib, it could be that you suddenly can’t publish
your application any more. Sure, you will have removed the two libraries from the build path of the
servlets project. If not, do so, but it will still not publish. What’s wrong now?
Remember that we referenced the two libraries from Properties for cookbookEAR / Java EE Module
Dependencies? They are not there now, that was the bug. Unfortunately Eclipse has remembered
some metadata. It is in

cookbookEAR/.settings/org.eclipse.wst.common.component

an XML file. Exit Eclipse, open the file in an editor and find two dependency stanzas, each refering
to one of the two libraries. Delete the dependencies (three lines each), save the file, exit the editor,
open Eclipse again, start GlassFish from the Servers View, re-publish the application, and all works

again. Oh well 

Configuration via JNDI Custom Resources


[back to top]
Frequently we want the configuration of an application flexible enough that we can change it without
recompilation. Typical candidates are URLs, host names, port numbers, etc. These are parameters
that can change for various reasons, and often we have to react to such changes quickly and without
involving a developer. Traditionally we have used properties files that were part of the application.
These are text files somewhere in the class path, consisting of lines with name/value pairs. There is
API support for loading properties files and for accessing individual properties. With the files being
text files, they can be edited with any text editor, and after re-starting the application, the new values
apply.

There is a problem with properties files though. If they are part of the application, the changes may
be lost after a re-deployment of the application.

If we think about it, the application is probably not the right place for such configuration data anyway.
The application should come with reasonable defaults, but it should be possible to override
application defaults with data resident in the application server. This way we could have a
development environment, a test server and a production server (or any other kind and number of
servers that your quality control process requires), and we would simply move the application from
stage to stage. The defaults would be configured for development, and they would be overridden in
the test and production server.

JNDI CUSTOM RESOURCES were made exactly for such a scenario. A custom resoure is a definition of
a named value in the application server. These values can be queried via JNDI (JAVA NAMING AND
DIRECTORY INTERFACE). We have already accessed JDBC datasources and EJBs via JNDI, so
principally this should be nothing really new.
Just like with EJBs and JDBC datasources, a convenient alternative to JNDI lookup is  DEPENDENCY
INJECTION, only that in this case it is a less than ideal solution. The resaon is, that we want to be able
to fall back to hardcoded defaults, in case the application server does not contain a definition. This is
not possible with dependency injection though. The EJB container always tries to satisfy all
references, and if it can’t, it does not deploy the application.
In case of EJBs this is not a problem. An EJB is a vital part of the application, part of the code. Sure,
there are some cases where we may want to configure which particular implementation of a certain
interface is used, and then JNDI lookup of EJBs makes sens, especially when the key is only known
at runtime, but in general EJBs will be injected, and that’s just fine.

It’s also just fine for databases. Normally there is not such a thing as an optional database. You
either use one or not, and if you do, you want the connection pool to be managed by the application
server. Thus in database applications there will always be a database present, and in almost all
cases it is the right thing to inject a datasource defined in the server and identified by a JNDI name.

With EJBs and databases being integral parts of the application, it certainly makes sense to not start
the application at all, when one of those resources is not present. On the other hand, we will want to
see configurations via custom resources more as server-specific configuration overrides. Thus we
will use JNDI lookup for all our configuration needs.

Let’s have a look at the Feed servlet, that was introduced in the last chapter. Here is a variant, that
uses an optional, server-resident configuration custom/url/template/geomap to configure the
geographical maps web application, that the countries in the feed are linked to. In the original we
have hardcoded it to the format string "http://maps.google.com/maps?q=%s", and this is also
the default in the new variant, expressed in the constant GEO_MAP_URL_TEMPLATE.

package com.manessinger.cookbook.service;
 
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.ejb.EJB;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.manessinger.cookbook.dto.CountryDump;
import com.sun.syndication.feed.synd.SyndContent;
import com.sun.syndication.feed.synd.SyndContentImpl;
import com.sun.syndication.feed.synd.SyndEntry;
import com.sun.syndication.feed.synd.SyndEntryImpl;
import com.sun.syndication.feed.synd.SyndFeed;
import com.sun.syndication.feed.synd.SyndFeedImpl;
import com.sun.syndication.io.SyndFeedOutput;
 
@WebServlet(name = "Feed", urlPatterns = { "/Feed" })
public class Feed extends HttpServlet {
 
private static final long serialVersionUID = 1L;
 
// default if JNDI lookup fails
private static final String GEO_MAP_URL_TEMPLATE = "http://maps.google.com/maps?q=
%s";
 
@EJB CookbookBean cbBean;
 
public Feed() { super(); }
 
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
processRequest(request, response);
}
 
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
processRequest(request, response);
}
 
protected void processRequest(HttpServletRequest request, HttpServletResponse
response)
throws ServletException, IOException
{
PrintWriter out = response.getWriter();
try {
SyndFeed feed = new SyndFeedImpl();
 
feed.setTitle("Cookbook Sample Feed");
feed.setLink("http://localhost:8084/cookbookServlets/Feed");
feed.setDescription("This is a feed of available countries");
 
List<SyndEntry> entries = new ArrayList<SyndEntry>();
SyndEntry entry;
SyndContent description;
 
String geoMapUrlTemplate;
try {
// Lookup via JNDI
geoMapUrlTemplate = (String) new InitialContext()
.lookup("custom/url/template/geomap");
} catch (NamingException e) {
// initialize with default
geoMapUrlTemplate = (String) GEO_MAP_URL_TEMPLATE;
}
 
for (CountryDump cd : cbBean.dumpCountries()) {
entry = new SyndEntryImpl();
entry.setTitle(cd.getName());
entry.setUri(String.format(geoMapUrlTemplate, cd.getName()));
entry.setPublishedDate(new Date());
description = new SyndContentImpl();
description.setType("text/html");
StringBuilder sb = new StringBuilder();
sb.append("<ul>\n");
for (String city : cd.getCities()) {
sb.append("<li>");
sb.append(city);
sb.append("</li>\n");
}
sb.append("</ul>\n");
description.setValue(sb.toString());
entry.setDescription(description);
entries.add(entry);
}
feed.setEntries(entries);
feed.setFeedType("rss_2.0");
response.setContentType("application/xml;charset=UTF-8");
SyndFeedOutput output = new SyndFeedOutput();
output.output(feed, response.getWriter());
} catch (Exception e) {
e.printStackTrace();
String msg = "Could not generate feed of countries";
log(msg, e);
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, msg);
} finally {
out.close();
}
}
 
@Override
public String getServletInfo() { return "Feed of countries"; }
}

It’s largely the same servlet as before, only the geoMapUrlTemplate is looked up in the application
server under the name custom/url/template/geomap. If nothing is found, the hardcoded
defaultGEO_MAP_URL_TEMPLATE is taken.
If no definition in the application server is present, we get a response like
<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0">
<channel>
<title>Cookbook Sample Feed</title>
<link>http://localhost:8084/cookbookServlets/Feed</link>
<description>This is a feed of available countries</description>
<item>
<title>Austria</title>
 
<description>&lt;ul&gt;
&lt;li&gt;Linz&lt;/li&gt;
&lt;li&gt;Salzburg&lt;/li&gt;
&lt;li&gt;Graz&lt;/li&gt;
&lt;li&gt;Wien&lt;/li&gt;
 
&lt;/ul&gt;</description>
<pubDate>Thu, 17 Jun 2010 20:40:24 GMT</pubDate>
<guid isPermaLink="false">http://maps.google.com/maps?q=Austria</guid>
<dc:date>2010-06-17T20:40:24Z</dc:date>
</item>
<item>
<title>Italy</title>
 
<description>&lt;ul&gt;
&lt;li&gt;Firenze&lt;/li&gt;
&lt;li&gt;Roma&lt;/li&gt;
&lt;li&gt;Venezia&lt;/li&gt;
&lt;li&gt;Bologna&lt;/li&gt;
 
&lt;/ul&gt;</description>
<pubDate>Thu, 17 Jun 2010 20:40:24 GMT</pubDate>
<guid isPermaLink="false">http://maps.google.com/maps?q=Italy</guid>
<dc:date>2010-06-17T20:40:24Z</dc:date>
</item>
<item>
<title>USA</title>
 
<description>&lt;ul&gt;
&lt;li&gt;Los Angeles&lt;/li&gt;
&lt;li&gt;New York&lt;/li&gt;
&lt;li&gt;Atlanta&lt;/li&gt;
&lt;li&gt;Washington&lt;/li&gt;
 
&lt;/ul&gt;</description>
<pubDate>Thu, 17 Jun 2010 20:40:24 GMT</pubDate>
<guid isPermaLink="false">http://maps.google.com/maps?q=USA</guid>
<dc:date>2010-06-17T20:40:24Z</dc:date>
</item>
</channel>
</rss>

The links point to Google Maps as defaulted. Now let’s define a JNDI custom resource and let it
point to Microsoft’s Bing:

In the GlassFish Administration Console we choose Resources / JNDI / Custom Resources / New,


usecustom/url/template/geomap for the name, choose java.lang.String as resource type (the factory
class is filled automatically), and add one Additional Property via Add Property. For the property
name we usevalue and for the property value http://www.bing.com/maps/?where1=%s.
In our example the resources are not cached, they are looked up per invocation, thus when we
refresh the feed in the browser and display the source, we now get

<?xml version="1.0" encoding="UTF-8"?>


<rss xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0">
<channel>
<title>Cookbook Sample Feed</title>
<link>http://localhost:8084/cookbookServlets/Feed</link>
<description>This is a feed of available countries</description>
<item>
<title>Austria</title>
 
<description>&lt;ul&gt;
&lt;li&gt;Graz&lt;/li&gt;
&lt;li&gt;Wien&lt;/li&gt;
&lt;li&gt;Linz&lt;/li&gt;
&lt;li&gt;Salzburg&lt;/li&gt;
 
&lt;/ul&gt;</description>
<pubDate>Thu, 17 Jun 2010 20:57:51 GMT</pubDate>
<guid isPermaLink="false">http://www.bing.com/maps/?where1=Austria</guid>
<dc:date>2010-06-17T20:57:51Z</dc:date>
</item>
<item>
<title>Italy</title>
 
<description>&lt;ul&gt;
&lt;li&gt;Venezia&lt;/li&gt;
&lt;li&gt;Firenze&lt;/li&gt;
&lt;li&gt;Bologna&lt;/li&gt;
&lt;li&gt;Roma&lt;/li&gt;
 
&lt;/ul&gt;</description>
<pubDate>Thu, 17 Jun 2010 20:57:51 GMT</pubDate>
<guid isPermaLink="false">http://www.bing.com/maps/?where1=Italy</guid>
<dc:date>2010-06-17T20:57:51Z</dc:date>
</item>
<item>
<title>USA</title>
 
<description>&lt;ul&gt;
&lt;li&gt;Los Angeles&lt;/li&gt;
&lt;li&gt;Atlanta&lt;/li&gt;
&lt;li&gt;New York&lt;/li&gt;
&lt;li&gt;Washington&lt;/li&gt;
 
&lt;/ul&gt;</description>
<pubDate>Thu, 17 Jun 2010 20:57:51 GMT</pubDate>
<guid isPermaLink="false">http://www.bing.com/maps/?where1=USA</guid>
<dc:date>2010-06-17T20:57:51Z</dc:date>
</item>
</channel>
</rss>
Access via REST
[back to top]
You may find yourself in the situation of having to access your services from clients, that don’t
support SOAP or don’t support it fully. SOAP is a nice thing when you’ve got mature libraries to
handle the complexity. This is the case in Java and .NET, but it can get pretty nasty when you have
to take care of the protocol yourself. AJAX clients with nothing runnning but JavaScript come to
mind. In such scenarios we still want access via HTTP, which is universally available, and XML is a
good choice anyway, only without namespaces, schemas, WSDL and all that stuff please.

REST is the popular compromise between the total freedom (and tediousness) of free-form ad-hoc
protocols and the complex strictness of SOAP. Basically REST means
 XML via HTTP
 no client-specific state at the server, no sessions
 plain XML without namespaces or schema
In a strict sense REST uses the metaphor of RESOURCES that are fetched from the server (HTTP
GET), created (HTTP POST), updated (HTTP PUT) or deleted (HTTP DELETE). I don’t think this
strict sense is in any way useful for us. It places the semantics on a much too low level, basically
treating server resources as remote XML data only, putting all the burden on the client. That’s
nonsens, but due to the enigmatic name (“Representational State Transfer“! Cool, huh?

Management loves it almost as much as “SOA“) nobody so far has noticed 


Nevertheless, REST has some support in .NET and in Java, and an implementation of it is part of
the Java Enterprise Edition 6. We will abuse it to a have a cheap and uncomplicated way to
exchange XML data with clients that can’t do SOAP.

The REST servlet


[back to top]
One of the standardized technologies bundled with the Java Enterprise Edition 6 is  JAX-RS,
the JAVA API FOR RESTFUL WEB SERVICES, and in GlassFish it is Jersey, the reference
implementation, while JBoss will bundleRESTEasy.
While web services via SOAP (JAX-WS) are tightly integrated with GlassFish, even to the extent
where you can access any EJB via SOAP and don’t even have to create a servlet, support for REST
is not yet there. You have to bring your own servlet, but it’s easy enough to do so.
We have all our sevlets in cookbookServlets, thus we’re gonna add the REST servlet there as
well:

package com.manessinger.cookbook.service;
 
@javax.ws.rs.ApplicationPath("REST")
public class RESTServlet extends javax.ws.rs.core.Application {
}

That’s it. Simple and painless. Upon startup it searches the class path for REST annotated classes
and registers them. I suppose it searches only in its own package and below, but I have not tried.

The name of the class does not matter and we don’t need to add to the parent
classjavax.ws.rs.core.Application. With the annotation @ApplicationPath we specify
the second part of the URL under that the REST “resources” will be available. The first part of the
URL is (just as for the other servlets so far) equal to the project name. Thus everything that we
expose via REST will be available under the base URL

http://localhost:8084/cookbookServlets/REST/

The REST delegator


[back to top]
The REST servlet itself does nothing but looking for REST annotated classes and making them
available. Thus we need some annotations, and although we could annotate the EJBs directly, in
general we will need a layer in between. This layer will transform parameters when necessary, but
otherwise it simply delegates to an EJB. We call it the REST delegator.

package com.manessinger.cookbook.service;
 
import java.io.IOException;
import java.io.InputStream;
import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.interceptor.Interceptors;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import com.manessinger.cookbook.dto.DumpResult;
import com.manessinger.cookbook.dto.ZipDto;
import com.manessinger.cookbook.exception.EntityNotFoundException;
import com.manessinger.cookbook.exception.TransactionRollbackException;
import com.manessinger.cookbook.exception.ValidationException;
import com.manessinger.cookbook.util.ValidationInterceptor;
 
@Path("method")
@Stateless
public class RESTDelegator {
 
@EJB
private CookbookBean bean;
 
@GET
@Path("add/{a}/{b}")
@Consumes(MediaType.APPLICATION_XML)
@Produces(MediaType.TEXT_PLAIN)
public String add(@PathParam(value="a") int a, @PathParam(value="b") int b) {
Integer out = a + b;
return out.toString();
}
 
@GET
@Path("countryCount")
@Produces(MediaType.APPLICATION_XML)
public String countryCount() throws TransactionRollbackException {
return "<country_count>"+bean.countryCount()+"</country_count>";
}
 
@GET
@Path("dumpCountries")
@Produces(MediaType.APPLICATION_XML)
public DumpResult dumpCountries() throws TransactionRollbackException {
return new DumpResult(bean.dumpCountries());
}
 
@POST
@Path("storeZip")
@Consumes(MediaType.APPLICATION_XML)
@Produces(MediaType.APPLICATION_XML)
@Interceptors(ValidationInterceptor.class)
public ZipDto storeZip(ZipDto in)
throws EntityNotFoundException, TransactionRollbackException, ValidationException
{
return bean.storeZip(in);
}
 
@POST
@Path("inputStream")
@Consumes(MediaType.APPLICATION_OCTET_STREAM)
@Produces(MediaType.TEXT_PLAIN)
public String inputStream(InputStream is) throws IOException {
Long totalBytesReceived = 0L;
 
byte[] buffer = new byte[1000];
long bytesReceived = 0;
do {
totalBytesReceived += bytesReceived;
bytesReceived = is.read(buffer);
} while (bytesReceived != -1);
is.close();
 
return totalBytesReceived.toString();
}
}

We have made the delegator a stateless session bean, in order to get access to our service bean via
injection. The class is annotated with a @Path annotation. Think of it as a resource class, a way of
grouping the resources that the methods of this class will give access to. In our context this does not
make that much sense, thus I have simply called it method. It makes, you guess it, for the next part of
the URL. We can’t omit it, because the REST servlet searches for classes with a @Path annotation.
Leave it away and the REST annotations on the methods will never be seen.
I’ve included two test methods here, that don’t delegate down to an EJB, but that show some useful
tricks. The first is add(), and it shows two things: Firstly, you can access parameters, that are given
as part of the URL, so-called PATH PARAMETERS. Here we have two parameters a and b. The
method signature declares both as integer, and if we call the REST URL with anything in one of
these positions, that can’t be converted to integer, for instance with the character “x“, we simply get
an HTTP 404, “The resource is not available”. The second thing is, that we can return only one
single scalar type, and that is java.lang.String. When we want to return an Integer, we have
to convert it to a string and return that.
countryCount() demonstrates the other way to return a scalar. It produces the MIME type
“application/xml” (in the @Produces annotations I have used the constants supplied with JAX-
RS), XML is text, thus we again return a string, this time hand-crafted XML.
In dumpCountries() and storeZip() we return DTOs. The one
in dumpCountries(), DumpResult, is a wrapper type that we need, because JAX-RS can’t
implicitly serialize lists. This wrapper type is only needed for REST, thus we create a
package com.manessinger.cookbook.dto in cookbookServlets and put it there.
Complex types like DumpResult and ZipDto are automatically serialized behind the scenes, and
again it is JAXB that does the work. Thus we can influence the serialization result by annotating the
data types and their fields. In general we don’t need anything but a
single @XmlRootElement annotation on every type that is used as a top-level parameter. Here
is DumpResult:

package com.manessinger.cookbook.dto;
 
import java.util.List;
import javax.xml.bind.annotation.XmlRootElement;
 
@XmlRootElement(name="countries")
public class DumpResult {
 
public List<CountryDump> country;
 
public DumpResult() { }
 
public DumpResult(List<CountryDump> l) {
this.country = l;
}
}

ZipDto is also used as a parameter, thus we have to annotate it as well.

package com.manessinger.cookbook.dto;
 
import java.io.Serializable;
 
import javax.validation.constraints.Min;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;
import javax.xml.bind.annotation.XmlRootElement;
 
@XmlRootElement(name="zip")
public class ZipDto implements Serializable {
 
private static final long serialVersionUID = 1L;
 
private Integer id;
 
@Size(min=1, max=50)
private String name;
 
@Pattern(regexp="^(\\d{4,5}|\\d{5}-\\d{4})$")
private String code;
 
@Min(1)
private Integer countryId;
 
public void setId(Integer id) { this.id = id; }
public Integer getId() { return id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getCode() { return code; }
public void setCode(String code) { this.code = code; }
 
public Integer getCountryId() { return countryId; }
public void setCountryId(Integer countryId) { this.countryId = countryId; }
}

The default XML element name for a class is the class name. Here we have overridden it to simply
use zip.
If we ever forget to annotate a type that is used as a top-level parameter, for instance DumpResult,
then we get an error, and in the server log we’ll see, among tons of stack traces, the messages
SEVERE: A message body writer for Java type, class
com.manessinger.cookbook.dto.DumpResult,
and MIME media type, application/xml, was not found
SEVERE: Internal server error
javax.ws.rs.WebApplicationException
...

Regarding input parameters we see three variants:

 add() uses path parameters. We’ve already covered that.


 storeZip() uses XML supplied as content of a POST request, and due to the type of the
parameter in the message signature, and due to the fact, that this type is annotated
with @XmlRootElement, deserialization is automatic. No further annotations are needed.
 inputStream() is the second method, that I have added just for demonstration of a useful
feature, and that does not delegate to an EJB. Here the input is declared as
“application/octet-stream“, while the method parameter is a java.io.InputStream.
Again the mapping is automatic, and this can be used to realize a simple file upload mechanism.
In the example the stream is read and the number of bytes is returned as plain text.

Examples of HTTP traffic


[back to top]
Let me show you some HTTP traffic, that I have captured with soapUI:

add()

[back to top]

GET http://localhost:8084/cookbookServlets/REST/method/add/2/3 HTTP/1.1


Accept-Encoding: gzip,deflate
User-Agent: Jakarta Commons-HttpClient/3.1
Host: localhost:8084

HTTP/1.1 200 OK
X-Powered-By: Servlet/3.0
Server: GlassFish v3
Content-Type: text/plain
Transfer-Encoding: chunked
Date: Fri, 18 Jun 2010 12:28:41 GMT
 
5

countryCount()

[back to top]
GET http://localhost:8084/cookbookServlets/REST/method/countryCount HTTP/1.1
Accept-Encoding: gzip,deflate
User-Agent: Jakarta Commons-HttpClient/3.1
Host: localhost:8084

HTTP/1.1 200 OK
X-Powered-By: Servlet/3.0
Server: GlassFish v3
Content-Type: application/xml
Transfer-Encoding: chunked
Date: Fri, 18 Jun 2010 11:37:19 GMT
 
<country_count>3</country_count>

dumpCountries()

[back to top]

GET http://localhost:8084/cookbookServlets/REST/method/dumpCountries HTTP/1.1


Accept-Encoding: gzip,deflate
User-Agent: Jakarta Commons-HttpClient/3.1
Host: localhost:8084

HTTP/1.1 200 OK
X-Powered-By: Servlet/3.0
Server: GlassFish v3
Content-Type: application/xml
Content-Length: 474
Date: Fri, 18 Jun 2010 13:06:54 GMT
 
<countries>
<country>
<cities>Linz</cities>
<cities>Salzburg</cities>
<cities>Wien</cities>
<cities>Graz</cities>
<name>Austria</name>
</country>
<country>
<cities>Roma</cities>
<cities>Firenze</cities>
<cities>Bologna</cities>
<cities>Venezia</cities>
<name>Italy</name>
</country>
<country>
<cities>Los Angeles</cities>
<cities>New York</cities>
<cities>Atlanta</cities>
<cities>Washington</cities>
<name>USA</name>
</country>
</countries>

storeZip()

[back to top]
POST http://localhost:8084/cookbookServlets/REST/method/storeZip HTTP/1.1
Accept-Encoding: gzip,deflate
Content-Type: application/xml
User-Agent: Jakarta Commons-HttpClient/3.1
Host: localhost:8084
Content-Length: 102
 
<zip>
<code>9010</code>
<countryId>1</countryId>
<id>4</id>
<name>Klagenfurt</name>
</zip>

HTTP/1.1 200 OK
X-Powered-By: Servlet/3.0
Server: GlassFish v3
Content-Type: application/xml
Content-Length: 140
Date: Fri, 18 Jun 2010 13:08:45 GMT
 
<zip>
<code>9010</code>
<countryId>1</countryId>
<id>4</id>
<name>Klagenfurt</name>
</zip>

inputStream()

[back to top]

POST http://localhost:8084/cookbookServlets/REST/method/inputStream HTTP/1.1


Accept-Encoding: gzip,deflate
Content-Type: application/octet-stream
User-Agent: Jakarta Commons-HttpClient/3.1
Host: localhost:8084
Content-Length: 5
 
xxäxx

HTTP/1.1 200 OK
X-Powered-By: Servlet/3.0
Server: GlassFish v3
Content-Type: text/plain
Transfer-Encoding: chunked
Date: Fri, 18 Jun 2010 11:54:27 GMT
 
5

Please note that the server code simply counts bytes. On Windows 7 I get the result 5, while on
Xubuntu 10.4 at work I get 6 for the same input.
The reason is, that in Windows the default character set for soapUI (where I have created the input)
seems to be ISO-8859-1, while on Linux it is UTF-8. The third character is a german Umlaut, in UTF-
8 represented as a two-byte sequence, thus the number of bytes differs, depending on the system
where the client runs.

PostgreSQL as database backend


[back to top]
PostgreSQL is the most advanced and mature open source database on the market. To use it with
GlassFish v3, you need to download the JDBC4 driver and install it in either
GlassFish’s lib directory or the libdirectory of the GlassFish domain. On Unix a symbolic link is
sufficient. In Eclipse you have to make sure that it is in the build path of all projects, that access the
database directly, not via the application server. For us, this is only the test
project cookbookJUnitOutOfServer. You also have to add a database definition to Eclipse
(viaDatasource Explorer), in case you want to access the database from a SQL Scrapbook or simply
need to use JPA Tools / Generate Entities from Tables to generate entities.

Installing PostgreSQL and creating a database user


[back to top]
This is not even a weak attempt at providing an introduction to PostgreSQL, just some notes of what
I stumbled upon when I tried it.

When I did this at work, I simply asked our database administrators for a test database and got one
running on Linux, that I could only connect to via SSL. We run all our PostgreSQL database servers
like that. I tried to reproduce this here at home on Windows, it didn’t work initially, thus I decided to
ignore SSL, as it is not crucial to this tutorial.

When you install PostgreSQL on Windows, make sure that you run the installer as administrator. It
needs to install a service. Just accept all the defaults.

Note please, that you have to start/restart/stop the server as administrator as well. Navigate to the
menu entries in the PostgreSQL 8.4 program group, while being on the menu entry (for
exampleRestart Server), use the right mouse button and select Run as Administrator.

Immediately after the installation, without explicitly starting, the server is already running.
From Start / All Programs / PostgreSQL 8.4 / pgAdmin III you can start the PostgreSQL
administration utility. It has the familiar tree view, here called Object Browser, on the left side. At the
bottom there is something called Login Roles (for our purpose that’s users), with just one
entry postgres. From the context menu add a new login role called cookbookuser with
password cookbook. Now we’re ready to create the database.

Creating the database


[back to top]
In pgAdmin III, in the Object Browser, under Databases, you have just one database called postgres.
From the context menu of Databases choose New Database … and use the name cookbookdb. Now
you have a new, empty database. Select it, and that should make a button available in the toolbar,
the sixth from the left, a SQL editor with the tool tip Execute arbitrary SQL queries. Click it and the
editor opens.
Make sure that the title bar of the editor window says Query – cookbookdb on
postgres@localhost:5432. If not, if it reads Query – postgres on postgres@localhost:5432, you had
the wrong database selected. Close the editor, select database cookbookdb and open the editor
again.
There are two tabs in the editor, a SQL Editor and a Graphical Query Builder. We only need the SQL
editor, so make sure that’s selected, and then replace the current content with the following SQL
text:

-- Database: cookbookdb
 
-- remove comment when re-running script
-- DROP DATABASE cookbookdb;
 
CREATE DATABASE cookbookdb
WITH OWNER = cookbookuser
ENCODING = 'UTF8'
TABLESPACE = pg_default
LC_COLLATE = 'English, United States'
LC_CTYPE = 'English, United States'
CONNECTION LIMIT = -1;
 
CREATE SEQUENCE country_id_seq
START WITH 1
INCREMENT BY 1
NO MAXVALUE
NO MINVALUE
CACHE 1;
ALTER TABLE country_id_seq OWNER TO cookbookuser;
 
CREATE TABLE country (
id integer NOT NULL,
name character varying(10) NOT NULL
);
ALTER TABLE country OWNER TO cookbookuser;
ALTER TABLE ONLY country
ADD CONSTRAINT country_name_idx UNIQUE (name);
ALTER TABLE ONLY country
ADD CONSTRAINT country_pk PRIMARY KEY (id);
 
 
CREATE SEQUENCE city_id_seq
START WITH 1
INCREMENT BY 1
NO MAXVALUE
NO MINVALUE
CACHE 1;
ALTER TABLE city_id_seq OWNER TO cookbookuser;
 
CREATE TABLE city (
id integer NOT NULL,
country_id integer NOT NULL,
name character varying(30) NOT NULL
);
ALTER TABLE city OWNER TO cookbookuser;
ALTER TABLE ONLY city
ADD CONSTRAINT city_name_idx UNIQUE (name);
ALTER TABLE ONLY city
ADD CONSTRAINT city_pk PRIMARY KEY (id);
ALTER TABLE ONLY city
ADD CONSTRAINT city_country_fk FOREIGN KEY (country_id)
REFERENCES country(id) ON DELETE CASCADE;
 
 
CREATE SEQUENCE zip_id_seq
START WITH 1
INCREMENT BY 1
NO MAXVALUE
NO MINVALUE
CACHE 1;
ALTER TABLE zip_id_seq OWNER TO cookbookuser;
 
CREATE TABLE zip (
id integer NOT NULL,
country_id integer NOT NULL,
code character varying(20) NOT NULL,
name character varying(50) NOT NULL
);
ALTER TABLE zip OWNER TO cookbookuser;
ALTER TABLE ONLY zip
ADD CONSTRAINT zip_name_idx UNIQUE (name);
ALTER TABLE ONLY zip
ADD CONSTRAINT zip_pk PRIMARY KEY (id);
ALTER TABLE ONLY zip
ADD CONSTRAINT zip_country_fk FOREIGN KEY (country_id)
REFERENCES country(id) ON DELETE CASCADE;
 
 
INSERT INTO country (id, name) VALUES (NEXTVAL('country_id_seq'), 'Austria');
INSERT INTO country (id, name) VALUES (NEXTVAL('country_id_seq'), 'Italy');
INSERT INTO country (id, name) VALUES (NEXTVAL('country_id_seq'), 'USA');
 
 
INSERT INTO city (id, country_id, name)
VALUES (NEXTVAL('city_id_seq'), (SELECT id FROM country WHERE name = 'Austria'),
'Graz');
INSERT INTO city (id, country_id, name)
VALUES (NEXTVAL('city_id_seq'), (SELECT id FROM country WHERE name = 'Austria'),
'Linz');
INSERT INTO city (id, country_id, name)
VALUES (NEXTVAL('city_id_seq'), (SELECT id FROM country WHERE name = 'Austria'),
'Salzburg');
INSERT INTO city (id, country_id, name)
VALUES (NEXTVAL('city_id_seq'), (SELECT id FROM country WHERE name = 'Austria'),
'Wien');
 
INSERT INTO city (id, country_id, name)
VALUES (NEXTVAL('city_id_seq'), (SELECT id FROM country WHERE name = 'Italy'),
'Bologna');
INSERT INTO city (id, country_id, name)
VALUES (NEXTVAL('city_id_seq'), (SELECT id FROM country WHERE name = 'Italy'),
'Firenze');
INSERT INTO city (id, country_id, name)
VALUES (NEXTVAL('city_id_seq'), (SELECT id FROM country WHERE name = 'Italy'),
'Roma');
INSERT INTO city (id, country_id, name)
VALUES (NEXTVAL('city_id_seq'), (SELECT id FROM country WHERE name = 'Italy'),
'Venezia');
 
INSERT INTO city (id, country_id, name)
VALUES (NEXTVAL('city_id_seq'), (SELECT id FROM country WHERE name = 'USA'),
'Atlanta');
INSERT INTO city (id, country_id, name)
VALUES (NEXTVAL('city_id_seq'), (SELECT id FROM country WHERE name = 'USA'), 'Los
Angeles');
INSERT INTO city (id, country_id, name)
VALUES (NEXTVAL('city_id_seq'), (SELECT id FROM country WHERE name = 'USA'), 'New
York');
INSERT INTO city (id, country_id, name)
VALUES (NEXTVAL('city_id_seq'), (SELECT id FROM country WHERE name = 'USA'),
'Washington');
 
 
INSERT INTO zip (id, country_id, code, name)
VALUES (NEXTVAL('zip_id_seq'), (SELECT id FROM country WHERE name = 'Austria'),
'8054', 'Graz-Webling');
 
INSERT INTO zip (id, country_id, code, name)
VALUES (NEXTVAL('zip_id_seq'), (SELECT id FROM country WHERE name = 'Italy'),
'30124', 'Venezia');
 
INSERT INTO zip (id, country_id, code, name)
VALUES (NEXTVAL('zip_id_seq'), (SELECT id FROM country WHERE name = 'USA'),
'20001-6000', 'Metropolitan Washington Airports Authority');

In the Object Browser you can verify that it worked by looking at the tables under Databases /
cookbookdb / Schemas / public / Tables.

PostgreSQL connection pool in GlassFish


[back to top]
In GlassFish, using the GlassFish Administration Console web application, create a new connection
pool as usual via Resource / JDBC / Connection Pools / New.
dialog page field value
1 Name CookbookPoolPg
Resource Type javax.sql.ConnectionPoolDataSource
Database Vendor Postgresql
2 Ping Enabled
Additional Properties
DatabaseName cookbookdb
User cookbookuser
Password cookbook
ServerName localhost
PortNumber 5432
Ssl false

Instead of creating a new JDBC resource, we simply change the existing


resource jdbc/cookbookdb to point to the PostgreSQL datasource instead of the Derby datasource.

Definition of the datasource in Eclipse


[back to top]
In the Datasource Explorer we choose Database Connections / New to get to the New Connection
Profiledialog:

dialog field value


page
1 Connection Profile PostgreSQL
Type
Name CookbookPg Database
2 Drivers New Driver Definition > Jar List > Add JAR/Zip >
OK
Database cookbookdb
URL jdbc:postgresql:cookbookdb
User Name cookbookuser
Password cookbook

Entities
[back to top]
At this point our in-server test suite would already run, while for the out-of-server test suite we would
have to change the connection details in its copy of persistence.xml. Be aware though, that it
would only work, because we have no test case that inserts data. Inserting data requires values for
primary keys, and while Derby uses columns of type IDENTITY, in PostgreSQL we use values taken
from a sequence. Remember, in the generated entities we had

@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;

while in Oracle we had something like

@Id
@SequenceGenerator(name="CITY_ID_GENERATOR", sequenceName="CITY_ID_SEQ")
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="CITY_ID_GENERATOR")
private Long id;

Obviously we need different generated entities for different database types. It does not work to
generate entities into database-specific packages, because the generated entities have
an @Entity annotation without attributes, thus their internal reference name defaults to the class
name, and that’s also the default for the table name. Having different entities for e.g. table ZIP in
different packages (com.manessinger.cookbook.entity.derby and com.manessinger.cookbook.entity.pg)
does not help, because both would have the same (defaulted) entity name.
We have no way to specify entity name and table name in the code generator, but we could edit the
generated entities, changing the entity declarations from e.g.

@Entity
public class Zip extends com.manessinger.util.jpa.Entity implements Serializable {
...
}

to

@Entity(name="ZipPg")
@Table(name="ZIP")
public class Zip extends com.manessinger.util.jpa.Entity implements Serializable {
...
}
This is all a matter of how many tables you have, how often you expect to re-generate the entities
and how likely it is to have to support differnet databases for the same data.

In practice we would most likely not care. Database switches would occur rarely if at all in the
lifetime of a project, and having to support different database systems for the same data at the same
time would be extremely rare. Thus we would keep to our principle of never changing generated
code, and simply generate to com.manessinger.cookbook.entity, accepting to have to overwrite Derby
entities if we have to change to PostgreSQL or Oracle. No big deal.

Access to PostgreSQL via SSL


[back to top]
As I said, at work our PostgreSQL database servers are configured to only accept SSL connections.
No problem, that’s what the attribute Ssl is for. Just set it to true in the datasource definition in
GlassFish. If you happen to encounter an error where the JDBC driver refuses to connect to a server
whose SSL certificate it can’t verify, you have the problem, that your PostgreSQL server uses a self-
signed certificate. You can either add your certificate to the certificate store of the Java runtime you
use, or else tell the driver with an addditional property sslfactory with
value org.postgresql.ssl.NonValidatingFactory to not validate.
In the case of the GlassFish datasource you just define the additional property. In Eclipse you need
to add the property to the URL in the style of HTTP URL parameters. It would look like this:

jdbc:postgresql://host.domain.com:5432/cookbookdb?
ssl=true&sslfactory=org.postgresql.ssl.NonValidatingFactory

Mind please, that this URL has the character & in it as separator between parameters. If you use this
URL as value in an XML file (you’ll have to in the version of persistence.xml used for the out-of-
server tests), you have to encode that as character entity, otherwise it will be seen as the start of an
unterminated character entity, and the XML parser parsing persistence.xml will complain

The reference to entity "sslfactory" must end with the ';' delimiter

This will be embedded in a nice, fat stack trace 


Thus the persistence.xml of the out-of-server test project may look like this:

<?xml version="1.0" encoding="UTF-8"?>


<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
<persistence-unit name="cookbookEJB_junit">
<jta-data-source>jdbc/cookbookdb</jta-data-source>
<class>com.manessinger.cookbook.entity.City</class>
<class>com.manessinger.cookbook.entity.Country</class>
<class>com.manessinger.cookbook.entity.Zip</class>
<properties>
<property name="javax.persistence.jdbc.driver"
value="org.postgresql.Driver" />
<property name="javax.persistence.jdbc.url"
value="jdbc:postgresql:cookbookdb?
ssl=true&amp;sslfactory=org.postgresql.ssl.NonValidatingFactory" />
<property name="javax.persistence.jdbc.user"
value="cookbookuser" />
<property name="javax.persistence.jdbc.password"
value="cookbook" />
 
<property name="eclipselink.logging.level"
value="FINE" />
<property name="eclipselink.target-server"
value="com.manessinger.junit.JTATransactionController"/>
</properties>
</persistence-unit>
</persistence>

Conclusion
[back to top]
We have covered quite some terrain in this tutorial, although it is mainly focused on services. There
may be more to say, but I think that following these directions should give you a clean architecture
and a nice, uncomplicated start for a broad range of projects.

So far I have completely ignored user interfaces. At work we use rich clients implemented in Adobe
Flash, but of course Microsoft Silverlight or Java FX are equally suited as frontends, and so is
JavaScript/AJAX. Server-side frameworks like Java Server Faces (JSF) are another possibility, but
whatever client technology you prefer, I currently have no experience in it and certainly no patterns
to share.
Given my ulterior motive of serching for an integrated, muli-layered, pattern-centric approach to
model-driven application construction, it is clear though, that I will have to look into client

technologies at some time. Feel free to make suggestions 

This work, unless otherwise expressly stated, is licensed under a Creative Commons Attribution-
NonCommercial-ShareAlike 3.0 Unported License.
Posted by andreas at 1:33 pm

33 Responses to “An Eclipse / GlassFish / Java EE 6 Tutorial”

1.

Ken says:
July 25, 2010 at 1:04 am

Great tutorial! I have been looking for a JEE6 tutorial using Glassfish/Eclipse. Down to earth programmer to

programmer explanations, set up instructions, screenprints, real world. Can’t wait to try it. I wish I had a book just like

this!!!!

Reply

andreas says:
July 25, 2010 at 1:46 am

Thanks. Honestly, it’s been a lot of work as well 

Reply

2.
Julian says:
July 25, 2010 at 6:55 am

Thanks for your great tutorial!

Reply

3.

ali says:
August 6, 2010 at 12:57 pm

really a great tutorial. thanks a lot….. a good summary of EJB technology, integration and best tools… was just

searching that.

Reply

4.

ali says:
August 9, 2010 at 5:41 pm

I am now at “In-container testing”. All tests run correctly, but when running TestCookbookBean.dumpTest i am getting

exception at line

for (City city : country.getCities()){ }

in Conversion.java. There seems to be a problem fetching city entities of a coutry because of serialization.

Danke im Voraus…

Caused by: Exception [EclipseLink-7242] (Eclipse Persistence Services – 2.0.1.v20100213-r6600):

org.eclipse.persistence.exceptions.ValidationException

Exception Description: An attempt was made to traverse a relationship using indirection that had a null Session. This

often occurs when an entity with an uninstantiated LAZY relationship is serialized and that lazy relationship is

traversed after serialization. To avoid this issue, instantiate the LAZY relationship prior to serialization.

at

org.eclipse.persistence.exceptions.ValidationException.instantiatingValueholderWithNullSession(ValidationException.

java:979) …….
Reply

5.

ali says:
August 9, 2010 at 6:02 pm

i have solved my problem with lazy binding. When entities with relationships are serialized, with lazy field binding the

relationship field may be null. So here my solution is to add FetchType in Country.java as follows

@OneToMany(mappedBy=”country”, fetch=FetchType.EAGER)

private Set cities;

Reply

6.

Richard says:
August 11, 2010 at 4:38 am

Thanks Andreas!

This was definately one of the really good tutorials that I have worked through. I get frustrated with so many other

“tutorials” that just leave so much out. Often, they don’t have clear language and make way too many assumptions

about the reader and his/her environment, etc, etc…

Anyway, I got a lot from this tutorial. It was very clear, understandable, and well written.

-Richard

Reply

7.

FMora says:
August 12, 2010 at 4:56 pm
My compliments as well – I like it!

One detail – if you annotate a constraint with @NotNull and then insert a null value via SoapUI, one gets a NPE

instead of a constraint violation caused by

d.setInvalidItemValue(violation.getInvalidValue().toString());

in the ValidationInterceptor.

Reply

andreas says:
August 12, 2010 at 8:31 pm

Haha, thanks, that’s a good one 

Reply

8.

X. J. says:
August 13, 2010 at 9:59 pm

Could you recommend a good and hopefully not too expensive book on NetBeans that is very straight forward for a

new person. I used to use the JDK with the command prompt, but lately it can recognize Javac for some reason, ever

since my hard drived was cleaned out and I had to start over again.

Also, when I get good, I can also build e-commerce websites through NetBeans Right? Thank you for your time.

Reply

o
andreas says:
August 15, 2010 at 10:50 am

Sorry, I’ve no idea. I’ve never used NetBeans and I almost never use programming books 

Reply

9.

fadi says:
August 21, 2010 at 6:15 pm

you don’t need a book to learn netbeans, use google. Nebeans now doesn’t have a visual designer unless you use

an older version of netbeans with ICEfaces, if you want a visual designer then i think eclipse offers it.

Reply

10.

jame chang says:
August 26, 2010 at 1:16 am

This is an outstanding article to read so I don’t want to miss it by failing to try some features you gave. I fired asadmin

as you said in your article on pg 24 but got following error: (PATH is being resolved point to ..jre6\bin and

glassfish\bin) don’t know why asadim just don’t function properly.

– James

C:\Documents and Settings\james.chang>asadmin

Exception in thread “main” java.lang.UnsupportedClassVersionError: com/sun/enter

prise/admin/cli/AsadminMain (Unsupported major.minor version 49.0)

at java.lang.ClassLoader.defineClass0(Native Method)

at java.lang.ClassLoader.defineClass(ClassLoader.java:537)

at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:12

3)

at java.net.URLClassLoader.defineClass(URLClassLoader.java:251)
at java.net.URLClassLoader.access$100(URLClassLoader.java:55)

at java.net.URLClassLoader$1.run(URLClassLoader.java:194)

at java.security.AccessController.doPrivileged(Native Method)

at java.net.URLClassLoader.findClass(URLClassLoader.java:187)

at java.lang.ClassLoader.loadClass(ClassLoader.java:289)

at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:274)

at java.lang.ClassLoader.loadClass(ClassLoader.java:235)

at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:302)

Reply

andreas says:
August 26, 2010 at 9:33 am

I can’t try it right now, but I’ll look into it. It’ll take me one or two days though.

Reply

jame chang says:
August 26, 2010 at 7:18 pm

Gogeous! I had been on this much more than one or two days plus agonized.

Reply

andreas says:
August 27, 2010 at 11:04 am

Sorry, I can’t reproduce your problem. I just started a “cmd.exe”, changed directory to “C:\GlassFish-Tools-

Bundle-For-Eclipse-1.2\glassfishv3\glassfish\bin” (that’s where I’ve installed the bundle), and when I call

“asadmin” like
C:\GlassFish-Tools-Bundle-For-Eclipse-1.2\glassfishv3\glassfish\bin>asadmin --port

4860 --user admin list-jdbc-resources

jdbc/__TimerPool

jdbc/__default

jdbc/cookbookdb

jdbc/xa_test_derby

jdbc/xa_test_pg

Command list-jdbc-resources executed successfully.

it just works. Now when I change to my home directory and call

C:\Users\Andreas>C:\GlassFish-Tools-Bundle-For-Eclipse-

1.2\glassfishv3\glassfish\bin\asadmin.bat --port 4860 --user admin list-jdbc-

resources

jdbc/__TimerPool

jdbc/__default

jdbc/cookbookdb

jdbc/xa_test_derby

jdbc/xa_test_pg
Command list-jdbc-resources executed successfully.

it works as well. I have not set any special environment variables either:

C:\Users\Andreas>set

ALLUSERSPROFILE=C:\ProgramData

APPDATA=C:\Users\Andreas\AppData\Roaming

CommonProgramFiles=C:\Program Files\Common Files

CommonProgramFiles(x86)=C:\Program Files (x86)\Common Files

CommonProgramW6432=C:\Program Files\Common Files

COMPUTERNAME=TRAINSCHNUCKE

ComSpec=C:\Windows\system32\cmd.exe

FP_NO_HOST_CHECK=NO

HOMEDRIVE=C:

HOMEPATH=\Users\Andreas

LOCALAPPDATA=C:\Users\Andreas\AppData\Local

LOGONSERVER=\\TRAINSCHNUCKE

NUMBER_OF_PROCESSORS=2
OS=Windows_NT

Path=C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\Wi

ndowsPowerShell\v1.0\

PATHEXT=.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC

PROCESSOR_ARCHITECTURE=AMD64

PROCESSOR_IDENTIFIER=Intel64 Family 6 Model 23 Stepping 6, GenuineIntel

PROCESSOR_LEVEL=6

PROCESSOR_REVISION=1706

ProgramData=C:\ProgramData

ProgramFiles=C:\Program Files

ProgramFiles(x86)=C:\Program Files (x86)

ProgramW6432=C:\Program Files

PROMPT=$P$G

PSModulePath=C:\Windows\system32\WindowsPowerShell\v1.0\Modules\

PUBLIC=C:\Users\Public

SESSIONNAME=Console

SystemDrive=C:

SystemRoot=C:\Windows
TEMP=C:\Users\Andreas\AppData\Local\Temp

TMP=C:\Users\Andreas\AppData\Local\Temp

USERDOMAIN=Trainschnucke

USERNAME=Andreas

USERPROFILE=C:\Users\Andreas

VBOX_INSTALL_PATH=C:\Program Files\Oracle\VirtualBox\

windir=C:\Windows

My Java is:

C:\Users\Andreas>java -version

java version "1.6.0_21"

Java(TM) SE Runtime Environment (build 1.6.0_21-b06)

Java HotSpot(TM) 64-Bit Server VM (build 17.0-b16, mixed mode)

The operating system is an up-to-date Windows 7 64 bit on a Sony VAIO Z21 laptop with 4GB memory. Sorry,

I’m afraid I can’t give you a better recommendation than to try it with exactly my setup, i.e. use theGlassFish

Tools Bundle for Eclipse 1.2 from December 17.


Reply

jame chang says:
September 7, 2010 at 11:47 pm
Hi Andreas, Thank you for your detailed reply. It must took you some time and I appreciate. I checked by

using java -version and amazingly found mine is:

C:\Program Files\Java\jdk1.6.0_21>java -version

java version “1.4.2_03″

Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.2_03-b02)

Java HotSpot(TM) Client VM (build 1.4.2_03-b02, mixed mode)

Although I download the java se from the most recent oracle published site, you can see it easily from my

prompt. Don’t know why this happened?

Reply

andreas says:
September 15, 2010 at 5:36 am

Sorry for the late reply. That can only be an issue with your path variable. Hmm … 1.4.2, wow, that’s

pretty ancient 

Reply

11.

JohnE says:
September 6, 2010 at 6:09 pm

Just excelent!

we use this tools and methods here on our company, i think this is a great tutorial for beginers and a it has a couple

of good tips for advanced users as well.

this is an excelente material for starting a book, i will buy it 


again, thanks a lot.

Reply

12.

Justin Theiss says:
September 10, 2010 at 5:39 pm

Fanatastic Tutorial! I would like to pose a question to author and the general audience.

When trying to run Out-of-container testing, I’m getting an exception as follows:

“javax.persistence.PersistenceException: No Persistence provider for EntityManager named cookbookEJB_junitat…”

(rest of the stack trace on demand)

My “copied” persistence per the iinstructions can be found below.

Please note that I also tried adding a persistence provider:

org.eclipse.persistence.jpa.PersistenceProvider

This also did not help.

persistence.xml———————————————————-

jdbc/cookbookdb

com.jtheiss.cookbook.entity.City

com.jtheiss.cookbook.entity.Country

Reply

Justin Theiss says:
September 10, 2010 at 5:55 pm
<?xml version="1.0" encoding="UTF-8"?>

<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://java.sun.com/xml/ns/persistence

http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">

<persistence-unit name="cookbookEJB_junit">

<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>

<jta-data-source>jdbc/cookbookdb</jta-data-source>

<class>com.jtheiss.cookbook.entity.City</class>

<class>com.jtheiss.cookbook.entity.Country</class>

<properties>

<property name="javax.persistence.jdbc.driver"

value="org.apache.derby.jdbc.ClientDriver" />

<property name="javax.persistence.jdbc.url"

value="jdbc:derby://localhost:1527/cookbookdb;create=true" />

<property name="javax.persistence.jdbc.user"

value="cookbookuser" />

<property name="javax.persistence.jdbc.password"

value="cookbook" />

<property name="eclipselink.logging.level"

value="FINE" />

<property name="eclipselink.target-server"

value="com.jtheiss.junit.JTATransactionController"/>

</properties>

</persistence-unit>

</persistence>

Reply

o
andreas says:
September 15, 2010 at 5:42 am

Hmm … no idea. Are you sure you’ve added the GlassFish server runtime (Add Library / Server Runtime /

GlassFish v3 Java EE6) to your build path? What software do you use?

Reply

Jochen says:
November 23, 2010 at 6:49 pm

Make sure you copy the entire META-INF folder from cookbookEJB/ejbModule/ and then adjust the

persistence.xml accordingly. Make sure your database is running (I needed to restart it manually). Then it

worked.

PS: Great tutorial 

Reply

13.

Mohammed Al-Takrity says:
September 18, 2010 at 6:40 pm

An excellent tutorial! Hervorragend   !

Reply

andreas says:
September 18, 2010 at 8:24 pm
Much appreciated. Herzlichen Dank 

Reply

14.

Alex Sánchez says:
September 23, 2010 at 12:34 am

Hi there! Thank you so much for the tutorial. It’s been really helpful, ‘cos I’ve just started programming in Java.

However, when I tried to open the Database Development Perspective I just couldn’t find it. I’ve googled the problem

and didn’t find any solution.

My Glassfish server is up & running, I’ve got the Java EE perspective open.

I’ve looked everywhere and couldn’t find it.

Any suggestions?

Reply

15.

Alex Sánchez says:
September 23, 2010 at 12:56 am

I forgot to add:

I’ve got JDK 1.6.0_16, Eclipse 3.6, Glassfish 3.0.1, and I’ve downloaded the Glassfish Plugin for Eclipse today (Sept

22nd).

I’d really thank any help…

Reply

16.
Alex Sánchez says:
September 23, 2010 at 6:08 pm

Found the problem! I needed the DTP! I thought I’d installed it but obviously I didn’t.

I’ll go on with the rest of your tutorial now.

Thanks!

Reply

17.

David Hájek says:
October 23, 2010 at 4:34 pm

Hi,

I’m going crazy. To the point where it should gave me exception “java.sql.SQLSyntaxErrorException: Table/View

‘COUNTRY’ does not exist.” it just worked. But as I configured JPA to use the cookbookdb,

CookbookBean.countryCount() method started giving me this exception:

WARNING: A system exception occurred during an invocation on EJB CookbookBean method

public long com.manessinger.cookbook.service.CookbookBean.countryCount()

javax.ejb.EJBTransactionRolledbackException

... lines omitted ...

Caused by: Exception [EclipseLink-4002] (Eclipse Persistence Services -

2.0.1.v20100213-r6600): org.eclipse.persistence.exceptions.DatabaseException

Internal Exception: java.sql.SQLSyntaxErrorException: Schema 'COOKBOOKUSER' does not

exist

Error Code: -1

Call: SELECT COUNT(ID) FROM COUNTRY

... lines omitted ...

Everything’s set up as in the tutorial, I can query the DB by hand, GlassFish can ping it, COOKBOKUSER schema is

present in the DB, but I still get this error. I trid to google for some suggestions, but no luck so far. I have no idea

what’s wrong.

Some suggestion please? I really want to finish this tutorial, it’s a good read…
Thanks

David

Reply

David Hájek says:
October 23, 2010 at 4:58 pm

Whooo, some bad settings. I just recreated the database, restarted GlassFish and it works… geez. Let’s go on

then.

Reply

18.

Gord says:
October 31, 2010 at 6:30 pm

This was an amazing tutorial – thanks for it. I went through it over the course of several evenings and I now feel ready

to re-architect my project so it’s not a hacky blob of JEE code. Thanks again for all this work!

Reply

andreas says:
October 31, 2010 at 9:38 pm

Gord, thanks for the flowers, very appreciated.

The pattern as I have described it is solid, but you tend to get tangled in DTOs and converters. The bigger your

application, the worse it scales. That’s the reason why I currently write a code generator. I analyze entities and

from there I can generate basic DTOs, basic services, converters and maybe more. Stay tuned
Reply

19.

Ram says:
November 22, 2010 at 11:33 pm

Thank you so much for such a detailed tutorial. Great work!

Reply

Leave a Reply

Name (required)

E-mail (required)

URI

Your Comment

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym
title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q
cite=""> <strike> <strong> <pre lang="" line="" escaped="">
Submit Comment
Notify me of followup comments via e-mail

Follow Me

NEWS

This is a totally new blog, so everything is new here, right?

Archives

     

Categories

       

Tags

Analysis Atom Code Generators Code ReuseConfiguration Corba/IIOP Derby Design


Patterns Distributed ComputingEclipse GlassFish v3 History HTTP Headers In-Server

TestingInterceptors Java Java Enterprise

Edition JNDI JPA JUnit Language Market Model Driven Design Operating System OracleOut-of-Server


Testing Pattern LanguagesPersistence PostgreSQL Programming
Languages REST ROME RPCmagiX RSS ServiceSOA SOAP SoapUI Software Engineering Syndicated Feed Time Unit
Test WADL Web Service Windows 7

1 - Links

 My Daily Photo Blog


 SKORKS

© 2010 Andreas Manessinger

Você também pode gostar