Using Jakarta Struts to Rewrite the University Admission Application
Using Jakarta Struts to Rewrite the Using Jakarta Struts to Rewrite the University Admission ApplicationUniversity Admission Application
Kristin Kinzler Deal - [email protected] Stevens - [email protected]
University of Minnesota
Using Jakarta Struts to Rewrite the University Admission Application
IntroductionIntroduction
Demo old Application for Admission MVC and Struts The Flow Conversion from EJB to Strut Coding Examples Demo the new Application for Admission Struts Affordances Environments Lessons learned: the good, the bad and the ugly
Using Jakarta Struts to Rewrite the University Admission Application
Requirements : Old vs. NewRequirements : Old vs. New
Using Jakarta Struts to Rewrite the University Admission Application
Old Application for AdmissionOld Application for Admission
EJB/JSP architecture Linear in flow Could save at any point and return Applications were of singleton nature
No data sharing between applications or campuses Took a looong time to reach the end Had to go through all sections (linearly) to submit
the application Could not access the application after it was
submitted
Using Jakarta Struts to Rewrite the University Admission Application
Old RequirementsOld Requirements
Ability to save the application and return to it later PeopleSoft compliance
Front-end validation for PeopleSoft Limited to the PeopleSoft field lengths, customized for each campus
Access to application through each campus’ Admissions website No bookmarking allowed Determined the campus to which the user was applying
Applications were “standalone” Derived flow, invisible to the user
Freshman vs. Transfer; Domestic vs. International Fees determined by campus and domestic vs.
International User able to review information before submission Submit payment online using credit card
Using Jakarta Struts to Rewrite the University Admission Application
Database
DBAccessors
DBAccessors
DBAccessors
EJB
BusinessLogic
Data Gettersand Setters
Old Application ArchitectureOld Application Architecture
Using Jakarta Struts to Rewrite the University Admission Application
New Application for AdmissionNew Application for Admission
MVC (Struts)/JSP architecture Small linear chunks of related questions grouped
into sections Users can jump between sections Application saves automatically at the end of each
section Selective required sections reduces complexity and
application length MyAccount established as umbrella over the whole
admission process Applications no longer singleton
Can copy an application within certain rules Can access the application for printing/viewing
after submission
Using Jakarta Struts to Rewrite the University Admission Application
Users will be able to save their application and return to it later
PeopleSoft compliance Access to application through each
campus website Derived flow, invisible to the user Fees determined by campus and
domestic vs. international User able to review information before
submission Applications were “stand alone” Linear flow within the application Submit payment online using credit card
Old vs. New RequirementsOld vs. New Requirements Users will be able to save their
application and return to it later PeopleSoft compliance Access to application through each
campus website Derived flow, invisible to the user Fees determined by campus and
domestic vs. international User able to review information before
submission Applications were “stand alone” Linear flow within the application Submit payment online using credit card
Ability to copy application Section “chunking” – required vs. optional Submit payment using credit card or e-
check Ability to jump around within the application Ability to access an application, for
review/print, after submission MyAccount used as an entry-point to Apply
for Admission
OLD
REQ
UIR
EMEN
TS
NEW
REQ
UIR
EMEN
TS
Using Jakarta Struts to Rewrite the University Admission Application
Model-View-Controller (MVC)Model-View-Controller (MVC)
1. User requests a business logic action through a VIEW.
2. The VIEW forwards the request to the CONTROLLER.
3. The CONTROLLER maps the request for action to the appropriate MODEL, then forwards the request onto the appropriate business logic action.
4. The MODEL may request additional actions from the CONTROLLER, OR:
5. The MODEL selects the appropriate VIEW and prepares it.
6. The MODEL presents the prepared VIEW to the user.
CONTROLLER
VIEW
MODEL
Controls the requests forMODELS including model run-
time parameters and whichVIEW to use.
Presents the data preparedby the MODEL to the user.Has no logic other than the
ability to request a newaction from the controller.
Represents the data and thebusiness logic actions that act onthe data. It is also responsible forpreparing and returning the VIEW.
1
2
3
4
56
Using Jakarta Struts to Rewrite the University Admission Application
StrutsStruts
Open-source implementation of MVC Framework provides
Central controller – ActionServlet• All paths go through controller• Configurable through XML
Action classes• Provide business logic
ActionForms• Hold data for each JSP• State functions handled “behind the scenes”
– Handles form lifecycle
Using Jakarta Struts to Rewrite the University Admission Application
Struts – continuedStruts – continued
Framework provides… XML configuration for application flow
• Actions, Forms, Validate=true Tag libraries
• Avoid scriptlets Built In Internationalization Built In Mechanism for Validation
Advantages Architecture and design Reuse, modularity, extensibility etc..
• Allowed for “cookie-cutter” code reuse Provides base architecture (starting point) for
application development Established framework Open source
Using Jakarta Struts to Rewrite the University Admission Application
The Flow :The Flow :User, Architecture and PageUser, Architecture and Page
Using Jakarta Struts to Rewrite the University Admission Application
User FlowUser Flow
AdmissionsOffice
CampusWebsite
CentralAuthentication
Login(Create Guest
Account)
My Account
Request forDetailed
Information
Apply forAdmission
Apply forHousing
CheckApplication
Status(reads fromPeopleSoft)
WebDatabase
Save
Save
SavePre-Student
Account
Browser
HTTPResponse/Request
PeopleSoftSQR Batch
Using Jakarta Struts to Rewrite the University Admission Application
Architecture FlowArchitecture Flow
END Server
Apache
Tomcat
OracleDatabase
PeopleSoftApache
Tomcat
Apache
Tomcat
Box 1
Box 2
Box n
Browser
HTTPResponse/Request
SQR Batch
Using Jakarta Struts to Rewrite the University Admission Application
Database
DBAccessors
DBAccessors
DBAccessors
Database
DBAccessors
DB Pooler
DBAccessors
DBAccessors
Database
DBAccessors
DBAccessors
DBAccessors
EJB
BusinessLogic
Data Gettersand Setters
Data Gettersand Setters
BusinessLogic
EJB EJB MVC MVC
EntityBean
ActionClass
ActionClass
Using Jakarta Struts to Rewrite the University Admission Application
Page FlowPage Flow
Go ToNext Section
BeginSection
Form 1
JSP 1
JSP 1Exit
Action
Form 1(performsvalidation)
ValidationFails
ExitSection
Save
Entity Bean
The flow throughone page
Using Jakarta Struts to Rewrite the University Admission Application
<action path="/enterAppPerInfoSection" scope="session“ type="edu.umn.web.apply.actions.EnterAppPerInfoSectionAction">
<forward name="next" path="/apply/EditAppPerInfoInstr.jsp" redirect="true"/></action><action path="/enterAppPerInfoNames" scope="session" name="appPerInfoName” type="edu.umn.web.apply.actions.EnterAppPerInfoNamesAction" unknown="false" validate="false">
<forward name="next" path="/apply/EditAppPerInfoNames.jsp" redirect="true"/></action><action path="/exitAppPerInfoNames" scope="session" name="appPerInfoNamesForm" type="edu.umn.web.apply.actions.ExitAppPerInfoNamesAction" unknown="false" input="/apply/EditAppPerInfoNames.jsp" validate="true">
<forward name="back" path="/apply/EditAppPerInfoInstr.jsp" redirect="true"/> <forward name="next" path="/apply/do/enterAppPerInfoHomeAddr" redirect="true"/>
<forward name="cancel" path="/myAccount/do/enterAdmissionApplication" redirect="true"/></action><action path="/saveAppPerInfoSection" scope="session"
type="edu.umn.web.apply.actions.SaveAppPerInfoSectionAction"> <forward name="next" path="/apply/do/exitAppPerInfoSection" redirect="true"/></action><action path="/exitAppPerInfoSection" scope="session"
type="edu.umn.web.apply.actions.ExitAppPerInfoSectionAction"> <forward name="next" path="/apply/do/enterAppMajClgSection" redirect="true"/>
</action>
Config file Action Mapping Code SnippetConfig file Action Mapping Code Snippet
Using Jakarta Struts to Rewrite the University Admission Application
EnterAppPerInfoSectionAction CodeEnterAppPerInfoSectionAction Code
package edu.umn.web.apply.actions;
import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.ActionForm;import org.apache.struts.action.ActionForward;import org.apache.struts.action.ActionMapping;
public class EnterAppPerInfoSectionAction extends ApplyAbstractAction {
public ActionForward perform(ActionMapping mapping, ActionForm xform, HttpServletRequest request, HttpServletResponse response) {
setCurrentSection(request, "personalInfo");return performStdSectionEnterFormAction(mapping, xform, request, response) ;
}
}
Using Jakarta Struts to Rewrite the University Admission Application
Name.java Entity Code SnippetName.java Entity Code Snippetprivate INameAccessor getDBA() { return dba ; }private void setDBA(INameAccessor dba) { this.dba = dba ; }
public IApplication getApplication() { return application ; }public void setApplication(IApplication application) { this.application = application ; }
public String getApplId() { try {return getApplication().getApplId() ;
}catch (Exception e) {} ;return null;}
public String getFirstName() { return getDBA().getFirstName() ; }public void setFirstName(String firstName) { getDBA().setFirstName(firstName) ; }public String getMiddleName() { return getDBA().getMiddleName() ; }public void setMiddleName(String middleName) { getDBA().setMiddleName(middleName) ; }public String getLastName() { return getDBA().getLastName() ; }public void setLastName(String lastName) { getDBA().setLastName(lastName) ; }public String getSuffix() { return getDBA().getSuffix() ; }public void setSuffix(String suffix) { getDBA().setSuffix(suffix) ; }
Using Jakarta Struts to Rewrite the University Admission Application
EnterAppPerInfoNamesAction CodeEnterAppPerInfoNamesAction Code
package edu.umn.web.apply.actions;
import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.ActionForm;import org.apache.struts.action.ActionForward;import org.apache.struts.action.ActionMapping;
public class EnterAppPerInfoNamesAction extends ApplyAbstractAction {
public ActionForward perform(ActionMapping mapping, ActionForm xform, javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) {
return performStdEnterFormAction(mapping, xform, request, response) ;}
}
Using Jakarta Struts to Rewrite the University Admission Application
AppPerInfoImpl Code SnippetAppPerInfoImpl Code Snippet
public class AppPerInfoNamesImpl extends ApplyAbstractImpl implements AppPerInfoNames {
private String lglFirstName = "" ;
private String lglMiddleName = "" ;
private String lglLastName = "" ;
private String lglSuffix = "" ;
public java.lang.String getLglFirstName() { return lglFirstName ; }
public void setLglFirstName( String lglFirstName ) { this.lglFirstName = lglFirstName ; }
public java.lang.String getLglMiddleName() { return lglMiddleName ; }
public void setLglMiddleName( String lglMiddleName ) { this.lglMiddleName = lglMiddleName ; }
public java.lang.String getLglLastName() { return lglLastName ; }
public void setLglLastName( String lglLastName ) { this.lglLastName = lglLastName ; }
Using Jakarta Struts to Rewrite the University Admission Application
Impl con’t – loadFormInfo SnippetImpl con’t – loadFormInfo Snippetpublic boolean loadFormInfo(IMyAccountSessionInfo myAccountSessionInfo) {
try {
MyAccountInfo myAccountInfoBean = myAccountSessionInfo.getMyAccountInfoBean() ;
setLglFirstName(myAccountInfoBean.getLglFirstName()) ;
setLglMiddleName(myAccountInfoBean.getLglMiddleName()) ;
setLglLastName(myAccountInfoBean.getLglLastName()) ;
setLglSuffix(myAccountInfoBean.getLglSuffix()) ;
AdmissionApplication applicationBean = myAccountSessionInfo.getAdmissionApplicationBean() ;
AdmissionForm admissionForm = applicationBean.getAdmissionForm() ;
setFrmrFirstName(admissionForm.getFormerFirstName()) ;
setFrmrMiddleName(admissionForm.getFormerMiddleName()) ;
setFrmrLastName(admissionForm.getFormerLastName()) ;
setFrmrSuffix(admissionForm.getFormerSuffix()) ;
return true;
}
catch (Exception e) { e.printStackTrace(); }
return false;
}
Using Jakarta Struts to Rewrite the University Admission Application
Impl con’t – saveFormInfo SnippetImpl con’t – saveFormInfo Snippetpublic boolean saveFormInfo(IMyAccountSessionInfo myAccountSessionInfo) {
try {
MyAccountInfo myAccountInfoBean = myAccountSessionInfo.getMyAccountInfoBean() ;
myAccountInfoBean.setLglFirstName(getLglFirstName()) ;
myAccountInfoBean.setLglMiddleName(getLglMiddleName()) ;
myAccountInfoBean.setLglLastName(getLglLastName()) ;
myAccountInfoBean.setLglSuffix(getLglSuffix()) ;
AdmissionApplication applicationBean = myAccountSessionInfo.getAdmissionApplicationBean() ;
AdmissionForm admissionForm = applicationBean.getAdmissionForm() ;
admissionForm.setFormerFirstName(getFrmrFirstName()) ;
admissionForm.setFormerMiddleName(getFrmrMiddleName()) ;
admissionForm.setFormerLastName(getFrmrLastName()) ;
admissionForm.setFormerSuffix(getFrmrSuffix()) ;
return true;
}
catch (Exception e) { e.printStackTrace(); }
return false;
}
Using Jakarta Struts to Rewrite the University Admission Application
AppPerInfoNamesForm Code SnippetAppPerInfoNamesForm Code Snippet
public final class AppPerInfoNamesForm extends ApplyAbstractForm {
private static final String validatorName = "AppPerInfoNamesForm" ;
IAppPerInfoNames appPerInfo = null ;
public ApplyAbstractImpl getFormInfo() { return (ApplyAbstractImpl) appPerInfo ; }
private void setFormInfo(IAppPerInfoNames appPerInfo) { this.appPerInfo = appPerInfo ; }
public void reset(ActionMapping mapping, HttpServletRequest request) {
setSessionInfo(request) ;
IMyAccountSessionInfo masi = getSessionInfo() ;
setFormInfo(new AppPerInfoNamesImpl()) ;
getFormInfo().loadFormInfo(masi) ;
}
Using Jakarta Struts to Rewrite the University Admission Application
Old JSP CodeOld JSP Code
JSP code for one page of the old application PersonalInfo.jsp (saved as .txt for easy viewing)
A lot of logic (java code) Contained many scriplet tags Long files Hard to work with and manage
Using Jakarta Struts to Rewrite the University Admission Application
JSP Code Snippet (New App)JSP Code Snippet (New App)<%@ taglib uri="/WEB-INF/lib/struts-bean.tld" prefix="bean" %><%@ taglib uri="/WEB-INF/lib/struts-html.tld" prefix="html" %><%@ taglib uri="/WEB-INF/lib/struts-logic.tld" prefix="logic" %><%@ taglib uri="/WEB-INF/lib/nested-tags.tld" prefix="nested" %><jsp:useBean id="suffixList" scope="application" class="edu.umn.web.util.dropdown.SuffixDropDown"/><html:html> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><head>
<title><bean:message key="prompt.appl.perInfo"/>-<bean:message key="prompt.appl.perInfo.names"/></title><META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"><META HTTP-EQUIV="Pragma" CONTENT="no-cache"><html:base/> <script language="JavaScript" src="../js/browserDetectApp.js"></script><script language="JavaScript" src="../js/popUp.js"></script>
</head><body>
<jsp:include page="/banner.jsp" flush="true"></jsp:include><jsp:include page="/applyTitle.jsp" flush="true"></jsp:include><jsp:include page="/navApply.jsp" flush="true"></jsp:include><jsp:include page="/navBar.jsp" flush="true"></jsp:include>
<html:form action="/exitAppPerInfoNames" focus="submit"> …
Using Jakarta Struts to Rewrite the University Admission Application
JSP Code Snippet con’t.JSP Code Snippet con’t.…<nested:nest property="formInfo">…
<tr> <td nowrap width="1%" class="label"><span class="required">*</span>
<bean:message key="prompt.lglLastName"/> </td><td width="99%" class="text">
<nested:text property="lglLastName" size="30" maxlength="30"/> </td>
</tr><tr>
<td nowrap width="1%" class="label"><bean:message key="prompt.lglSuffix"/>
</td> <td width="99%" class="text">
<nested:select property="lglSuffix" size="1"> <html:option value="">Select Suffix</html:option> <html:options collection="suffixList" property="value" labelProperty="name"/></nested:select>
</td></tr>
… </nested:nest> <jsp:include page="/formButtons.jsp" flush="true"></jsp:include></table>
</html:form> </body>
</html:html>
Using Jakarta Struts to Rewrite the University Admission Application
ExitAppPerInfoNamesAction CodeExitAppPerInfoNamesAction Code
package edu.umn.web.apply.actions;
import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.ActionForm;import org.apache.struts.action.ActionForward;import org.apache.struts.action.ActionMapping;
public class ExitAppPerInfoNamesAction extends ApplyAbstractAction {
public ActionForward perform(ActionMapping mapping, ActionForm xform, HttpServletRequest request, HttpServletResponse response) { return performStdExitFormAction(mapping, xform, request, response) ;
}
}
Using Jakarta Struts to Rewrite the University Admission Application
SaveAppPerInfoSectionAction CodeSaveAppPerInfoSectionAction Code…public class SaveAppPerInfoSectionAction extends ApplyAbstractAction {
public ActionForward perform(ActionMapping mapping, ActionForm xform, HttpServletRequest request, HttpServletResponse response) {
updateAdmissionApplicationEntry(mapping, xform, request, response) ;String dispatchTo = "next" ;IMyAccountSessionInfo masi = getSessionInfo(request) ;masi.setAppStatus("T");MyAccountInfo myAccountInfoBean = masi.getMyAccountInfoBean() ;AdmissionApplication applicationBean = masi.getAdmissionApplicationBean() ;MyAccountApplication myAccountApplicationBean = masi.getMyAccountApplicationBean() ;try {
myAccountInfoBean.commitMyAccountInfo() ;applicationBean.commitApplication() ;myAccountApplicationBean.commitMyAccountApplication() ;
} catch (Exception ex) {ex.printStackTrace() ;dispatchTo = "failCommit" ;
}return mapping.findForward( dispatchTo ) ;
}}
Using Jakarta Struts to Rewrite the University Admission Application
ExitAppPerInfoSectionAction CodeExitAppPerInfoSectionAction Codepackage edu.umn.web.apply.actions;
import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.ActionForm;import org.apache.struts.action.ActionForward;import org.apache.struts.action.ActionMapping;
import edu.umn.web.apply.ientities.*;
import edu.umn.web.myAccount.iform.* ;import edu.umn.web.myAccount.ientities.* ;
public class ExitAppPerInfoSectionAction extends ApplyAbstractAction {
public ActionForward perform(ActionMapping mapping, ActionForm xform, HttpServletRequest request, HttpServletResponse response) {
setSectionStatus(request, "personalInfo", "C"); return performStdSectionExitFormAction(mapping, xform, request, response) ;
}}
Using Jakarta Struts to Rewrite the University Admission Application
Struts Affordances, Environments Struts Affordances, Environments and Lessons Learnedand Lessons Learned
Using Jakarta Struts to Rewrite the University Admission Application
Code ReuseCode Reuse
The data and business logic components were split from the old EJBs Struts Actions house the business logic Struts ActionForms house the data components
Data accessors and the business logic remained (for the most part) unchanged to minimize the need to retest all business functionality
Majority of the Business Logic was removed from the JSPs and moved to the Action Classes
Validation was removed from the JSPs and moved to the Forms
Using Jakarta Struts to Rewrite the University Admission Application
How We Met Our DeadlineHow We Met Our Deadline
Code reuse Minimized testing requirements Facilitated minimal changes to the PeopleSoft data
load Allowed developers to concentrate on the new
application features Struts
Provided the means to meet our customers needs• Ability to jump around• Auto-save• Required vs. Optional sections
Provided instant framework for application architecture
Provided easy division of server side development labor
Using Jakarta Struts to Rewrite the University Admission Application
Development and TestingDevelopment and Testing
Three developed in Linux environment One developed in Win2K CVS for source control Testing tools
JProbe Mercury LoadRunner
Each developer had a development silo Integration silo Unit testing – daily Test silo
Thirteen rounds of functional testing Six rounds of “monkey tests” before we purchased our
testing tool Fifteen rounds of load balance testing using
LoadRunner Production
Using Jakarta Struts to Rewrite the University Admission Application
Lessons Learned (the Good)Lessons Learned (the Good)
Modularity allowed for quick conversion Nested tags allowed for easier view (JSP)
development Properties file
Allowed for reuse of common terminology, easy text changes, and, (if wanted), easier conversion for internationalization
Once the basic actions were complete – development became “cookie cutter”
Learning curve for experienced developers is acceptable Four months from development to implementation
Using Jakarta Struts to Rewrite the University Admission Application
Lessons Learned (the Bad)Lessons Learned (the Bad) Config file length became difficult to manage Any method in a servlet cannot be larger than 64K when
compiled Problem: Our JSP include files contained navigation logic that
exceeded this size restriction Solution: Use <jsp:include> vs. include directive
• <jsp:include> Includes a static file or sends a request to a dynamic file.
• Ex. <jsp:include page="/banner.jsp" flush="true"></jsp:include>• Include directive includes a file of text or code in a JSP file at
translation time, when the JSP file is compiled. • Ex. <%@ include file="checkSession.jsp" %>
Problem: Large included JSPs hide runtime errors Solution: Comment out the included files to get to the error
messages Servlet filters caused performance problems
Extended ActionServlet to manage authentication and session state
Unit Testing was not feasible until all three pieces were in place
Using Jakarta Struts to Rewrite the University Admission Application
Lessons Learned (the Ugly)Lessons Learned (the Ugly)
Testing, testing, testing There is no such thing as too much testing It is crucial to develop and test in an
environment that is EXACTLY the same as the production environment
Performance, performance, performance
Using Jakarta Struts to Rewrite the University Admission Application
Production EnvironmentProduction Environment
Tomcat 4.0.3 with Apache Web server to handle HTTP
Virtual Memory set to 256MB/512MB Dual Processor Intel Machines with RedHat Linux
7.3 E-Network Dispatcher, (END), provides load
balancing 70 Concurrent (Virtual) User “Sweet Spot” per
Tomcat instance Sustained three hour load test showed consistent
under five second response time with most transactions under one second response time
Using Jakarta Struts to Rewrite the University Admission Application
Testing and StatsTesting and Stats
Using Jakarta Struts to Rewrite the University Admission Application
Mercury LoadRunner TestMercury LoadRunner Test
• Three Hour, 70 User Load Test• Sub-second Average Transaction Response
Time Under Load• Average 35 Hits Per Second• Handled an average of 150,000 Bytes Per
Second• 117,287 Completed Transactions
Using Jakarta Struts to Rewrite the University Admission Application
Mercury LoadRunner Test ResultMercury LoadRunner Test Result
Using Jakarta Struts to Rewrite the University Admission Application
Stats as of 12/4/02 *Stats as of 12/4/02 *
8896 Accounts Created 8768 Applications
5258 Applications In Progress 3510 Applications Submitted
Applicants who have multiple in progress applications 177 have two applications 7 have three applications
Applicants who have multiple completed applications 114 have two applications 5 have three applications
* Stats do not account for multiple accounts, abandoned accounts, or duplicates.
Using Jakarta Struts to Rewrite the University Admission Application
For More Info on StrutsFor More Info on Struts
Jakarta Struts Official Site http://jakarta.apache.org/struts/
Nested Tag Lib Resource http://www.keyboardmonkey.com/next/index.JSP
JavaServer Pages (JSP) http://java.sun.com/products/JSP/ JSP v1.2 Syntax Reference
• http://java.sun.com/products/JSP/tags/12/syntaxref12.html
Ted Husted – Struts guru http://husted.com/struts/ http://husted.com/about/scaffolding/strutByStrut.htm
Message board -- very helpful! http://www.mail-archive.com/struts-user%40jakarta.apache.o
rg/
Top Related