Sunday, February 26, 2012

Deploy existing Spring MVC application to heroku

I have written a small spring-mvc application to demonstate handling internationalization for my last blog. Since then I attended a presentation about Heroku by James Ward. Heroku is a cloud application platform. It's hosted on EC2. I wanted to see what it takes to deploy a (very) basic, existing web app on heroku. Heroku provides a free (single dyno) service, which I'll use to host the application. Heroku supports java and maven out of the box and since the application I wanted to deploy is a spring mvc application built with maven I was in luck. I described steps I took to deploy application below.

Getting acquainted with heroku and preparing the application
1. I followed getting started steps to signup, install heroku tools locally and login.
2. I followed the instructions to add jetty runner to the pom file.
3. Added Procfile file to declare process runner instructions executed on heroku described here .
4.Tested application locally

Once I have verified that application runs fine locally I was ready to push it up to the cloud.
Heroku uses git to push apps to the cloud, since the app is stored on github I was ready to deploy the application.

Deploying application
Created the app on heroku by executing following command:
heroku create --stack cedar
The output I got was something like that.
Creating severe-dusk-1991... done, stack is cedar
http://severe-dusk-1991.herokuapp.com/ | git@heroku.com:severe-dusk-1991.git
Git remote heroku added
Note that the url listed in the second line of the output is the url for accessing the app on the web.
After creation I was ready to actually deploy the app to the heroku by executing following command:
 git push heroku master
Got the following output
....
-----> Heroku receiving push
-----> Java app detected
-----> Installing Maven 3.0.3..... done
-----> Installing settings.xml..... done
-----> executing /app/tmp/repo.git/.cache/.maven/bin/mvn -B 
		-Duser.home=/tmp/build_3pcwfaauez5e 
		-Dmaven.repo.local=/app/tmp/repo.git/.cache/.m2/repository 
		-s /app/tmp/repo.git/.cache/.m2/settings.xml -DskipTests=true clean install
       [INFO] Scanning for projects
       ....
-----> Discovering process types
       Procfile declares types -> web
-----> Compiled slug size is 14.0MB
-----> Launching... done, v5
       http://severe-dusk-1991.herokuapp.com deployed to Heroku
...
Note that maven build is executed out on heroku instance and output then deployed. Heroku also supports gradle as build tool.
After this step application is readily available for public viewing at: http://severe-dusk-1991.herokuapp.com/home . Note: this is a free account, I'm not sure how long this app is actually going to be available .

Logging and viewing logging output
Heroku provides access to application log output only when it's printed to standard output. Application I just deployed used logback library and outputs logging output to files. In order to take advantage of heroku logging service I had to re-direct output to system.out by changing logging configuration and redeploy the application.
Steps
1. Changed logback file to use console appender instead of file appenders (this is really beyound the scope of this article).
2. Re-deployed application to the heroku service by re-executing command:
	git push heroku master

3. Now I was able to monitor application logs by executing following command
 heroku logs --tail
Other possible application changes
Granted, that the application I have deployed is very, very simple. Hosting more complex applications might require significant configuration (and maybe even code) modifications. For one, heroku doesn't support session affinity. There are several approaches for dealing with that (i.e. using something like memcached, database, nosql store, or such for session state) which are beyond the scope of this article. There is also a question of deploying and configuation of external services such as databases, etc.., which will contribute to the complexity of cloud deployment and configuration. Heroku does provide a significant number of add on services available for deployed applications which might make things easier.

Saturday, February 11, 2012

Spring mvc internationalization support with cookies

Spring mvc has a great support for adding internationalization support to web applications. It allows adding support for displaying multi- messages in just several configuration settings. I have created a sample application to demonstrate one way to accomplish that. The application is available on github spring-internationalization. The app uses maven to resolve all dependencies and cargo plugin to download and run local tomcat instance. It should be fairly easy to check it out (once maven 3 is installed and configured) To try it out, make sure that maven is installed and configured properly. Pull down the app from the public github repository at spring-internationalization, open terminal window and execute following command in app root directory:
 
     mvn clean package cargo:run

Running this command will download, and execute a local copy of tomcat and deploy the application. Once tomcat has been started application can be accessed in web browser by going to following url:

http://localhost:5050/spring-internationalization/home

To check out language features, select a language from "Pick language" select box, on home page. Changing select box value changes the language used in entire application (2 humble jsp pages in this particular case) and re-loads home page with messages in newly selected locale.

Setup

This is a typical spring mvc web application, so I'm going to skip describing components in detail. Below I displayed configuration pieces needed to support internationalization:
1. Message source bean - tells spring where to find resource bundles and their file name pattern. In this application file name pattern is messages_xx_XX.properties (ie. messages_en_US.properties for english/US properties files) see files in src/main/resources/bundles path in project for details.

    <bean id="messageSource" 
         class="org.springframework.context.support.ReloadableResourceBundleMessageSource"
          p:basenames="classpath:bundles/messages"
          p:defaultEncoding="utf-8"
          p:fallbackToSystemLocale="true"/>


2. Mvc interceptor - component intercepting http requests checking whether locale needs to be changed.
This interceptor is configured to capture requests with parameter name of siteLanguage and attempts to change the locale based on parameter value:
For example a request to the home page with appended parameter value such as below
    http://localhost:5050/spring-internationalization/home?siteLanguage=fr_FR
will attempt to change application language to french.

   <mvc:interceptors>
        <bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor" >
            <property name="paramName" value="siteLanguage"/>
        </bean>
    </mvc:interceptors>


3. CookieLocaleResolver bean is the third piece of the puzzle. This bean stores locale selected by user in a browser cookie.
 
    
        
    


4. Finally jsp pages use spring:message tag to access bundle messages as listed below.

 

This is it in a nutshell. Note that this is just one of the strategies. Spring provides other tools for handling internationalization. One common strategy is to fallback to language settings in http request header to determine desired locale if cookie value is not available (or CookieLocaleResolver localization is not configured).