Monday, February 7, 2011

Spring Mobile M3 - Site Preference

A few weeks ago I started playing with Spring Mobile. For my app I want to use existing Spring MVC controllers to render different views depending on whether the client is a mobile device or a classic browser.

For that purpose Spring Mobile is really a very helpful asset (See my last Spring Mobile related blog post for more details). Back then I investigated a feature that allows you to manage a user's site preference. For example, the normal use case is that a user with a mobile device only sees the mobile version of your website.

Wouldn't it be desirable, though, to allow the user to switch to the full version of the website as well?  While hopefully not a regular use-case, your site's visitor may be for instance interested in some additional content that is unavailable in the mobile version. A good example for me is Wikipedia. For normal use, the mobile web version of Wikipedia is certainly quite functional. However, I am also bi-lingual (plus aspiring to learn Spanish), so I often use Wikipedia to look up articles, let's say in German, but then I want to switch over to the Spanish version of the same article in order to find certain translations. Because I can't do the language switch in the mobile web version, I at least have the option to change back to the full Wikipedia version and switch the article's language there.  

Well, Spring Mobile has a feature for site preference but unfortunately that feature (when I checked in the M2 release) had some limitations. It only worked with the SiteSwitcherHandlerInterceptor. This interceptor assumes you want to redirect the user to a dedicated mobile sub-domain that is hosting your application's mobile version.

In my simple use-case, however, I want to keep the mobile and non-mobile content on one domain (same urls) but let mobile users change to the full version of the website and stay on that full version for the duration of their session (or set via cookie for the duration of multiple visits).


Unfortunately, the "site preference" feature back then was somewhat embedded in the M2 release and you could not use it stand-alone easily. Well, I headed over to the Spring forums and posted my issue there and within 3 days, Keith had implemented and commited improvements for my requirements (I was truly impressed with the feedback!)

Well, only a month later, I finally found the time to look at the latest changes regarding the site preference feature. This has coincided also with the Spring Mobile M3 release 1 day later, which contains all the latest features. 

Checking out and building Spring Mobile

But in case you want to anyway, you can check out and build the Spring Mobile project easily yourself using Git and Gradle. You will find the sources here: http://git.springsource.org/spring-mobile

Just FYI, I was unable to check out the Spring Mobile project using Eclipse's EGit. It looks like Egit does not support (??) Git submodules, a feature used by Spring Mobile. However, checking out the project from the command line using worked well:

git clone --recursive git://git.springsource.org/spring-mobile/spring-mobile.git

Building project using Gradle is trivial. Under the spring-mobile directory execute either ./gradlew build or gradlew.bat. You don''t even have to have Gradle installed locally - it downloads Gradle for you. I am Maven fan but that was impressive!! I really owe it to myself to look at Gradle more closely very soon.

Spring Mobile M3 Changes regarding Site Preference

Anyway, the changes regarding the site preference feature in the M3 release are satisfying my needs perfectly. The site-preference functionality has been refactored out into its own feature and Spring Mobile now provides the following separate features:
  1. Device Resolution
  2. Site Preference Management
  3. Site Switching
The documentation has also been updated and is reflecting the feature changes and is quite helpful in that regard. Here is the configuration necessary to configure site-preference for my use-case:

I updated my Maven dependencies to:

     <dependency>
         <groupId>org.springframework.mobile</groupId>
         <artifactId>spring-mobile-device</artifactId>
         <version>1.0.0.M3</version>
     </dependency>

I updated my spring web context xml file:

  <mvc:interceptors>
       <bean class="org.springframework.mobile.device.DeviceResolverHandlerInterceptor" />
       <bean class="org.springframework.mobile.device.site.SitePreferenceHandlerInterceptor" />
  </mvc:interceptors>

In order to dependency inject:
  • org.springframework.mobile.device.site.SitePreference
  • org.springframework.mobile.device.Device
into your Spring MVC controllers, you need to add custom argument resolvers:

<bean class="org.springframework.mobile.device.DeviceWebArgumentResolver" />
<bean class="org.springframework.mobile.device.site.SitePreferenceWebArgumentResolver" /> 


See Chapter 2.4.4 of the Spring Mobile documentation for details. An interesting observation: If you're using the site preference feature, you probably only need to inject: org.springframework.mobile.device.site.SitePreference 
into your controllers. For example if users don't explicitly set the site preference through the request parameter ('currentSitePreference'), SitePreference will fall back to what Device would tell you.

I like the documentation change that instead of using a CustomWebArgumentResolverInstaller, the documentation now configures the resolvers directly in the context, which makes things easier to understand. I am impressed that with the M3 release the documentation looks very good.

Oh and in case you wondered how it works in practice - Check out http://www.devnexus.com/

It is admittedly (volunteer-) work in progress but I think the site preference feature is working nicely for my project now. Next, I need to beef up my jQuery Mobile skills to mobile-web-enable the entire site.

3 comments:

Mobile site said...

thanks, i will try your trick

Anonymous said...

I'm using SitePreference and it's working as expected. But how can I set the cookie timeout value ?

sudosu said...

Thanks, exactly what i searched for :)