Servlet Configuration <web-app …>1 <servlet>*
<context-param> *
<init-param>*
<param-name>1 <param-value>1
<param-name>1 <param-value>1 javax.servlet <<interface>> Javax.servlet.ServletContext <<interface>> javax.servlet.ServletConfig getInitParameter(String):String getInitParameterNames():Enumeration getServletName():String getServletContext():ServletContext
getInitParameter(String):String getInitParameterNames():Enumeration getRequestDispatcher(path:String):RequestDispatcher getResourceAsStream(path:String):InputStream getAttributeNames():Enumeration getAttribute(String):Object setAttribute(String, Object):void removeAttribute(String):void log(String):void log(String, Throwable):void
Vendor-specific log file
<<interface>> ServletContextAttributeListener
<<interface>> ServletContextListener
attributeAdded(ServletContextAttributeEvent) attributeRemoved(ServletContextAttributeEvent) attributeReplaced(ServletContextAttributeEvent)
contextInitialized(ServletContextEvent) contextDestroyed(ServletContextEvent)
ServletContextAttributeEvent
ServletContextEvent
getName():String getValue():Object
getServletContext():ServletContext
Can’t access internals of JARs in lib directory
Request Dispatching
javax.servlet <<interface>> ServletRequest
<<interface>> ServletContext
getRequestDispatcher(resource:String)
getRequestDispatcher(resource:String)
Relative to current location. You cannot move out of the web root.
Will throw IllegalStateException if output is committed to the response (WARNING – may have been autoflushed).
Must begin with a slash “/”
<<interface>> RequestDispatcher forward(req:ServletRequest, rsp:ServletResponse) include(req:ServletRequest, rsp:ServletResponse)
Temporarily suspends control.
Adds a number of attributes to the request: javax.servlet.include.request_uri javax.servlet.include.context_path javax.servlet.include.servlet_path javax.servlet.include.path_info javax.servlet.include.query_string There exist javax.servlet.forward versions for the forward() method.
Original query string
Filters javax.servlet <<interface>> Filter init(FilterConfig):void doFilter(ServletRequest, ServletResponse, FilterChain):void destroy():void <<interface>> FilterConfig
<<interface>> ServletRequest
<<interface>> ServletResponse
...
...
ServletRequestWrapper
ServletResponseWrapper
ServletRequestWrapper(ServletRequest)
getFilterName():String
ServletResponseWrapper(ServletResponse)
getInitParameter(String):String getInitParameterNames():Enumeration getServletContext():ServletContext <<interface>> FilterChain doFilter(ServletRequest, ServletResponse) javax.servlet.http
Filter Matching algorithm: (1) All URL-pattern filters in entry order (2) Servlet names in entry order
HttpServletRequestWrapper
HttpServletResponseWrapper
HttpServletRequestWrapper(HttpServletRequest)
HttpServletResponseWrapper(HttpServletResponse)
<web-app …>1 <filter>*
<filter-name>1 <filter-class>1
<filter-mapping> *
or1
<init-param>* <filter-name>1
<param-name>1 <param-value>1
<url-pattern>1
<dispatcher> *
<servlet-name>1
“REQUEST” “INCLUDE” “FORWARD” “ERROR”
Cookie Notes
The spec dictates that the session tracking cookie must be called JSESSIONID HTTP/1.1 200 OK Set-Cookie:JESSIONID=0A4… Content-Type: text/html …
POST /BeerTest.do HTTP/1.1 Host: www.trycatch.net Use-Agent:Mozilla/5.0 Cookie: JSESSIONID=0A4… Acccept: text/html
Client
Server
javax.servlet.http
<<interface>> HttpServletRequest
<<interface>> HttpServletResponse
getCookies():Cookie[] ...
addCookie(cookie:Cookie):void ...
<<interface>> Cookie Cookie(name:String, value:String) getName():String setName(name:String):void getValue():String setValue(value:String):void setMaxAge(seconds:int) getMaxAge():int
0 = Destroy <0 = Destroy when close browser
Design Patterns
Presentation Tier
Intercepting Filter
Business Tier
Service Locator
Intercepting Filter Business Delegate
Front Controller
Transfer Object
Security
<form method="post" action="j_security_check"> <input type="text" name="j_username"> <input type="password" name="j_password"> <input type="submit"> </form>
<web-app â&#x20AC;Ś>1 <security-role>*
<login-config> * <servlet>*
<role-name>1
<auth-method>?
<realm-name>?
<form-login-config>?
<security-role-ref>* 1
<role-name>
<form-login-page>1
?
<role-link>
Everybody
<security-constraint>* <display-name>1
<web-resource-collection>+
<web-resource-name>1 <url-pattern>+ <http-method>*
<auth-constraint>?
<user-data-constraint>?
<role-name>*
<transport-guarantee>1
HttpServletRequest BASIC_AUTH:String DIGEST_AUTH:String CLIENT_CERT_AUTH:String FORM_AUTH:String getAuthType():String getRemoteUser():String getUserPrinciple():Principle isUserInRole(String):boolean ...
<security-constraint> <auth-constraint> <role-name>*</role-name> </auth-constraint> </security-constraint>
Everybody <security-constraint> <!-- No auth-constraint --> </security-constraint>
javax.servlet.http
Not all containers support
<form-error-page>1
Nobody <security-constraint> <auth-constraint/> </security-constraint>
Constants returned by getAuthType() DD declares auth-method. Returns null if no authentication in place.
Everybody
Returns null if not yet authenticated. Returns an entity capable of logging into a system (contains user name) or null if not yet authenticated.
Everybody
<security-constraint> <auth-constraint> <role-name>Admin</role-name> </auth-constraint> </security-constraint> <security-constraint> <!-- No auth-constraint --> </security-constraint>
Guests and Admins <security-constraint> <auth-constraint> <role-name>Guest</role-name> </auth-constraint> <auth-constraint> <role-name>Admin</role-name> </auth-constraint> </security-constraint>
<security-constraint> <auth-constraint> <role-name>Guest</role-name> </auth-constraint> <auth-constraint> <role-name>*</role-name> </auth-constraint> </security-constraint>
Nobody <security-constraint> <auth-constraint> <role-name>Admin</role-name> </auth-constraint> <auth-constraint/> </security-constraint>
Sessions
<web-app …>1
SSL has a built-in mechanism that the container can use to obtain data used to define a session
<listener>*
<session-config>* <= 0 means NEVER invalidate 1
<listener-class>
Minutes...
<session-timeout>?
javax.servlet.http <<interface>> HttpSession
Has the session ID been sent to the client? Once this has been called, virtually all methods will throw an IllegalStateException if called except getServletContext()
getId():String isNew():boolean invalidate():void getAttributeNames():Enumeration setAttribute(String, Object):void getAttribute(String):Object removeAttribute(String):void
getServletContext():ServletContext
<<interface>> HttpServletResponse
getSession()HttpSession getSession(autoCreate:boolean):HttpSession
encodeURL(url:String):String encodeRedirectURL(url:String):String
Creates session if it doesn’t exist.
getCreationTime():long getLastAccessedTime():long setMaxInactiveInterval(seconds:int) getMaxInactiveInterval():int
<<interface>> HttpServletRequest
0 = Invalidate Now <0 = Never Invalidate
Appends vendor-specific string. Only happens if cookies fail. Won’t work with static pages.
Not in DD
<<interface>> HttpSessionAttributeListener
<<interface>> HttpSessionBindingListener
<<interface>> HttpSessionActivationListener
attributeAdded(HttpSessionBindingEvent):void attributeRemoved(HttpSessionBindingEvent):void attributeReplaced(HttpSessionBindingEvent):void
valueBound(HttpSessionBindingEvent):void valueUnbound(HttpSessionBindingEvent):void
sessionDidActivate(HttpSessionEvent):void sessionWillPassicate(HttpSessionEvent):void
HttpSessionBindingEvent getName():String getValue():Object getSession():HttpSession
Session attributes in a distributed environment must be Serializable… although the Container doesn’t have to use serialization!
Serializable
MyAttribute <<interface>> HttpSessionListener sessionCreated(HttpSessionEvent) sessionDestroyed(HttpSessionEVent)
HttpSessionEvent getSession():HttpSession
getMyVal():String setMyVal(val:String)
Deployment Tags <web-app …>1
<servlet>*
<mime-mapping>*
<load-on-startup>?
<resource-ref>* <extension>1
<jsp-config>* ...
<jsp-property-group>*
<tag-lib>*
<mime-type>1
Don’t include “.”
<taglib-uri>1 <taglib-location>1
<url-pattnern>?
<ejb-local-ref>* <el-ignored>?
<scripting-invalid>?
<ejb-ref-name>1
<local>1
<ejb-ref-type>1
<welcome-file-list>*
<local-home>1
<welcome-file>+ <error-page>* File name, not location (no slashes) If no match behaviour is vendor-specific
<ejb-ref>* or
<location>
<exception-type>1 <error-code>1
Fully-qualified subclass of Throwable.
1
Relative to root i.e. “/foo” Overridden by errorPage attribute
<ejb-ref-name>1 <ejb-ref-type>1 <env-entry>*
? <env-entry-name>1 <env-entry-type>1 <env-entry-value>
sendError(…), not setStatus(…) Must have a String or Character constructor
Must be a String or Character
<remote>1 <home>1
JSP
<jsp:root> no longer has to be root element. No semi-colon.
JSP Document Directive: Declaration: Scriptlet: Text: Expression: File Extension:
Comments
<%@ page import=”…” %> <%! int y = 3; %> <% list.add(7); %> There is no spoon <%= it.next() %> .jsp
<jsp:directive.page import=”...”/> <jsp:declaration>int = 3</jsp:declaration> <jsp:scriptlet> list.add(7) </jsp:scriptlet> <jsp:text>There is no spoon</jsp:text> <jsp:expression> it.next() </jsp:expression> .jspx Only needed if you want to use custom No semi-colon. Error is expression is void. tags namespaces declarations
Other
page request session application
config out response exception pageContext
javax.servlet
init(ServletConfig) destroy() getServletConfig():ServletConfig getServletInfo():String service(ServletRequest, ServletResponse)
JSP Config
javax.servlet.jsp
<%!
<web-app …>1
public void jspInit() { … } public void jspDestroy() { … }
<servlet>* <jsp-file>
Will get evaluated!
<<interface>> Servlet
Scopes
?
<%-- JSP comments will not appear in HTML --%> <!-- <%= session.getId() %> -->
%>
<<interface>> JspPage jspInit() jspDestroy()
<init-param>* Overridable
Path
<param-name>1
<param-value>1
<<interface>> HttpJspPage Cannot override
_jspService(HttpServletRequest, HttpServletResponse)
Directives
Attributes bound to request scope if error page:
General 1. Page Directive <%@ page import=”foo.*, bar.*” %> Possible attributes: import isThreadSafe contentType isELIgnored isErrorPage errorPage ... 2. Taglib Directive
Overrides Deployment Descriptor
Default to “false”. If “true” then the page can access exception implicit object and EL reference ${pageContext.exception}
Used for tag files. Must begin “/WEB-INF/tags”
<%@ taglib prefix=”p” tagdir=”/WEB-INF/tags” uri=”…” %> Used for custom tags
3. Include Directive <%@ include file=”…” %>
Tag Files 4. Attribute Directive
Default to “false”
<%@ attribute name=”...” required=”...” rtexprvalue=”…” %> 5. Tag Directive
javax.servlet.error.status_code javax.servlet.error.exception_type javax.servlet.error.message javax.servlet.error.exception javax.servlet.error.request_uri javax.servlet.error.servlet_name
“empty”, “scriptless” or “tagdependent”
<%@ tag body-content=”...” %> 6. Variable Directive <%@ variable name-given=”date” variable-class=”java.util.Date” %>
Standard Actions 1. Bean Actions
2. Include/Forward Actions
<jsp:useBean …> Must be a public class with a public no-arg constrctor
Defaults to “page”
<jsp:useBean id=”person” class=”foo.Person” scope=”request”/>
<jsp:forward page=”Other.jsp”> <jsp:param name=”name” value=”David”/> </jsp:forward> Clears buffer before forward. If output is flushed first an exception will be thrown, but as the output has been flushed, the user will not be informed!
Creates bean in scope if it doesn’t exist Only executed if new <jsp:useBean id=”person” class=”foo.Person” scope=”request”> bean was created <jsp:setProperty name=”person” property=”name” value=”Fred”/> </jsp:useBean> Reference variable type Object instance type
<jsp:include page=”Other.jsp”> <jsp:param name=”name” value=”David”/> </jsp:forward>
<jsp:useBean id=”person” type=”foo.Person” class=”foo.Employee”/> Will throw InstantiationException if attribute not already in scope as ‘class’ attribute not specified. <jsp:useBean id=”person” type=”foo.Person”/>
3. Tag File Actions <jsp:doBody/> <jsp:invoke/>
<jsp:getProperty…> <jsp:getProperty name=”person” property=”name”/>
Will throw an exception if used outside a tag file.
<jsp:setProperty…>
Only works with strings and primitives
<jsp:setProperty name=”person” property=”name” value=”Fred”/> Valid, but you must remember String-to-primitive conversion doesn’t work. <jsp:setProperty name=”person” property=”name” value=”<%= request.getParameter(“myName”) %>”/> <jsp:setProperty name=”person” property=”name” param=”inputField1”/> <jsp:setProperty name=”person” property=”name”/> <jsp:setProperty name=”person” property=”*”/>
Identifier of attribute in the request scope (added by a form)
Same name as identifier of attribute in the request scope (added by a form) Copies all attributes in the request scope which match properties on attribute
JSTL <c:forEach>
Current value between “begin” and “end” Exists only within the tag
<c:forTokens var=”t” items=”a~b~c” delims=”~”>
<%@ taglib prefix=”c” uri=”http://java.sun.com/jsp/jstl/core” %> … <c:forEach var=”m” items=”${movies}” varStatus=”loopStatus” begin=”…” end=”…” step=”…”> ${m} ${loopStatus.count} </c:forEach>
<c:redirect url=”...”>
<c:if>
<%@ taglib prefix=”c” uri=”http://java.sun.com/jsp/jstl/core” %> … <c:catch var=”myException”/> <%= 10/0 %> </c:catch> Accessible only after </c:cafch> ${myException.message}
<%@ taglib prefix=”c” uri=”http://java.sun.com/jsp/jstl/core” %> … <c:if test=”${userType eq ‘member’}” var=”testResult” scope=”request”> ... </c:if> Store test result in scope No “else”!
<c:remove>
“value” can be set using the contents of the tag body: <c:set>…</c:set>
<%@ taglib prefix=”c” uri=”http://java.sun.com/jsp/jstl/core” %> … <c:set var=”attributeName” scope=”request” value=”${...}”/> … Removes attribute if evaluates to null … ... <c:set target=”${…}” property=”pet” value=”${...}/>
Exception if null or not a map or bean
Defaults to page scope
Exception if property doesn’t exist
<c:url> <%@ taglib prefix=”c” uri=”http://java.sun.com/jsp/jstl/core” %> … <c:url value=”inputComments.jsp” var=”resolved”/>
<c:import>
<%@ taglib prefix=”c” uri=”http://java.sun.com/jsp/jstl/core” %> … <c:remove var=”attributeName” scope=”request”/> Name, not object
<c:catch>
<c:set>
<c:choose> <%@ taglib prefix=”c” uri=”http://java.sun.com/jsp/jstl/core” %> … <c:choose> <c:when test=”${userType == ‘Member’}”> ... </c:when> <c:otherwise> ... </c:otherwise> </c:choose>
<c:out value=”…”>
Encoded result
<%@ taglib prefix=”c” uri=”http://java.sun.com/jsp/jstl/core” %> … <c:import url=”http://www.trycatch.net/index.html”/> <c:param name=”subTitle” value=”Hello World”/> </c:import> Can go out of the container
Expression Language EL is turned on by default.
. Operator
[ ] Operator ${ ____ . ____ }
Can’t use with lists or arrays. or
${ ____ [ ____ ] }
Map key or bean property (lowercase) – must be valid identifier
If a string literal is used it acts as key/property/index, otherwise it is evaluated. Can be an invalid identifier e.g. 1, “1” or “a.b” ${foo.bar} == ${foo[“bar”]}
Map objects in blue. To get real objects... ${pageContext.request} Returns first
EL Implicit Object * pageScope * requestScope * sessionScope * applicationScope *param *paramValues *header *headerValues
Returns array
Context init parameters Reference to actual object
*cookie * initParam
Attribute name found in… * page scope * request scope * session scope * application scope
EL Configuration 1
<web-app …>
<jsp-config>*
*pageContext <jsp-property-group>*
<url-pattern>? <scripting-invalid>? <el-ignored>?
NOTE – Page attribute is isELIgnored.
Don’t be fooled by “-“ in variable names – this will be treated as a subtract! Precedence is left-to-right
EL Operators +, -, * /, div (x / 0 = INFINITY) %, mod (x % 0 = Exception) &&, and ||, or !, not ==, eq !=, ne <, lt >, gt <=, leg >=, ge true, false Reserved null instanceof empty Tests for null or empty Unknown variables treated as zero/false.
Page Composition 1. Directive <%@ include file=”Header.jsp” %>
Copies contents of JSP into current JSP before translation.
2. Standard Action Adds runtime call.
<jsp:include page=”Header.jsp”> <jsp:param name=”subTitle” value=”…”/> </jsp:include>
Test.jsp
Adds as a request parameter, overwriting if necessary.
3. JSTL
Can go out of the container.
<c:import url=”http://www.trycatch.net/index.html”> <c:param name=”subTitle” value=”…”/> </c:import> Included pages cannot change status codes, set headers/cookies or commit output. There will be no exception, it will fail silently.
${param.subTitle}
Tag Library Descriptors (TLD) Can be placed anywhere under /WEB-INF
<taglib …>1 <function> *
<tag-file> *
<tlib-version>1
<uri>1
<short-name>1
<tag>* <name>1
<name>1
<function-class>1 <function-signature>1
<path>1
Must start “META-INF/tags” <name>1
<tag-class>1
<body-content>?
<attribute> *
<dynamic-attributes>? <example>? <small-icon>? “true” or “false”
“empty”, “scriptless”, “tagdependent”, “jsp” Exception thrown if it isn’t!
<name>1
<required>1 <rtexprvalue>? <type>? Defaults to “false”. If true, the following are allowed:
Nothing <% … %> (Default Value) Body treated as plain-text
(1) EL (2) Scripting Expressions (3) Attribute Standard Actions
TLD for EL Function Test.jsp
MyTld.tld <uri>DiceFunctions</uri> <function> <name>rollIt</name> <function-class>foo.DiceRoller</function> <function-signature>int rollDice(...)</function-signature> </function> Must be public and static, should be void
Any arguments must be fully qualified.
<%@ taglib prefix=”mine” uri=”DiceFunctions” %> … ${mine:rollIt()}
Tag Files Tag files are found in:
Will need a TLD to specify location
(i) WEB-INF/tags or subdirectory (ii) WEB-INF/lib/{some jar}/META-INF/tags or subdirectory Page directive not allowed. This attribute only lasts for the tag scope. Test.jsp
Header.tag
<%@ taglib prefix=”p” tagdir=”/WEB-INF/tags” %> <p:Header subTitle=”Welcome”>Hello World</p:Header>
Tag filename without the extension Can’t include any scripting code (true for all custom tags)
Can call getJspContext().
<%@ attribute name=”subTitle” required=”true” rtexprvalue=”true” %> <%@ tag body-content=”tagdependent” %> <h1>{subTitle}</h1> <p><jsp:doBody/></p> Options: “empty”, “tagdependent” and “scriptless”
Simple Custom Tags javax.servlet.jsp
javax.servlet.jsp.tagext
<<interface>>
JspTag
JspException Instances reused.
Instances never reused. <<interface>> SimpleTag
<<interface>> Tag
(5) doTag():void
...
Invocation Order
getParent():JspTag (2)* setParent(JspTag)
* denotes optional invocations
(4)* setJspBody(JspFragment):void (1) setJspContext(JspContext):void
setJspBody(...) is only called if there is a body and TLD says so.
SkipPageException
Can have classic of simple parents.
SimpleTagSupport findAncestorWithClass(JspTag, Class):JspTag getJspBody():JspFragment getJspContext():JspContext <<interface>> JspFragment getJspContext():JspContext Invoice(Writer) <<interface>> DynamicAttributes setDynamicAttribute(String, String, Object) MyHandler (3)* setMyAttribute(MyAttributeType):void
Aborts the remaining generation of the current page.
Simple Custom Tags javax.servlet.jsp.tagext <<interface>>
JspTag
Instances reused.
Instances never reused. <<interface>> SimpleTag ...
<<interface>> Tag doStartTag():int doEndTag():int getParent():Tag setParent(Tag) setPageContext(PageContext) release()
MyHandler set…(…)
TagSupport pageContext:PageContext findAncestorWithClass(Tag, Class):Tag
BodyTagSupport getBodyContent():BodyContent
<<interface>> IterationTag doAfterBody():int <<interface>> BodyTag setBodyContent(BodyContent) doInitBody() <<abstract>> BodyContent
MyHandler setMyAttribute(MyAttributeType):void
javax.servlet.jsp <<abstract>> JspWriter
Classic Custom Tags setBodyContent(BodyContent)
EVAL_BODY_BUFFERED
doInitBody()
Only available if BodyTagSupport subclass. Body wonâ&#x20AC;&#x2122;t automatically be displayed unless you make it.
doStartTag()
EVAL_BODY_INCLUDE
Evaluate Body
SKIP_BODY
EVAL_BODY_AGAIN doAfterBody() SKIP_BODY doEndTag() EVAL_PAGE
Evaluate Page
Classic tags are never reused.
SKIP_PAGE
Page Context javax.servlet.jsp <<abstract>> JspContext Used by “Simple” tags getAttribute(String):Object getAttribute(String, int):Object getAttributesScope(String):int getAttributeNamesInScope(int):Enumeration Searches: (1) Page (2) Request (3) Session (4) Application
Used by “Classic” tags
findAttribute(String):Object setAttribute(…) removeAttribute(…) getOut():JspWriter
<<abstract>> PageContext APPLICATION_SCOPE PAGE_SCOPE REQUEST_SCOPE SESSION_SCOPE getRequest():ServletRequest getResponse():ServletResponse getServletConfig():ServletConfig getServletContext():ServletContext getSession():HttpSession forward(String) include(String)