Tuesday, 21 August 2012

HttpSessionListener

A HttpSessionListener is used when you want to be notified that a Session has been created or destroyed.  This simple interface only has two methods,

    void sessionCreated(HttpSessionEvent httpSessionEvent);

    void sessionDestroyed(HttpSessionEvent httpSessionEvent);

These methods can easily be used to get or put items on the new session or perhaps set login, logout times in a log or database.

Web.xml

SessionListeners must be wired into the web.xml in the same way that filters are.  The syntax is very simple though,

    <listener>
        <description>sessionListener</description>
        <listener-class>my.package.MyListener</listener-class>
    </listener>


Getting the HttpSession

The HttpSessionEvent can be used to get the HttpSession itself simply with

    HttpSession session = sessionEvent.getSession();

Spring Integration

Normally there are spring beans that you want to use from within a HttpSessionListener.  However, as the listeners are not wired by spring but sorted out by the container you can't just add the listener to the spring context and expect it to work.  To use other spring beans you need to do the following,


            ApplicationContext ctx = WebApplicationContextUtils
                                              .getWebApplicationContext(session.getServletContext());
            MySpringBean mySpringBean = (MySpringBean) ctx.getBean("beanName");


Chaining

Another option is to create all of HttpSessionListeners and wire them up with spring as normal.  Then create a list of these as a spring bean itself.  Now use the code above to get this list of session listeners and loop through them.  These allows a single HttpSessionListener to bridge the gap to a whole load of listeners wired up by spring.


    <util:list id="sessionListenerChain" value-type="javax.servlet.http.HttpSessionListener">
        <ref bean="firstSessionListener" />
        <ref bean="secondSessionListener" />
    </util:list>


Both 'firstSessionListener' and 'secondSessionListener' are fully wired up using spring in the normally way allowing interaction with the other spring beans.  The actually HttpSessionListener wired into the web.xml file can then call for this util:list and loop through the session listeners to call them.

    List<HttpSessionListener> listenerChain = (List<HttpSessionListener>) ctx.getBean("sessionListenerChain");
    for (HttpSessionListener listener : listenerChain)
    {
        listener.sessionCreated(sessionEvent);
    }

Of course similar code can be used in the sessionDestroyed() method.











Wednesday, 8 August 2012

JPA Notes


Here are a series of JPA notes that have been useful in the past.

EntityManager Methods

entityManager.persist() - creates a new object and saves it - will throw an EntityExistsException if it exists already - transaction is rolled back.

entityManager.merge() - will either save or update the current object as it is now!  Changes after this won't be saved.  See below - the merge creates a new object which is managed but the object which merge was called on isn't managed

entityManager.getReference() - gets a reference to the object assuming that it exists.  It does a look up against the @Id annotated field in the entity.  The reference will only exist for the duration of the transaction.  Hence get the data into a DTO before the transaction ends.

MyEntity e = new MyEntity();

// scenario 1
// tran starts
em.persist(e);
e.setSomeField(someValue);
// tran ends, and the row for someField is updated in the database

// scenario 2
// tran starts
e = new MyEntity();
em.merge(e);
e.setSomeField(anotherValue);
// tran ends but the row for someField is not updated in the database (you made the changes *after* merging)

// scenario 3
// tran starts
e = new MyEntity();
MyEntity e2 = em.merge(e);
e2.setSomeField(anotherValue);
// tran ends and the row for someField is updated (the changes were made to e2, not e)

JPA Callbacks

There are a number of callback methods in JPA which allow interaction at various points before and after the db save.  These are annotation driven and the names make it pretty clear when they are used.

@PrePersist

@PreUpdate

@PreRemove

@PostLoad

@PostPersist

@PostUpdate

@PostRemove


Annotations

JPA is usually annotation driven.  This provides the information locally to the class and is pretty tidy.  Here are some brief explanations about what the different annotations mean.

@Entity
Flags that an entity should be managed by JPA.  Note Entity exists in JPA and Hibernate so get the import statement right.

@Table
Defines the table that this entity maps to
    @Table(name = "MY_TABLE", schema = "MY_SCHEMA") 

@OneToMany
One of these classes links to many of another class

    @OneToMany(mappedBy = "<java_object_name>", targetEntity = <the_many_class.class>, cascade = CascadeType.ALL, fetch = FetchType.LAZY)

mappedBy shows that the other table is the 'owner' of the foreign key and a @ManyToOne would be expected on that table for a bi-direction relationship.  The mappedBy is only necessary for a bi-directional relationship.  The targetEntity is usually not required because the class variable that this annotation applies to will give this information. If there is only a uni-direction relationship then just a

    @OneToMany
    @JoinColumn(name="column_name")

@ManyToOne
The reverse of the annotation above.  This will allow a bidirection link from the many class back to the one class.
    @ManyToOne(targetEntity = <the_one_class.class>, fetch = FetchType.EAGER, optional = false)
    @JoinColumn(name = "MY_COLUMN")

@ManyToMany
A join that uses a join table. Bi-directional is still possible using the mappedBy as above.  The owning class (Employee in this case) would have this code.

    @ManyToMany
    @JoinTable(name=EMPLOYEE_TO_PROJECT, joinColumns=@JoinColumn(name="EMPLOYEE_ID"), inverseJoinColumns=@JoinColumn(name="PROJECT_ID"))
    private List<ProjectEntity> projects;

The inverted side of this annotation (Project) would have the following,

    @ManyToMany(mappedBy = "projects")
    private List<EmployeeEntity> employees;

@OneToOne
A link between tables on a 1 : 1 basis.  For the table that has the column foreign key use

    @OneToOne
    @JoinColumn(name = "EMPLOYEE_ID")
    private Person person;

on the non-hosting table (ie without the join column) use

    @OneToOne(mappedBy = "person")
    private Employee employee;
 
@Embeddable
A set of 'columns' which can be in a reusable java class but exist in the underlying table.  Address might be an example of this.

@Embedded
An object which is used in this @Entity but is itself @Embeddable.

@MappedSuperClass
Allows class heirarchy in the Java and maps the contents of this class onto the table of the subclass.  EG map a column which exists on every table in a class annotated with @MappedSuperClass and then subclasses will 'inherit' this column into their table. There is still only one table though.  See @Inheritance for table inheritance. If all columns have an OBJECT_ID, CREATED_DATE then these could go in a class with the @MappedSuperClass and all classes could extend this.

@Inheritance
When a class with @Entity extends another class with @Entity then the @Inheritance rules can be set using this annotation.  The 'strategy' can be JOINED (there are two tables which are 'joined' using the sql request), SINGLE_TABLE (there is a single table a bit like Embedded) or TABLE_PER_CLASS (every table has a complete copy of all the data from the whole hierarchy but every table has that)

@OrderBy
Used on a list to order the elements directly out of the database.  The syntax is @OrderBy("<variable name> ASC").  The variable name is the variable in the objects which make up the list so for example List<Person> personList would have a variable from the Person class.

@PersistenceContext

Using the @PersistenceContext allows spring to wire in the JPA EntityManager to be used within the domain structure.

Create a BaseRepository that includes

    public class BaseRepository
    {

        @PersistenceContext
        private EntityManager entityManager;


        /**
         * Gets the entityManager value.
         * 
         * @return the entityManager
         */
        protected EntityManager getEntityManager()
        {
            return this.entityManager;
        }
    }


Spring will then populate this with the entity manager provided the spring configuration has the following line


    <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />


A getEntityManager() can be used in the SubClasses to get the entity manager instance.

Query Examples

Get a list of objects from a table,


    public List<MyEntity> getMyEntities()
    {
        final Query query = getEntityManager().createQuery("from MyEntity");
        return query.getResultList();
    }



Get a specific object using a primary key,


    final MyEntity myEntity = getEntityManager().find(MyEntity.class, id);



Use a query with parameters, where name is a provided value and type is an enumeration,


    final Query query = getEntityManager().createQuery("from MyEntity where name = :name and type = :type");
    query.setParameter("name", name);
    query.setParameter("type", MyEntityType.TYPE);
    return query.getResultList();


Creating a query that has a @OneToMany relationship needs a little bit more work.  Here the Company has a list of Products.  It is the products that need to be searched but the companies that need to be returned.  The SELECT only returns the CompanyEntity alias and because this is a @OneToMany the IN(c.products) is used.

    Query query = getEntityManager().createQuery("SELECT c FROM CompanyEntity AS c, IN(c.products) AS p WHERE p.name like :name");
    query.setParameter("name", name);
    return query.getResultList();


Friday, 29 June 2012

Spring Property Place Holder

Basic spring configuration makes using property files and their key-value pairs really easy!

property-placeholder

The most simple way to do this is to use the property-placeholder tag.  This is as simple as including the line,

    <context:property-placeholder location="classpath:app.properties"/>

However, sometimes it is easier to have a list of properties files.  This can simply be done by giving a comma separated list in the example above,

    <context:property-placeholder location="classpath:app.properties,classpath:alt_app.properties"/>

This is starting to get a bit unclear though.  Perhaps a better way is to no longer use the spring property-placeholder and instead use the 'full' bean version.

 PropertyPlaceholderConfigurer

This 'full' bean version is the PropertyPlaceholderConfigurer class and can be used like this,

    <bean id="appProperties" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <list>
                <value>classpath:app.properties</value>
                <value>classpath:alt_app.properties</value>
            </list>
        </property>
        <property name="ignoreResourceNotFound" value="true" />
        <property name="ignoreUnresolvablePlaceholders" value="false" />
    </bean>

This is, to my mind at least, rather more clear.  Spring will mash all the properties file together and present them as a single set of properties.  It will also override values with those found in later files if the keys are the same.  This is a really useful function as you can then specify some items to be overridden but not necessarily all!

We also get to set the ignoreResourceNotFound and ignoreUnresolvablePlaceholders values.

ignoreResourceNotFound:  If a property file cannot be found then spring won't throw an error
ignoreUnresolvablePlaceholders: If a key cannot be found then it is ignored and no error is thrown.

Having ignoreResourceNotFound=true is sensible because you may choose to put in place the ability to override a default properties file but not necessarily populate it.  However, you would normally want all the keys to be defined somewhere so having the ignoreUnresolvablePlaceholders=false is probably going to help diagnose problems.

Referencing a value

A key-value pair can be referenced using the ${key_name} notation.  This can also be used to get properties configured in the jvm with -Dmyprop=value or set into the application server.

Using the PropertyPlaceholderConfigurer you can also set the prefix and suffix characters so that you can specify

        <property name="placeholderPrefix" value="$myapp{" />
        <property name="placeholderSuffix" value="}" />

and then reference your key-value pairs as $myapp{key_name} - or whatever you want.  This is useful where you may have different properties files to control different aspects of your application and you don't necessarily want to leak properties between them.  For example keeping security settings separate.

Tuesday, 19 June 2012

Spring Security

Spring Security

Spring have done a brilliant security framework for securing pages and elements of a website simply and easily.

Concept

The concept is very straightforward.  Certain resources / pages need to be secured while others don't.  The spring framework deals with all this though a filter chain.  This means that no configuration is necessary in the controllers or jsp pages.  In testing for a login failure is impossible in a Controller because the filter takes care of it before the controller is given the request by the MessageDispatcherServlet!  Remember though that because it is a servlet filter that a few extra bits are necessary!

web.xml

As noted above the spring-security framework is a filter.  Therefore the filter needs to be added to the web.xml file so that the deployment container knows about it.  There are two entries here.  The latter clearly enables spring-security.  The first entry however is really important.  Without it the scope="request" is not possible for beans because that scope is only valid with the MessageDispatcherServlet.  Therefore to allow for session scope this additional filter must be put into the web.xml page.  Unfortunately ordering is important here.  The RequestContextFilter must be before the security filter.  This is obvious really!  If the filters are dealt with in turn then the RequestContextFilter needs to make the request scope available before the security framework filter.


    <filter>
        <filter-name>requestContextFilter</filter-name>
        <filter-class>org.springframework.web.filter.RequestContextFilter
        </filter-class>
    </filter>
    <filter-mapping>
        <filter-name>requestContextFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <filter>
        <filter-name>springSecurityFilterChain</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy
        </filter-class>
    </filter>
    <filter-mapping>
        <filter-name>springSecurityFilterChain</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

Maven Dependencies

The maven dependencies required for the spring-security framework are as follows


        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-web</artifactId>
            <version>3.1.0</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-config</artifactId>
            <version>3.1.0</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-ldap</artifactId>
            <version>3.1.0</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-taglibs</artifactId>
            <version>3.1.0</version>
        </dependency>

At the time of writing the current version is 3.1.0, however, have a look at the maven public repo to find the latest version. Search the repo at http://search.maven.org or specifically for spring-security at http://search.maven.org/#browse|875588238.

spring-context.xml

This is where the behaviour configuration starts.  It is pretty easy to get the behaviour exactly as you want it.  Here is an example,

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:sec="http://www.springframework.org/schema/security"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="
           http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/security
        http://www.springframework.org/schema/security/spring-security-3.1.xsd    
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-3.0.xsd">

    <sec:http pattern="/resources/**" security="none" />
    <sec:http pattern="/login" security="none" />

    <sec:http access-denied-page="/login?access=denied" use-expressions="true" >  
        <sec:intercept-url pattern="/app/**" access="hasAnyRole({'APP_USER','APP_ADMIN'})" />
        <sec:intercept-url pattern="/app/admin/**" access="hasRole('APP_ADMIN')" />
        <sec:intercept-url pattern="/**" access="denyAll" />
        <sec:form-login login-page="/login"  authentication-success-handler-ref="authenticationSuccessHandler" authentication-failure-handler-ref="authenticationFailureHandler"/>
        <sec:logout logout-success-url="/login" invalidate-session="true" />
    </sec:http>

    <sec:authentication-manager>
        <sec:authentication-provider ref="activeDirectoryAuthProvider"></sec:authentication-provider>
    </sec:authentication-manager>
   
    <bean id="authenticationSuccessHandler" class="app.login.AppAuthenticationSuccessHandler">
        <property name="alwaysUseDefaultTargetUrl" value="false" />
        <property name="defaultTargetUrl" value="/app/home" />
    </bean>
   
    <bean id="authenticationFailureHandler" class="app.login.AppAuthenticationFailureHandler">
        <property name="defaultFailureUrl" value="/login?access=denied" />
    </bean>
   
    <bean id="appGrantedAuthoritiesMapper" class="app.login.AppGrantedAuthoritiesMapper" />

    <bean id="activeDirectoryAuthProvider" class="org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider">
        <constructor-arg value="myapp.com" />
        <constructor-arg value="ldap://myapp.com:389/" />               
        <property name="authoritiesMapper" ref="appGrantedAuthoritiesMapper" />
        <property name="useAuthenticationRequestCredentials" value="true" />
    </bean>

Here is some explanation...

<sec:http pattern="/resources/**" security="none" /> - This means that anything in the /resources/ is available.  css, images, js should live here as these don't need to be secured and in fact if you secure them it means you can't style your login page properly.

<sec:http pattern="/login" security="none" /> - Obviously you can't secure your login page because otherwise someone can't log in!!

<sec:http access-denied-page="/login?access=denied" use-expressions="true" > - the login page maps to a jsp (through a controller) therefore an error message can be added if the param access=denied is there.  So the access denied page sends the user back to the login page so that they can try again, with the addition of a failure message somewhere on the screen.

<sec:intercept-url pattern="/app/**" access="hasAnyRole({'APP_USER','APP_ADMIN'})" /> - any url from /app/ downwards can only be accessed by people in particular roles.  In this case the roles are 'APP_USER' or 'APP_ADMIN'.

<sec:intercept-url pattern="/app/admin/**" access="hasRole('APP_ADMIN')" /> - only users in the APP_ADMIN role can view urls beneath /app/admin.

<sec:intercept-url pattern="/**" access="denyAll" /> - All other pages are denied!

<sec:form-login login-page="/login"  authentication-success-handler-ref="authenticationSuccessHandler" authentication-failure-handler-ref="authenticationFailureHandler"/> - The login page is at the url /login.  When a login is successful then use the authenticationSuccessHandler bean, when login has failed use the authenticationFailureHandler bean (see later for examples and reason).

<sec:logout logout-success-url="/login" invalidate-session="true" /> - when the user logs out send them back to the login page at the url /login.

<sec:authentication-manager>
    <sec:authentication-provider ref="activeDirectoryAuthProvider"></sec:authentication-provider> 
</sec:authentication-manager> - Use the activeDirectoryAuthProvider to lookup the users.  ActiveDirectory is Microsoft's implementation of LDAP (pretty much anyway!).  Obviously other types of lookup can be performed.  The spring documentation contains a very simple example of configuring the users in the spring context itself.

Success

The success and failure handlers give access to the flow when certain criteria have been met. In the case of the success you might want to load information about a user from a database or log the fact that they have accessed the system.  A very simple way of doing this is to create a class which extends SimpleUrlAuthenticationFailureHandler and overrides the onAuthenticationSuccess() method.  Both the success and failure handler rely on a response.sendRedirect() to shift the client to the landing page or error page.  However, the SimpleUrlAuthenticationFailureHandler takes a defaultTargetUrl in the spring configuration so all that is necessary is to call super.onAuthenticationSuccess() in the subclass and everything is done for you!

    <bean id="authenticationSuccessHandler" class="app.login.AppAuthenticationSuccessHandler">
        <property name="alwaysUseDefaultTargetUrl" value="false" />
        <property name="defaultTargetUrl" value="/app/home" />
    </bean>

 



 Failure & Ajax


The failure mechanism acts exactly the same way.  Normally there is no need to override the success and failure as the standard behaviour is perfectly adequate.  However, where you have ajax requests there is a specific problem.  In the situation where ajax requests may access a session which is timed out then there is a redirect by spring to the login page.  This is a problem  for the client as it is probably expecting xml or json objects to be returned but instead will get html.  The cure for this is to create a custom AuthenticationFailureHandler such as that below,

public class AppAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler
{

    /**
     * {@inheritDoc}
     *
     * Looks at the request url and if this contains the "X-Requested-With" header which is the de-facto standard for ajax libraries.
     */
    @Override
    public void onAuthenticationFailure(final HttpServletRequest request, final HttpServletResponse response,
            final AuthenticationException authException) throws ServletException, IOException
    {

        final String requestedWith = request.getHeader("X-Requested-With");

        if (requestedWith != null && requestedWith.equals("XmlHttpRequest"))
        {
            response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
        }
        else
        {
            super.onAuthenticationFailure(request, response, authException);
        }
    }
}

This works because Ajax requests have the 'X-Requested-With' http header.  This can be examined and if it exists return a 401 (or something) to the client.  Bare in mind that authentication has already failed at this point so now you are just deciding what to do.  This method will allow Ajax clients to check for the response code as a safe way of making sure there is no timeout.



Wednesday, 13 June 2012

SQL Server & Tomcat

JTDS Library

It is necessary sometimes to connect Tomcat to MS SQL server using SSO from the user currently logged into the windows machine they are on.  This is possible with the jtds (http://jtds.sourceforge.net/) library.  This brilliant library requires a small dll file (ntlmauth.dll) to be put on the system path (eg jre/bin) and the jtds jar file to be put into the tomcat lib directory.  The dll interacts with Windows to get the user credentials and the jtds jar does the normal jdbc connection bits.

Tomcat context.xml

The context file now needs to have the resource added.  The username and password elements are not required if you want the SSO.


    <Resource
       name="jdbc/myDS"
       auth="Container"
       type="javax.sql.DataSource"
       maxActive="100"
       maxIdle="30"
       maxWait="10000"
       driverClassName="net.sourceforge.jtds.jdbcx.JtdsDataSource"
       url="jdbc:jtds:sqlserver://<servername>:<port>/<databasename>;instance=<instance>;
          domain=<userdomain>"/>

It is necessary to specify the instance because the SQL Server may specify a

    Server name: servername\instance

but this isn't a valid network servername.  Therefore this has to be split into two parts.  The actual server name and the instance.  The port is usually 1433 for SQL Server.



Friday, 8 June 2012

Tiles Tutorial / Setup

Tiles

Tiles is a layout technology which carves pages into different sections or 'tiles'.  These can then be controlled and set using an xml file.  The easiest way to see this is just from a simple example.

Basic Tiles Config

The basic tiles configuration is an xml file (or multiple files) which defines the layouts.


<!DOCTYPE tiles-definitions PUBLIC
       "-//Apache Software Foundation//DTD Tiles Configuration 3.0//EN"
       "http://tiles.apache.org/dtds/tiles-config_3_0.dtd">
      
<tiles-definitions>

    <!-- Main layout -->
    <definition name="myapp.main" template="/WEB-INF/views/main.jsp">
        <put-attribute name="header" value="
/WEB-INF/views/header.jsp" />
        <put-attribute name="footer" value="
/WEB-INF/views/footer.jsp" />
    </definition>

    <definition name="myapp.home" extends="
myapp.main">
        <put-attribute name="body" value="
/WEB-INF/views/home.jsp" />
    </definition>

</tiles-definitions>

JSP Layout

The main.jsp page above is a standard JSP page which has a couple of 'holders' for the tiles elements.

    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    <%@ taglib uri="http://tiles.apache.org/tags-tiles" prefix="tiles" %>

    <html>
       <head />
        <body> 
            <!-- header -->
            <div class="header">
                <tiles:insertAttribute name="header" />
            </div>
             
            <!-- Central Container -->
            <div class="main_content">
                <tiles:insertAttribute name="body" />
            </div>
             
            <!-- footer -->
            <div class="footer">
                <tiles:insertAttribute name="footer" />
            </div>
        </body>
    </html>

Here you can see that the 'tiles' elements are brought in by the tiles tag.  These place holders are resolved by the xml file configuration for the page that has been requested. The ModelAndView will control the tiles name that is to be used.

Controller

The ModelAndView which is returned by the Controller will define the view to use based on the definition name in the tiles configuration.  For example


    ModelAndView mav = new ModelAndView("myapp.home");

This will use the 'myapp.home' definition which itself extends the 'myapp.main' definition.  As a result the full page is rendered using this hierarchy.

Spring Config

Finally the spring configuration needs to be told how to resolve the view name.  This is standard with spring, whether it is jsp view resolver, Freemarker, etc.  For tiles the configuration looks like this,

    <!-- Configure Tiles -->
    <bean id="tilesConfigurer" class="org.springframework.web.servlet.view.tiles2.TilesConfigurer">

        <property name="definitions">
            <list>
                <value>/WEB-INF/tiles/myapp.xml</value>
            </list>
        </property>

        <property name="preparerFactoryClass"
                  value="org.springframework.web.servlet.view.tiles2.SpringBeanPreparerFactory"/>
    </bean>

    <bean id="viewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver">
        <property name="viewClass" value="org.springframework.web.servlet.view.tiles2.TilesView"/>
    </bean>

Here the 'tileConfigurer' gives a list of the definitions that are used.  This means that the definitions can be split into logical lumps and you don't end up with a file which is unmanageably large!  The 'viewResolver' is a standard spring element which tells spring how to resolve the view name.

Maven

Maven dependencies,

  <dependency>
    <groupId>org.apache.tiles</groupId>
    <artifactId>tiles-extras</artifactId>
    <version>3.0.4</version>
  </dependency>

Preparer Classes

In the situation of having a menu defined in Tiles you don't want to have to remember to get every controller to put particular elements in the model. An easy way of extracting this is to use a ViewPreparer. Implement the ViewPreparer interface and complete the execute() method.  Then in the tiles definition you can add a preparer="myAppPreparer"

    <!-- Main layout -->
    <definition name="myapp.main" template="/WEB-INF/views/main.jsp" preparer="myAppPreparer">
        <put-attribute name="header" value="
/WEB-INF/views/header.jsp" />
        <put-attribute name="footer" value="
/WEB-INF/views/footer.jsp" />
    </definition>

The preparer name here is a fully qualified path name by default but can be a spring bean and therefore have its dependencies injected by spring. To make spring resolve these beans you need to have the 'preparerFactoryClass' configured in the spring tilesConfigurer(see above).

The HttpServletRequest can be obtained within a ViewPreparer as follows,

    /**
     * {@inheritDoc}
     */
    @Override
    public void execute(final TilesRequestContext tilesRequestContext, final AttributeContext attributeContext)
    {
        final HttpServletRequest request = (HttpServletRequest) tilesRequestContext.getRequestObjects()[0];
        ... other code to add to the request ...
    }

Loose Ends

There are occasions when a url is required within the application or spring context and the url needs to be mapped to the tiles names.  This is possible by using a spring mvc:controller

  <mvc:view-controller path="my_url" view-name="my.tiles.definition"/>

This then allows the 'my_url' to be used within the application and context.

Thursday, 7 June 2012

Basic JSP Tags

Basic JSP Commands

Here are a load of basic jsp tags that I'll add to over time.  Initially though, it'll just cover the real basics

In a JSP page there are certain elements which are always available.  These include

request - HttpServletRequest
session - HttpSession

For example to view the username of the currently logged in user you can use

    <%= request.getUserPrincipal().getName() %>

You can also do this with the c:out command below if you use the pageContext first.

JSP Tags

To use the basic JSP tags you'll need to include the import at the top of the jsp page.

    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>  
 

c:out

Use this to 'print' to the screen eg

    <c:out value="${modelValue}"/>

where modelValue is put into the ModelMap in the controller.

c:if

Use this to conditionally add items

    <c:if test="${myValue == 'Value'}">
        do something
    </c:if>

c:choose / c:when / c:otherwise

This is the equivalent to the if - else if - else statement

    <c:choose>
        <c:when test="${myValue == 'Value'}">
            do something
        </c:when>
        <c:when test="${myValue == 'AnotherValue}">
            do something else
        </c:when>
        <c:otherwise>
            do the fall back action
        </c:otherwise>
    </c:choose>

c:url

This is a really useful tag which allows you to just create a link and the tag will take care of the server name, port and application context

    <c:url value="/my_link" />

you can also add attributes

    <c:url value="/my_link"> 
        <c:param name="link" value="${linkId}" /> 
    </c:url>

c:forEach

This is a basic iterator for looping through lists etc

    <c:forEach var="item" items="${itemList}" varStatus="status">

        ${status.first ? 'Start' : ''}

        ${status.index}: ${item.name}

        ${status.last ? 'End' : ''}

    </c:forEach>

c:set

It is occasionally necessary to create a variable that is used by other jsp commands or tags. You can do this by using the c:set tag, for example

    <c:set var="linkId" value="${param.link}"/>
You can set different scopes for these by using the scope="..." attribute,
    <c:set var="linkId" scope="session" value="${param.link}" />
but by default it is page-scope only.