Mapping enums with Hibernate

First a mapping that uses the enum ordinal:
        <property name="type" column="user_type_code">
            <type name="org.hibernate.type.EnumType">
                <param name="enumClass">com.blogspot.pragmatastic.UserType</param>
            </type>
        </property>
and then a variation that uses the enum name:

        <property name="type" column="user_type_name">
            <type name="org.hibernate.type.EnumType">
                <param name="enumClass">com.blogspot.pragmatastic.UserType</param>
                <param name="type">12</param>
            </type>
        </property>

Multiple login pages with Spring Security

I ran into this problem with spring security recently. My application has two different sides, administrator side and user side. I want them to be completely separated with their own login pages and all. I'm writing this tutorial since I couldn't find comprehensive instructions on how to do it anywhere. Also note that this tutorial has been written for Spring Security 2.0.

First I had to define the springSecurityFilterChain in my security.xml and define the filter chains for the url patterns for /user/** and /admin/**. The list of filters is quite long so I'm going to skip the uninteresting ones but you can see the whole configuration in the sources.

<bean id="springSecurityFilterChain" class="org.springframework.security.util.FilterChainProxy">
        <security:filter-chain-map path-type="ant">
            <security:filter-chain pattern="/user/**"
                                   filters="httpSessionContextIntegrationFilter, anonymousProcessingFilter, userLogoutFilter,
                   userAuthenticationProcessingFilter, securityContextHolderAwareRequestFilter,
                   userExceptionTranslationFilter, sessionFixationProtectionFilter,
                   userFilterSecurityInterceptor"/>
            <security:filter-chain pattern="/admin/**"
                                   filters="httpSessionContextIntegrationFilter, anonymousProcessingFilter, adminLogoutFilter,
                   adminAuthenticationProcessingFilter, securityContextHolderAwareRequestFilter,
                   adminExceptionTranslationFilter, sessionFixationProtectionFilter,
                   adminFilterSecurityInterceptor"/>
            <security:filter-chain pattern="/**"
                                   filters="httpSessionContextIntegrationFilter, anonymousProcessingFilter, securityContextHolderAwareRequestFilter"/>
        </security:filter-chain-map>
    </bean>

Then we have the admin specific part of the configuration. Here we define the login and logout urls and filters for the admin side of the application.

<bean id="adminAuthenticationProcessingFilter"
          class="org.springframework.security.ui.webapp.AuthenticationProcessingFilter">
        <property name="invalidateSessionOnSuccessfulAuthentication" value="true"/>
        <property name="authenticationManager" ref="_authenticationManager"/>
        <property name="authenticationFailureUrl" value="/admin/login.htm?error=1"/>
        <property name="defaultTargetUrl" value="/admin/index.htm"/>
        <property name="filterProcessesUrl" value="/admin/j_spring_security_check"/>
    </bean>

    <bean id="adminLogoutFilter" class="org.springframework.security.ui.logout.LogoutFilter">
        <constructor-arg value="/"/>
        <constructor-arg>
            <list>
                <bean class="org.springframework.security.ui.logout.SecurityContextLogoutHandler"/>
            </list>
        </constructor-arg>
        <property name="filterProcessesUrl" value="/admin/j_spring_security_logout"/>
    </bean>

    <bean id="adminExceptionTranslationFilter" class="org.springframework.security.ui.ExceptionTranslationFilter">
        <property name="authenticationEntryPoint">
            <bean class="org.springframework.security.ui.webapp.AuthenticationProcessingFilterEntryPoint">
                <property name="loginFormUrl" value="/admin/login.htm"/>
                <property name="forceHttps" value="false"/>
            </bean>
        </property>
        <property name="accessDeniedHandler" ref="accessDeniedHandler"/>
    </bean>

    <bean id="adminFilterSecurityInterceptor"
          class="org.springframework.security.intercept.web.FilterSecurityInterceptor">
        <property name="accessDecisionManager" ref="accessDecisionManager"/>
        <property name="authenticationManager" ref="_authenticationManager"/>
        <property name="objectDefinitionSource" ref="adminInterceptUrlDefinition"/>
    </bean>

Then the user side is just a copy of the admin configuration.

<bean id="userAuthenticationProcessingFilter"
          class="org.springframework.security.ui.webapp.AuthenticationProcessingFilter">
        <property name="invalidateSessionOnSuccessfulAuthentication" value="true"/>
        <property name="authenticationManager" ref="_authenticationManager"/>
        <property name="authenticationFailureUrl" value="/user/login.htm?error=1"/>
        <property name="defaultTargetUrl" value="/user/index.htm"/>
        <property name="filterProcessesUrl" value="/user/j_spring_security_check"/>
    </bean>

    <bean id="userLogoutFilter" class="org.springframework.security.ui.logout.LogoutFilter">
        <constructor-arg value="/"/>
        <constructor-arg>
            <list>
                <bean class="org.springframework.security.ui.logout.SecurityContextLogoutHandler"/>
            </list>
        </constructor-arg>
        <property name="filterProcessesUrl" value="/user/j_spring_security_logout"/>
    </bean>

    <bean id="userExceptionTranslationFilter" class="org.springframework.security.ui.ExceptionTranslationFilter">
        <property name="authenticationEntryPoint">
            <bean class="org.springframework.security.ui.webapp.AuthenticationProcessingFilterEntryPoint">
                <property name="loginFormUrl" value="/user/login.htm"/>
                <property name="forceHttps" value="false"/>
            </bean>
        </property>
        <property name="accessDeniedHandler" ref="accessDeniedHandler"/>
    </bean>

    <bean id="userFilterSecurityInterceptor"
          class="org.springframework.security.intercept.web.FilterSecurityInterceptor">
        <property name="accessDecisionManager" ref="accessDecisionManager"/>
        <property name="authenticationManager" ref="_authenticationManager"/>
        <property name="objectDefinitionSource" ref="userInterceptUrlDefinition"/>
    </bean>

And then we have the urls mapped to the required roles and the users used in this tutorial.

<security:filter-invocation-definition-source id="adminInterceptUrlDefinition">
        <security:intercept-url pattern="/admin/login*" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
        <security:intercept-url pattern="/admin/logout*" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
        <security:intercept-url pattern="/admin/**" access="ROLE_ADMINISTRATOR"/>
    </security:filter-invocation-definition-source>

    <security:filter-invocation-definition-source id="userInterceptUrlDefinition">
        <security:intercept-url pattern="/user/login*" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
        <security:intercept-url pattern="/user/logout*" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
        <security:intercept-url pattern="/user/**" access="ROLE_USER"/>
    </security:filter-invocation-definition-source>

    <security:authentication-provider>
        <security:user-service>
          <security:user name="jimi" password="password" authorities="ROLE_USER, ROLE_ADMIN" />
          <security:user name="bob" password="password" authorities="ROLE_USER" />
        </security:user-service>
    </security:authentication-provider>

You can download the sources from here. To run the sample using the maven jetty plugin use:
mvn org.mortbay.jetty:maven-jetty-plugin:6.1.26RC0:run

Managing database changes in Java

All past projects I have worked with have used some kind of version control software. Almost all of them have also used a relational database. But with few exceptions the database changes have never been managed using the version control.

For example this is how my current project used to manage the changes:

  • Ad hoc

    Everyone is responsible of their own database. Changes to the database are maybe communicated with email. Production database is the only one that is being kept in working order, fixes being applied to it as things break.
    • Everyone will have a different version of the database
    • Taking dumps from production is the only way to get the latest version of the database
    • Making changes to the database is so difficult that any database refactoring is out of the question
  • Hibernate schema update

    Enable the schema update and hibernate will make schema changes to the database as the mapped objects change.
    • Your database will be littered with obsolete tables and columns, especially if you are using JPA
    • Hibernate will only manage your schema, it won't manage your data
    • The changes Hibernate does are very limited
    • Hibernate developers don't recommend it
Both of the ways were, wrong, and didn't really manage the database changes. But of course there is a proper way to do it:
  • Use a database changes management tool

    As you make changes to your code, you also write a migration that will update your database as your code is deployed. You commit this migration to source control with the code that requires the change. The migrations have version information which describes the order they should be applied and lets the tool determine if the change has already been applied to the database.
    • Your code and database will always have the same version, when you branch your code you will also branch your database
    • If you like you can apply the changes automatically in deployment
    • You can make any kind of changes to your database
    • Database changes are so easy that it encourages database refactoring

Currently there are several tools available for database change management for Java. Some of them use raw SQL for the migrations while the more advanced ones like LiquiBase provide support for multiple different DBMS systems using an additional layer of abstraction for the migrations.

The tool I'm currently using for database migrations is c5-db-migration. It supports migrations written in SQL, which I prefer for our project since we are only using MySQL. The migrations are versioned by timestamp and with the Spring support they are installed automatically to the database when the web application is being deployed. We have even extended it to support migrations written in Java, which was needed for a very special case!

Minesweeper portlet tutorial update for Liferay 6

Here are the updated sources for the Minesweeper portlet tutorial for Liferay 6. I have tested that it works with version 6.0.5.

The problem with the old version was that it was giving me "jQuery is not defined" error when loading the page. Reason for this is that since Liferay 6 the jQuery is no longer built-in for your portlets so you have to include it separately. To me this sounds great since now I can always use the latest version of jQuery and not rely on the old, built-in version.

The fix was straight forward, download the latest version of jQuery, include it in the /js directory and add the following line to the liferay-portlet.xml file

<header-portlet-javascript>/js/jquery-1.4.2.min.js</header-portlet-javascript>

Adding project local libraries to maven

Before moving to maven our libraries were kept in the project lib directory and shared through version control. Now we have moved to using maven I can find all my dependencies from the maven repositories.

However I have found out that it can be sometimes handy to still use the old approach for those special dependencies, especially if you don't have a repository setup in your local network. So we have a dependency for old-stuff.jar which is in the lib directory in our new-fantastic maven project.

 Directory of new-fantastic

[.]       [..]      [lib]     pom.xml   [src]               

 Directory of new-fantastic\lib

[.]             [..]            old-stuff.jar
  1. First we add the lib directory as a repository to the pom.xml
  2.   <repositories>
            <repository>
                <id>local-project-libraries</id>
                <name>Local project libraries</name>
                <url>file://${project.basedir}/lib</url>
                <layout>default</layout>
            </repository>
       </repositories>
    
  3. Then we add a depencency to the old-stuff.jar to the pom.xml
  4.   <dependencies>
        <dependency>
          <groupId>com.blogspot.pragmastic</groupId>
          <artifactId>old-stuff</artifactId>
          <version>0.9</version>
        </dependency>
      </dependencies>
  5. Now if we run maven it will helpfully tell us that the dependency cannot be found and that we should either install it or deploy it to a repository
  6. Missing:
    ----------
    1) com.blogspot.pragmastic:old-stuff:jar:0.9
    
      Try downloading the file manually from the project website.
    
      Then, install it using the command:
          mvn install:install-file -DgroupId=com.blogspot.pragmastic
    -DartifactId=old-stuff -Dversion=0.9 -Dpackaging=jar -Dfile=/path/to/file
    
      Alternatively, if you host your own repository you can deploy the file there:
          mvn deploy:deploy-file -DgroupId=com.blogspot.pragmastic
    -DartifactId=old-stuff -Dversion=0.9 -Dpackaging=jar -Dfile=/path/to/file
    -Durl=[url] -DrepositoryId=[id]
  7. Now we use the command from the message and deploy the file to our Local project libraries repository
  8. mvn deploy:deploy-file -DgroupId=com.blogspot.pragmastic -DartifactId=old-stuff -Dversion=0.9 
    -Dpackaging=jar -Dfile=lib/old-stuff.jar -Durl=file://${project.basedir}/lib 
    -DrepositoryId=local-project-libraries
  9. After this we can run maven and it will load the dependency from our local repository

Simple way for making POST request with silverlight

I came up with this way to make a post request from silverlight because I find the WebClient too cumbersome and the post requests to relative URLs didn't work. My solution is to use javascript for making the posts with Ajax and then call the javascript method from the silverlight. First we have the javascript on the page for making the post with jQuery:
<script type="text/javascript" src="http://www.google.com/jsapi"></script>
<script type="text/javascript">
google.load("jquery", "1.4");
function makeRequest(url, args) {
    $.ajax({type: 'POST', url: url, data: args});
}
</script>
Thanks to jQuery the code is really short. Then we have the helper class for making the post request from silverlight, here the trick is the ToJSDictionary-method converting the arguments dictionary to a javascript object.
public class WebHelper {  
    public static void MakeRequest(string url, 
            IDictionary<string, object> args) {
        try
        {
            HtmlPage.Window.Invoke("makeRequest",url, 
                    ToJSDictionary(args));
        }
        catch (Exception e)
        {
            // Ignored  
        }
    }

    public static object ToJSDictionary(IDictionary<string, object> args)
    {
        var jsdict = HtmlPage.Window.CreateInstance("Object");
        foreach (string key in args.Keys)
        {
            jsdict.SetProperty(key, args[key].ToString());
        }
        return jsdict;
    }
}
Now we can make post requests from our silverlight code like this:
    var args = new Dictionary<string,object>();
    args["p1"] = "test";
    args["p2"] = 1;
    WebHelper.MakeRequest("http://my.site.com/test", args); 
Of course since we are not handling the response this approach is only suitable when that is not required.

Part four: Making the UI with jQuery and Freemarker

This is the fourth and final part of my Minesweeper portlet tutorial.

This part focuses on the html side of the portlet and shows how we use jQuery and freemarker to make our UI dynamic.

Implementing the hover effect

First we will show how the jQuery javascript library is used to get a hover effect on the squares in the game board. The liferay portal 5.2.3 comes built-in with jQuery version 1.2.6, which is slightly dated but works in most cases. In liferay the used notation is jQuery() instead of the normal $() used in the jQuery documentation.

The freemarker template _game_board.ftl contains the following javascript which changes the class of the <td> element on hover.
jQuery(document).ready(function() {
    jQuery(".not-clicked").hover(
        function() {
            if (jQuery(this).hasClass("not-clicked")) {
                jQuery(this).removeClass("not-clicked").addClass("not-clicked-hover");
            }
        },
        function() {
            if (jQuery(this).hasClass("not-clicked-hover")) {
                jQuery(this).removeClass("not-clicked-hover").addClass("not-clicked");
            }
        }
    );
});
With the following style definitions in minesweeper.css
.not-clicked {
    background-image: url('../images/button.png');
}

.not-clicked-hover {
    cursor: pointer;
    background-image: url('../images/button_hover.png');
}
we get the desired effect.


Doing the click with Ajax

Next we will see how we can update parts of the html using Ajax. We are going to use jQuery for that also.

First lets look at the following snippet of javascript from _game_board.ftl
jQuery(document).ready(function() {
    jQuery(".game-board .not-clicked").click(function() {        
Here we use jQuery selectors to bind a handler for the click event on those squares, which are not yet clicked. The actual event handling code does first the following:
        
        var x = jQuery(this).attr("xloc");
        var y = jQuery(this).attr("yloc");
        var url = '<@s.url action="click"/>';
The attributes xloc and yloc contain the x and y coordinates of the square. Then we use the freemarker built in @s.url taglib to get the url for the click action.

Next line in the click handler changes the p_p_state parameter value to exclusive:
        
        url = url.replace('p_p_state=normal', 'p_p_state=exclusive');
The exclusive tells liferay that the page should be loaded without any of the layout html that is normally used. Finally we have
        
        jQuery("#game-board-container").load(url, {x: x, y: y});
    });
});
which loads the click result to the <div> containing the game board.

References

http://docs.jquery.com/Main_Page
http://freemarker.sourceforge.net/docs/ref.html

Part three: Wiring the backend with Spring Framework and Hibernate

This is part three of the Minesweeper portlet tutorial.

This part of the tutorial describes how we can wire our Struts actions with Spring beans and how we can utilize the Spring dao support with Hibernate.

Saving the highscore to database

The following steps try to illustrate how to combine Struts with Spring and Hibernate for easy data access.
  1. First we create the HighScore class to represent a highscore entry in the database
  2. public class HighScore {
        private Long id;
        private int score;
        private String name;
    }
    
  3. We map it to database table highscore with HighScore.hbm.xml mapping file
  4. <hibernate-mapping>
        <class name="com.blogspot.pragmatastic.minesweeper.HighScore" table="highscore">
            <id name="id" column="id">
                <generator class="native"/>
            </id>
            <property name="score" column="score"/>
            <property name="name" column="name"/>
        </class>
    </hibernate-mapping>
    
  5. Then we create a HighScoreDao class for saving the data with the spring hibernate support
  6. public class HighScoreDaoImpl extends HibernateDaoSupport implements HighScoreDao {
        public void save(HighScore highScore) {
            getHibernateTemplate().save(highScore);
        }
    }
    
  7. Now we create a spring application context file minesweeper-applicationContext.xml
  8. First we define the data source for the database which is configured by db.properties
  9. <beans>
        <bean id="dbConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
            <property name="location">
                <value>classpath:db.properties</value>
            </property>
            <property name="placeholderPrefix" value="${db."/>
            <property name="ignoreUnresolvablePlaceholders" value="true"/>
        </bean>
    
        <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
            <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
            <property name="url" value="${db.url}"/>
            <property name="username" value="${db.username}"/>
            <property name="password" value="${db.password}"/>
        </bean>
    
  10. Then we define the hibernate session factory and list our HighScore.hbm.xml mapping file as resource
  11.     
        <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
            <property name="dataSource" ref="dataSource" />
            <property name="mappingResources">
                <list>
                    <value>com/blogspot/pragmatastic/minesweeper/HighScore.hbm.xml</value>
                </list>
            </property>
            <property name="hibernateProperties">
                <props>
                    <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
                    <prop key="hibernate.show_sql">true</prop>
                    <prop key="hibernate.hbm2ddl.auto">update</prop>
                    <prop key="hibernate.cache.provider_class">org.hibernate.cache.NoCacheProvider</prop>
                </props>
            </property>
        </bean>
    
  12. And finally we define our dao
  13.     
        <bean id="highScoreDao" class="com.blogspot.pragmatastic.minesweeper.HighScoreDaoImpl">
            <property name="sessionFactory" ref="sessionFactory"/>
        </bean>
    </beans>
    
  14. Now we need to make the beans defined in the minesweeper-context.xml available for our struts action. First we configure spring to load the context file and create a application context from it in web.xml
  15. <web-app>
        <context-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:minesweeper-applicationContext.xml</param-value>
        </context-param>    
        <listener>
            <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
        </listener>
    </web-app>
    
  16. Next we enable the struts spring integration in the struts.xml
  17. <struts>
        <constant name="struts.objectFactory" value="org.apache.struts2.spring.StrutsSpringObjectFactory"/>
    </struts>
    
  18. After that we can refer to the HibernateDao object in HighScoreAction, spring will automatically wire our action with the bean
  19. public class HighScoreAction extends ActionSupport {
        private HighScore highScore;
        private HighScoreDao highScoreDao;
    
        // Auto wired byName from spring
        public void setHighScoreDao(HighScoreDao highScoreDao) {
            this.highScoreDao = highScoreDao;
        }
    
        public HighScore getHighScore() {
            return highScore;
        }
    
        // Saves the form
        public String save() {
            highScoreDao.save(highScore);
            return SUCCESS;
        }
    }
    
Continue to Part four: Making the UI with jQuery and Freemarker

References

http://www.springbyexample.org/examples/simple-hibernate-xml-config.html
http://static.springsource.org/spring/docs/2.5.x/reference/orm.html#orm-hibernate
http://docs.jboss.org/hibernate/core/3.3/reference/en/html/mapping.html
http://struts.apache.org/2.0.11/docs/spring-plugin.html

Part two: Making the portlet with Struts2

This is part two of the Minesweeper portlet tutorial.

The portlet is configured with several xml files which can be found in the minesweeper/src/main/webapp/WEB-INF and minesweeper/src/main/resources directories. The following steps try to illustrate how a Struts2 action can be configured to become a Liferay portlet.
  1. Our action class GameAction has a method start for starting a new game
  2. public class GameAction extends ActionSupport {
        private Game game;
        
        public String start() {
            game.init();
            return SUCCESS;
        }
    }
    
  3. We configure action startGame in the struts.xml to call that method and render the result success with a freemarker template
  4. <struts>
        <package name="minesweeper" extends="struts-portlet-default" namespace="/minesweeper">
            <action name="startGame" class="com.blogspot.pragmatastic.minesweeper.GameAction" method="start">
                <result name="success" type="freemarker">/pages/game.ftl</result>
            </action>
        </package>
    </struts>
    
  5. We define the minesweeper struts portlet in the portlet.xml
  6. <portlet-app>
        <portlet id="minesweeper">
            <portlet-name>minesweeper</portlet-name>
            <display-name>Minesweeper Portlet</display-name>
            <portlet-class>org.apache.struts2.portlet.dispatcher.Jsr168Dispatcher</portlet-class>
    
  7. We map the portlet to the action defined in the struts.xml by setting the viewNameSpace and defaultViewAction parameters
  8.         <!-- The view mode namespace. Maps to a namespace in the Struts2 config file. -->
            <init-param>
                <name>viewNamespace</name>
                <value>/minesweeper</value>
            </init-param>
            <!-- The default action to invoke in view mode. -->
            <init-param>
                <name>defaultViewAction</name>
                <value>startGame</value>
            </init-param>
        </portlet>
    </portlet-app>
    
  9. We add Liferay specific configuration for our portlet in the liferay-portlet.xml, in this case we define a portlet specific css file
  10. <liferay-portlet-app>
        <portlet>
            <portlet-name>minesweeper</portlet-name>
            <header-portlet-css>/css/minesweeper.css</header-portlet-css>
        </portlet>
    </liferay-portlet-app>
    
  11. And finally we make it visible in the dock menu "Add application" listing by defining the category for it in the liferay-display.xml file
  12. <display>
        <category name="example">
            <portlet id="minesweeper"/>
        </category>
    </display>
    
Continue to Part three: Wiring the backend with Spring Framework and Hibernate

References

http://struts.apache.org/2.0.14/docs/struts-2-portlet-tutorial.html
http://www.liferay.com/community/wiki/-/wiki/Main/liferay-portlet.xml+%285.2.0%29

Part one: POJOs behind the game

This is part one of the Minesweeper portlet tutorial.



The source classes can be found in the minesweeper/src/main directory. The Game class represents a single minesweeper game session. It has one GameBoard object which contains a two dimensional array of Cell objects. Each Cell object represents a square in the game board.
public class Game {
    public long score = 0;
    private GameBoard gameBoard;
    private GameState gameState = GameState.ACTIVE;
}

public class GameBoard {
    private Cell[][] cells;
}

public class Cell {
    private GameBoard gameBoard;
    private boolean mine;
    private int x;
    private int y;
    private boolean clicked;
}

Handling the click

The main functionality of the Game class is the handling of the click event. Depending on the clicked cell the click can result in:
  • Uncovering a number, which tells how many mines lay hidden in the eight surrounding cells.
  • Uncovering an empty cell, and revealing all empty cells in the area.
  • Uncovering a mine, and the game is lost.
  • Uncovering the last clear cell, and winning the game.
The Game object delegates the click event to GameBoard and handles the losing and winning of the game.
public class Game {
   public void click(int x, int y) {
        Cell cell = gameBoard.click(x,y);
        if (cell.isMine()) {
            gameState = GameState.LOST;
            gameBoard.clickAll();
        } else if (gameBoard.isAllCleared()) {
            gameState = GameState.WIN;
            score = MAX_TIME - (System.currentTimeMillis() - startTime);
            if (score < 0) {
                score = 0;
            }
            gameBoard.clickAll();
        }
    }
}
The GameBoard delegates the click to the corresponding Cell object and handles the special case of uncovering all empty cells in the area if the cell is empty (count == 0).
public class GameBoard {
    public Cell click(int x, int y) {
        Cell cell = get(x, y);
        click(cell);
        return cell;
    }

    protected void click(Cell cell) {
        if (!cell.isClicked()) {
            cell.click();
            if (!cell.isMine()) {
                int count = cell.countNearMines();
                if (count == 0) {
                    click(listNear(cell));
                }
            }
        }
    }

    protected void click(Collection<Cell> cells) {
        for (Cell cell : cells) {
            click(cell);
        }
    }
}
The Cell just updates its state to clicked.
public class Cell {
    public void click() {
        clicked = true;        
    }
}

Generating the game board html

The Cell has methods which are used to generate the html for the game board.
public class Cell {
    public String getLabel() {
        if (clicked) {
            if (mine || countNearMines() == 0) {
                return "";
            } else {
                return String.valueOf(countNearMines());
            }
        } else {
            return "";
        }
    }

    public String getCssClass() {
        if (clicked) {
            StringBuilder builder = new StringBuilder();
            builder.append("clicked ");
            if (mine) {
                builder.append("mine");
            } else {
                builder.append("near-mines-" + countNearMines());
            }
            return builder.toString();
        } else {
            return "not-clicked";
        }
    }
}
These methods are used in the freemarker template _game_board.ftl.
<td class="${cell.cssClass}" xloc="${cell.x?c}" yloc="${cell.y?c}" >${cell.label}</td>
The actual style is defined in the minesweeper.css file.

Continue to Part two: Making the portlet with Struts2

Minesweeper portlet tutorial

This tutorial illustrates the technologies I use in liferay portlet development. It's a portlet version of the minesweeper game and you can download the sources here. I have broken the tutorial to the following parts:

I would recommend that you build and run the portlet before reading the other parts of this tutorial.

Building and running the tutorial

To build and run this tutorial you will need:
The following instructions assume that you have successfully installed the above listed items on your local environment.
  1. Download the sources from here
  2. Extract the minesweeper.zip archive
  3. In MySQL create a new database with the name minesweeper
  4. CREATE DATABASE minesweeper;
    
  5. Edit the minesweeper/src/main/resources/db.properties to set the right connection settings for your local MySQL instance
  6. url=jdbc:mysql://localhost:3306/minesweeper
    username=root
    password=
    
  7. Start your Liferay portal instance
  8. Edit the todir attribute in the following line in the minesweeper/pom.xml to point to the deploy directory under your Liferay directory:
  9. <copy todir="C:\liferay-portal-5.2.3\deploy" file="${project.build.directory}/${project.build.finalName}.war"/>
    
  10. In the minesweeper directory run following maven command:
  11. mvn integration-test
  12. This should build and deploy the minesweeper.war. Check the Liferay output for the following lines to verify that the portlet was deployed successfully:
  13. INFO  [PortletHotDeployListener:346] 1 portlet for minesweeper is available for use
  14. Open your browser at http://localhost:8080 and login
  15. From the top right dock menu choose "Add application"
  16. Select the example category and click "Add" for Minesweeper portlet
  17. Now the portlet is ready to go!
Continue to Part one: POJOs behind the game

References

http://www.liferay.com/web/guest/community/wiki/-/wiki/Main/Quick+Installation+Instructions
http://maven.apache.org/download.html
http://dev.mysql.com/doc/refman/5.1/en/installing.html
http://en.wikipedia.org/wiki/Minesweeper_%28computer_game%29

Struts and Freemarker Liferay Portlet Tutorial

It took me a while to get the Liferay to work with the web frameworks I used before, Struts2 + Freemarker. The sources are available for download in here. I have developed and tested this example with the liferay-5.2.3+tomcat-5.5 version.

Configuring the portlet

Below is the file structure I have used in this example.



In Liferay the portlet is configured with the configuration files in the web/WEB-INF directory. We will start with portlet.xml file.

<portlet-app ... >

    <portlet id="struts-freemarker-hello">
        <portlet-name>struts-freemarker-hello</portlet-name>
        <display-name>Struts+Freemarker Hello Example</display-name>
        <portlet-class>org.apache.struts2.portlet.dispatcher.Jsr168Dispatcher</portlet-class>

        <!-- The view mode namespace. Maps to a namespace in the Struts2 config file. -->
        <init-param>
            <name>viewNamespace</name>
            <value>/sample</value>
        </init-param>

        <!-- The default action to invoke in view mode. -->
        <init-param>
            <name>defaultViewAction</name>
            <value>hello</value>
        </init-param>
        ...
    </portlet>
    ...
</portlet-app>

The first important thing in the portlet.xml is the portlet id, which is used in the other, liferay specific configuration files. The we have the portlet class which in our case is set to org.apache.struts2.portlet.dispatcher.Jsr168Dispatcher.

We give two init parameters to the portlet class, viewNamespace and defaultViewAction, which tell our portlet what action to initially call from conf/struts.xml.

Next we have liferay-portlet.xml, which for this example just contains the id of our portlet.

<liferay-portlet-app>
    <portlet>
        <portlet-name>struts-freemarker-hello</portlet-name>
    </portlet>
...
</liferay-portlet-app>

And last is the liferay-display.xml where the our portlet is listed under the category example.

<display>
    <category name="example">
        <portlet id="struts-freemarker-hello"/>
    </category>
</display>

Making the action


Our struts action HelloAction.java is pretty simple, just has 2 methods for the 2 actions we are going to use and getter/setter for the name parameter.

package com.hyperin.sample;
import com.opensymphony.xwork2.ActionSupport;
/**
 * @author heikkiu
 */
public class HelloAction extends ActionSupport {

    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String execute() {
        return SUCCESS;
    }

    public String sayHello() {
        return SUCCESS;
    }
}

Our actions are defined in the src/conf/struts.xml.

<struts>
    <package name="sample" extends="struts-portlet-default" namespace="/sample">
        <action name="hello" class="com.hyperin.sample.HelloAction">
            <result name="success" type="freemarker">/pages/hello_form.ftl</result>
        </action>
        <action name="sayHello" class="com.hyperin.sample.HelloAction" method="sayHello">
            <result name="success" type="freemarker">/pages/hello_response.ftl</result>
        </action>
    </package>
</struts>

Only difference to a normal struts configuration is the struts-portlet-default package we are extending. The results are mapped to the freemarker templates in web/pages. First template hello_form.ftl contains the form.

<form action="<@s.url action="sayHello"/>" method="post">
    <h1>Your name:</h1>
    <input type="text"name="name" value="${name!"Bob Brown"}"/>
    <input type="submit" value="Say hello!"/>
</form>

It's pretty plain html with one very important thing: the generation of the form's action with the freemarker built-in <@s action="sayHello"/> taglib. The response template is even plainer.

<h1>Hello ${name}!</h1>
<a href="<@s.url action="hello" name="${name}"/>">Go Back...</a>

Here also the important bit is the url for the back link url <@s.url action="hello" name="${name}"/>, which now has the name parameter given to the url.

Building and running the example


Once you have downloaded the zip, unzip and edit the deploy.dir property in the build.xml to point to the deploy directory under your liferay installation.

<property name="deploy.dir" value="C:/liferay-portal-5.2.3/deploy"/>

After that go to the project root and run the build with ant

C:\temp\struts-sample-portlet>ant

After a while the webserver log should tell you that
22:33:17,228 INFO  [PortletHotDeployListener:346] 1 portlet for struts-sample-portlet is available for use

Now you can open your browser and under the Add Application menu you should find a new category called example, which contains the portlet Struts+Freemarker Hello Example. Once you add the portlet to your page you can see it in action.

First post

My goal for this blog is to share things I have discovered in my work. I'll try to focus on practical examples that might be useful to others.