This exercise will step through a few issues that can be encountered while developing a more rich Web/EJB interface.
We will want to add a use case to the Web UI that allows us to
The RMI Test has already been testing getPeopleByName() and now we want to add a simple getAllPeople that takes indexing and count properties that could be used in a paging function. We don't need to worry about hydrating at this point because we only want the core person properties.
$ cat ./javaeeExEJB/src/main/java/myorg/javaeeex/ejb/RegistrarRemote.java
@Remote
public interface RegistrarRemote {
...
Collection<Person> getAllPeople(int index, int count)
throws RegistrarException;$ cat javaeeExEJB/src/main/java/myorg/javaeeex/ejb/RegistrarEJB.java
...
public Collection<Person> getAllPeople(int index, int count)
throws RegistrarException {
log.debug(String.format("*** getAllPeople(index=%d, count=%d) ***", index, count));
try {
return registrar.getAllPeople(index, count);
}
catch (Throwable ex) {
log.error(ex);
throw new RegistrarException(ex.toString());
}
}$ cat javaeeExTest/src/test/java/myorg/javaeeex/ejbclient/RegistrarIT.java
...
@Test
public void testWebUseCase() throws Exception {
log.info("*** testWebUserCase ***");
final int PAGE_SIZE=24;
final int PAGES=4;
final int TOTAL = PAGES*PAGE_SIZE;
for(int i=0; i<TOTAL; i++) {
Person person = makePerson();
person.setFirstName("first" + i);
person.setLastName("last" + i);
registrar.createPerson(person);
}
int index = 0;
int count = 0;
int pages = 0;
int loops = 0;
Collection<Person> people = null;
do {
people = registrar.getAllPeople(index, PAGE_SIZE);
pages = (!people.isEmpty()) ? pages + 1 : pages;
count += people.size();
index += people.size();
loops += 1;
} while (!people.isEmpty() && loops <= PAGES + 1);
assertEquals("unexpected # of pages", PAGES, pages);
assertEquals("unexpected number of people", TOTAL, count);
}$ mvn clean install -rf :javaeeExEJB ... -*** testWebUserCase *** Tests run: 6, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 7.466 sec Results : Tests run: 6, Failures: 0, Errors: 0, Skipped: 0 ... [INFO] Java EE Exercise EJB .............................. SUCCESS [5.481s] [INFO] Java EE Exercise WAR .............................. SUCCESS [2.841s] [INFO] Java EE Exercise EAR .............................. SUCCESS [1.530s] [INFO] Java EE Exercise Remote Test ...................... SUCCESS [25.191s] [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS
$cat javaeeExTest/src/test/java/myorg/javaeeex/ejbclient/RegistrarIT.java
loops += 1;
for (Person person : people) {
log.debug(String.format("person: (%d) %s %s",
person.getId(), person.getFirstName(), person.getLastName()));
}
} while (!people.isEmpty() && loops <= PAGES + 1);$ mvn clean install -rf :javaeeExEJB ... -testUtil.resetAll() complete -*** testWebUserCase *** -person: (1) first0 last0 -person: (2) first1 last1 -person: (3) first2 last2 ... -person: (93) first92 last92 -person: (94) first93 last93 -person: (95) first94 last94 -person: (96) first95 last95 Tests run: 6, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 1.421 sec
$ cat javaeeExTest/src/test/java/myorg/javaeeex/ejbclient/RegistrarIT.java
...
log.debug("people=" + people);
} while (!people.isEmpty() && loops <= PAGES + 1); -person: (24) first23 last23 Tests run: 6, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 3.359 sec <<< FAILURE! Results : Tests in error: testWebUseCase(myorg.javaeeex.ejbclient.RegistrarIT): failed to lazily initialize a collection of role: myorg.javaeeex.bo.Person.addresses, no session or session was closed Tests run: 6, Failures: 0, Errors: 1, Skipped: 0 ... [INFO] Java EE Exercise EJB .............................. SUCCESS [6.483s] [INFO] Java EE Exercise WAR .............................. SUCCESS [2.300s] [INFO] Java EE Exercise EAR .............................. SUCCESS [1.392s] [INFO] Java EE Exercise Remote Test ...................... FAILURE [12.783s] [INFO] ------------------------------------------------------------------------ [INFO] BUILD FAILURE
./javaeeExTest/target/failsafe-reports/myorg.javaeeex.ejbclient.RegistrarIT.txt
-------------------------------------------------------------------------------
Test set: myorg.javaeeex.ejbclient.RegistrarIT
-------------------------------------------------------------------------------
Tests run: 6, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 3.359 sec <<< FAILURE!
testWebUseCase(myorg.javaeeex.ejbclient.RegistrarIT) Time elapsed: 0.98 sec <<< ERROR!
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: myorg.javaeeex.bo.Person.addresses, no session or session
was closed
at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:393)
...
at org.hibernate.collection.internal.PersistentBag.iterator(PersistentBag.java:266)
at myorg.javaeeex.bo.Person.toString(Person.java:55)
at java.lang.String.valueOf(String.java:2838)
...
at java.lang.StringBuilder.append(StringBuilder.java:132)
at myorg.javaeeex.ejbclient.RegistrarIT.testWebUseCase(RegistrarIT.java:215)$ cat ./javaeeExEJB/src/main/java/myorg/javaeeex/ejb/RegistrarRemote.java
...
@Remote
public interface RegistrarRemote {
...
Collection<Person> getAllPeople(int index, int count)
throws RegistrarException;
Collection<Person> getAllPeopleHydrated(int index, int count)
throws RegistrarException;$ cat javaeeExEJB/src/main/java/myorg/javaeeex/ejb/RegistrarEJB.java
...
@Stateless
public class RegistrarEJB implements RegistrarLocal, RegistrarRemote {
...
public Collection<Person> getAllPeopleHydrated(int index, int count)
throws RegistrarException {
log.debug(String.format("*** getAllPeopleHydrated(index=%d, count=%d) ***", index, count));
try {
Collection<Person> people = registrar.getAllPeople(index, count);
for (Person person : people) {
hydratePerson(person);
}
return people;
}
catch (Throwable ex) {
log.error(ex);
throw new RegistrarException(ex.toString());
}
}$ cat javaeeExTest/src/test/java/myorg/javaeeex/ejbclient/RegistrarIT.java
...
do {
people = registrar.getAllPeopleHydrated(index, PAGE_SIZE);$ mvn clean install -rf :javaeeExEJB
...
-person: (96) first95 last95
-people=[id=73:first72 last72 123, addresses={{street1 city1, state1 zip1},}, id=74:first73 last73 123, addresses={{str
...
1, state1 zip1},}, id=94:first93 last93 123, addresses={{street1 city1, state1 zip1},}, id=95:first94 last94 123, addres
ses={{street1 city1, state1 zip1},}, id=96:first95 last95 123, addresses={{street1 city1, state1 zip1},}]
-people=[]
-person: (1) first0 last0
-address: (1) street1 city1, state1 zip1
-person: (1) first0 last0
-address: (97) street12 city12, state12 zip12
Tests run: 6, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 6.504 sec
Results :
Tests run: 6, Failures: 0, Errors: 0, Skipped: 0
...
[INFO] Java EE Exercise EJB .............................. SUCCESS [5.259s]
[INFO] Java EE Exercise WAR .............................. SUCCESS [2.834s]
[INFO] Java EE Exercise EAR .............................. SUCCESS [1.138s]
[INFO] Java EE Exercise Remote Test ...................... SUCCESS [24.765s]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS$ cat javaeeExTest/src/test/java/myorg/javaeeex/ejbclient/RegistrarIT.java
...
assertEquals("unexpected number of people", TOTAL, count);
//view a specific user
long id = registrar.getAllPeople(0, PAGE_SIZE).iterator().next().getId();
Person person = registrar.getPersonById(id);
log.debug(String.format("person: (%d) %s %s",
person.getId(), person.getFirstName(), person.getLastName()));
Address address = person.getAddresses().iterator().next();
log.debug(String.format("address: (%d) %s %s, %s %s",
address.getId(),
address.getStreet(),
address.getCity(), address.getState(), address.getZip()));$ mvn clean install -rf :javaeeExTest ... Tests run: 6, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 1.437 sec FAILURE! Results : Tests in error: testWebUseCase(myorg.javaeeex.ejbclient.RegistrarIT): failed to lazily initialize a collection of role: myorg.javaeeex.bo.Person.addresses, no session or session was closed Tests run: 6, Failures: 0, Errors: 1, Skipped: 0 [INFO] ------------------------------------------------------------------------ [ERROR] BUILD FAILURE [INFO] ------------------------------------------------------------------------ [INFO] There are test failures.
./javaeeExTest/target/failsafe-reports/myorg.javaeeex.ejbclient.RegistrarIT.txt
::::::::::::::
-------------------------------------------------------------------------------
Test set: myorg.javaeeex.ejbclient.RegistrarIT
-------------------------------------------------------------------------------
Tests run: 6, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 3.356 sec <<< FAILURE!
testWebUseCase(myorg.javaeeex.ejbclient.RegistrarIT) Time elapsed: 1.111 sec <<< ERROR!
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: myorg.javaeeex.bo.Person.addresses, no session or session
was closed
at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:393)
...
at org.hibernate.collection.internal.PersistentBag.iterator(PersistentBag.java:266)
at myorg.javaeeex.ejbclient.RegistrarIT.testWebUseCase(RegistrarIT.java:226)
$ cat javaeeExEJB/src/main/java/myorg/javaeeex/ejb/RegistrarRemote.java
@Remote
public interface RegistrarRemote {
...
Person getPersonById(long id)
throws RegistrarException;
Person getPersonByIdHydrated(long id)
throws RegistrarException;$cat ./javaeeExEJB/src/main/java/myorg/javaeeex/ejb/RegistrarEJB.java
...
public Person getPersonByIdHydrated(long id) throws RegistrarException {
log.debug("*** getPersonByIdHydrated() ***");
try {
Person person = registrar.getPersonById(id);
hydratePerson(person);
return person;
}
catch (Throwable ex) {
log.error(ex);
throw new RegistrarException(ex.toString());
}
}$ cat javaeeExTest/src/test/java/myorg/javaeeex/ejbclient/RegistrarIT.java
...
//view a specific user
long id = registrar.getAllPeople(0, PAGE_SIZE).iterator().next().getId();
Person person = registrar.getPersonByIdHydrated(id);$ mvn clean install -rf :javaeeExEJB ... -person: (1) first0 last0 -address: (1) street1 city1, state1 zip1 Tests run: 6, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 6.501 sec Results : Tests run: 6, Failures: 0, Errors: 0, Skipped: 0 ... [INFO] Java EE Exercise EJB .............................. SUCCESS [4.890s] [INFO] Java EE Exercise WAR .............................. SUCCESS [2.655s] [INFO] Java EE Exercise EAR .............................. SUCCESS [1.114s] [INFO] Java EE Exercise Remote Test ...................... SUCCESS [24.296s] [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS
$ cat javaeeExEJB/src/main/java/myorg/javaeeex/ejb/RegistrarRemote.java
...
import myorg.javaeeex.bo.Address;
@Remote
public interface RegistrarRemote {
...
Person getPersonById(long id)
throws RegistrarException;
Person getPersonByIdHydrated(long id)
throws RegistrarException;
Person changeAddress(Person person, Address address)
throws RegistrarException;$ cat javaeeExEJB/src/main/java/myorg/javaeeex/ejb/RegistrarEJB.java
...
@Stateless
public class RegistrarEJB implements RegistrarLocal, RegistrarRemote {
...
public Person changeAddress(Person person, Address address)
throws RegistrarException {
log.debug("*** changeAddress() ***");
try {
return registrar.changeAddress(person, address);
}
catch (Throwable ex) {
log.error(ex);
throw new RegistrarException(ex.toString());
}
}$ cat javaeeExTest/src/test/java/myorg/javaeeex/ejbclient/RegistrarIT.java
...
//update the address of a specific user
Address address2 = new Address();
address2.setStreet(address.getStreet() + 2);
address2.setCity(address.getCity() + 2);
address2.setState(address.getState() + 2);
address2.setZip(address.getZip() + 2);
Person p3 = registrar.changeAddress(person, address2);
Address a3 = p3.getAddresses().iterator().next();
assertEquals("unexpected street" , address2.getStreet(), a3.getStreet());
assertEquals("unexpected city" , address2.getCity(), a3.getCity());
assertEquals("unexpected state" , address2.getState(), a3.getState());
assertEquals("unexpected zip" , address2.getZip(), a3.getZip());$ cat javaeeExTest/src/test/java/myorg/javaeeex/ejbclient/RegistrarIT.java
...
//view user again
person = registrar.getPersonByIdHydrated(id);
log.debug(String.format("person: (%d) %s %s",
person.getId(), person.getFirstName(), person.getLastName()));
address = person.getAddresses().iterator().next();
log.debug(String.format("address: (%d) %s %s, %s %s",
address.getId(),
address.getStreet(),
address.getCity(), address.getState(), address.getZip()));-person: (1) first0 last0 -address: (1) street1 city1, state1 zip1 -person: (1) first0 last0 -address: (97) street12 city12, state12 zip12 Tests run: 6, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 1.313 sec Results : Tests run: 6, Failures: 0, Errors: 0, Skipped: 0 ... [INFO] Java EE Exercise EJB .............................. SUCCESS [5.834s] [INFO] Java EE Exercise WAR .............................. SUCCESS [2.136s] [INFO] Java EE Exercise EAR .............................. SUCCESS [1.946s] [INFO] Java EE Exercise Remote Test ...................... SUCCESS [13.410s] [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS
We now are at a point where we now have new methods needed by the web-tier that have been tested by the RMI integration tests.
We will start the transition into the WAR using the remote interface of the EJB. This will allow us to implement most of the initial implementation within the client-side Jetty framework.
$ cat javaeeExWAR/src/main/java/myorg/javaeeex/web/RegistrarHandlerServlet.java
...
private abstract class Handler {
...
protected static final String INDEX_PARAM = "index";
protected static final String COUNT_PARAM = "count";
...
public abstract void doHandle(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException, Exception;
...$ cat javaeeExWAR/src/main/java/myorg/javaeeex/web/RegistrarHandlerServlet.java
...
import java.util.Collection;
...
import myorg.javaeeex.bo.Person;
...
private class GetAllPeople extends Handler {
public void doHandle(HttpServletRequest request,
HttpServletResponse response)
throws Exception {
action = "EJB.getAllPeople"; //describe action in case of exception
String indexStr = (String)request.getParameter(INDEX_PARAM);
String countStr = (String)request.getParameter(COUNT_PARAM);
int index = Integer.parseInt(indexStr);
int count = Integer.parseInt(countStr);
Collection<Person> people = registrar.getAllPeopleHydrated(index, count);
request.setAttribute(RESULT_PARAM, people);
RequestDispatcher rd =
getServletContext().getRequestDispatcher(DISPLAY_RESULT_URL);
rd.forward(request, response);
}
}$ cat javaeeExWAR/src/main/java/myorg/javaeeex/web/RegistrarHandlerServlet.java
...
public class RegistrarHandlerServlet extends HttpServlet {
...
public static final String GET_ALL_PEOPLE_COMMAND = "Get All People";
...
public void init() throws ServletException {
...
if (ADMIN_TYPE.equals(handlerType)) {
handlers.put(GET_ALL_PEOPLE_COMMAND, new GetAllPeople());
}
...$ mkdir -p javaeeExWAR/src/main/webapp/admin
$ cat javaeeExWAR/src/main/webapp/admin/admin_menu.jsp
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>JavaEE Exercise Admin Menu</title>
</head>
<body>
<h2>Hello JavaEE Admin User</h2>
<ul>
<li><a href="../model/admin/handler?command=Get+All+People&index=0&count=10">Get All People</a></li>
</ul>
</body>
</html>$ cat javaeeExWAR/src/main/webapp/index.jsp
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>JavaEE Exercise Main Page</title>
</head>
<body>
<h2>Hello JavaEE Controller</h2>
<ul>
<li><a href="model/admin/handler">invoke servlet</a></li>
<li><a href="model/admin/handler?command=Ping">invoke admin EJB.ping()</a></li>
<li><a href="model/handler?command=Ping">invoke anonymous EJB.ping()</a></li>
<li><a href="admin/admin-menu.jsp">Admin</a></li>
</ul>
</body>
</html>$ mvn clean integration-test -rf :javaeeExTest)
$ (cd javaeeExWAR; mvn clean jetty:run)
HTTP ERROR: 404 NOT_FOUND RequestURI=/javaeeExWAR/admin/admin-menu.jsp Powered by Jetty://
<li><a href="admin/admin_menu.jsp">Admin</a></li>
Hello JavaEE Admin User
* Get All People -error in EJB.getAllPeople
java.lang.reflect.UndeclaredThrowableException
at $Proxy16.getAllPeopleHydrated(Unknown Source)
at myorg.javaeeex.web.RegistrarHandlerServlet$GetAllPeople.doHandle(RegistrarHandlerServlet.java:186)
at myorg.javaeeex.web.RegistrarHandlerServlet$Handler.handle(RegistrarHandlerServlet.java:145)
at myorg.javaeeex.web.RegistrarHandlerServlet.doGet(RegistrarHandlerServlet.java:98)
...
at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:582)
Caused by: java.lang.ClassNotFoundException: org.hibernate.collection.internal.PersistentBag$ cat javaeeExWAR/pom.xml
<plugins>
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>maven-jetty-plugin</artifactId>
<dependencies>
...
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>${hibernate-entitymanager.version}</version>
</dependency>$ (cd javaeeExWAR; mvn clean jetty:run)
Result: [id=1:first0 last0 123, addresses={{street12 city12, state12 zip12},}, id=2:first1 last1 123, addresses={{street1 city1, state1 zip1},}, id=3:first2 last2 123, addresses={{street1 city1, state1 zip1},}, id=4:first3 last3 123, addresses={{street1 city1, state1 zip1},}, id=5:first4 last4 123, addresses={{street1 city1, state1 zip1},}, id=6:first5 last5 123, addresses={{street1 city1, state1 zip1},}, id=7:first6 last6 123, addresses={{street1 city1, state1 zip1},}, id=8:first7 last7 123, addresses={{street1 city1, state1 zip1},}, id=9:first8 last8 123, addresses={{street1 city1, state1 zip1},}, id=10:first9 last9 123, addresses={{street1 city1, state1 zip1},}]
Go to Main Page $ cat javaeeExWAR/src/main/webapp/WEB-INF/content/DisplayPeople.jsp
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<jsp:directive.page errorPage="/WEB-INF/content/ErrorPage.jsp"/>
<jsp:directive.page import="java.util.*"/>
<jsp:directive.page import="myorg.javaeeex.bo.*"/>
<html>
<title>People Display</title>
<body>
<h2>People Display</h2>
<jsp:scriptlet>
List people = (List)request.getAttribute("result");
int index = ((Integer)request.getAttribute("index")).intValue();
int count = ((Integer)request.getAttribute("count")).intValue();
int nextIndex = ((Integer)request.getAttribute("nextIndex")).intValue();
String handler = request.getContextPath() + "/model/admin/handler";
</jsp:scriptlet>
<ul>
<jsp:scriptlet>
for(Object o: people) {
Person p = (Person)o;
String firstName = p.getFirstName();
String lastName = p.getLastName();
</jsp:scriptlet>
<li><%= firstName %> <%= lastName %></li>
<jsp:scriptlet>
}
</jsp:scriptlet>
</ul>
<form method="GET"
action="<%=request.getContextPath()%>/model/admin/handler">
Index: <%= index %><p/>
Count: <%= count %><p/>
<input type="hidden" name="index" value="<%= nextIndex %>"/>
<input type="hidden" name="count" value="<%= count %>"/>
<input type="submit" name="command" value="Get All People"/>
</form>
<p/><a href="<%=request.getContextPath()%>/index.jsp">Go to Main Page</a>
</body>
</html> private abstract class Handler {
...
protected static final String NEXT_INDEX_PARAM = "nextIndex";
protected static final String DISPLAY_PEOPLE_URL =
"/WEB-INF/content/DisplayPeople.jsp";
...
private class GetAllPeople extends Handler {
public void doHandle(HttpServletRequest request,
HttpServletResponse response)
throws Exception {
...
Collection<Person> people = registrar.getAllPeopleHydrated(index, count);
int nextIndex = (people.size()==0) ?
index : index + people.size();
//request.setAttribute(RESULT_PARAM, people);
request.setAttribute(RESULT_PARAM, people);
request.setAttribute(INDEX_PARAM, index);
request.setAttribute(COUNT_PARAM, count);
request.setAttribute(NEXT_INDEX_PARAM, nextIndex);
//RequestDispatcher rd =
// getServletContext().getRequestDispatcher(DISPLAY_RESULT_URL);
RequestDispatcher rd =
getServletContext().getRequestDispatcher(DISPLAY_PEOPLE_URL);
rd.forward(request, response);People Display
* first0 last0
* first1 last1
* first2 last2
* first3 last3
* first4 last4
* first5 last5
* first6 last6
* first7 last7
* first8 last8
* first9 last9
Index: 0
Count: 10
[Get All People]
Go to Main Page People Display
Index: 96
Count: 10
[Get All People]
Go to Main Page $ cat javaeeExWAR/src/main/webapp/WEB-INF/content/DisplayPeople.jsp
...
<jsp:scriptlet>
for(Object o: people) {
Person p = (Person)o;
String firstName = p.getFirstName();
String lastName = p.getLastName();
String url = "?id=" + p.getId() + "&command=Get+Person";
</jsp:scriptlet>
<li><a href="<%= url %>"><%= firstName %> <%= lastName %> </a></li>Command Error A request was made, but the command was not recognized. command=Get Person Go to Main Page
$ cat javaeeExWAR/src/main/java/myorg/javaeeex/web/RegistrarHandlerServlet.java
...
private abstract class Handler {
protected static final String ID_PARAM = "id";
...$ cat javaeeExWAR/src/main/java/myorg/javaeeex/web/RegistrarHandlerServlet.java
...
private class GetPerson extends Handler {
public void doHandle(HttpServletRequest request,
HttpServletResponse response)
throws Exception {
action = "EJB.getPerson"; //describe action in case of exception
String idStr = (String)request.getParameter(ID_PARAM);
long id = Long.parseLong(idStr);
Person person = registrar.getPersonByIdHydrated(id);
request.setAttribute(RESULT_PARAM, person);
RequestDispatcher rd =
getServletContext().getRequestDispatcher(DISPLAY_RESULT_URL);
rd.forward(request, response);
}
}$ cat javaeeExWAR/src/main/java/myorg/javaeeex/web/RegistrarHandlerServlet.java
...
public class RegistrarHandlerServlet extends HttpServlet {
...
public static final String GET_PERSON_COMMAND = "Get Person";
...
public void init() throws ServletException {
...
if (ADMIN_TYPE.equals(handlerType)) {
handlers.put(GET_ALL_PEOPLE_COMMAND, new GetAllPeople());
handlers.put(GET_PERSON_COMMAND, new GetPerson());
} [INFO] Restart completed at Sun Apr 05 18:31:51 EDT 2009
Result: id=91:first90 last90 123, addresses={{street1 city1, state1 zip1},}
Go to Main Page $ cat javaeeExWAR/src/main/webapp/WEB-INF/content/DisplayPerson.jsp
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<jsp:directive.page errorPage="/WEB-INF/content/ErrorPage.jsp"/>
<jsp:directive.page import="myorg.javaeeex.bo.*"/>
<html>
<title>Display Person</title>
<body>
<jsp:scriptlet>
Person person = (Person)request.getAttribute("result");
Address address = (person.getAddresses() != null) ?
(Address)person.getAddresses().iterator().next() :
new Address();
</jsp:scriptlet>
Id: <%= person.getId() %><p/>
First Name: <%=person.getFirstName()%><p/>
Last Name: <%=person.getLastName()%><p/>
SSN: <%=person.getSsn()%><p/>
<form method="GET"
action="<%=request.getContextPath()%>/model/admin/handler">
Street: <input type="text" name="street" size="25" value="<%= address.getStreet()%>"/><p/>
City: <input type="text" name="city" size="25" value="<%= address.getCity()%>"/><p/>
State: <input type="text" name="state" size="2" value="<%= address.getState()%>"/><p/>
Zip: <input type="text" name="zip" size="5" value="<%= address.getZip()%>"/><p/>
<input type="hidden" name="id" value="<%= person.getId() %>"/>
<input type="submit" name="command" value="Change Address"/>
</form>
<p/><a href="<%=request.getContextPath()%>/index.jsp">Go to Main Page</a>
</body>
</html>$ cat javaeeExWAR/src/main/java/myorg/javaeeex/web/RegistrarHandlerServlet.java
...
private abstract class Handler {
...
protected static final String DISPLAY_PERSON_URL =
"/WEB-INF/content/DisplayPerson.jsp";$ cat javaeeExWAR/src/main/java/myorg/javaeeex/web/RegistrarHandlerServlet.java
...
private class GetPerson extends Handler {
public void doHandle(HttpServletRequest request,
HttpServletResponse response)
throws Exception {
...
RequestDispatcher rd =
//getServletContext().getRequestDispatcher(DISPLAY_RESULT_URL);
getServletContext().getRequestDispatcher(DISPLAY_PERSON_URL);
rd.forward(request, response);
}
}Id: 91 First Name: first14 Last Name: last14 SSN: 123 Street: street1 City: city1 State: state1 Zip: zip1 [Change Address] Go to Main Page
Command Error A request was made, but the command was not recognized. command=Change Address Go to Main Page
$ cat javaeeExWAR/src/main/java/myorg/javaeeex/web/RegistrarHandlerServlet.java
...
private abstract class Handler {
...
protected static final String STREET_PARAM = "street";
protected static final String CITY_PARAM = "city";
protected static final String STATE_PARAM = "state";
protected static final String ZIP_PARAM = "zip";$ cat javaeeExWAR/src/main/java/myorg/javaeeex/web/RegistrarHandlerServlet.java
...
import myorg.javaeeex.bo.Address;
...
private class ChangeAddress extends Handler {
public void doHandle(HttpServletRequest request,
HttpServletResponse response)
throws Exception {
action = "EJB.changeAddress"; //describe action in case of exception
log.debug("Change Address: id=" + request.getParameter(ID_PARAM) +
", uri=" + request.getRequestURI());
String idStr = (String)request.getParameter(ID_PARAM);
long id = Long.parseLong(idStr);
String street = (String)request.getParameter(STREET_PARAM);
String city = (String)request.getParameter(CITY_PARAM);
String state = (String)request.getParameter(STATE_PARAM);
String zip = (String)request.getParameter(ZIP_PARAM);
Address address = new Address();
address.setStreet(street);
address.setCity(city);
address.setState(state);
address.setZip(zip);
Person person = registrar.getPersonByIdHydrated(id);
person = registrar.changeAddress(person, address);
request.setAttribute(RESULT_PARAM, person);
RequestDispatcher rd =
getServletContext().getRequestDispatcher(DISPLAY_PERSON_URL);
rd.forward(request, response);
}
}$ cat javaeeExWAR/src/main/java/myorg/javaeeex/web/RegistrarHandlerServlet.java
...
public class RegistrarHandlerServlet extends HttpServlet {
...
public static final String CHANGE_ADDRESS_COMMAND = "Change Address";
...
public void init() throws ServletException {
...
if (ADMIN_TYPE.equals(handlerType)) {
handlers.put(GET_ALL_PEOPLE_COMMAND, new GetAllPeople());
handlers.put(GET_PERSON_COMMAND, new GetPerson());
handlers.put(CHANGE_ADDRESS_COMMAND, new ChangeAddress());
} [INFO] Restart completed at Sun Apr 05 20:37:16 EDT 2009
-init() called
-initRegistrar(), registrar=null
-jndiProperties={java.naming.provider.url=jnp://localhost:1099, java.naming.factory.initial=org.jnp.interfaces.NamingCo
ntextFactory, java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces}
-registrar initialized:jboss.j2ee:ear=javaeeEx.ear,jar=javaeeExEJB-1.0-SNAPSHOT.jar,name=RegistrarEJB,service=EJB3
-configured handler type:admin with {Change Address=myorg.webtier.web.RegistrarHandlerServlet$ChangeAddress@1396ef7, Ge
t All People=myorg.webtier.web.RegistrarHandlerServlet$GetAllPeople@1a422f6, Get Person=myorg.webtier.web.RegistrarHandl
erServlet$GetPerson@f36e59}
-doGet() called
-command=Change Address
-Change Address: id=91, uri=/javaeeExWAR/model/admin/handler
-doGet() called
-command=Change Address
-Change Address: id=91, uri=/javaeeExWAR/model/admin/handler$ mvn clean install -rf :javaeeExEJB ... [INFO] Java EE Exercise EJB .............................. SUCCESS [5.753s] [INFO] Java EE Exercise WAR .............................. SUCCESS [3.233s] [INFO] Java EE Exercise EAR .............................. SUCCESS [1.359s] [INFO] Java EE Exercise Remote Test ...................... SUCCESS [26.487s] [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS
All the functionality we put in place so far leverages the Remote interface of the EJB. The remote aspect of the EJB was quite helpful, in that it could be developed and tested with the RMI Test framework and WAR development could be done without server-side deployment delays by using Jetty. In this section, we will put a little work into trying to leverage the Local interface of the EJB, while still retaining some development functionality if the remote interface.
$ cat javaeeExEJB/src/main/java/myorg/javaeeex/ejb/RegistrarLocal.java
package myorg.javaeeex.ejb;
import java.util.Collection;
import javax.ejb.Local;
import myorg.javaeeex.bl.RegistrarException;
import myorg.javaeeex.bo.Address;
import myorg.javaeeex.bo.Person;
@Local
public interface RegistrarLocal {
void ping();
Person getPersonByIdHydrated(long id)
throws RegistrarException;
Person changeAddress(Person person, Address address)
throws RegistrarException;
Collection<Person> getAllPeopleHydrated(int index, int count)
throws RegistrarException;
}We could refactor the common methods of the Remote and Local interfaces at this point to establish a reusable base interface. However, we will keep them separate at this point of development to highlight that Local and Remote interfaces should be thought of as independent.
$ cat javaeeExWAR/src/main/java/myorg/javaeeex/web/RegistrarHandlerServlet.java
...
import javax.ejb.EJB;
import myorg.javaeeex.ejb.RegistrarLocal;
...
public class RegistrarHandlerServlet extends HttpServlet {
...
@EJB(beanInterface=RegistrarLocal.class)
private Object registrar; if (registrar instanceof RegistrarRemote) {
((RegistrarRemote)registrar).ping();
} else {
((RegistrarLocal)registrar).ping();
} Collection<Person> people = (registrar instanceof RegistrarRemote) ?
((RegistrarRemote)registrar).getAllPeopleHydrated(index, count) :
((RegistrarLocal)registrar).getAllPeopleHydrated(index, count);
Person person = (registrar instanceof RegistrarRemote) ?
((RegistrarRemote)registrar).getPersonByIdHydrated(id) :
((RegistrarLocal)registrar).getPersonByIdHydrated(id); Person person = (registrar instanceof RegistrarRemote) ?
((RegistrarRemote)registrar).getPersonByIdHydrated(id) :
((RegistrarLocal)registrar).getPersonByIdHydrated(id);
person = (registrar instanceof RegistrarRemote) ?
((RegistrarRemote)registrar).changeAddress(person, address) :
((RegistrarLocal)registrar).changeAddress(person, address);$ mvn clean install -DskipTests
$ mvn pre-integration-test -rf javaeeExTest; (cd javaeeExWAR; mvn clean jetty:run)
...
[INFO] Starting scanner at interval of 10 seconds.
-initRegistrar(), registrar=null
-java.naming.factory.initial=org.jboss.naming.remote.client.InitialContextFactory
-registrar initialized:Proxy for remote EJB StatelessEJBLocator{appName='javaeeExEAR', moduleName='javaeeExEJB', distinctName='', beanName='RegistrarEJB', view='interface myorg.javaeeex.ejb.RegistrarRemote'}//SERVER LOG 22:51:03,551 DEBUG [myorg.javaeeex.web.RegistrarHandlerServlet] (http--127.0.0.1-8080-2) initRegistrar(), registrar=Proxy for view class: myorg.javaeeex.ejb.RegistrarLocal of EJB: RegistrarEJB
$ cat javaeeExEJB/src/main/java/myorg/javaeeex/ejb/RegistrarLocal.java
...
@Local
public interface RegistrarLocal {
void ping();
Person getPersonById(long id)
throws RegistrarException;
Collection<Person> getAllPeople(int index, int count)
throws RegistrarException;$ cat javaeeExWAR/src/main/java/myorg/javaeeex/web/RegistrarHandlerServlet.java
...
private class GetPerson extends Handler {
public void doHandle(HttpServletRequest request,
HttpServletResponse response)
throws Exception {
...
Person person = (registrar instanceof RegistrarRemote) ?
((RegistrarRemote)registrar).getPersonByIdHydrated(id) :
//((RegistrarLocal)registrar).getPersonByIdHydrated(id);
((RegistrarLocal)registrar).getPersonById(id);$ mvn clean integration-test -rf :javaeeExEJB
http://localhost:8080/javaeeEx/model/admin/handler?id=1&command=Get+Person General Exception Page An error was reported by the application. More detailed information may follow. . org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: myorg.javaeeex.bo.Person.addresses, no session or session was closed at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:358) at ... myorg.webtier.web.RegistrarHandlerServlet$GetPerson.doHandle(RegistrarHandlerServlet.java:250) at myorg.webtier.web.RegistrarHandlerServlet$Handler.handle(RegistrarHandlerServlet.java:169) at
At this point we are going to try to initiate the transaction from the Web tier to have it active throughout the handler code. We will implement this logic with a Servlet Filter.
$ cat javaeeExWAR/src/main/java/myorg/javaeeex/web/JPAFilter.java
package myorg.javaeeex.web;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class JPAFilter implements Filter {
private static final Log log = LogFactory.getLog(JPAFilter.class);
public void init(FilterConfig config) throws ServletException {
log.debug("*** JPAFilter.init() ***");
}
public void doFilter(ServletRequest request,
ServletResponse response,
FilterChain chain) throws IOException, ServletException {
log.debug("*** JPAFilter.doFilter() ENTER ***");
chain.doFilter(request, response);
log.debug("*** JPAFilter.doFilter() EXIT ***");
}
public void destroy() {}//required by interface
}$ cat javaeeExWAR/src/main/webapp/WEB-INF/web.xml
...
<filter>
<filter-name>JPAFilter</filter-name>
<filter-class>myorg.javaeeex.web.JPAFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>JPAFilter</filter-name>
<url-pattern>/model/admin/handler</url-pattern>
<url-pattern>/model/handler</url-pattern>
</filter-mapping>
</web-app>2009-04-05 23:00:46.573::INFO: No Transaction manager found - if your webapp requires one, please configure one. -*** JPAFilter.init() *** [INFO] Restart completed at Sun Apr 05 23:00:47 EDT 2009 ... -*** JPAFilter.doFilter() ENTER *** -doGet() called -command=Get Person -*** JPAFilter.doFilter() EXIT ***
$ cat javaeeExWAR/src/main/java/myorg/javaeeex/web/JPAFilter.java
...
import javax.transaction.UserTransaction;
...
public class JPAFilter implements Filter {
...
@Inject
private static UserTransaction tx;
...$ cat javaeeExWAR/src/main/java/myorg/javaeeex/web/JPAFilter.java
...
import javax.transaction.Status;
...
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
log.debug("*** JPAFilter.doFilter() ENTER ***");
boolean ownTx = false;
if (tx != null) {
try {
if (tx.getStatus() != Status.STATUS_ACTIVE) {
tx.begin();
ownTx = true;
}
} catch (Exception ex) {
log.error("error starting transaction:", ex);
throw new ServletException("error starting transaction", ex);
}
} else {
log.debug("no UserTransaction injected -- moving on without one");
}
chain.doFilter(request, response);
if (tx != null) {
try {
if (ownTx) {
if (tx.getStatus() == Status.STATUS_MARKED_ROLLBACK) {
tx.rollback();
} else if (tx.getStatus() == Status.STATUS_ACTIVE) {
tx.commit();
}
}
} catch (Exception ex) {
log.error("error ending transaction:", ex);
throw new ServletException("error ending transaction", ex);
}
}
log.debug("*** JPAFilter.doFilter() EXIT ***");
}
-*** JPAFilter.doFilter() ENTER *** -no UserTransaction injected -- moving on without one ... -doGet() called -command=Get All People -*** JPAFilter.doFilter() EXIT ***
22:21:36,782 DEBUG [myorg.javaeeex.web.RegistrarHandlerServlet] init() called
22:21:36,783 DEBUG [myorg.javaeeex.web.RegistrarHandlerServlet] jndiProperties={java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory, java.naming.provider.url=jnp://127.0.0.4:1099, java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces}
22:21:36,794 DEBUG [myorg.javaeeex.ejb.RegistrarEJB] **** init ****
22:21:36,795 DEBUG [myorg.javaeeex.ejb.RegistrarEJB] em=org.jboss.jpa.tx.TransactionScopedEntityManager@2399a1
22:21:36,795 DEBUG [myorg.javaeeex.ejb.RegistrarEJB] init complete, registrar=myorg.javaeeex.blimpl.RegistrarImpl@1d6fc09
22:21:36,795 DEBUG [myorg.javaeeex.ejb.RegistrarEJB] ping called
22:21:36,795 DEBUG [myorg.javaeeex.web.RegistrarHandlerServlet] registrar initialized:Proxy to jboss.j2ee:ear=javaeeEx.ear,jar=javaeeExEJB-1.0-SNAPSHOT.jar,name=RegistrarEJB,service=EJB3 implementing [interface myorg.javaeeex.ejb.RegistrarLocal]
22:21:36,795 DEBUG [myorg.javaeeex.web.RegistrarHandlerServlet] jndiName used:/myorg/javaeeEx/RegistrarEJB/local
22:21:36,796 DEBUG [myorg.javaeeex.web.RegistrarHandlerServlet] configured handler type:admin with {Get Person=myorg.javaeeex.web.RegistrarHandlerServlet$GetPerson@13cdfec, Get All People=myorg.javaeeex.web.RegistrarHandlerServlet$GetAllPeople@19131da, Change Address=myorg.javaeeex.web.RegistrarHandlerServlet$ChangeAddress@15ff8a2}
22:21:36,796 DEBUG [myorg.javaeeex.web.JPAFilter] *** JPAFilter.doFilter() ENTER ***
22:21:36,801 DEBUG [myorg.javaeeex.web.RegistrarHandlerServlet] doGet() called
22:21:36,801 DEBUG [myorg.javaeeex.web.RegistrarHandlerServlet] command=Get Person
22:21:36,802 DEBUG [myorg.javaeeex.ejb.RegistrarEJB] *** getPersonById(89) ***
22:21:36,969 DEBUG [myorg.javaeeex.web.JPAFilter] *** JPAFilter.doFilter() EXIT ***$ cat javaeeExWAR/src/main/java/myorg/javaeeex/web/RegistrarHandlerServlet.java
...
private class GetAllPeople extends Handler {
...
Collection<Person> people = (registrar instanceof RegistrarRemote) ?
((RegistrarRemote)registrar).getAllPeopleHydrated(index, count) :
//((RegistrarLocal)registrar).getAllPeopleHydrated(index, count);
((RegistrarLocal)registrar).getAllPeople(index, count); private class ChangeAddress extends Handler {
...
Person person = (registrar instanceof RegistrarRemote) ?
((RegistrarRemote)registrar).getPersonByIdHydrated(id) :
//((RegistrarLocal)registrar).getPersonByIdHydrated(id);
((RegistrarLocal)registrar).getPersonById(id);In this exercise we added a good deal more beef to our Web UI; specifically...