Presentation Layer Sérgio Silva October 2013
May 27, 2015
Presentation Layer
Sérgio Silva October 2013
Fenix Architecture
MYSQL
Application Container (Tomcat, Jetty)
Fenix Framework(STM)
DomainModel
JSPsrenderers
Struts
Faces
Jersey(REST API)
Today
MYSQL
Application Container (Tomcat, Jetty)
Fenix Framework(STM)
DomainModel
JSPsrenderers
Struts
Faces
Jersey(REST API)
StrutsControl Layer
● open-source web application framework
● uses and extends the Java Servlet API
● model–view–controller (MVC) architecture
● version 1.2.7
● http://struts.apache.org/release/1.2.x/
StrutsControl Layer
StrutsControl Layer
Struts Dispatching
fenix.ist.utl.pt/publico/executionCourse.do?method=marks&executionCourseID=1610612925705
Struts DispatchingModule
Semantic division in modules
● struts-publico.xml
● .do maps to Struts Servlet (JavaServlet API)
○ src/main/resources/web.xml
fenix.ist.utl.pt/publico/executionCourse.do?method=marks&executionCourseID=1610612925705
Struts DispatchingMapping
Mapping between path and action
● The path is a string
○ “/executionCourse”
● Where is the mapping ?
○ Mapping with annotations (what you should use)
@Mapping(module="publico" path="/executionCourse")
○ struts-publico.xml (read-only, don’t create things here)<action type="n.s.f.p.A.p.ExecutionCourseDA" parameter="method" path="/executionCourse">
fenix.ist.utl.pt/publico/executionCourse.do?method=marks&executionCourseID=1610612925705
Struts DispatchingMapping
Mapping between path and action● Action Class ( ExecutionCourseDA.java)
● each action is module aware
● usually extends FenixDispatchAction (check outline on eclipse)
○ helper methods■ getFromRequest
■ redirect
■ getLoggedPerson
■ getDomainObject(request,parameter)
● method execute runs always
DEMO
fenix.ist.utl.pt/publico/executionCourse.do?method=marks&executionCourseID=1610612925705
ExecutionCourseDA.java
public ActionForward marks(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) { final String executionCourseOID = request.getParameter("executionCourseID"); final ExecutionCourse executionCourse = FenixFramework.getDomainObject(executionCourseOID); Map<> attendsMap = getAttendsMap(executionCourse); request.setAttribute("executionCourse", executionCourse); request.setAttribute("attendsMap", attendsMap); request.setAttribute("dont-cache-pages-in-search-engines", Boolean.TRUE); return mapping.findForward("execution-course-marks");}
● Parameters○ get values on query string
● Attributes○ get or set state on request
Struts @ FenixActionfenix.ist.utl.pt/publico/executionCourse.do?method=marks&executionCourseID=1610612925705
StrutsWrapping Up
JSPsPresentation Layer
StrutsPresentation Layer
● Tiles○ templating system○ create a common look and feel for a web application○ create reusable view components○ bridge to JSPs○ module aware
● tiles-<module>-definitions.xml○ template definitions
● tiles-<module>-pages-definitions.xml○ fill in the template
ExecutionCourseDA.java
public ActionForward marks(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) { final String executionCourseOID = request.getParameter("executionCourseID"); final ExecutionCourse executionCourse = FenixFramework.getDomainObject(executionCourseOID); Map<> attendsMap = getAttendsMap(executionCourse); request.setAttribute("executionCourse", executionCourse); request.setAttribute("attendsMap", attendsMap); request.setAttribute("dont-cache-pages-in-search-engines", Boolean.TRUE); return mapping.findForward("execution-course-marks");}
Struts @ FenixForwards
ExecutionCourseDA.java
public ActionForward marks(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) { final String executionCourseOID = request.getParameter("executionCourseID"); final ExecutionCourse executionCourse = FenixFramework.getDomainObject(executionCourseOID); Map<> attendsMap = getAttendsMap(executionCourse); request.setAttribute("executionCourse", executionCourse); request.setAttribute("attendsMap", attendsMap); request.setAttribute("dont-cache-pages-in-search-engines", Boolean.TRUE); return mapping.findForward("execution-course-marks");}
● What is mapping.findForward(..) ?
Struts @ FenixForwards
ExecutionCourseDA.java
public ActionForward marks(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) { final String executionCourseOID = request.getParameter("executionCourseID"); final ExecutionCourse executionCourse = FenixFramework.getDomainObject(executionCourseOID); Map<> attendsMap = getAttendsMap(executionCourse); request.setAttribute("executionCourse", executionCourse); request.setAttribute("attendsMap", attendsMap); request.setAttribute("dont-cache-pages-in-search-engines", Boolean.TRUE); return mapping.findForward("execution-course-marks");}
● Forwards annotation (what you should use)@Forwards({ @Forward(name = "execution-course-marks", path = "/publico/executionCourse/marks.jsp") })public class ExecutionCourseDA extends FenixDispatchAction { … }
● name - forward name● path - logic name for tiles
Struts @ FenixForwards
ExecutionCourseDA.java
public ActionForward marks(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) { final String executionCourseOID = request.getParameter("executionCourseID"); final ExecutionCourse executionCourse = FenixFramework.getDomainObject(executionCourseOID); Map<> attendsMap = getAttendsMap(executionCourse); request.setAttribute("executionCourse", executionCourse); request.setAttribute("attendsMap", attendsMap); request.setAttribute("dont-cache-pages-in-search-engines", Boolean.TRUE); return mapping.findForward("execution-course-marks");}
● struts-publico.xml<action type="n.s.f.p.A.p.ExecutionCourseDA" parameter="method" path="/executionCourse"> <forward path="execution-course-marks" name="execution-course-marks"></forward> …………………………………………………</action>
● name - forward name● path - logic name for tiles
Struts @ FenixForwards (Deprecated)
● tiles-public-definitions.xml<definition name="execution-course-marks" extends="definition.public.executionCourse"> <put name="body" value="/publico/executionCourse/marks.jsp"/></definition>
● tiles-public-pages-definitions.xml<definition name="definition.public.executionCourse" page="/layout/istLayout.jsp"> <put name="title" value="/commons/functionalities/courseTitle.jsp" /> <put name="hideLanguage" value="true"/> <put name="symbols_row" value="/publico/degreeSite/symbolsRow.jsp" /> <put name="profile_navigation" value="/publico/degreeSite/profileNavigation.jsp" /> <put name="main_navigation" value="/publico/executionCourse/mainNavigation.jsp" /> <put name="body_header" value="/publico/executionCourse/executionCourseHeader.jsp" /> <put name="body" value="/commons/blank.jsp" /> <put name="footer" value="/publico/degreeSite/footer.jsp" /> <put name="rss" value="/messaging/announcements/rssHeader.jsp"/> <put name="keywords" value="/messaging/announcements/keywordsHeader.jsp"/></definition>
● istLayout.jsp<tiles:insert attribute="body" ignore="true"/><tiles:insert attribute="footer" ignore="true"/>
Struts @ FenixForwards (Deprecated)
JSPs
● JavaServer Pages (JSP)
● create dynamically generated web pages
based on HTML
● HTML with behaviour
DEMO
publico/executionCourse/marks.jsp
● publico/executionCourse/marks.jsp
<logic:iterate id="evaluation" name="executionCourse" property="orderedAssociatedEvaluations">
● ExecutionCourseDA.javapublic ActionForward marks(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) { final String executionCourseOID = request.getParameter("executionCourseID"); final ExecutionCourse executionCourse = FenixFramework.getDomainObject(executionCourseOID); Map<Attends, Map<Evaluation, Mark>> attendsMap = getAttendsMap(executionCourse); request.setAttribute("executionCourse", executionCourse); request.setAttribute("attendsMap", attendsMap); request.setAttribute("dont-cache-pages-in-search-engines", Boolean.TRUE); return mapping.findForward("execution-course-marks");}
JSPswithout renderers
● publico/executionCourse/marks.jsp
<logic:iterate id="evaluation" name="executionCourse" property="orderedAssociatedEvaluations">
● ExecutionCourseDA.javapublic ActionForward marks(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) { final String executionCourseOID = request.getParameter("executionCourseID"); final ExecutionCourse executionCourse = FenixFramework.getDomainObject(executionCourseOID); Map<Attends, Map<Evaluation, Mark>> attendsMap = getAttendsMap(executionCourse); request.setAttribute("executionCourse", executionCourse); request.setAttribute("attendsMap", attendsMap); request.setAttribute("dont-cache-pages-in-search-engines", Boolean.TRUE); return mapping.findForward("execution-course-marks");}
● name - get from request attribute or parameter with that name● property - get property from object
○ executionCourse.getOrderedAssociatedEvaluations ()
● uses Java Bean conventions● id - defines bean in jsp scope
JSPswithout renderers
● simple bean example
<h3><bean:write name="executionCourse" property="name"></h3>
● executionCourse.getName()
● Tag libs○ <bean:*>○ <logic:*>○ <html:*>○ http://struts.apache.org/release/1.2.x/userGuide/
JSPswithout renderers
● integration with domain model and fenix-
framework
● our taglib <fr:*>○ fr:view - display domain objects
○ fr:create - create domain objects
○ fr:edit - edit domain objects
● renderers-config.xml
○ All renderers definitions
JSPsRenderers
● What is a renderer ?○ java class used to produce HTML○ Properties
■ layout● logical name for renderer definition
■ mode ● input● output
■ class● rendered type
○ String○ ExecutionCourse○ int
■ properties● render specific properties
JSPsRenderers
● output renderer
<renderer type="java.util.Collection" layout="contact-list" class="n.s.f.p.r.ContactListRenderer"> <property name="bundle" value="APPLICATION_RESOURCES"/> <property name="defaultLabel" value="label.partyContacts.defaultContact"/></renderer>
● input renderer<renderer mode="input" type="j.u.Collection" layout="option-select" class="p.i.fr.InputCheckBoxListRenderer"> <property name="eachClasses" value="dinline" /></renderer>
JSPsrenderers-config.xml
● manageApplications.jsp
<fr:view name="appsOwned" schema="oauthapps.view.apps"> <fr:layout name="tabular"> <fr:property name="classes" value="tstyle4 thcenter thcenter"/> <fr:property name="columnClasses" value="tdcenter, tdcenter, ..."/> </fr:layout></fr:view>
● renderers-config.xml
<renderer type="java.util.Collection" layout="tabular" class="p.i.f.r.CollectionRenderer"> <property name="groupLinks" value="true"/> <property name="linkGroupSeparator" value=", "/></renderer>
JSPsRenderers
● manageApplications.jsp
<fr:view name="appsOwned" schema="oauthapps.view.apps"> <fr:layout name="tabular"> <fr:property name="classes" value="tstyle4 thcenter thcenter"/> <fr:property name="columnClasses" value="tdcenter, tdcenter, ..."/> </fr:layout></fr:view>
● renderers-config.xml
<renderer type="java.util.Collection" layout="tabular" class="p.i.f.r.CollectionRenderer"> <property name="groupLinks" value="true"/> <property name="linkGroupSeparator" value=", "/></renderer>
JSPsRenderers
JSPsRenderers
JSPsRenderers
● manageApplications.jsp
<fr:view name="appsOwned" schema="oauthapps.view.apps"> <fr:layout name="tabular"> <fr:property name="classes" value="tstyle4 thcenter thcenter"/> <fr:property name="columnClasses" value="tdcenter, tdcenter, ..."/> </fr:layout></fr:view>
Renderers(reusable) Schemas
● manageApplications.jsp
<fr:view name="appsOwned" schema="oauthapps.view.apps"> <fr:layout name="tabular"> <fr:property name="classes" value="tstyle4 thcenter thcenter"/> <fr:property name="columnClasses" value="tdcenter, tdcenter, ..."/> </fr:layout></fr:view>
Renderers(reusable) Schemas
● Schemas
<fr:view name="appsOwned" schema="oauthapps.view.apps"> <fr:layout name="tabular"> <fr:property name="classes" value="tstyle4 thcenter thcenter"/> <fr:property name="columnClasses" value="tdcenter, tdcenter, ..."/> </fr:layout></fr:view>
● specify how object’s slots are rendered
● schemas-config.xml
● *-schemas.xml
○ logical separation
Renderers(reusable) Schemas
● personnelSection-schemas.xml
<schema name="oauthapps.view.apps" type="net.sourceforge.fenixedu.domain.ExternalApplication" bundle="APPLICATION_RESOURCES"> <slot name="name" key="oauthapps.label.app.name" /> <slot name="description" layout="longText" key="oauthapps.label.app.description"/> <slot name="scopes" layout="flowLayout"> <property name="eachLayout" value="values"></property> <property name="eachSchema" value="oauthapps.view.scope.name"></property> <property name="htmlSeparator" value=", "></property> </slot> <slot name="siteUrl" key="oauthapps.label.app.site.url" /></schema>
● name ○ unique identifier
● type○ schema target type
● slot○ object slot to render
Renderers(reusable) Schemas
<fr:view name="appsOwned" schema="oauthapps.view.apps"> <fr:layout name="tabular"> <fr:property name="classes" value="tstyle4 thcenter thcenter"/> <fr:property name="columnClasses" value="tdcenter, tdcenter, ..."/> </fr:layout></fr:view>
Renderers(inline) Schemas
<fr:view name="appsOwned"> <fr:schema type="net.sourceforge.fenixedu.domain.ExternalApplication" bundle="APPLICATION_RESOURCES"> <fr:slot name="name" key="oauthapps.label.app.name" /> <fr:slot name="description" layout="longText" key="oauthapps.label.app.description"/> <fr:slot name="scopes" layout="flowLayout"> <fr:property name="eachLayout" value="values"></property> <fr:property name="eachSchema" value="oauthapps.view.scope.name"></property> <fr:property name="htmlSeparator" value=", "></property> </fr:slot> <fr:slot name="siteUrl" key="oauthapps.label.app.site.url" /> </fr:schema> <fr:layout name="tabular"> <fr:property name="classes" value="tstyle4 thcenter thcenter"/> <fr:property name="columnClasses" value="tdcenter, tdcenter, ..."/> </fr:layout></fr:view>
Renderers(inline) Schemas
Resource Bundles
<fr:view name="appsOwned"> <fr:schema type="net.sourceforge.fenixedu.domain.ExternalApplication" bundle="APPLICATION_RESOURCES"> <fr:slot name="name" key="oauthapps.label.app.name" /> <fr:slot name="description" layout="longText" key="oauthapps.label.app.description"/> <fr:slot name="scopes" layout="flowLayout"> <fr:property name="eachLayout" value="values"></property> <fr:property name="eachSchema" value="oauthapps.view.scope.name"></property> <fr:property name="htmlSeparator" value=", "></property> </fr:slot> <fr:slot name="siteUrl" key="oauthapps.label.app.site.url" /> </fr:schema> <fr:layout name="tabular"> <fr:property name="classes" value="tstyle4 thcenter thcenter"/> <fr:property name="columnClasses" value="tdcenter, tdcenter, ..."/> </fr:layout></fr:view>
● src/main/resources/resources/ApplicationResources_pt.properties○ oauthapps.label.app.name="Nome Aplicação"
● src/main/resources/resources/ApplicationResources_en.properties○ oauthapps.label.app.name="Application Name"
JavaServer Faces
● JavaServer Faces○ version 1.1
● component-based user interfaces for web
apps
● servlet mapping *.faces
● faces-config.xml
https://fenix.ist.utl.pt/publico/degreeSite/viewCurricularCourse.faces?degreeID=2761663971474
JavaServer Faces
● publico/degreeSite/viewCurricularCourse.jsp
<h:outputFormat value="<h1>#{CurricularCourseManagement.degreePresentationName}</h1>" escape="false"/>
● Backing Bean
○ name - CurricularCourseManagement
● faces-config.xml
<managed-bean> <description>ManagerCurricularCourseManagementBackingBean</description> <managed-bean-name>ManagerCurricularCourseManagement</managed-bean-name> <managed-bean-class>n.s.f.p.b.m.c.ManagerCurricularCourseManagementBackingBean</managed-bean-class> <managed-bean-scope>request</managed-bean-scope></managed-bean>
DEMO
https://fenix.ist.utl.pt/publico/degreeSite/viewCurricularCourse.faces?degreeID=2761663971474
JavaServer Faces
Golden Rules
● don’t create stuff in struts-*.xml○ use annotations
■ @Mapping■ @Forwards
● @Forward
● renderers-config.xml○ read-only (unless you are going to create a new renderer)
● read renderers docs○ Administrador > Frameworks > Renderers > Exemplos Renderers
● install resource bundle editor○ https://fenix-ashes.ist.utl.pt/fenixWiki/I18NConventions
Q & A ?