This exercise will add a user interface for our application using a Web UI. The Web UI will demonstrate how to leverage MVC architecture with Servlets, JSPs, and integration with the EJB Tieri and EAR. The development environment will also be a focus of this exercise.
We will use a maven war project type to host the web tier for the application.
$ ls javaeeExEAR javaeeExEJB javaeeExImpl javaeeExTest pom.xml $ mkdir javaeeExWAR
$ mkdir -p javaeeExWAR/src/main/webapp/WEB-INF
$ cat javaeeExWAR/src/main/webapp/WEB-INF/web.xml
<web-app
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<display-name>Web Tier Exercise Web Application</display-name>
</web-app>$ mkdir -p javaeeExWAR/src/test/webapp/WEB-INF
$ cat javaeeExWAR/src/main/webapp/WEB-INF/web.xml
<web-app
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<!-- place elements specific to development/test here -->
</web-app>$ cat javaeeExWAR/pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>javaeeEx</artifactId>
<groupId>myorg.javaee</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<groupId>myorg.javaee</groupId>
<artifactId>javaeeExWAR</artifactId>
<packaging>war</packaging>
<name>Java EE Exercise WAR</name>
<dependencies>
</dependencies>
<build>
</build>
<profiles>
</profiles>
</project>$ (cd javaeeExWAR; mvn clean install) ... [INFO] [INFO] --- maven-war-plugin:2.1.1:war (default-war) @ javaeeExWAR --- [INFO] Packaging webapp [INFO] Assembling webapp [javaeeExWAR] in [/home/jcstaff/proj/exercises/javaeeEx/javaeeExWAR/target/javaeeExWAR-1.0-SNAPSHOT] [INFO] Processing war project [INFO] Copying webapp resources [/home/jcstaff/proj/exercises/javaeeEx/javaeeExWAR/src/main/webapp] [INFO] Webapp assembled in [134 msecs] [INFO] Building war: /home/jcstaff/proj/exercises/javaeeEx/javaeeExWAR/target/javaeeExWAR-1.0-SNAPSHOT.war [INFO] WEB-INF/web.xml already added, skipping [INFO] [INFO] --- maven-install-plugin:2.3.1:install (default-install) @ javaeeExWAR --- ... [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS
...
javaeeExWAR/
|-- pom.xml
|-- src
| |-- main
| | `-- webapp
| | `-- WEB-INF
| | `-- web.xml
| `-- test
| `-- webapp
| `-- WEB-INF
| `-- web.xml
`-- target
|-- javaeeExWAR-1.0-SNAPSHOT
| |-- META-INF
| `-- WEB-INF
| |-- classes
| `-- web.xml
|-- javaeeExWAR-1.0-SNAPSHOT.war
...Web UI development requires a great deal of change, save, view, and repeat. We will want to cut the time it takes to complete that cycle as much as possible and use the lightweight Jetty Servlet engine and maven plugin to help do that for us and saving some of the significant build and deploy time to server. Refer to the Jetty Plugin Documentation for more details.
<properties>
<maven-jetty-plugin.version>6.1.26</maven-jetty-plugin.version>
...
<jetty.reload>automatic</jetty.reload>
<jetty.scanIntervalSeconds>10</jetty.scanIntervalSeconds>
<jetty.port>9080</jetty.port>$ cat pom.xml
...
</pluginManagement>
</plugins>
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>maven-jetty-plugin</artifactId>
<version>${maven-jetty-plugin.version}</version>
<configuration>
<jetty.reload>${jetty.reload}</jetty.reload>
<scanIntervalSeconds>${jetty.scanIntervalSeconds}</scanIntervalSeconds>
<overrideWebXml>${basedir}/src/test/webapp/WEB-INF/web.xml</overrideWebXml>
<useTestClasspath>true</useTestClasspath>
<systemProperties>
</systemProperties>
<connectors>
<connector implementation="org.mortbay.jetty.nio.SelectChannelConnector">
<port>${jetty.port}</port>
<maxIdleTime>60000</maxIdleTime>
</connector>
</connectors>
</configuration>
</plugin>
... <systemProperties>
<systemProperty>
<name>slf4j</name>
<value>true</value>
</systemProperty>
<systemProperty>
<name>log4j.configuration</name>
<value>file:./target/test-classes/log4j.xml</value>
</systemProperty>
</systemProperties>$ (cd javaeeExWAR; mvn jetty:run -Pjetty) [INFO] Scanning for projects... [INFO] [INFO] ------------------------------------------------------------------------ [INFO] Building Java EE Exercise WAR 1.0-SNAPSHOT [INFO] ------------------------------------------------------------------------ [INFO] [INFO] >>> maven-jetty-plugin:6.1.26:run (default-cli) @ javaeeExWAR >>> [INFO] [INFO] --- maven-resources-plugin:2.4.3:resources (default-resources) @ javaeeExWAR --- [WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent! [INFO] skip non existing resourceDirectory /home/jcstaff/solutions/javaeeEx/javaeeExWAR/src/main/resources [INFO] [INFO] --- maven-compiler-plugin:2.3.2:compile (default-compile) @ javaeeExWAR --- [INFO] No sources to compile [INFO] [INFO] --- maven-resources-plugin:2.4.3:testResources (default-testResources) @ javaeeExWAR --- [WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent! [INFO] skip non existing resourceDirectory /home/jcstaff/solutions/javaeeEx/javaeeExWAR/src/test/resources [INFO] [INFO] --- maven-compiler-plugin:2.3.2:testCompile (default-testCompile) @ javaeeExWAR --- [INFO] No sources to compile [INFO] [INFO] <<< maven-jetty-plugin:6.1.26:run (default-cli) @ javaeeExWAR <<< [INFO] [INFO] --- maven-jetty-plugin:6.1.26:run (default-cli) @ javaeeExWAR --- [INFO] Configuring Jetty for project: Java EE Exercise WAR [INFO] Webapp source directory = /home/jcstaff/solutions/javaeeEx/javaeeExWAR/src/main/webapp [INFO] Reload Mechanic: automatic [INFO] Classes directory /home/jcstaff/solutions/javaeeEx/javaeeExWAR/target/classes does not exist 2011-04-12 23:00:49.304:INFO::Logging to STDERR via org.mortbay.log.StdErrLog [INFO] Context path = /javaeeExWAR [INFO] Tmp directory = determined at runtime [INFO] Web defaults = org/mortbay/jetty/webapp/webdefault.xml [INFO] Web overrides = none [INFO] web.xml file = /home/jcstaff/solutions/javaeeEx/javaeeExWAR/src/main/webapp/WEB-INF/web.xml [INFO] Webapp directory = /home/jcstaff/solutions/javaeeEx/javaeeExWAR/src/main/webapp [INFO] Starting jetty 6.1.26 ... 2011-04-12 23:00:49.511:INFO::jetty-6.1.26 2011-04-12 23:00:49.663:INFO::No Transaction manager found - if your webapp requires one, please configure one. 2011-04-12 23:00:50.049:INFO::Started SelectChannelConnector@0.0.0.0:9080 [INFO] Started Jetty Server [INFO] Starting scanner at interval of 10 seconds.
(cd javaeeExWAR/; mvn jetty:run -Djetty.reload=manual)
...
[INFO] Started Jetty Server
[WARNING] scanIntervalSeconds is set to 10 but will be IGNORED due to manual reloading
[INFO] Console reloading is ENABLED. Hit ENTER on the console to restart the context.
[INFO] restarting org.mortbay.jetty.plugin.Jetty6PluginWebAppContext@8d5a91{/javaeeExWAR,/home/jcstaff/proj/exercises/javaeeEx/javaeeExWAR/src/main/webapp}
[INFO] Webapp source directory = /home/jcstaff/proj/exercises/javaeeEx/javaeeExWAR/src/main/webapp
[INFO] Reload Mechanic: manual
[INFO] Classes directory /home/jcstaff/proj/exercises/javaeeEx/javaeeExWAR/target/classes does not exist
[INFO] Context path = /javaeeExWAR
[INFO] Tmp directory = determined at runtime
[INFO] Web defaults = org/mortbay/jetty/webapp/webdefault.xml
[INFO] Web overrides = /home/jcstaff/proj/exercises/javaeeEx/javaeeExWAR/src/test/webapp/WEB-INF/web.xml
[INFO] web.xml file = /home/jcstaff/proj/exercises/javaeeEx/javaeeExWAR/src/main/webapp/WEB-INF/web.xml
[INFO] Webapp directory = /home/jcstaff/proj/exercises/javaeeEx/javaeeExWAR/src/main/webapp
2012-11-10 10:09:45.960:INFO::No Transaction manager found - if your webapp requires one, please configure one.
[INFO] Restart completed at Sat Nov 10 10:09:46 EST 2012http://localhost:9080/
Error 404 - Not Found.
No context on this server matched or handled this request.
Contexts known to this server are:
/javaeeExWAR ---> org.mortbay.jetty.plugin.Jetty6PluginWebAppContext@1cc5d23{/javaeeExWAR,/home/jcstaff/proj/exercises/javaeeEx/javaeeExWAR/src/main/webapp}http://localhost:9080/javaeeExWAR/ Directory: /javaeeExWAR/ WEB-INF/ 4096 bytes Nov 9, 2012 9:31:27 PM
$ cat 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</h2>
</body>
</html>http://localhost:9080/javaeeExWAR/ Hello
$ cat pom.xml
...
<modules>
<module>javaeeExImpl</module>
<module>javaeeExEJB</module>
<module>javaeeExWAR</module>
<module>javaeeExEAR</module>
</modules>
...$ cat javaeeExEAR/pom.xml
...
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>javaeeExWAR</artifactId>
<version>${project.version}</version>
<type>war</type>
</dependency>
...$ cat javaeeExEAR/pom.xml
...
<build>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-ear-plugin</artifactId>
<configuration>
...
<modules>
...
<webModule>
<groupId>${project.groupId}</groupId>
<artifactId>javaeeExWAR</artifactId>
<contextRoot>javaeeEx</contextRoot>
</webModule>
</modules>
</configuration>
</plugin>
</build>
...$ mvn clean pre-integration-test mvn clean pre-integration-test -rf :javaeeExWAR ... [INFO] Java EE Exercise WAR .............................. SUCCESS [4.244s] [INFO] Java EE Exercise EAR .............................. SUCCESS [25.545s] [INFO] Java EE Exercise Remote Test ...................... SUCCESS [9.800s] [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS
//SERVER LOG 10:22:39,454 INFO [org.jboss.web] (MSC service thread 1-1) JBAS018210: Registering web context: /javaeeEx 10:22:39,467 INFO [org.jboss.as.server] (management-handler-thread - 65) JBAS018559: Deployed "javaeeExEAR-1.0-SNAPSHOT.ear" ...
http://localhost:8080/javaeeEx/ Hello
This is what the solution should look like so far.
javaeeExWAR/
|-- pom.xml
|-- src
| |-- main
| | `-- webapp
| | |-- index.jsp
| | `-- WEB-INF
| | `-- web.xml
| `-- test
| `-- webapp
| `-- WEB-INF
| `-- web.xml
`-- target
|-- javaeeExWAR-1.0-SNAPSHOT
| |-- index.jsp
| |-- META-INF
| `-- WEB-INF
| |-- classes
| `-- web.xml
|-- javaeeExWAR-1.0-SNAPSHOT.war
...$ jar tf javaeeExWAR/target/javaeeExWAR-1.0-SNAPSHOT.war | sort index.jsp ... WEB-INF/ WEB-INF/classes/ WEB-INF/web.xml
$ cat javaeeExWAR/pom.xml
...
<dependencies>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<scope>provided</scope>
</dependency>
</dependencies> <pluginManagement>
<plugins>
...
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>maven-jetty-plugin</artifactId>
<configuration>
...
</configuration>
<dependencies>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>${commons-logging.version}</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
</dependencies> # javaeeEx/pom.xml
...
<properties>
...
<maven-compiler-plugin.version>2.5.1</maven-compiler-plugin.version>
...
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.version}</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
...$ mkdir -p javaeeExWAR/src/main/java/myorg/javaeeex/web
$ cat javaeeExWAR/src/main/java/myorg/javaeeex/web/RegistrarHandlerServlet.java
package myorg.javaeeex.web;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@SuppressWarnings("serial")
public class RegistrarHandlerServlet extends HttpServlet {
private static final Log log = LogFactory.getLog(RegistrarHandlerServlet.class);
public void init() throws ServletException {
log.debug("init() called ");
}
protected void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
log.debug("doGet() called");
}
protected void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
log.debug("doPost() called, calling doGet()");
doGet(request, response);
}
public void destroy() {
log.debug("destroy() called");
}
}$ cat javaeeExWAR/src/main/webapp/WEB-INF/web.xml
<web-app
...
<servlet>
<servlet-name>AdminHandler</servlet-name>
<servlet-class>myorg.javaeeex.web.RegistrarHandlerServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>AdminHandler</servlet-name>
<url-pattern>/model/admin/handler</url-pattern>
</servlet-mapping>
</web-app>$ cat javaeeExWAR/src/main/webapp/index.jsp
...
<body>
<h2>Hello</h2>
<ul>
<li><a href="model/admin/handler">invoke servlet</a></li>
</ul>
</body>
</html>$ mkdir -p javaeeExWAR/src/test/resources
$ cat javaeeExWAR/src/test/resources/log4j.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/" debug="false">
<appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">
<param name="Target" value="System.out"/>
<layout class="org.apache.log4j.PatternLayout">
<!-- The default pattern: Date Priority [Category] Messagen -->
<!--
<param name="ConversionPattern" value="%d{ABSOLUTE} %-5p [%c{1}] %m%n"/>
-->
<param name="ConversionPattern" value=" -%m%n"/>
</layout>
</appender>
<appender name="logfile" class="org.apache.log4j.RollingFileAppender">
<param name="File" value="/tmp/log4j-out.txt"/>
<param name="Append" value="false"/>
<param name="MaxFileSize" value="100KB"/>
<param name="MaxBackupIndex" value="1"/>
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%-5p %d{dd-MM HH:mm:ss,SSS} [%c] (%F:%M:%L) -%m%n"/>
</layout>
</appender>
<logger name="myorg">
<level value="debug"/>
</logger>
<root>
<priority value="info"/>
<appender-ref ref="CONSOLE"/>
</root>
</log4j:configuration>$ (cd javaeeExWAR; mvn clean jetty:run)
//CONSOLE [INFO] Starting scanner at interval of 10 seconds. -init() called -doGet() called
$ mvn clean pre-integration-test -rf :javaeeExWAR [INFO] Scanning for projects... [INFO] ------------------------------------------------------------------------ [INFO] Reactor Build Order: [INFO] [INFO] Java EE Exercise WAR [INFO] Java EE Exercise EAR [INFO] Java EE Exercise Remote Test ...
//SERVER LOG 16:35:20,789 INFO [org.jboss.web] (MSC service thread 1-4) JBAS018210: Registering web context: /javaeeEx 16:35:20,834 INFO [org.jboss.as.server] (management-handler-thread - 4) JBAS018559: Deployed "javaeeExEAR-1.0-SNAPSHOT.ear" 16:36:00,669 DEBUG [myorg.javaeeex.web.RegistrarHandlerServlet] (http--127.0.0.1-8080-1) init() called 16:36:00,680 DEBUG [myorg.javaeeex.web.RegistrarHandlerServlet] (http--127.0.0.1-8080-1) doGet() called
Your WAR contains all the UI constructs but delegates all business logic to the EJB tier. The EJBs are deployed to the server and now we need to make the Web tier an RMI client of the EJB tier to perform end-to-end functionality.
<pluginManagement>
<plugins>
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>maven-jetty-plugin</artifactId>
...
<dependencies>
...
<dependency>
<groupId>ejava.common</groupId>
<artifactId>jboss-rmi-client</artifactId>
<version>${ejava.version}</version>
<type>pom</type>
</dependency>
</dependencies>
</plugin> $ cat javaeeExWAR/src/test/resources/jndi.propeties
java.naming.factory.initial=${jboss.remoting.java.naming.factory.initial}
java.naming.provider.url=${jboss.remoting.java.naming.provider.url}
java.naming.factory.url.pkgs=${jboss.remoting.java.naming.factory.url.pkgs}
java.naming.security.principal=${jboss.remoting.java.naming.security.principal}
java.naming.security.credentials=${jboss.remoting.java.naming.security.credentials}
jboss.naming.client.ejb.context=true <build>
<!-- filter test/resource files for profile-specific valies -->
<testResources>
<testResource>
<directory>src/test/resources</directory>
<filtering>true</filtering>
</testResource>
</testResources>$ (cd javaeeExWAR; mvn clean process-test-resources) $ cat javaeeExWAR/target/test-classes/jndi.propeties java.naming.factory.initial=org.jboss.naming.remote.client.InitialContextFactory java.naming.provider.url=remote://127.0.0.1:4447 java.naming.factory.url.pkgs= java.naming.security.principal=known java.naming.security.credentials=password1! jboss.naming.client.ejb.context=true
$ cat ./javaeeExWAR/src/main/java/myorg/javaeeex/web/RegistrarHandlerServlet.java
import java.util.Properties;
...
import javax.naming.InitialContext;
import javax.servlet.ServletConfig;
...
private void initRegistrar(ServletConfig config) throws Exception {
InitialContext jndi = null;
String ctxFactory = config.getServletContext()
.getInitParameter(Context.INITIAL_CONTEXT_FACTORY);
log.debug(Context.INITIAL_CONTEXT_FACTORY + "=" + ctxFactory);
if (ctxFactory!=null) {
Properties env = new Properties();
env.put(Context.INITIAL_CONTEXT_FACTORY, ctxFactory);
jndi = new InitialContext(env);
}
else {
jndi = new InitialContext();
}
} public void init() throws ServletException {
log.debug("init() called ");
try {
ServletConfig config = getServletConfig();
initRegistrar(config);
}
catch (Exception ex) {
log.fatal("error initializing handler", ex);
throw new ServletException("error initializing handler", ex);
}
}$ cat javaeeExWAR/src/test/webapp/WEB-INF/web.xml
...
<!-- place elements specific to development/test here -->
<context-param>
<param-name>java.naming.factory.initial</param-name>
<param-value>org.jboss.naming.remote.client.InitialContextFactory</param-value>
</context-param>
</web-app>[INFO] Restart completed at Sat Nov 10 15:43:35 EST 2012 -init() called -java.naming.factory.initial=org.jboss.naming.remote.client.InitialContextFactory -doGet() called
$ mvn clean pre-integration-test -rf :javaeeExWAR ...
//SERVER LOG 16:36:00,669 DEBUG [myorg.javaeeex.web.RegistrarHandlerServlet] (http--127.0.0.1-8080-1) init() called 16:36:00,670 DEBUG [myorg.javaeeex.web.RegistrarHandlerServlet] (http--127.0.0.1-8080-1) java.naming.factory.initial=null 16:36:00,680 DEBUG [myorg.javaeeex.web.RegistrarHandlerServlet] (http--127.0.0.1-8080-1) doGet() called
$ cat javaeeExWAR/pom.xml
...
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>javaeeExEJB</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>javaeeExImpl</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>$ cat javaeeExWAR/pom.xml
<build>
...
<plugins>
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>maven-jetty-plugin</artifactId>
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>javaeeExEJB</artifactId>
<version>${project.version}</version>
<type>ejb-client</type>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>javaeeExImpl</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>$ cat javaeeExWAR/src/test/webapp/WEB-INF/web.xml
...
<context-param>
<param-name>registrar.remote</param-name>
<param-value>javaeeExEAR/javaeeExEJB/RegistrarEJB!myorg.javaeeex.ejb.RegistrarRemote</param-value>
</context-param>
...$ cat ./javaeeExWAR/src/main/java/myorg/javaeeex/web/RegistrarHandlerServlet.java
import javax.ejb.EJB;
...
import myorg.javaeeex.ejb.RegistrarRemote;
...
public class RegistrarHandlerServlet extends HttpServlet {
...
@EJB
private RegistrarRemote registrar; private void initRegistrar(ServletConfig config) throws Exception {
log.debug("initRegistrar(), registrar=" + registrar);
if (registrar == null) {
//build an InitialContext from Servlet.init properties in web.xml
InitialContext jndi = null;
...
String jndiName = config.getServletContext().getInitParameter("registrar.remote");
registrar = (RegistrarRemote)jndi.lookup(jndiName);
log.debug("registrar initialized:" + registrar);
}
}(cd javaeeExWAR; mvn -Dslf4j=true -Dlog4j.configuration=file:./src/test/resources/log4j.xml jetty:run -Pjetty)
-init() called
-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'}
-doGet() called$ mvn clean pre-integration-test -rf :javaeeExWAR ...
17:29:30,960 DEBUG [myorg.javaeeex.web.RegistrarHandlerServlet] (http--127.0.0.1-8080-2) init() called
17:29:30,961 DEBUG [myorg.javaeeex.web.RegistrarHandlerServlet] (http--127.0.0.1-8080-2) initRegistrar(), registrar=Proxy for remote EJB StatelessEJBLocator{appName='javaeeExEAR', moduleName='javaeeExEJB', distinctName='', beanName='RegistrarEJB', view='interface myorg.javaeeex.ejb.RegistrarRemote'}
17:29:30,963 DEBUG [myorg.javaeeex.web.RegistrarHandlerServlet] (http--127.0.0.1-8080-2) doGet() called$ cat javaeeExWAR/src/main/java/myorg/javaeeex/web/RegistrarHandlerServlet.java
import javax.inject.Inject;
...
@Inject
private RegistrarRemote registrar;package myorg.javaeeex.web;
import javax.ejb.EJB;
import javax.enterprise.inject.Produces;
import myorg.javaeeex.ejb.RegistrarRemote;
/**
* This class is used to define the injection type for RegistrarRemote
* types
*/
public class RegistrarWebConfig {
@Produces
@EJB
public RegistrarRemote registrar;
} $ touch javaeeExWAR/src/main/webapp/WEB-INF/beans.xml
$ mvn clean pre-integration-test -rf :javaeeExWAR ...
18:40:19,395 INFO [org.jboss.weld.deployer] (MSC service thread 1-1) JBAS016008: Starting weld service for deployment javaeeExEAR-1.0-SNAPSHOT.ear
18:40:19,584 INFO [org.jboss.web] (MSC service thread 1-1) JBAS018210: Registering web context: /javaeeEx
18:40:19,602 INFO [org.jboss.as.server] (management-handler-thread - 18) JBAS018559: Deployed "javaeeExEAR-1.0-SNAPSHOT.ear"
...
18:49:19,219 DEBUG [myorg.javaeeex.web.RegistrarHandlerServlet] (http--127.0.0.1-8080-2) init() called
18:49:19,224 DEBUG [myorg.javaeeex.web.RegistrarHandlerServlet] (http--127.0.0.1-8080-2) initRegistrar(), registrar=Proxy for remote EJB StatelessEJBLocator{appName='javaeeExEAR', moduleName='javaeeExEJB', distinctName='', beanName='RegistrarEJB', view='interface myorg.javaeeex.ejb.RegistrarRemote'}
18:49:19,227 DEBUG [myorg.javaeeex.web.RegistrarHandlerServlet] (http--127.0.0.1-8080-2) configured handler type:anonymous with {Ping=myorg.javaeeex.web.RegistrarHandlerServlet$Ping@549a16}
18:49:19,229 DEBUG [myorg.javaeeex.web.RegistrarHandlerServlet] (http--127.0.0.1-8080-2) doGet() called
18:49:19,234 DEBUG [myorg.javaeeex.web.RegistrarHandlerServlet] (http--127.0.0.1-8080-2) command=Ping
18:49:19,252 DEBUG [myorg.javaeeex.ejb.RegistrarEJB] (http--127.0.0.1-8080-2) **** init ****
18:49:19,252 DEBUG [myorg.javaeeex.ejb.RegistrarEJB] (http--127.0.0.1-8080-2) init complete, registrar=myorg.javaeeex.blimpl.RegistrarImpl@14316bd
18:49:19,254 DEBUG [myorg.javaeeex.ejb.RegistrarEJB] (http--127.0.0.1-8080-2) ping calledAt this point we now have a functional servlet/WAR with an injected EJB ready to start adding methods.
In this step we are going to add some structure to the Web Tier. The structure will be consistent with the ideas of Model View Controller (MVC), but we will make a few shortcuts to keep this simple. We are going to deploy two instances of the Controller Servlet; one for anonymous users and another for admin users. We can leverage this separation later when security is added.
$ cat javaeeExWAR/src/main/webapp/WEB-INF/web.xml
...
<servlet>
<servlet-name>AdminHandler</servlet-name>
<servlet-class>myorg.javaeeex.web.RegistrarHandlerServlet</servlet-class>
<init-param>
<param-name>type</param-name>
<param-value>admin</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>AdminHandler</servlet-name>
<url-pattern>/model/admin/handler</url-pattern>
</servlet-mapping>$ cat javaeeExWAR/src/main/webapp/WEB-INF/web.xml
...
<servlet>
<servlet-name>AnonymousHandler</servlet-name>
<servlet-class>myorg.javaeeex.web.RegistrarHandlerServlet</servlet-class>
<init-param>
<param-name>type</param-name>
<param-value>anonymous</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>AnonymousHandler</servlet-name>
<url-pattern>/model/handler</url-pattern>
</servlet-mapping>$ cat ./javaeeExWAR/src/main/java/myorg/javaeeex/web/RegistrarHandlerServlet.java
import javax.servlet.RequestDispatcher;
...
private abstract class Handler {
protected static final String RESULT_PARAM = "result";
protected static final String EXCEPTION_PARAM = "exception";
protected static final String DISPLAY_EXCEPTION_URL =
"/WEB-INF/content/DisplayException.jsp";
protected static final String DISPLAY_RESULT_URL =
"/WEB-INF/content/DisplayResult.jsp";
protected String action;
public void handle(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
try {
doHandle(request, response);
}
catch (Exception ex) {
log.error("error in " + action, ex);
request.setAttribute(EXCEPTION_PARAM, ex);
RequestDispatcher rd = getServletContext().getRequestDispatcher(
DISPLAY_EXCEPTION_URL);
rd.forward(request, response);
}
}
public abstract void doHandle(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException;
}$ mkdir -p javaeeExWAR/src/main/webapp/WEB-INF/content
$ cat javaeeExWAR/src/main/webapp/WEB-INF/content/DisplayException.jsp
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>General Exception Page</title>
</head>
<body>
<center><h1>General Exception Page</h1></center>
<p>An error was reported by the application. More detailed information
may follow.</p>.
<p>
<jsp:scriptlet>
Exception ex = (Exception)request.getAttribute("exception");
if (ex != null) {
java.io.PrintWriter writer = new java.io.PrintWriter(out);
ex.printStackTrace(writer);
}
</jsp:scriptlet>
</p>
<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 class Ping extends Handler {
public void doHandle(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
action = "EJB.ping"; //describe action in case of exception
registrar.ping();
request.setAttribute(RESULT_PARAM, "ping() complete");
RequestDispatcher rd =
getServletContext().getRequestDispatcher(DISPLAY_RESULT_URL);
rd.forward(request, response);
}
}$ cat javaeeExWAR/src/main/webapp/WEB-INF/content/ErrorPage.jsp
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<%-- ErrorPage.jsp
This page is registered to handle errors in JSP files.
--%>
<%@ page isErrorPage="true" %>
<html>
<head>
<title>General Exception Page</title>
</head>
<body>
<center><h1>General Exception Page</h1></center>
<p>An error was reported by the application. More detailed information
may follow.</p>.
<p><%
java.io.PrintWriter writer = new java.io.PrintWriter(out);
exception.printStackTrace(writer);
%></p>
<p/><a href="<%=request.getContextPath()%>/index.jsp">Go to Main Page</a>
</body>
</html>$ cat javaeeExWAR/src/main/webapp/WEB-INF/content/DisplayResult.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>Result</title>
<body>
<jsp:scriptlet>
Object result = request.getAttribute("result");
</jsp:scriptlet>
Result: <%= result %>
<p/><a href="<%=request.getContextPath()%>/index.jsp">Go to Main Page</a>
</body>
</html>import java.util.HashMap;
import java.util.Map;
...
private Map<String, Handler> handlers = new HashMap<String, Handler>();
...
public static final String ADMIN_TYPE = "admin";
public static final String ANONYMOUS_TYPE = "anonymous";
public static final String PING_COMMAND = "Ping";
public void init() throws ServletException {
log.debug("init() called ");
try {
ServletConfig config = getServletConfig();
initRegistrar(config);
//build a list of handlers for individual commands
String handlerType = config.getInitParameter(HANDLER_TYPE_KEY);
if (ADMIN_TYPE.equals(handlerType)) {
//adminHandlers.put(XXX_COMMAND, new XXX());
}
else if (ANONYMOUS_TYPE.equals(handlerType)) {
handlers.put(PING_COMMAND, new Ping());
}
log.debug("configured handler type:" + handlerType +
" with " + handlers);
}
catch (Exception ex) {
log.fatal("error initializing handler", ex);
throw new ServletException("error initializing handler", ex);
}
}$cat javaeeExWAR/src/main/java/myorg/javaeeex/web/RegistrarHandlerServlet.java
...
public class RegistrarHandlerServlet extends HttpServlet {
...
public static final String EXCEPTION_PARAM = "exception";
private static final String UNKNOWN_COMMAND_URL =
"/WEB-INF/content/UnknownCommand.jsp";
public static final String COMMAND_PARAM = "command";
public static final String HANDLER_TYPE_KEY = "type";
...
protected void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
log.debug("doGet() called");
String command = request.getParameter(COMMAND_PARAM);
log.debug("command=" + command);
try {
if (command != null) {
Handler handler = handlers.get(command);
if (handler != null) {
handler.handle(request, response);
}
else {
RequestDispatcher rd =
getServletContext().getRequestDispatcher(
UNKNOWN_COMMAND_URL);
rd.forward(request, response);
}
}
else {
throw new Exception("no " + COMMAND_PARAM + " supplied");
}
}
catch (Exception ex) {
log.error("error within GET", ex);
request.setAttribute(EXCEPTION_PARAM, ex);
RequestDispatcher rd = getServletContext().getRequestDispatcher(
UNKNOWN_COMMAND_URL);
rd.forward(request, response);
}
}$ cat javaeeExWAR/src/main/webapp/WEB-INF/content/UnknownCommand.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"/>
<html>
<head>
<title>Unknown Command</title>
</head>
<body>
<center><h1>Command Error</h1></center>
A request was made, but the command was not recognized<p/>.
command=<%=request.getParameter("command")%>
<p/><a href="<%=request.getContextPath()%>/index.jsp">Go to Main Page</a>
</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>
</ul>
</body>
</html>(cd javaeeExWAR; mvn clean jetty:run)
...
[INFO] Starting scanner at interval of 10 seconds.
-init() called
-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'}
-configured handler type:anonymous with {Ping=myorg.javaeeex.web.RegistrarHandlerServlet$Ping@b0f0ae}
-doGet() called
-command=Ping//http://localhost:9080/javaeeExWAR/model/handler?command=Ping Result: ping() complete Go to Main Page
//JBoss SERVER LOG 18:10:03,283 DEBUG [myorg.javaeeex.ejb.RegistrarEJB] (EJB default - 1) **** init **** 18:10:03,283 DEBUG [myorg.javaeeex.ejb.RegistrarEJB] (EJB default - 1) init complete, registrar=myorg.javaeeex.blimpl.RegistrarImpl@11c8d64 18:10:03,295 DEBUG [myorg.javaeeex.ejb.RegistrarEJB] (EJB default - 1) ping called
//http://localhost:9080/javaeeExWAR/model/admin/handler?command=Ping Command Error A request was made, but the command was not recognized. command=Ping Go to Main Page
//http://localhost:9080/javaeeExWAR/model/admin/handler Command Error A request was made, but the command was not recognized. command=null Go to Main Page
$ mvn clean pre-integration-test -rf :javaeeExWAR ...
//http://localhost:8080/javaeeEx/model/handler?command=Ping Result: ping() complete Go to Main Page
//SERVER LOG 18:31:54,797 DEBUG [myorg.javaeeex.web.RegistrarHandlerServlet] (http--127.0.0.1-8080-2) doGet() called 18:31:54,799 DEBUG [myorg.javaeeex.web.RegistrarHandlerServlet] (http--127.0.0.1-8080-2) command=Ping 18:31:54,823 DEBUG [myorg.javaeeex.ejb.RegistrarEJB] (http--127.0.0.1-8080-2) **** init **** 18:31:54,824 DEBUG [myorg.javaeeex.ejb.RegistrarEJB] (http--127.0.0.1-8080-2) init complete, registrar=myorg.javaeeex.blimpl.RegistrarImpl@1abc8dd 18:31:54,825 DEBUG [myorg.javaeeex.ejb.RegistrarEJB] (http--127.0.0.1-8080-2) ping called
//http://localhost:8080/javaeeEx/model/admin/handler?command=Ping Command Error A request was made, but the command was not recognized. command=Ping Go to Main Page
//SERVER LOG 18:32:55,336 DEBUG [myorg.javaeeex.web.RegistrarHandlerServlet] (http--127.0.0.1-8080-2) doGet() called 18:32:55,337 DEBUG [myorg.javaeeex.web.RegistrarHandlerServlet] (http--127.0.0.1-8080-2) command=Ping
//http://localhost:8080/javaeeEx/model/admin/handler Command Error A request was made, but the command was not recognized. command=null Go to Main Page
//SERVER LOG
18:34:30,421 DEBUG [myorg.javaeeex.web.RegistrarHandlerServlet] (http--127.0.0.1-8080-2) doGet() called
18:34:30,422 DEBUG [myorg.javaeeex.web.RegistrarHandlerServlet] (http--127.0.0.1-8080-2) command=null
18:34:30,423 ERROR [myorg.javaeeex.web.RegistrarHandlerServlet] (http--127.0.0.1-8080-2) error within GET: java.lang.Exception: no command supplied
at myorg.javaeeex.web.RegistrarHandlerServlet.doGet(RegistrarHandlerServlet.java:104) [classes:]This is what your configuration should look like when complete.
javaeeEx |-- javaeeExImpl |-- javaeeExEJB |-- javaeeExWAR | |-- pom.xml | `-- src | |-- main | | |-- java | | | `-- myorg | | | `-- javaeeex | | | `-- web | | | |-- RegistrarHandlerServlet.java | | | `-- RegistrarWebConfig.java | | `-- webapp | | |-- index.jsp | | `-- WEB-INF | | |-- beans.xml | | |-- content | | | |-- DisplayException.jsp | | | |-- DisplayResult.jsp | | | |-- ErrorPage.jsp | | | `-- UnknownCommand.jsp | | `-- web.xml | `-- test | |-- resources | | |-- jndi.properties | | `-- log4j.xml | `-- webapp | `-- WEB-INF | `-- web.xml |-- javaeeExEAR |-- javaeeExTest `-- pom.xml
The built WAR looks as follows.
javaeeExWAR/target/javaeeExWAR-1.0-SNAPSHOT
|-- index.jsp
|-- META-INF
`-- WEB-INF
|-- beans.xml
|-- classes
| `-- myorg
| `-- javaeeex
| `-- web
| |-- RegistrarHandlerServlet$1.class
| |-- RegistrarHandlerServlet.class
| |-- RegistrarHandlerServlet$Handler.class
| |-- RegistrarHandlerServlet$Ping.class
| `-- RegistrarWebConfig.class
|-- content
| |-- DisplayException.jsp
| |-- DisplayResult.jsp
| |-- ErrorPage.jsp
| `-- UnknownCommand.jsp
`-- web.xml