You are on page 1of 40

Professional Jakarta Struts (ISBN 0-7645-4437-3)

by James Goodwill & Richard Hightower


last change 4/14/10

Java Review
Flow charts: http://jdurrett.ba.ttu.edu/Resources/Programming/index.html
Basic MyEclipse
Chapter by Chapter
Debugging in MyEclipse

1) Chapter 1:Struts Intro


a) Jakarta project
i) http://jakarta.apache.org/
ii) http://struts.apache.org/
iii) Model-View-Controller design pattern
(p2 note about other patterns)
(1) Model: supporting data objects usually with jdbc connections
(2) View: JSP driven GUI representation of current state of Model (extensive use of tag libraries)
(3) Controller: View-Model interface
iv) Struts version of MVC (p3 chart & steps involved)

b) Java Web applications


i) Servlets
ii) JSP
iii) Custom tag libraries
iv) java classes
v) Static HTML, etc
vi) Web app deployment descriptor (web.xml p7, 67))
vii) Directory Structure
(1) .../wroxapp
(2) .../wroxapp/WEB-INF xml config & tld files go here
(3) .../wroxapp/WEB-INF/classes
(4) .../wroxapp/WEB-INF/lib

c) Tomcat servlet container (The following assumes individual installs not the All-in-one MyEclipse)
i) Install java jdk first
(1) I am using the 1.7.0x version in Linux & 1.6.0 in Windows
(2) http://java.sun.com
(3) Important: make sure the versions (32bit or 64bit) of java & Eclipse match
ii) Now install Apache Tomcat
(1) http://tomcat.apache.org
(2) Use only the release builds
(3) If you have errors installing the first time, set an environment variable
JAVA_HOME=”C:\where\ever\jdk\is” then try again
iii) Then install your IDE
(1) If using eclipse and MyEclipse (docs are here)
(a) Eclipse (3.4 Works Now) first: http://www.eclipse.org/
if you have zip problems get WinZip
(b) then MyEclipse (8.0GA): http://www.myeclipseide.com
if you have install problems use the manual install version
(c) Put jdk bin directory at first of PATH

** Note as of MyEclipse 6 the All in One installation does everything in Windows **


(d)
==================================================
2) Servlet & JSP Overview
a) I assume some familiarity from previous Classes
b) JHTP 5th edition Servlets (ch24), JSP (ch25)
c) Servlets
i) Figure 2.2: HttpServlet Object Model (Sun's Reference Site & Servlet API)
ii) Setting up book code examples
iii) Lifecycle: contructor, init, service, destroy
iv) SimpleServlet (L 2.1)
v) Deploying a servlet exploded and as war file
vi) Servlet Context
(1) Facilitates servlet-container communication
(2) Storage area for objects available to all components in a webapp
(3) Every webapp has only one ServletContext
(4) getAttribute(), setAttribute, getAttributeNames()
(5) ContextServlet.java (p21): jsp will return “could not find...”
(a) implicit objects in Context.jsp (23): application, out
(6) run context servlet on zeus
(7) then rerun Context.jsp
vii) Http data
(1) ServletRequest methods
String getParameter(String name)
String[] getParameterValues(String name)
java.util.Enumeration getParameterNames()
ParameterServlet.java (26) & Form.html(28)

d) JSP: jsp quick reference cards


i) Steps of a JSP request (fig 2.9 p 31)
(1) Request: container recognizes the extension & passes to JSP engine
(2) First time requested since change, jsp is used to create a servlet
(3) Servlet is compiled & run
(4) Response is sent back to client

ii) Components of a JSP


(1) JSP Directives provide global info about a jsp page (p32)
(a) <%@ page
(i) import=”somefiletoimport”
(ii) session=”true|false”
(iii) errorPage=”someerrorpageurl.jsp”
(iv) isErrorPage=”true|false”

(b) include Directives are used to insert text and/or code at JSP translation time
(i) <$@ include file=”somefile.jsp” %>

(c) taglib Directive says that the including page uses a custom tag library
(i) <%@ taglib url=”tagLibraryURL” prefix=”tagXMLprefix %>
(ii) <tiles:putlist ....

(2) JSP Scripting (p34)


(a) <%! declaration
(i) <%! String name=”John R Durrett” %>
(ii) <%! public String SomeMethod(String name) {...
(b) <%= expression
(i) Hello <b><%=name %></b> how are you today <br>
(c) <% scriptlet source %>
(i) <% callsomeclass.method() %> more html
<% someotherjavacode %> etc

(3) JSP Error Pages


(a) errorpage.jsp (36)
(b) testerror.jsp (37)

(4) Implicit Objects


(a) out
(b) request (request.jsp 39)
(c) response
(d) pageContext
(e) session (session.jsp 40)
(f) application
(g) config
(h) pagesexception

(5) Object scope: page vs request vs session vs application

(6) Standard Actions (p42+)


(a) <jsp:userBean id=”name” scope=”...” class=”project.class” />
(b) <jsp:setProperty name=”beanName” property=”propname” value=”assign a value” />
(c) <jsp:getPropery name=”beanName” property=”propname” />
(d) Example: Counter.java (45), counter.jsp (46)

(e) <jsp:param name=”paramName” value=”someParamValue” /> provides parameters for include, forward, &
plugin

(f) <jsp:include page=”url” flush=”true /> evaluated each time page is requested as opposed to include
directive include.jsp (48)

(g) <jsp:forward page=”relativeURL” > <jsp:param .../> </jsp:forward>


(i) forward.jsp (50), welcome.jsp (51), management.jsp (51)
(ii) http://localhost:8080/ch02app/forward.jsp?role=user;user=Bob

(h) <jsp:plugin type=bean|applet” code=”classfile” codebase=”objectURL”> <jsp:params ...> ...

(i) see quick reference card, Cheat-Sheets.org,


==================================================

e) JavaServer Faces
i) Horstmann Core JSF links
3) Struts – Apache User Guide
a) jakarta.apache.org --> struts.apache.org --> why are we using struts 1.1 ???

b) Installation with / without MyEclipse


i) WEB-INF/lib Tomcat/common/lib
ii) web.xml
iii) struts-config.xml
iv) tld definitions

c) A New struts webapp using MyEclipse


i) file-new-Web Application
(1) gives directory structure & web.xml file (steps 2 & 4)

ii) MyEclipse-Add Struts capabilities


(1) look at config path, action servlet name, servlet url pattern, base package (ch03), install jars & tld
(2) when Finished have jars, struts-config.xml, web.xml, tld files (steps 1, 3, & 5)

-----------------------------------------------------------

d) The first struts webapp

i) index.jsp view: create the query view


(1) file-new-jsp struts 1.1 with a form
(a) lots of tag lib defs + basic jsp with html:form tags

(2) fix form to match book index.jsp


(3) <html:form
(a) action == used to find ActionMapping in structs-config file
(b) name == used to lookup ActionForm in struts-config files
(c) type == fully qualified java classname to use as form bean
(4) <taglib> MyEclipse version versus book

ii) LookupForm.java: create the form bean


(1) file-new-class LookupForm.java
(2) change parent class to be ActionForm
(3) paste code from example into new class
(4) Edit struts-config.xml file to match pg 61
<form-bean name=”lookupForm” type=”ch03.lookupForm” />

(5) Note the names of the methods. You MUST the JavaBean standard naming convention

iii) quote.jsp: Create using standard jsp template ie no struts code


(1) Add Current Price: <%= request.getAttribute("PRICE") %>

iv) LookupAction.java: Create the controller


(1) file-new-class LookupAction
(a) extend org.apache.struts.action.Action
(2) paste code from example into new class
(3) remove all the Wiley logging stuff
(4) edit struts-config.xml file to match p65
<action-mappings>
<action path=”/Lookup”
type=”ch03.LookupAction”
name=”lookupForm”>
<forward name=”success” path=”/quote.jsp”>
<forward name=”failure” path=/index.jsp”>
</action>
</action-mappings>

(a) be careful using right click on the outline

v) Deploying: MyEclipse changed the web.xml file already


(1) servlet def in p66
(2) servlet-mapping on p66
(3) web.xml file on p67

vi) Run it, remember to use SUNW if you want a quote


(1) <html:form>
(a) 1 – creates necessary html code for form

(b) 2 – checks for instance of LookupForm in session scope

(c) 3 – submit causes /ch03app/Lookup.do to be called


(i) this uses the action-mapping to call the ActionServlet

(d) 4 – ActionServlet looks for an ActionMapping entry that matches Lookup


(i) creates ActionMapping objects for all values in action-mapping element
(ii) creates LookupAction
(iii) calls LookupAction.execute(...)
(iv)when control returned to ActionServlet it uses returned ActionForward to call appropriate
view

vii) Other ways to create simple web app

==================================================
4) Actions & ActionServlet
The Controller components: ActionServlet.class, Action.class, Plugins (which we will mostly ignore), & the
RequestProcessor

a) ActionServlet

When a request is received:


i) doGet() or doPost() invoke the process() method
ii) process() gets current RequestProcess and calls process() method
iii) RequestProcessor.process()
(1) Uses struts-config action element to match request path
(2) Uses action name attribute to match form-bean
iv) Creates or retrieves form bean
v) Populations the bean
vi) Validates using ActionForm.validate() method if required
vii) Creates an Action class and calls Action.execute()
viii) When processing returns a ActionForward object uses it to send control to target

ix) Configuring ActionServlet:


(1) Init parameters in web.xml (table 4.1 pg 76)

b) Action Class
The most common component in struts webapps

i) Create class that extends Action


ii) Implement the execute() method
iii) Return ActionForward object
iv) Put action element in struts-config.xml
v) Put class and xml files on server

vi) Configuring Action classes


(1) Path attribute in action element must be unique
(2) Class can be reused as required by other unique paths
(3) Forward, input, path, & type attributes in Table 4.3 pg 82

c) Plugins
i) Must implement the org.apache.struts.action.Plugin interface
ii) Useful for allocating resources (properties files), setting up jdbc or jndi, & other init functions
ex: tiles.TilesPlugin & validator.ValidatorPlugin
iii) Create a class that implements the Plugin interface
iv) Add an empty constructor, a init(ActionServlet, ModuleConfig), & a destroy() method
v) Put what you want to happen at application startup in the init method
We will use logging from http://logging.apache.org/log4j/1.2/index.html & reading a properties file
vi) Add the <plug-in className=”ch04Plugin” /> to the main struts-config.xml file
Please note from the example that this must be the last element in the config file
vii) Put controller element in struts-config file after action-mapping and before message-resources
(listing 4.3 pg 89)
d) Logging with log4j
i) Logging in any webapp is critical to track problems, use of the system, &/or development progress
ii) System.out.println or err.println can be used but is not as effective
iii) Get the log4j jar file from the apache.org web site above
iv) Put the jar file in your project’s WEB-INF/lib folder and click Refresh in eclipse
v) The online docs at the apache site are the best source of info on the properties file and its loggers,
appenders, conversion patterns, log levels, etc
vi) Please note priority of log levels is debug < info < warn < error < fatal and that incoming log level
request must be equal to or greater than the system loggers level set in the properties file to be
printed

--- To use the default tomcat logging system ---


vii) Create a log4j.properties file (leave that as the name) and put it in the root of your src folder
#Example log4j.properties file
log4j.rootLogger=INFO, fileout
log4j.appender.fileout=org.apache.log4j.RollingFileAppender

log4j.appender.fileout.File=/home/durrett/temp/durrett.log
log4j.appender.fileout.MaxFileSize=10MB
log4j.appender.fileout.MaxBackupIndex=10

log4j.appender.fileout.layout=org.apache.log4j.PatternLayout
log4j.appender.fileout.layout.ConversionPattern=%d %-5p %-30.30c{1} %x - %m%n

viii) For any class where you wish to use logging


(1) import the commons logging jars
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

(2) Create a class level static attribute


private static Log log = LogFactory.getLog(FindDogAction.class);
Please note the logger naming convention

(3) Anytime you wish to output logging information


if (log.isInfoEnabled()) { log.info("Getting dogtype property"); }

-- The next part assumes you are creating a Plugin to initialize your own logging system ---
ix) Create a log4j.properties (log4j.pjsprops) file and put it in your WEB-INF folder
Please note that putting the log4j.properties file in WEB-INF/classes overrides the default logger
x) Initialize a static Logger object in your PlugIn class
public static Logger pjsLog = Logger.getLogger(“A1”);
xi) Configure the pjsLog object
String fullPathtoYourWebapp = servlet.getServletContext().getRealPath("/");
PropertyConfigurator.configure(fullPathtoYourWebapp + “/WEB-INF/log4j.pjsprops”);
xii) Anywhere in your application that you want to log use the instructions from viii above and,
Logger pjsLog = Logger.getLogger("A1"); // get the specific logger you created in your plugin
pjsLog.info("Symbol: " + sStk);
e) Properties files
i) Setup a properties file. This can be xml or java properties (the version I use in the pjs project) type
SYSTEM_TITLE=Professional Jakarta Struts
ii) Save the file in the WEB-INF folder of your app
iii) Create a file object
File file = new File(fullPathtoYourWebapp + "/WEB-INF/props.txt");
iv) Open a FileInputStream: FileInputStream fis = new FileInputStream(file);
v) Load the properties: properties.load(fis);
vi) Add the properties to the ServletContext (the webapplication memory space)
ServletContext context = servlet.getServletContext();
context.setAttribute(“PROPERTIES”, properties);
vii) You can use the set properties anywhere in your webapp like this:
ServletContext context = request.getSession().getServletContext();
Properties rProperties = (Properties)context.getAttribute("PROPERTIES");
String sTitle = rProperties.getProperty("SYSTEM_TITLE");

f) RequestProcessor
When customizing ActionServlet this is where to start

i) Create a class that extends action.RequestProcessor


ii) Override processPreprocess() method
iii) Return true for success ie continue as normal
iv) Return false for processing completed, ie do not call Action
v) Put controller element in struts-config file after action-mapping and before message-resources
(listing 4.3 pg 89)

============================================
5) Advanced Action Classes

a) Design Notes
i) Limit the “business logic” in your jsp
(1) jsp's are for user views,
they DO NOT talk to the model, they only display pieces of it
(2) Actions are for control & select the next view not the jsp
(3) the struts-config.xml file controls ALL system flow
(4) Helper object models implement business logic

b) Forward Actions (basic)


i) Typical link: <html:link page='/somepage.jsp”>Page link</html:link>
ii) Forward:
<html:link action=”pagelink”>Page link</html:link>

struts-config.xml:
<action path=”/pagelink”
parameter=”/somepage.jsp”
type=”org.apache.struts.actins.ForwardAction”
/>

First is harder to maintain, harder to change and update


iii)
c) Forward Attribute
i) instead of the “formal” version above use the forward attribute in the action element
ii) struts-config.xml:
<action path=”/pagelink”
forward=”/somepage.jsp”
/>

iii) <global-forwards>
<forward name="ch05" path="/ch05/index.jsp"></forward>
</global-forwards>A
---------------------------------------------------------------------------------------

d) DispatchAction
i) Helps to “condense” simple actions into one action class
ii) Steps:
(1) Create an action handler that extends DispatchAction (pg 98)
(2) Create a method in the new class for each logical action
(3) Create an action mapping for your new class in struts-config.xml
This mapping should use the parameter attribute to specify the http request parameter that will
care the method name (pg 99)
(4) Pass the action an appropriate request parameter in your jsp code (pg 99)
e) DynaLookupForm

<form-bean name="dynalookupform" type="org.apache.struts.action.DynaActionForm">


<form-property name="symbol" type="java.lang.String" />
<form-property name="price" type="java.lang.String" />
</form-bean

<action path="/Ch05Lookup" name="dynalookupform"


attribute="dynalookupform" parameter="method" scope="request" type="ch05.StockActions">
<forward name="success" path="/ch05/index.jsp" />
</action>

Skipped: Legacy Forwards, IncludeAction, & SwitchAction Plus


f) LookupDispatchAction
i) Move files from ch05 directory to new ch05/DispatchAction
ii) Create new ch05/LookupDispatchAction dir
iii) copy all files form DispatchAction to new LookupDispatchAction dir
iv) change all three index.jsp’s to work with new structure
v) change existing actions to work with new structure
vi) Create a new Action that subclasses LookupDispatchAction
(1) Make sure to add the existing userdynaform name to the new LookupAction
(2) Leave forwards out to be copied over later
(3) Make sure to put in a parameter (I used bob)
vii) Copy each of the methods from UserDispatchAction to UserLookupDispatchAction
viii) Create a protected Map getKeyMethodMap() method
ix) Create a pjs.Constants interface
x) Copy & update existing DispatchActions to new LoginDispatchActions (remember bob)
xi) Update messages in resource bundle to match getKeyMethodMap keys
xii) Update login, newuser, etc jsps to user resource bundle
(1) remove hidden parameter
(2) add <html:submit property=”bob”><bean:message key=”userform.login”/></html:submit> to login.jsp
<form-bean name="dynalookupform" type="org.apache.struts.action.DynaActionForm">
<form-property name="symbol" type="java.lang.String" />
<form-property name="price" type="java.lang.String" />
</form-bean

<action path="/Ch05Lookup" name="dynalookupform"


attribute="dynalookupform" parameter="method" scope="request" type="ch05.StockActions">
<forward name="success" path="/ch05/index.jsp" />
(3) </action>
g) Checking for logged in user
i) Create new class that extends org.apache.struts.action.RequestProcessor
ii) Add and implement the processPreprocess method
(1) make sure to check for both a Login.do and a StartLogin.do action if using html:link action tags
(2) since we are using a Vector and not a database make sure to setup a “default” user
iii) Add <controller processorClass=”pjs.PjsRequestProcessor” /> to struts-config
6) The Presentation Layer: Struts Views

a) Building a View
A view is a combination of JSP's, Tag libraries, and Form beans

i) JSP's serve two main functions:


1) to present results of controller actions
2) to gather data

ii) Gathering Data

(1) <html:form action="/login">


action must match complete path defined in struts-config file
ActionForm must be defined in action name attribute

optional attributes
(a) focus=”name of initial focus attribute”

(2) resulting html:


<form name="loginform" method="post"
action="/ch05/login.do;
jsessionid=DC3145E99C1148DDA85B845E19E46840"
>

(3) <html:text property="userid"/>


property must be a property in the ActionForm class

optional attributes
(a) value=”initial value of attribute”
(b) readonly=”true if desired”

(4) resulting html

userid : <input type="text" name="userid" value="">

(5) struts-config

<action name="loginform" path="/login" type="LoginAction">


<forward name="success" path="/Welcome.jsp" />
<forward name="failure" path="/Login.jsp" />
</action>

iii) ActionForm Beans


(1) get & set Methods for each attribute
(2) reset() method called to reset all attributes to default values This help avoid stale data being left
in form bean

(3) struts-config

<form-bean name="loginform" type="LoginForm" />


iv) Steps in submission of struts form

(1) Controller creates (or retrieves) instance of LoginForm & stores it in session
(2) Controller calls LoginForm.reset()
(3) Controller populates LoginForm object with data from html:form attributes
(4) Controller invokes LoginAction.execute method
(5) Controller forwards processing to appropriate jsp after execute returns ActionForward

v) DynaActionForm
Dynamic ActionForm for use with simple data inputs

(1) Add form-bean element to struts-config file

<form-bean name="dynamicloginform"
type="org.apache.struts.action.DynaActionForm">
<form-property name="userid" type="java.lang.String" initial="" />
<form-property name="password" type="java.lang.String" initial="" />
</form-bean>

(2) Create data input jsp (DynamicLogin.jsp)


only difference is the action name

<html:form action="/DynamicLogin" focus="userid">

(3) Create new action class (DynamicLoginAction)


the only changes needed are to the following lines

// Use the DynamicForm to get the request parameters


//LoginForm lf = (LoginForm) form;
DynaActionForm lf = (DynaActionForm)form;

// make sure arguments match form-property names


//String su = lf.getUserid(), sp = lf.getPassword();
String su = (String)lf.get("userid"),
sp = (String)lf.get("password");

(4) Add DynamicAction to struts-config file


<action path="/DynamicLogin"
name="dynamicloginform"
type="DynamicLoginAction"
>
<forward name="success" path="/Welcome.jsp" />
<forward name="failure" path="/DynamicLogin.jsp" />
</action>

============================================
7) Debugging Struts

8) Custom Action Mappings


http://struts.apache.org/userGuide/index.html
a) ActionMapping class
i) An ActionMapping object describes an Action instance to the ActionServlet
It uniquely defines an instance of a particular action class
They are setup / defined by the action element in the struts-config file

b) Custom Action Mappings


i) allow addition of parameters to custom ActionMapping classes

c) Attributes of ActionMapping Object in struts-config file (p 144)


i) className -- fully qualified ActionMapping class name
typically used for custom ActionMappings

ii) type – Action class that will process the request

iii) input – where to return control if ActionErrors are returned

iv) name – ActionForm key

v) path – Context relative path of submitted request, must start with /


used by ActionServlet to determine which Action to call for each request

vi) parameter – used to pass additional arguments to Action object


for instance the parameter=method in the DispatchAction

d) Creating a custom ActionMapping


(1) Extend ActionMapping
(a) Create new class such as:
public class WroxActionMapping extends ActionMapping

(b) Add new properties: add property, get and set methods

(c) make sure to call super() as first line in constructor

(2) Setup struts-config file action element to use new ActionMapping


(a) add className attribute to action element definition
className=”ch08.WroxActionMapping”

(b) add new set-property element


<set-property property=”logResults” value=”true” />

(3) Create Action class that utilizes new Attribute in ActionMapping sub class
WroxActionMapping wm = (WroxActionMapping) mapping;
if (wm.getLogResults()) ...
9) Internationalizing Struts (i18n)

a) i18n Components
i) Resource bundle based Message class
ii) <bean:message /> tag

b) Controller
i) java properties file containing key=value pairs
ex: app.symbol=Symbol

ii) ApplicationResources.properties (default file)


iii) ApplicationResources_language_COUNTRY.properties (naming pattern)
(1) ApplicationResources_en_US.properties
(2) ApplicationResources_it_IT.properties

(3) supported locales: http://java.sun.com/j2se/1.4.2/docs/guide/intl/locale.doc.html

iv) Resources filename can be anything. Depends on config file setting


v) When changing resource messages webapp must be reloaded or tomcat restarted

c) Deployment of resource bundle

EITHER
i) web.xml file
(1) servlet element
(2) <init-param>

(3) ex:
<init-param>
<param-name>application</param-name>
<param-value>ApplicationResources</param-value>
</init-param>

OR
ii) struts-config.xml file
(1) <message-resources element
<message-resources parameter="ch09ApplicationResources" />

iii) default placement in WEB-INF/classes


iv) other placement per java package format
ie. WEB-INF/classes/com/notreally/ApRes.properties

d) bean tag Library


If using eclipse/MyEclipse when you enable struts it is done for you

i) <bean:message key=”app.symbol”/>

e) Example files: http://jdurrett.ba.ttu.edu/4383/Examples/ch09/index.html


10) Managing Errors
a) ActionError
pattern is key, placeholder, may have 0-4 placeholders or use array
i) new ActionError(String key)
ii) new ActionError(String key, Object objRef)
iii) new ActionError(String key, Object ...)

iv) ex new ActionError(“errors.sql.insert.one”);

b) ActionErrors
i) ActionErrors errs = new ActionErrors()
ii) errs.add(“some_property_value”, new ActionError(“somekey”));
iii) property value is the property in the input jsp that caused the error

c) ActionForm validate method returns ActionErrors Object Reference

d) struts-config (pg 162)


i) validate=”true”
ii) input=”/where_the_error_came_from.jsp”
usually a jsp with a struts-based input form

e) ActionForm
i) public ActionErrors validate(ActionMapping mapping, HttpServletRequest request)

ii) ex: (pg 164)


public ActionErrors validate(ActionMapping mapping, HttpServletRequest request) {
ActionErrors errs = new ActionErrors();

if (some test is true) {


errs.add(“this param”, new ActionError(“errors.sql.select.only”));
}

return errs;

f) ApplicationResources.properties (pg 165)

i) errors.header=<font color="red"><h3>Error List</h3><ul>


ii) errors.footer=</ul></font><hr>
iii) errors.sql.select.only=<li>Sorry only select is currently supported</li>
iv) errors.sql.sqlerror=<li>{0}</li>
Note the use of the {0} as placeholder
placeholders are formatted according to java.text.MessageFormat

g) jsp's
i) <html:errors /> tag (pg 166)

(1) any where in jsp


(2) be careful of tags inserted by MyEclipse

h) Action.execute (pg 168)


(1) test for error condition

(2) set forward string to failure

(3) create ActionErrors object


ActionErrors errs = new ActionErrors();

(4) add ActionError to ActionErrors object


errs.add("sql", new ActionError("errors.sql.sqlerror", sqlException.getMessage()));

(5) save ActionErros if not empty collection


saveErrors(request, errs);

(6) return ActionForward

(7) As long as
the key used in the ActionError constructor is in the ApplicationResources.properties file
<html:errors /> or is in the input or failure forward jsp

IT WILL WORK, hopefully :-)

Example Steps

1. Create /ch10/index.jsp copy index.jsp from ch09/


2. Change actions in ch10/index.jsp
3. Change struts-config: add new actions for ch10 (copy ch9, change paths & forwards)
4. Edit ch09.LookupForm: change validate method & add ActionError import
5. Add error message key used in 4 to ApplicationResources files
6. Add error.header & error.footer to ApplicationResources files

Run the project in tomcat, put in no symbol

7. Edit the struts-config file and put in validate=”false” in the ch10 action

Reload & run test it again

8. Change the validate to true


9. Edit the ch09.LookupAction & add no symbol found error check
10. Add unknown symbol error to ApplicationResources files
11. Remove <html:errors element after <html:input
11) Jakarta Commons Database Connection Pool (DBCP)
a) Provides a faster reusable pool of datasources
b) does NOT provide transaction management, (please see ibatis notes that follow this chapter)
c) Manages the driver loading and connection process for you
d) Steps:
(1) Create the database and add rows (p 172-173)
(2) Create a ch11 directory
(3) Copy the displaytag/index.jsp file to the new dir
(or create a new jsp that inputs a sql statement and allows display of the result set)
(4) Copy (or create new) displaytag package to ch11 package dir
(5) Edit ch11/index.jsp & ch11/SQLForm (I eliminated all inputs except sql)
(6) Edit ch11/SQLAction
(a) Change source from
Class.forName( “com.mysql.jdbc.Driver” ):
connection = DriverManager.getConnection ( …

to

javax.sql.DataSource ds = getDataSource(httpservletrequestObj, DATASOURCE_KEY);


connection = ds.getConnection();

(7) Edit struts-config (for Eclipse V 3.1.0 MyEclipse V 4.0.3):


(a) new form to match new ch11.SQLForm above (do not duplicated form-bean name)
(b) new action to match new ch11.SQLAction (do not duplicate path & use new input & form)
(c) create new DataSource making sure to:
(i) put in correct user and password
(ii) put in correct url (jdbc:mysql://localhost:3306/Reference)
(iii) have a minimum count of at least 1
(iv)put in correct driver (com.mysql.jdbc.Driver)
(v) if creating more than one DataSource put in unique key

(8) Edit master index if you have one


(9) Redeploy (sometimes you have to recreate the deployment description in MyEclipse)

(10) Copy the mysql.connector jar file to the tomcat/common/lib folder


MyEclipse does not deploy it and will erase it from the WEB-INF/lib folder

(11) Run the query and process the results

(12) Note in Tomcat output:


(a) createConnection
(b) getConnection
(c) releaseConnection instead of closing if you have con.close() in your code

============================================
12) Validator Plugin
Validation of form input while not “required” is good practice, enables reuse, & follows MVC
This chapter shows how to use the Validator Plugin to replace or augment the validate method

---- validator.xml in the text is validation.xml in the blank struts app ----

a) Steps in creating a form (pg 182)


Note: if using modules remember to place the struts-config file in a sub folder of WEB-INF

i) 1. Create an ActionForm class or decide to use DynaActionForm (p183)


ii) 2. Create an Action (LoginAction) (p183)
iii) 3. Setup a resource bundle (ch12.ApplicationResources)
Convention is: formName.propertyName = Some error message

iv) 4. As you work add keys & labels to the jsp's and resource bundle
Remember the goal is that all static text is removed from the jsp

v) 5. Create an input jsp (login,jsp) using the action form & fields (step 1) above (p184)
be careful using value=”something” attributes in the html:text element.
They will override previous entries in the form

vi) 6. Use keys from resource bundle for all prompts (step 4)
vii) 7. Add form bean declaration to the module (or default) struts config file (p185)
viii) 8. Add Action mapping to the module (or default) struts config file
ix) 9. Create a response page to return as the “success” view

To add validation to the project

x) 10. Add the Validator plugin to the config file

<plug-in className="org.apache.struts.validator.ValidatorPlugIn">
<set-property
property="pathnames"
value="/WEB-INF/ch12/validator-rules.xml, /WEB-INF/ch12/validator.xml" />
</plug-in>

xi) 11. Copy the validator-rules.xml and validation.xml files into WEB-INF
or the module folder under WEB-INF

GOTCHA: be very sure you are using the same versions of your struts.jar & the validator xml files
if you do not you will get strange errors like this:
java.lang.NoSuchMethodException: org.apache.struts.validator.FieldChecks.validateRequired(java.lang.Object,
org.apache.commons.validator.ValidatorAction, org.apache.commons.validator.Field,
org.apache.struts.action.ActionMessages, javax.servlet.http.HttpServletRequest)

xii) 12. Subclass ValidatorForm instead of ActionForm in your form (step 1 above)
public class RegistrationForm extends ValidatorForm {
GOTCHA: if you have a validate method make sure to call super.validate and assign the result to an
ActionErrors object. Only then can you run your own validation logic and add errors to the existing
ActionErrors object.
xiii) 13. Add a form to the form sets in the validation.xml file
Note: When debugging watch the console output in Eclipse.
Small errors like zipcode instead of zipCode will show up easily

Note: regular expressions and the mask rule are very powerful

xiv) 14. Add a field, rules, errors, & error arguments to the form set created in step 13
xv) 15. Add error messages to the resource bundle for all errors created in step 14
Note: use the examples from the top of the validator-rules.xml file as a start

xvi) Misc. Points:


Two Rules with one depends, regular expression masks, constants, dates

b) Overriding the validate method, ex:validation between two fields

public ActionErrors validate(ActionMapping mapping, HttpServletRequest request) {


ActionErrors errs = super.validate(mapping, request);

if (!password.equals(passwordChk)) {
errs.add("password", new ActionError("errors.password.mismatch"));
}
return errs;
}
c) Writing Your own rules
i) 1. Create a java class (it can extend anything you wish)
public class ValidatePassword

ii) 2. Add a static validation method


public static boolean matchPasswords(Object bean, ValidatorAction va, Field pass1,
ActionErrors errors, HttpServletRequest request) {
return true if everything is ok false if not
iii) 3. Create an entry in the validator-rules.xml file
<validator name="passwordmatch"
classname="util.ValidatePassword"
method="matchPasswords"
methodParams="java.lang.Object,
org.apache.commons.validator.ValidatorAction,
org.apache.commons.validator.Field,
org.apache.struts.action.ActionErrors,
javax.servlet.http.HttpServletRequest"
msg="errors.password.mismatch">
</validator>

iv) 4. To use your new rule simply follow steps 13 – 15 above

d) DynaActionForms
use DynaValidatorForm instead of DynaActionForm in the form-bean element

<form-bean name="inputform" type="org.apache.struts.validator.DynaValidatorForm">


<form-property name="userName" type="java.lang.String" initial=""/>
</form-bean>
e) Client-Side JavaScript
Saves round trip communication requirements
Each validator in the validator-rules.xml file can have script associtated with it
Can add a js file with all scripts to enable caching by browser
(1) Add <html:javascript tag to jsp

<head>
<title><bean:message key="registration.title" /></title>
<html:javascript formName="registrationform"/>
</head>

(2) Add onsubmit attribute to html:form tag


if return statement left out of submit both validations (client & server) will run
<html:form action="/register" onsubmit="return validateRegistrationform (this)">

(3) Add cancel Boolean variable to <html:cancel tag and Action.execute

jsp:
<html:submit /> <html:cancel onclick=”bCancel=true” />

ActionForm:
if (this.isCancelled(request)) {
sFwd = "home";
}
global-forward:
<forward name=”home” path=”/index.jsp” />

(4) To optimize Client-Server traffic put JavaScript in separate js file


a. create a new file with the extension .js
b. Put your JavaScript code in this file;
do not include opening and closing SCRIPT tags
you can get this from a test run of the jsp setup in 1, 2, & 3 above
c. change the <html:javascript above to read
<html:javascript formName="registrationform" staticJavascript="false" src="val_src.js"

f) Error Logic

<logic:messagesPresent>
<font color='red'>
<strong><bean:message key="errors.header" /></strong>
<ul>
<html:messages id="error">
<li><%= error%></li>
</html:messages> </font>
</ul>
</font>
</logic:messagesPresent>

g) Wizard style Work Flow: or multiple jsp for the same ActionForm / Validate process
i) Benefits:
Allows multiple jsp to access a single form
Allows “Wizard” style input streams

Basic Process (this is slightly different from the text)


(1) Change Action to subclass DispatchAction (see ch5, p97)
this makes small incremental actions possible

public class PhasedRegisterAction extends org.apache.struts.actions.DispatchAction {


public ActionForward step1( …
public ActionForward step2( …

(2) Create new Form to hold new stream of input data


(3) Add parameter=”method” to new Form allow passing of method to Action
ie. if method=”step1” then the Action.step1 method will be used
remember to add getMethod() and setMethod()

private String method;

public String getMethod() { return method; }


public void setMethod(String s) { this.method = s; }

(4) Create two input jsp


(my examples are reg1.jsp & reg2.jsp and are simply segments of the previous version)

(5) Add two form & action-mappings to struts-config


<form-bean name="phasedregisterform" type="ch12.PhasedRegForm" />

<action path="/regphase1" name="phasedregisterform"


scope="request" input="/reg1.jsp" validate="false"
parameter="method" type="ch12.PhasedRegisterAction">
<forward name="success" path="/reg2.jsp" />
<forward name="failure" path="/reg1.jsp" />
</action>

<action path="/regphase2" name="phasedregisterform"


scope="request" input="/reg2.jsp" validate="false"
parameter="method" type="ch12.PhasedRegisterAction">
<forward name="success" path="/Welcome.jsp" />
<forward name="failure" path="/reg2.jsp" />
</action>

(6) Create two input jsp, use the new form and actions created above
(7) Add a hidden field to the jsp to identify the Action method to use
for example on the first step input jsp:
<html:hidden property="method" value="step1" />

Test it now, if you look at the form data when you are in the second input phase (either debug or
System.err.println) you will notice everything from the first input is gone.
The problem is request scope.

(8) In the action-mappings in the struts-config file, change form to session scope to allow repeated
access
<action path="/regphase2" name="phasedregisterform"
scope="session" input="/reg2.jsp" validate="false"
parameter="method" type="ch12.PhasedRegisterAction">
<forward name="success" path="/Welcome.jsp" />
<forward name="failure" path="/reg2.jsp" />
</action>

(9) Modify validation.xml & make necessary changes to the Form and the Action classes to allow
validation
Following the books naming
(a) Add an additional hidden field for page to each of the input jsp
<html:hidden property="method" value="step1" />

Notice that you can either set the page variable value in the Action as the book
does or as a “static” value in the tag as I do above.

(b) Add a new validation form to the validation.xml file & setup all field validation rules

(c) Add a page=’?’ attribute to each field element indicating where (on which jsp) the field
should be validated
13) Tiles or visual struts components
Goal is reusable presentation components & ability to standardize webapp views

a) Definitions & Overview


i) Tiles are reusable visual components (page == tile)
ii) Arguments are passed to Tiles as parameters in tile scope
iii) Tile scope is similar to page scope, less general than request scope
iv) Parameters and Arguments are available ONLY to the tile they are passed to
v) Tile layouts can provide default argument to tiles
That means the individual visual components need override only those args specific to them
vi) A region is an area in a tile layout
vii) A Tile Definition defines parameters for calling a tile layout
viii) Tile definitions can extend other definitions
ix) The tiles framework provides a custom RequestProcessor

There are several ways to “define” a site layout in my opinion the xml version is best

b) Steps in creating and using a tile layout (METHOD 1)


(1) Find the similarities between jsp or design the structure of a web site
(2) Create a new layout page
(a) Import the Tiles taglib into the jsp
<%@ taglib uri="/WEB-INF/struts-tiles.tld" prefix="tiles" %>

versus

<%@ taglib uri="http://jakarta.apache.org/struts/tags-tiles" prefix="tiles" %>

(b) Use <tiles:getAsString tags to display string parameters such as page title
<title> <tiles:getAsString name="title" ignore="true"/> </title>

(c) Use <tiles:insert tags to insert the tiles into the correct regions of the layout
(d) Use <tiles:put sub tags to pass parameters to tiles being used
<tiles:insert attribute="header" ignore="true">
<tiles:put name="title" beanName="title" beanScope="tile"/>
</tiles:insert>

(3) Create two new content pages that contain only the differences between jsp
(4) Insert the tile layout into the new pages and send parameters to the tiles to customize content
(a) Import the Tiles taglib
(b) Use the <tiles:insert tag to put the layout into the current jsp
(c) Use <tiles:put sub tags to pass parameters (both strings and other tiles)
Example passing just tiles as region components

<tiles:insert page="siteLayout.jsp" flush="true">


<tiles:put name="title" type="string" value="Get Wrox Stock Quote" />
<tiles:put name="header" value="header.jsp" />
<tiles:put name="footer" value="footer.jsp" />
<tiles:put name="content" value="indexContent.jsp"/>
</tiles:insert>
Example passing text (html) as region component

<tiles:insert page="siteLayout.jsp" flush="true">


<tiles:put name="title" type="string" value="Wrox Stock Quote" />
<tiles:put name="header" value="header.jsp" />
<tiles:put name="footer" value="footer.jsp" />
<tiles:put name="content" type="string">
<bean:message key="app.price"/>
<%= request.getAttribute("PRICE") %>
</tiles:put>
</tiles:insert>

(d) Build the component pages (footer.jsp, header.jsp, & indexContent.jsp above)

c) creating and using a tile layout definition in a non visual jsp (METHOD 2)
tile definitions add the ability to pass default parameters, this ability helps limit code repetition

(1) import the Tiles tag library


(2) use <logic:notPresent tag to insure that the definition is created only once in this webapp
(3) create the layout using <tiles:definition
(4) Use sub <tiles:put tags to setup the layout and pass default parameters

<logic:notPresent name="siteLayoutDef" scope="application">


<tiles:definition id="siteLayoutDef" page="/siteLayout.jsp" scope="application">
<tiles:put name="title" type="string" value="Wrox Stock Quote System" />
<tiles:put name="header" value="/header.jsp" />
<tiles:put name="footer" value="/footer.jsp" />
<tiles:put name="content" type="string"> Content goes here </tiles:put>
</tiles:definition>
</logic:notPresent>

Create the page that uses the new layout definition


(5) Use <jsp:include to put the definition into this new page

<jsp:include page="siteLayoutDefinition.jsp"/>

(6) Use <tiles:insert & <tiles:put tags to override default definitions (index2.jsp)
<tiles:insert beanName="siteLayoutDef" beanScope="application">
<tiles:put name="title" type="string" value="Get Wrox Stock Quote 2" />
<tiles:put name="content" value="indexContent.jsp"/>
</tiles:insert>
d) creating and using a tile layout definition in a non visual XML (METHOD 3)

(1) Add the Tiles plugin for struts to the struts-config file

<plug-in className="org.apache.struts.tiles.TilesPlugin" >


<set-property property="definitions-config" value="/WEB-INF/ch13/tiles-defs.xml" />
<set-property property="moduleAware" value="true" />
<set-property property="definitions-parser-validate" value="true" />
</plug-in>
(2) Create a new <tiles-definitions> <definition in the tiles-defs.xml file

<tiles-definitions>

<definition name="siteLayoutDef" path="/siteLayout.jsp">


<put name="title" value="Wrox Stock Quote System" />
<put name="header" value="/header.jsp" />
<put name="footer" value="/footer.jsp" />
<put name="content" type="string">
Content goes here
</put>
</definition>

</tiles-definitions>.

(3) Replace the beanName and beanScope tags in the previous index2.jsp (index3.jsp)
<tiles:insert definition="siteLayoutDef">
<tiles:put name="title" type="string" value="Get Wrox Stock Quote 3" />
<tiles:put name="content" value="indexContent.jsp"/>
</tiles:insert>

e) Notes:
i) If you are using modules remember to make all the jsp in tile:put tags relative
ii) If you have set the validate xml property in the plugin to true
<set-property property="definitions-parser-validate" value="true" />
Remember to include a link to the dtd in the tiles-defs.xml file

<?xml version="1.0" encoding="ISO-8859-1" ?>

<!DOCTYPE tiles-definitions PUBLIC "-//Apache Software Foundation//DTD Tiles Configuration 1.1//EN"


"http://jakarta.apache.org/struts/dtds/tiles-config_1_1.dtd">

iii)
14) Developing a Complete Struts application
A link to a similar article from The Server Side: Struts Redirect-after-Post
These notes follow the creation of the employees application in PJS: Ch14 as adapted to our system
a) Basic Tomcat / eclipse /MyEclipse / MySql webapp setup
(1) Create a new Project (I followed the book and named mine employees)
(2) Use MyEclipse to add struts capabilities
(I used com.wrox as the base package and employeesResources for the resource file)
(3) Add the mysql jdbc driver jar file to your java build path
(4) Create an English resource bundle (Listing 14.3 pg 247)
(5) Create the /WebRoot/images folder with required images
(6) NOTE: Setting up the tag libraries. In the book the authors always put tag lib defs in the
web.xml file, however when using our environment none are ever found there. The following
note from http://struts.apache.org/userGuide/configuration.html explains why:

Servlet 2.3 users only: The Servlet 2.3 specification simplifies the deployment and configuration of
tag libraries. The instructions above will work on older containers as well as 2.3 containers (Struts
only requires a servlet 2.2 container); however, if you're using a 2.3 container such as Tomcat 4.x,
you can take advantage of a simplified deployment.

All that's required to install the Struts tag libraries is to copy struts.jar into your /WEB-INF/lib
directory and reference the tags in your code like this:

<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>

Note that you must use the full uri defined in the various tlds (see the example configuration for
reference) so that the container knows where to find the tag's class files. You don't have to alter your
web.xml file or copy tlds into any application directories.

(7) Create the employees database:


mysqladmin create employees -u root –p
grant all privileges on employees.* to '4383'@'%' identified by 'durrett';
grant all privileges on employees.* to '4383'@'localhost';
mysql -p employees < mysqlscripts.sql
(I removed the first two line so that I could add my own new db and user)

b) Create the basic data model objects


(1) com.wrox.Employee.java
(a very simple struts form)

(2) com.wrox.EmployeeData.java
Provides the webapp --- business model interface

(3) Add the data-source element to your struts-config file


Remember to change the username and password
c) Create the list, add, edit, & delete transactions for the employee database
i) Welcome
(1) create the index.jsp page (it is a simple forward to the EmployeeList action)

(2) add the index.jsp url to the welcome-file-list element in the web.xml file

ii) list employees


(1) Create the com.wrox.EmployeeListAction.java

(2) Create the /WebRoot/employeelist.jsp


Since we did not put the tag defs in web.xml, remember to change the uri’s in the jsp
<%@ taglib uri="http://jakarta.apache.org/struts/tags-bean" prefix="bean" %>
<%@ taglib uri="http://jakarta.apache.org/struts/tags-html" prefix="html" %>
<%@ taglib uri="http://jakarta.apache.org/struts/tags-logic" prefix="logic" %>

Also, note the edit and delete links for each employee

<a href="Edit.do?username=<bean:write name="employee" property="username"


/>">Edit</a>
<a href="Delete.do?username=<bean:write name="employee" property="username"
/>"> Delete</a>

(3) Add the /EmployeeList action-mapping to the struts-config file

iii) add employee


(1) Create the /WebRoot/addemployee.jsp

(2) Create the com.wrox.EmployeeForm.java


the reset method simply sets the default values
the validate method enforces not null requirements of the employees table

(3) Create the com.wrox.AddEmployeeAction.java

(4) Add the employeeForm form-bean and the the /Add action-mapping to the struts-config file

iv) edit employee


(1) Create the com.wrox.GetEmployee.java

(2) Create the /WebRoot/editemployee.jsp

(3) Create the com.wrox.EditEmployeeAction.java

(4) Add the /Edit & /EditEmployee paths to the action-mappings in the struts-config file

v) delete employee
(1) Create the com.wrox.DeleteEmployeeAction.java
(2) Add the /Delete path to the action-mappings in the struts-config file

vi) test the webapp, every thing should work


15) The struts-config.xml File
An amplification / overview of the heart of any struts project
http://struts.apache.org/dtds/struts-config_1_2.dtd

<!ELEMENT struts-config (display-name?, description?, data-sources?, form-beans?,


global-exceptions?, global-forwards?, action-mappings?, controller?, message-resources*, plug-in*)>

The elements must be in exactly this order (they must follow the dtd listed above)

a) XML
i) Elements are delimited by angle brackets and identify the nature of the content they surround.
ii) The element’s content model follows the element name.
iii) ? in the content model indicate optional sub-elements that can occur only once
iv) * in the content model indicate optional sub-elements that may occur zero or more times
v) + indicate optional sub-elements that must occur once but can more times
vi) Attributes are name-value pairs that occur inside start-tags after the element name
vii) % identifies a parameter entry in an element definition
viii)Comments begin with <!-- and end with -->
(1) A CDATA section instructs the parser to ignore most markup characters
<![CDATA[
What ever code
>

Between the start of the section, <![CDATA[ and the end of the section, >, all character data is passed
directly to the application, without interpretation

b) Top-level sub-elements
i) <icon> <small-icon> <large-icon>
<!ELEMENT icon (small-icon?, large-icon?)>
<!ELEMENT small-icon (%Location;)>
<!ELEMENT large-icon (%Location;)>

ii) <display-name>
<!ELEMENT display-name (#PCDATA)>

iii) <description>
<!ELEMENT description (#PCDATA)>

iv) <set-property
<!ELEMENT small-icon (%Location;)>

<set-property property="minCount" value="" />

c) data-sources
<!ELEMENT data-sources (data-source*)>
<!ELEMENT data-source (set-property*)>

<data-sources >
<data-source key="durrett_db_stocks" type="org.apache.commons.dbcp.BasicDataSource">
<set-property property="minCount" value="" />
<set-property property="password" value="guest" />
<set-property property="maxCount" value="" />
<set-property property="username" value="guest" />
<set-property property="driverClassName" value="com.mysql.jdbc.Driver" />
<set-property property="description" value="" />
<set-property property="url" value="jdbc:mysql://129.118.51.8:20/durrett_db" />
<set-property property="readOnly" value="true" />
</data-source>
</data-sources>

i) type – optional DataSource class (default: javax.sql.DataSource) must meet java bean specs
ii) className – optional configuration object must extend org.apche.struts.config.DataSourceConfig
iii) key – unique identifier required if more than one data-source used

d) form-beans
<!ELEMENT form-beans (form-bean*)>
<!ELEMENT form-bean (icon?, display-name?, description?, set-property*, form-property*)>`

<form-beans >
<form-bean name="registrationform" type="ch12.RegistrationForm" />
<form-bean name="sqlform" type="db_sql.SqlForm" />
<form-bean name="phasedregisterform" type="ch12.PhasedRegForm" />
</form-beans>
i) name – unique identifier
ii) type – class name of the form class

e) global-exceptions
<!ELEMENT global-exceptions (exception*)>
<!ELEMENT exception (icon?, display-name?, description?, set-property*)>

defines an ExceptionHandler to execute when an Action's execute method throws an Exception.

(1) subclass org.apache.struts.action.ExceptionHandler and override the execute method


(2) Your execute method should process the Exception and return an ActionForward object
(3) Edit struts-config

<global-exceptions>
<exception key="some.key" type="java.io.IOException" handler="com.yourcorp.ExceptionHandler"/>
</global-exceptions>

This configuration element says that com.yourcorp.ExceptionHandler.execute will be called when


any IOException is thrown by an Action. The key is a key into your message resources properties
file that can be used to retrieve an error message.

ii) You can override exception handlers by defining an exception inside an action

f) global-forwards
<!ELEMENT global-forwards (forward*)>
<!ELEMENT forward (icon?, display-name?, description?, set-property*)>

<global-forwards>
<forward name="home" path="/index.jsp" redirect="false" />
</global-forwards>
i) name: The logical name for this forward. Used in Action’s execute method to forward to the next
appropriate resource.
ii) path: The context relative path to the resource. Example: /index.jsp or /index.do
iii) redirect: True or false. Should ActionServlet redirect to the resource instead of forward? [false]

g) action-mappings
<!ELEMENT action-mappings (action*)>
<!ELEMENT action (icon?, display-name?, description?, set-property*, exception*, forward*)>

<action-mappings >
<action path="/regform" forward="/registration.jsp" />
<action path="/sqlform" forward="/SqlQuery.jsp" />
<action path="/phasedregform" forward="/reg1.jsp" />

<action path="/register" attribute="registrationform" name="registrationform"


scope="request" input="/registration.jsp" validate="true"
type="ch12.RegisterAction">
<forward name="success" path="/Welcome.jsp" />
<forward name="failure" path="/registration.jsp" />
</action>

</action-mappings>

h) controller (all attributes are optional and can be selectively changed)


http://struts.apache.org/userGuide/configuration.html
<!ELEMENT controller (set-property*)>

<controller bufferSize="4096" processorClass="com.gaite.GaiteRequestProcessor" />

i) For each request made of the controller, the method process(HttpServletRequest,


HttpServletResponse) will be called. This method determines which module should service the
request and then invokes that module's Request Processor’s process method, passing the same request and
response.
public class GaiteRequestProcessor extends TilesRequestProcessor {
protected boolean processPreprocess(HttpServletRequest request, HttpServletResponse response) {
// If user is trying to access login page
// then don't check
String sServletPath = request.getServletPath();
if( sServletPath.equals("/Login.do") || sServletPath.equals("/locale.do") ) return true;

// Check if userName attribute is there is session.


// If so, it means user has allready logged in
User user = (User)request.getSession().getAttribute(GaiteSystemConstants.USERKEY);
if( user != null ) return true;
else { try {
// If no redirect user to login Page
request.getRequestDispatcher("/Login.do").forward(request,response);
}catch(Exception ex){
}
}
return false;
}
}

ii) bufferSize – size (bytes) of the input buffer used for processing file uploads. [4096]
iii) className - Classname of configuration bean. [org.apache.struts.config.ControllerConfig]
iv) contentType - Default content type (and optional character encoding) to be set on each response.
May be overridden by the Action, JSP, or other resource to which the request is forwarded.
[text/html]
v) forwardPattern - Replacement pattern defining how the "path" attribute of a <forward> element is
mapped to a context-relative URL when it starts with a slash (and when the contextRelative property
is false). This value may consist of any combination of the following:

* $M - Replaced by the module prefix of this module.


* $P - Replaced by the "path" attribute of the selected <forward> element.
* $$ - Causes a literal dollar sign to be rendered.
* $x - (Where "x" is any character not defined above) Silently swallowed, reserved for future use.

If not specified, the default forwardPattern is consistent with the previous behavior of forwards. [$M$P]

vi) inputForward - Set to true if you want the input attribute of <action> elements to be the name of a
local or global ActionForward, instead of as a module-relative path to the resource to be used as the
input form. [false]
vii) locale - Set to true if you want a Locale object stored in the user's session if not present. [true]
viii) processorClass - The fully qualified Java class name of the RequestProcessor subclass to be used
with this module. [org.apache.struts.chain.ComposableRequestProcessor]
ix) maxFileSize - The maximum size (bytes) of a file to be accepted as a file upload. Can be
expressed as a number followed by a "K", "M", or "G", [250M]

i) message-resources
multiple resource files can be used
<!ELEMENT message-resources (set-property*)>

<message-resources parameter="ch12Resources" resources key="main"/>


<message-resources parameter="MainErrors" resources key="errors"/>

<bean:message key="key.in.resourcefile" bundle="key name in message-resources element"/>

j) plugins
<!ELEMENT plug-in (set-property*)>

<plug-in className="org.apache.struts.validator.ValidatorPlugIn">
<set-property property="pathnames"
value="/WEB-INF/ch12/validator-rules.xml, /WEB-
INF/ch12/validation.xml" />
</plug-in>

k) Gotcha:
i) Forward vs. redirect: if you set the redirect attribute to true in the forward
you loose the request scope objects (you keep the session scope object of course)
<forward name="success" path="/welcome.do" redirect="true"/>

16) The HTML tag library http://struts.apache.org/struts-taglib/tlddoc/


Tag library documentation is IMHO lacking. So what you are going to get here is interesting examples

a) The Problem: you need to create a combo box from database information
for example a set of departments from a dept table as in the chapter 14 employees app

b) The solution

(1) Create java bean class with all the properties necessary for each of your “options”
In my example project (jrd) this is the MenuItem class

public class MenuItem {

private String prompt;


private String value;
private String link;

Note: the link attribute is not used in the html:select tag but in the logic:iterate example later

(2) Create a collection (a simple array is the easiest) of the beans from your database
In my example I simply “fake it”

MenuItem[] menu = new MenuItem[3];


menu[0] = new MenuItem("BA", "3", "http://www.ba.ttu.edu/");
menu[1] = new MenuItem("Accounting", "4", "http://accounting.ba.ttu.edu/");
menu[2] = new MenuItem("Finance", "5", "http://finance.ba.ttu.edu/");

GOTCHA: If any item in your collection is null you will get server errors

(3) Save the collection you created in some scope (in my example request)
request.setAttribute("menu", menu);

(4) Create your standard struts jsp – form-bean – action to allow input
(5) On the input jsp add the html:select tag
<html:form action="/DeptChoice">
department :
<html:select property="department" size="1">
<html:options collection="menu" property="value" labelProperty="prompt" />
</html:select>
<html:submit/><html:cancel/>
</html:form>

property is the property in your input form-bean


(a)
size is the number of selections to allow
(b)
(6) Add the html:options tag as a sub-element in the select element
(a) collection is the name of the bean that you saved in some scope
(b) property is the “value”
(c) labelProperty is the prompt for each option
(d) scope is the memory space in which to look for the collection bean
17)
18) The Logic Tag Library http://struts.apache.org/userGuide/dev_logic.html

a) The Problem: you need to create a set of links from database information
for example the main menu in a webapp depends on the role of the person who logs in

b) The solution

(1) – (4) Follow the same pattern as in the html tag example above

(5) On the input jsp add the logic:iterate code

<logic:iterate id="mnu" name="menu" >


<a href=<bean:write name="mnu" property="link" /> >
<bean:write name="mnu" property="prompt" /></a><br>
</logic:iterate>.

(a) id is the object name used in the loop for the collection
(b) name is the collection name in some memory space
(c) scope is where to look for the collection of beans
.
(6) Add the bean:write tags in the logic:iterate element
(a) name is the object name from id in the logic:iterate element
(b) property is the bean property to call with a getSomeProperty query
(c) The rest is normal html

(7)
Addendum

1. Modules
Using modules allows developers to partition a single web application into functional areas. This allows independent
development without struts-config, form, and action coordination problems.
(a)Steps in Using Modules
i. Create a struts-config file for each module
ii.Configure the web.xml deployment descriptor for each module
iii. Co

(b)struts configuration files


Having seperate config files allows independent forwards, forms, actions, etc
The only difference with module config files is how the Tiles and Validator plugins are setup

i. The typical naming convention for module config files is


struts-config-MODULE.xml where MODULE is the name of the specific module

ii.However when using Tiles and/or Validator this option is more practical
/WEB-INF/moduleA/struts-config.xml
/WEB-INF/moduleB/struts-config.xml

this struture allows seperate placement of the Tiles and Validator config files:
And in Eclipse allows adding forms, etc through the outline (Linux)
/WEB-INF/moduleA/tiles-defs.xml
/WEB-INF/moduleA/validation.xml
/WEB-INF/moduleB/tiles-defs.xml
/WEB-INF/moduleB/validation.xml

(c)Configure the web.xml file for each module

i. The typical, single module web.xml file the struts-config file is specified as:
<init-param>
<param-name>config</param-name>
<param-value>/WEB-INF/struts-config.xml</param-value>
</init-param>

ii.When using modules each config parameter must be named to exactly identify the module. The
param-name must be: config/moduleName where moduleName is the exact name you want to use for
your module in this webapplication. For instance, assume you have two modules named ch08 and
ch10:

<init-param>
<param-name>config/ch08</param-name>
<param-value>/WEB-INF/struts-config-ch08.xml</param-value>
</init-param>
<init-param>
<param-name>config/ch10</param-name>
<param-value>/WEB-INF/struts-config-ch10.xml</param-value>
</init-param>

iii. The
module-prefix and is very important. It is used by struts to distinguish and route requests to each
module. The module-prefix becomes part of the URL that is always used to access module jsps,
actions, etc>

All of a module's action paths are relative to the module. For instance, if we have a webapp named
s05_4383 a module named ch08 and an action who's path is /query the URL becomes:
http://someserver:someport/s05_4383/ch08/query

iv. Wh
module name and specified in the web.xml file as simply config, is the default struts-config file and is
used when no module is listed in the URL. Thus files placed in the webapp root or in folders not
named after modules will be controlled through this default config file.

(d)Configure links and actions to access module specific jsps and actions
When using modules you cannot simply link to the relative directory (ch08/index.jsp)
The problem is that the jsp URL will not go through the struts servlet and thus the relative module
configuration will not be loaded and any tag libraries or actions used will be loaded from the default
config file.

To correct this problem all requests for module changing jsps must be routed through the struts servlet.
This is accomplished as follows:

i. Add the SwitchAction mapping to each struts-config file


<action path=”/switchMod” type=”org.apache.struts.actions.SwitchAction” />
You may use any action path you wish

ii.When linking from a jsp to go to a sub-module index.jsp use:


<html:link action="/switchMod?prefix=/ch08&page=/index.jsp">

to go to the top level “default” module index.jsp use:


<html:link action="/switchMod?prefix=&page=/index.jsp">

iii. Yo

(e)Using Eclipse 3.1.0 with MyEclipse 3.8.4

i. Create a web project, add struts capabilities (PJS in this example)


Be sure to backup the project (or deploy it) before continuing just in case :-)

ii.Add a new module to the new project (ch11)


You will get an web.xml file with the correct config param:
<init-param>
<param-name>config/ch11</param-name>
<param-value>/WEB-INF/struts-config-ch11.xml</param-value>
</init-param>

if you wish to use Tiles or the Validator remember to change the structure per b.ii. Above.
And a “blank” module config file

iii. Op
iv. Cr
Right click on the form-beans element in the outline and chose new Form
You may use the default package or a package name for the form class
Note that the new module is chosen by default
Create the form as you have before do not add the module name to any of the paths

You will end up with a typical form-bean entry and a new ActionForm class
Make the appropriate changes to the class

v. Create a new action


Right click on the action-mapping element in the outline and chose new Action
Fill out the appropriate entries as always, Remember that all paths are relative to the module.

You should now have an Action class and an action entry in the module struts-config file. Edit the
Action class as you wish to accomplish your action.

vi. Cre

vii. Cre

viii. If y
<global-forwards>
<forward name="localmain" path="/localmain.do"/>
</global-forwards>
<action-mappings>
<action path="/localmain" forward="/index.jsp" />
<action path="/switchMod"type="org.apache.struts.actions.SwitchAction" />
</action-mappings>

and create the index using standard struts links for local module actions and SwitchAction links for
changing to other modules
<html:link action="/switchMod?prefix=&page=/index.jsp">

ix. Ma

x. Deploy and reload the project to the Tomcat server


2. MyEclipseIDE Database Explorer
MyEclipse Database Explorer

Requirements:
1. Java 2 SDK, Standard Edition 1.4 or later installed
2. Eclipse 3.0.x SDK
3. MyEclipse 3.8.3 at least
4. A database server that is supported bythe MyEclipse Database Explorer
5. The MyEclipse Database Explorer configured to browse a sample database

(a)Database Explorer

i. Install Driver: /Window/Preferences/MyEclipse/Database Explorer/Drivers


A. Disable Row Limit
B.Load all database meta data

ii.New profile (the icon on the browser pane)


A. Change the driver to the one you just edited
B.Change the URL to 129.118.51.6:20/yourdb_db
C.I suggest prompt for password

iii. Rig

iv. Be

(b)ER diagrams
Currently limited to creating diagrams from current databases

i. Open database connection


ii.Right click on database and choose create ER diagram

iii. No
A. You might have to edit the diagram colors in Preferences
B.MySQL (version 4.1.7) supports foreign keys only in InnoDB tables
C.InnoDB create sql
D. InnoDB insert sql

iv. Inte
A. show engines;
B.show create table SomeTableName;
C.show table status;
D. describe SomeTableName;
E.show tables;
3. User authentication
(a)Authentication
i. Option 1: include a user table in the db schema
A. This option assumes that your db contains a table something like this: (email is the userid)
create table RefUsers (
password varchar(20) NOT NULL, nickname varchar(20) NOT NULL,
email varchar(50) NOT NULL, scope varchar(15) NOT NULL, lastname varchar(30),
firstname varchar(30), bselect boolean default 1, binsert boolean default 0,
bupdate boolean default 0, bdelete boolean default 0,
PRIMARY KEY (email) );

B. With insert statement like:


insert into RefUsers values ("bob", "DrBob", "bob@bob.com", "select", "Bob", "Bob");
insert into RefUsers values ("durrett", "DrJohn", "john@durrett.org", "admin", "Durrett", "John");

C. And validation queries like (u is userid and p is password) :


select * from RefUsers where email=\"" + u + "\" and password=\"" + p + "\"”

D. The problem here is that if I give the ability to do a generic sql query on the db and the user
does:
select * from RefUsers
They are going to get

Password nickname email scope lastname firstname


Bob DrBob bob@bob.com select Bob Bob
Durrett DrJohn john@durrett.org admin Durrett John

Probably not what you would want

The solution is to use encryption

E. Leave the create table syntax the same but change the insert statements to:
insert into RefUsers values
(AES_ENCRYPT('Tom','DrJohnisaGreatTeacher!'), "Just Tom", "tom@tom.com", "select", "Tom", "Thompson");

F. And valiation queries like:


select * from RefUsers where email=”useridvar" and
AES_DECRYPT(password,\'DrJohnisaGreatTeacher!\') ="passvar”;

G. Then your query results above look like:


Password nickname Email scope Lastname firstname
Bob DrBob bob@bob.com select Bob Bob
Tﱪ6£Mak/æÏ Just Tom tom@tom.com select Tom Thompson

Much less informative. The problem is keeping track of the encryption key

H. If you do select @enckey:='DrJohnisaGreatTeacher!'; when creating a connection object then


select * from RefUsers where email=”useridvar" and AES_DECRYPT(password,@enckey) ="passvar”;

to validate the user the key stays on the server


ii. Option 2: Do not include users in the db that the user has access to
A. First, create two completely different databases on the server
in our example these will be ref_db (for the data files) and Ref_User_db for user validation

B. Second, insert data into ref_db and users into Ref_User_db and add appropriate users to MySQL

C. Third, either create two data-source elements in your struts-config file or connect to the
Ref_User_db in LogonAction and the ref_db in SqlQueryAction

iii. Optio
possible too.

iv. To s
A. Extend ActionServlet and override the init() method
public class RefActionServlet extends ActionServlet {

public void init() throws ServletException {


super.init();

B. In the init method:


C. Call super.init() as the first line in the new method
D. Get a DataSource from the servlet context for the ref_user_db
(DataSource)getServletContext().getAttribute("ref_user"); .
E. Get a connection and a statement
F. Execute the select to setup the constant
statement.executeQuery("select @enckey:='DrJohnisaGreatTeacher!'"); .
I would put the constant value and the variable name in GlobalConstants

G. Change the web.xml file to use the new ActionServlet


<servlet-name>action</servlet-name>
<servlet-class>ref.RefActionServlet</servlet-class>

H. Change the select statement in the LoginAction to use the new constant

You might also like