Building the skeleton worklist

This post is part of a series on building a custom worklist for BPM/SOA 11g.

In this post, we will establish the skeleton of the web application by creating the various pages and some JSP fragments to handle the page header, footer and navigation.

Setting up Spring Web MVC

The first thing we need to do is to set up our project to use Spring Web MVC.  As we discussed earlier, Spring (like many web frameworks) uses a Dispatcher Servlet, so we need to add this into our deployment descriptor.  Here is the relevant part of the web.xml:

  <servlet>
    <servlet-name>worklist</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>

  <servlet-mapping>
    <servlet-name>worklist</servlet-name>
    <url-pattern>*.do</url-pattern>
  </servlet-mapping>

  <servlet-mapping>
    <servlet-name>worklist</servlet-name>
    <url-pattern>home</url-pattern>
  </servlet-mapping>

The servlet entry tells WebLogic that we want to register the Spring Dispatcher Servlet in our application, call it worklist and load it when the web application starts.

We then add two servlet mappings to tell WebLogic when to use this servlet.  The first entry tells WebLogic to use the Spring Dispatcher Servlet if the URL ends with .do.  The second entry tells WebLogic to use it if the URL is home.  The reason we have two URL mappings here is because we are going to define different security rules for these two (in the next post in the series).

Note that we named the servlet worklist.  This is important, as it tells Spring where to look for its configuration file.  The first part of the configuration file’s name will match the servlet name.  So we will create our configuration file as src/main/webapp/WEB-INF/worklist-servlet.xml.  Here it is (note that there are more comments in the file on Subversion):

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

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

<!-- the application context definition for the springapp DispatcherServlet -->

 <bean id="tasklistController" class="com.oracle.ateam.TaskListController">
    <property name="successView" value="/WEB-INF/jsp/tasklist.jsp"/>
  </bean>

 <bean id="initiateListController" class="com.oracle.ateam.InitiateListController">
    <property name="successView" value="/WEB-INF/jsp/initiatelist.jsp"/>
  </bean>

 <bean id="initiateTaskController" class="com.oracle.ateam.InitiateTaskController">
    <property name="successView" value="/WEB-INF/jsp/initiatelist.jsp"/>
  </bean>

 <bean id="taskdetailController" class="com.oracle.ateam.TaskDetailController">
    <property name="successView" value="/WEB-INF/jsp/taskdetail.jsp"/>
  </bean>

 <bean id="homeController" class="com.oracle.ateam.HomeController">
    <property name="successView" value="/WEB-INF/jsp/Home.jsp"/>
  </bean>

 <bean id="loginController" class="com.oracle.ateam.LoginController">
    <property name="successView" value="/WEB-INF/jsp/tasklist.jsp"/>
    <property name="failureView" value="/WEB-INF/jsp/Home.jsp"/>
  </bean>

 <bean id="createTestTasksController" class="com.oracle.ateam.CreateTestTasksController">
    <property name="successView" value="/WEB-INF/jsp/Home.jsp"/>
 </bean>

 <bean id="processTaskController" class="com.oracle.ateam.ProcessTaskController">
    <property name="successView" value="/WEB-INF/jsp/tasklist.jsp"/>
  </bean>

 <bean id="addCommentController" class="com.oracle.ateam.AddCommentController">
    <property name="successView" value="/WEB-INF/jsp/taskdetail.jsp"/>
  </bean>

 <bean id="logoutController" class="com.oracle.ateam.LogoutController">
    <property name="successView" value="/WEB-INF/jsp/Home.jsp"/>
  </bean>

 <bean id="errorController" class="com.oracle.ateam.ErrorController">
    <property name="successView" value="/WEB-INF/jsp/Home.jsp"/>
  </bean>

 <bean id="handlerMapping">
     <property name="mappings">
       <value>
         /home=homeController
         /tasklist.do=tasklistController
         /taskdetail.do=taskdetailController
         /login.do=loginController
         /logout.do=logoutController
         /createtasks.do=createTestTasksController
         /processtask.do=processTaskController
         /addcomment.do=addCommentController
         /initiatelist.do=initiateListController
         /initiatetask.do=initiateTaskController
         /error.do=errorController
       </value>
     </property>
   </bean>
</beans>

In this configuration file, you can see that we define each of our controllers.  Let’s take a look at the first one:

  <bean id="tasklistController" class="com.oracle.ateam.TaskListController">
    <property name="successView" value="/WEB-INF/jsp/tasklist.jsp"/>
  </bean>

This defines a controller called tasklistController and tells the Spring Dispatch Controller which class to send control to – com.oracle.ateam.TaskListController.  As most of our controllers inherit from our com.oracle.ateam.SimpleSuccessFailureController, they expect two properties: successView and failureView.  We only define a failureView where it is needed.  You can see in the example above that the (success) view for this controller is /WEB-INF/jsp/tasklist.jsp.

This establishes the linkage between the Controller and the View.

In the last part of the configuration file, in the handlerMapping section, you can see that we create a mapping between URLs and Controllers.  Here is an example:

/tasklist.do=tasklistController

This tells Spring that the Controller that matches the URL /tasklist.do is the tasklistController defined above.

We will write our various controllers and views in the next several posts in this series.  For now, let’s just create some empty pages and our header and footer fragments.

Setting up the skeleton pages

Here are the pages in our worklist application:

src/main/webapp/WEB-INF/jsp/common/head.jspf
src/main/webapp/WEB-INF/jsp/common/Include.jspf
src/main/webapp/WEB-INF/jsp/common/tail.jspf

src/main/webapp/WEB-INF/jsp/Home.jsp
src/main/webapp/WEB-INF/jsp/initiatelist.jsp
src/main/webapp/WEB-INF/jsp/taskdetail.jsp
src/main/webapp/WEB-INF/jsp/tasklist.jsp

The first group are JSP fragments which are used (included) on the other pages to provide consistent headers, footers and navigation (menus) across our application.

The second group are the actual views.  Home.jsp is the login page that is shown to unauthenticated users.  The others are only available to logged in users.

Notice that all of the JSP pages are located inside the WEB-INF directory.  WebLogic Server will not serve pages located inside this directory to users.  They can only be accessed by a Servlet, i.e. a Controller.  This provides additional security to our application, as there is no way that a malicious user is able to enter a URL to access these pages.

Let’s take a look at the fragments first.

Common includes

The src/main/webapp/WEB-INF/jsp/common/Include.jspf fragment contains common include directives that we want to include on many pages.  Here is the content:

<%@ page session="true" contentType="text/html; charset=ISO-8859-15" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="x" uri="http://java.sun.com/jsp/jstl/xml" %>
<%@ taglib prefix="f" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>

The first line sets the content type and enables the JSP session object.  The remaining lines are loading some JSP Tag Libraries.  We are using the Java Standard Tag Library (JSTL) in our view, as we will see shortly.  The first three taglibs enable JSTL.  The last two are for Spring and Spring Forms support.

The page header

We want the same header and navigation on each page.  This is handled in our page header fragment, src/main/webapp/WEB-INF/jsp/common/head.jspf.  Here is the content of this file:

<%@ include file="Include.jspf" %>

<html>
<head>
  <title>Custom BPM Worklist</title>
  <link rel="stylesheet" href="ateam.css" type="text/css">
</head>
<c:choose>
  <c:when test="${empty pageContext.request.remoteUser}">
    <body onLoad="document.x_form.j_username.focus();">
  </c:when>
  <c:otherwise>
    <body>
  </c:otherwise>
</c:choose>
<table border="0" width="100%" height="40" cellpadding="0" cellspacing="0">
  <tr>
    <td style="width:119"><img src="images/oracle.gif" width="119"></td>
    <td align="left" class="page-head">&nbsp;&nbsp;Custom BPM Worklist</td>
    <td style="width:250; text-align:right">&nbsp;</td>
  </tr></table><table border="0" width="100%" height="40" cellpadding="0" cellspacing="0">
  <tr>
    <c:choose>
      <c:when test="${empty pageContext.request.remoteUser}">
        <td></td>
      </c:when>
      <c:otherwise>
        <td class="main-menu">
          <a class="main-menu" href="tasklist.do">Task List</a>
          &nbsp;&nbsp;|&nbsp;&nbsp;
          <a class="main-menu" href="initiatelist.do">Initiate a Task</a>
        </td>
      </c:otherwise>
    </c:choose>
    <c:choose>
      <c:when test="${empty pageContext.request.remoteUser}">
        <td></td>
      </c:when>
      <c:otherwise>
        <td align="right" class="main-menu">
          Logged on as ${pageContext.request.remoteUser}.&nbsp;&nbsp;|&nbsp;&nbsp;
          <a class="main-menu" href="logout.do">Logout</a>
        </td>
      </c:otherwise>
    </c:choose>
  </tr>
  <tr>
    <td class="message">${message}</td>
  </tr>
</table>

We start by importing our common page directives, then we set the title and import our stylesheet – we will create that shortly.

<%@ include file="Include.jspf" %>

<html>
<head>
  <title>Custom BPM Worklist</title>
  <link rel="stylesheet" href="ateam.css" type="text/css">
</head>

Next, we start the HTML BODY.  If the user is not logged in yet, we want to move the cursor to the username field in the login form automatically, so the user will not need to click in the field or user the keyboard to navigate to it.

To build conditional logic, we are using JSTL’s choose/when/otherwise construct and Expression Language to specify the test (condition).  You can have as many when clauses as you like.  In our test here, to check if the user is logged on, we are going to check if the remoteUser in the request in the pageContext scope has a value.  WebLogic Server will set the value of remoteUser to the user (principal) name if a user is logged in to WebLogic.  The expression ${empty pageContext.request.remoteUser} is equivalent to saying if (request.getRemoteUser() == null) in a Servlet (more or less…) where request is the HttpServletRequest parameter on the Servlet.

<c:choose>
  <c:when test="${empty pageContext.request.remoteUser}">
    <body onLoad="document.x_form.j_username.focus();">
  </c:when>
  <c:otherwise>
    <body>
  </c:otherwise>
</c:choose>

Following this, we start an HTML TABLE and build our page header with an image and some text.

Then we draw our menu.  Again, we test pageContext.request.remoteUser to see if a user is logged in.  We only draw the menu if there is a user logged in.

    <c:choose>
      <c:when test="${empty pageContext.request.remoteUser}">
        <td></td>
      </c:when>
      <c:otherwise>
        <td class="main-menu">
          <a class="main-menu" href="tasklist.do">Task List</a>
          &nbsp;&nbsp;|&nbsp;&nbsp;
          <a class="main-menu" href="initiatelist.do">Initiate a Task</a>
          &nbsp;&nbsp;|&nbsp;&nbsp;
          <a class="main-menu" href="createtasks.do">Create Test Tasks</a>
        </td>
      </c:otherwise>
    </c:choose>

We also show a message indicating the name of the logged in user and a logout link, if there is a user logged in.

    <c:choose>
      <c:when test="${empty pageContext.request.remoteUser}">
        <td></td>
      </c:when>
      <c:otherwise>
        <td align="right">
          Logged on as ${pageContext.request.remoteUser}.&nbsp;&nbsp;|&nbsp;&nbsp;
          <a class="main-menu" href="logout.do">Logout</a>
        </td>
      </c:otherwise>
    </c:choose>

Finally, we have an area reserved for messages to the user.  This area is used when the user enters incorrect login credentials for example.

  <tr>
    <td class="message">${message}</td>
  </tr>

The page footer

The footer is fairly simple, it just displays our Copyright message and finishes the HTML for the page.

<table border="0" width="100%" height="20" cellpadding="0" cellspacing="0">
  <tr>
    <td align="center" class="copyright">Copyright 2011, Oracle and/or its affiliates.  All Rights Reserved.</td>
  </tr>
</table>
</body>
</html>

Stylesheet

We built a small CSS stylesheet to make the application look ‘beautiful,’ well, a little more beautiful than plain old Times New Roman on a white background anyway.

There are a few images used in the application.  These are available in Subversion in the src/main/webapp/images directory.  See this page for details of how to access Subversion.

Our CSS file is located at src/main/webapp/ateam.css.  Here are the contents (without all the white space and comments that are in the file in Subversion):

body {background-color: #ffffee  font-family: tahoma, verdana, geneva, arial, helvetica, sans-serif;  font-size: 11px;}
.filters {font-family: tahoma, verdana, geneva, arial, helvetica, sans-serif;  font-size: 11px;}
.stylenormal {font-family: tahoma, verdana, geneva, arial, helvetica, sans-serif;  font-size: 11px;}
td.page-head {font-family: tahoma, verdana, geneva, arial, helvetica, sans-serif;  font-size: 18px;  color: #093e7d;  font-weight: normal;}
td.copyright {font-family: Arial, Helvetica, sans-serif;  font-size: 12px;}
td.message {font-family: Arial, Helvetica, sans-serif;  color: red;  font-size: 12px;}
td.main-menu {border-top: 1px solid #8c8e95;  border-bottom: 1px solid #8c8e95;  padding: 3px;}
.main-menu {font-family: tahoma, verdana, geneva, arial, helvetica, sans-serif;  font-size: 14px;}
a.main-menu:link {text-decoration: none; color: blue; }a.main-menu:visited { text-decoration: none; color: blue; }
a.main-menu:active  { text-decoration: none; color: blue; }a.main-menu:hover   { text-decoration: underline; color: red; }
th.tl-head {font-family: Tahoma, Verdana, Helvetica, sans-serif;  font-size: 11px;  border-right: 1px solid #8c8e95;  text-align: left;}
h1.td-h1 {font-family: tahoma, verdana, geneva, arial, helvetica, sans-serif;  font-size: 18px;  font-weight: bold;}
h2.td-h2 {font-family: tahoma, verdana, geneva, arial, helvetica, sans-serif;  font-size: 14px;  font-weight: bold;}
td.tl-row {font-family: Tahoma, Verdana, Helvetica, sans-serif;  font-size: 11px;  margin-left: 3px;  margin-right: 3px;}
td.tl-alt-row {font-family: Tahoma, Verdana, Helvetica, sans-serif;  font-size: 11px;  margin-left: 3px;  margin-right: 3px;  background-color: #eeeeee;}
td.p1 {font-family: Tahoma, Verdana, Helvetica, sans-serif;  font-size: 11px;  margin-left: 3px;  margin-right: 3px;  background-color: #992200; }
td.p2 {font-family: Tahoma, Verdana, Helvetica, sans-serif;  font-size: 11px;  margin-left: 3px;  margin-right: 3px;  background-color: #cc5511; }
td.p3 {font-family: Tahoma, Verdana, Helvetica, sans-serif;  font-size: 11px;  margin-left: 3px;  margin-right: 3px;  background-color: #ccaa11; }
td.p4 {font-family: Tahoma, Verdana, Helvetica, sans-serif;  font-size: 11px;  margin-left: 3px;  margin-right: 3px;  background-color: #ffff00; }
td.p5 {font-family: Tahoma, Verdana, Helvetica, sans-serif;  font-size: 11px;  margin-left: 3px;  margin-right: 3px;  background-color: #ffffee; }
th.td-head {font-family: tahoma, verdana, geneva, arial, helvetica, sans-serif;  font-size: 11px;  color: #755600;  text-align: right;  margin-right: 3px;}
td.td-row {font-family: tahoma, verdana, geneva, arial, helvetica, sans-serif;  font-size: 11px;  color: #333;}
td.homepage {font-family: tahoma, verdana, geneva, arial, helvetica, sans-serif;  font-size: 11px;  color: #755600;  text-align: right;  margin-right: 3px;}
td.td-row {font-family: tahoma, verdana, geneva, arial, helvetica, sans-serif;  font-size: 11px;  color: #333;}
td.homepage {background-color: #fcfcfc;  background: url(images/background_dark_blue_whitegradient_.png);  background-position: 0% 0%;  background-repeat: repeat-x;}
div.globe {left: 1em;  position: absolute;  top: 16em;}
.lefttop {margin:0;padding:12px 0 12px 0;background:url("images/leftmedium.png") top left no-repeat;}
.leftmiddle {background-image: url("images/leftmidmedium.png"); background-position: left; background-repeat: repeat-y;}
.leftbottom {margin: 0; padding: 0 0 0 12px; background: url("images/leftmedium.png") bottom left no-repeat;}
.topmiddle {width:100%; background-image:url("images/topmidmedium.png"); background-position:top; background-repeat:repeat-x;}
.boxcontent {background: transparent; background-color: #FFFFFF; margin: 0;}
.bottommiddle {background-image:url("images/bottommidmedium.png"); background-position:bottom; background-repeat:repeat-x;}
.righttop {margin: 0; padding: 12px 0 12px 0; background: url("images/rightmedium.png") top right no-repeat;}
.rightmiddle {background-image:url("images/rightmidmedium.png"); background-position: right; background-repeat: repeat-y;}
.rightbottom {display: block; padding: 0 12px 12px 0; background: url("images/rightmedium.png") bottom right no-repeat;}
.tableBody {background-image:url("../img/login/background_white_mesh_whitegradient_.png"); background-position:left upper corner; background-repeat:no-repeat;}
table.tl-table {background-color: #f9f9fb;  background-image: url(images/ch_bg_ena.png);  background-repeat: repeat-x;  border-bottom: 1px solid #e5e5e5;  background-position: 50% 100%;}

I wont go through this in detail, but just make a couple of comments – there is only this one CSS file, so you wont have to go hunting to find where a style came from.  Also, I have tried to give things reasonable names so you can guess where they belong.  For example td-head and td-row are styles for table head and table row on the Task Detail (td) page.  tl-head and tl-row similar for the Task List (tl) page.

The skeleton pages

We will also create our three JSP pages for logged in users:

src/main/webapp/WEB-INF/jsp/initiatelist.jsp
src/main/webapp/WEB-INF/jsp/taskdetail.jsp
src/main/webapp/WEB-INF/jsp/tasklist.jsp

For now, each of these can just contain the following code.  Note that you should change pagename to the name of the page, e.g. tasklist, taskdetail, etc.  This skeleton will just include the header and footer and send some logging messages to let us know we entered and left the page.

<%@ include file="/WEB-INF/jsp/common/head.jspf"      %>
<%  MLog.log("pagename.jsp", "Entered tasklist.jsp"); %>

Page contents will go here.

<%@ include file="/WEB-INF/jsp/common/tail.jspf"      %>
<%  MLog.log("pagename.jsp", "Done");                 %>

We will create the Home.jsp page in the next post.

Summary

We are still not a point where we can run our application, but we have some pretty solid foundations in place now.  Let’s move on to set up security, and then we can create our Controllers and Views.

In the next post in this series we will set up the security environment for the worklist.

About Mark Nelson

Mark Nelson is an Architect (an "IC6") in the Fusion Middleware Central Development Team at Oracle. Mark's job is to make Fusion Middleware easy to use in the cloud and at home, for developers and operations folks, with special focus on continuous delivery, configuration management and provisioning - making it simple to manage the configuration of complex environments and applications built with Oracle Database, Fusion Middleware and Fusion Applications, on-premise and in the cloud. Before joining this team, Mark was a senior member of the A-Team since 2010, and worked in Sales Consulting at Oracle since 2006 and various roles at IBM since 1994.
This entry was posted in Uncategorized and tagged , , , . Bookmark the permalink.

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s