dineshonjava

Spring Mobile Tutorial

In this Spring Mobile tutorial we will discuss about how to spring work into web environment to detecting device.
Table of Contents
  1. Introduction
  2. Maven Dependency
  3. Device Module
  4. Device Resolution Classes 
    1. DeviceResolver 
    2. Device
    3. DeviceResolverHandlerInterceptor
    4. DeviceResolverRequestFilter
    5. DeviceHandlerMethodArgumentResolver
  5. Site Preference Management 
    1. SitePreferenceHandler
    2. SitePreference
    3. SitePreferenceHandlerInterceptor
    4. SitePreferenceRepository
  6. Site Switching
  7. Device Aware View Management
    1. Enabling Device Aware Views
    2. Fallback View Resolution
  8. Sample Example for Spring Mobile Overview
  9. Summary


1. Introduction
Spring community provide another project Spring Mobile as an extensions to Spring MVC for developing mobile web applications. This module provide the server side device detection and provide site preferences to open website according to device resolution.

2. Maven Dependency
For getting this project following is maven dependency to be added to pom file.
<dependency>
    <groupId>org.springframework.mobile</groupId>
    <artifactId>spring-mobile-device</artifactId>
    <version>${org.springframework.mobile-version}</version>
</dependency>

3. Device Module
Spring Mobile provide extension to Spring MVC for device detection. It is useful when any request by mobile deices need to handled differently from requests made by desktop browsers. This supported provided by Spring Module with the help of Device Resolver in the framework. Let see how device resolver works.
4. Device Resolution Framework
This device resolution module is a framework which has collection of interfaces, filters, handler classes and enum to working as device resolver. Lets have look following classes in this module.
4.1 DeviceResolver interface
In Spring Mobile, the DeviceResolver interface defines the API for device resolution:
public interface DeviceResolver {
    Device resolveDevice(HttpServletRequest request);
}

This interface's method return the Device interface object as below
4.2 Device interface
public interface Device {
    boolean isNormal();
    boolean isMobile();
    boolean isTablet();
    DevicePlatform getDevicePlatform();
}

Device resolution is nothing but it is the simple process of introspecting an HTTP request to determine the device that originated the request by analyzing the User-Agent header and other request headers.

In Spring MVC, web applications perform device resolution at the beginning before any request handler is invoked. Then by the help of Device resolver implementation request handlers can obtain the Device instance and by using of it request served differently as desktop request.

Spring Mobile provides by default implementation of DeviceResolver is LiteDeviceResolver. It is used for device resolution. You may plug-in another DeviceResolver implementation by injecting a constructor argument. For activating device resolver Spring Mobile provides an interceptor so initially we have register this interceptor as below.

4.3 DeviceResolverHandlerInterceptor interceptor

XML Configuration
<interceptors>
  <!-- On pre-handle, resolve the device that originated the web request -->
  <bean class="org.springframework.mobile.device.DeviceResolverHandlerInterceptor" />
</interceptors>
Java Configuration
@Bean
public DeviceResolverHandlerInterceptor deviceResolverHandlerInterceptor() {
return new DeviceResolverHandlerInterceptor();
}

@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(deviceResolverHandlerInterceptor());
}
Alternative to the DeviceResolverHandlerInterceptor, Spring Mobile also provides one servlet filter for support to the device resolver. Configured as below

4.4 DeviceResolverRequestFilter filter

To enable, add the DeviceResolverRequestFilter to your web.xml:
<filter>
  <filter-name>deviceResolverRequestFilter</filter-name>
  <filter-class>org.springframework.mobile.device.DeviceResolverRequestFilter</filter-class>
</filter>

4.5 DeviceHandlerMethodArgumentResolver 
Find the Current Device
There is an Untility class in the Spring Mobile to fetching current device to generate the request.

Device currentDevice = DeviceUtils.getCurrentDevice(servletRequest);

If you'd like to pass the current Device as an argument to one of your @Controller methods, configure a DeviceWebArgumentResolver:

<annotation-driven>
  <argument-resolvers>
    <bean class="org.springframework.mobile.device.DeviceWebArgumentResolver" />
  </argument-resolvers>
</annotation-driven>

You can alternatively configure a DeviceHandlerMethodArgumentResolver using Java-based configuration:

@Bean
public DeviceHandlerMethodArgumentResolver deviceHandlerMethodArgumentResolver() {
    return new DeviceHandlerMethodArgumentResolver();
}

@Override
public void addArgumentResolvers(List argumentResolvers) {
    argumentResolvers.add(deviceHandlerMethodArgumentResolver());
}

You can then inject the Device into your @Controllers as shown below:

@Controller
public class HomeController {

    private static final Logger logger = LoggerFactory.getLogger(HomeController.class);

    @RequestMapping("/")
    public void home(Device device) {
        if (device.isMobile()) {
            logger.info("Hello mobile user!");
        } else if (device.isTablet()) {
            logger.info("Hello tablet user!");
        } else {
            logger.info("Hello desktop user!");         
        }
    }

}

5. Site Preference Management
This feature called site preference management allows user to set preference (SitePreference) to view a particular site in either "normal", "mobile" or "tablet" mode from a particular device. After device resolution we have to decide site preference either open mobile site or desktop or tablet site.

5.1 SitePreferenceHandler
Following interface provided by the Spring Mobile.

public interface SitePreferenceHandler {

    final String CURRENT_SITE_PREFERENCE_ATTRIBUTE = "currentSitePreference";
    
    SitePreference handleSitePreference(HttpServletRequest request, HttpServletResponse response);

}
Above interface has one method handleSitePreference with request and response parameters to decide SitePreference, it is actually an enum.

5.2 SitePreference enum
public enum SitePreference {
//...
}

To selecting site preference as below

Site: <a href="${currentUrl}?site_preference=normal">Normal</a> |
<a href="${currentUrl}?site_preference=mobile">Mobile</a>

Spring Mobile provides handler for SitePreference is SitePreferenceHandler, it's implementation is StandardSitePreferenceHandler.

5.3 SitePreferenceHandlerInterceptor
To enable SitePreference management before requests are processed, add the SitePreferenceHandlerInterceptor to your DispatcherServlet configuration:
<interceptors>
  <!-- On pre-handle, manage the user's site preference (declare after DeviceResolverHandlerInterceptor) -->
  <bean class="org.springframework.mobile.device.site.SitePreferenceHandlerInterceptor" />
</interceptors>
 
Java-based configuration is also available:
@Bean
public SitePreferenceHandlerInterceptor sitePreferenceHandlerInterceptor() {
    return new SitePreferenceHandlerInterceptor();
}

@Override
public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(sitePreferenceHandlerInterceptor());
}

5.4 Site Preference Storage
'CookieSitePreferenceRepository' (default implementation of SitePreferenceRepository) stores the user's preference in client side cookie so that it can be used for the future requests made by that user.

For getting current site preference Spring Mobile provides utility class SitePreferenceUtils, it give current site preference instance as below.

SitePreference sitePreference = SitePreferenceUtils.getCurrentSitePreference(servletRequest);

You could pass this site preference as argument with following configuration.

To configure a SitePreferenceWebArgumentResolver:
<annotation-driven>
  <argument-resolvers>
    <bean class="org.springframework.mobile.device.site.SitePreferenceWebArgumentResolver" />
  </argument-resolvers>
</annotation-driven>
  
Java-based configuration is also available:
@Bean
public SitePreferenceHandlerMethodArgumentResolver sitePreferenceHandlerMethodArgumentResolver() {
    return new SitePreferenceHandlerMethodArgumentResolver();
}

@Override
public void addArgumentResolvers(List argumentResolvers) { 
    argumentResolvers.add(sitePreferenceHandlerMethodArgumentResolver());
}

You can then inject the indicated SitePreference into your @Controller as shown below:

@Controller
public class HomeController {

    @RequestMapping("/")
    public String home(SitePreference sitePreference, Model model) {
        if (sitePreference == SitePreference.NORMAL) {
            logger.info("Site preference is normal");
            return "home";
        } else if (sitePreference == SitePreference.MOBILE) {
            logger.info("Site preference is mobile");
            return "home-mobile";
        } else if (sitePreference == SitePreference.TABLET) {
            logger.info("Site preference is tablet");
            return "home-tablet";
        } else {
            logger.info("no site preference");
            return "home";
        }
    }

}
6. Site Switching
Spring mobile also provides different types of site switchers (like mDot, dotMobi and urlPath SiteSwitcher) which automatically redirect users to the device specific site based on the device generating the request and site preference set by the user.

SiteSwitcherHandlerInterceptor redirect users to device specific site. There are different types of site switchers available like mDot, dotMobi and urlPath SiteSwitcher. Bute here we have used urlPath SiteSwitcher which redirects users to different paths within the application based on the device and site preference.

<interceptors>
  <!-- On pre-handle, resolve the device that originated the web request -->
  <bean class="org.springframework.mobile.device.DeviceResolverHandlerInterceptor" />
  <!-- On pre-handle, redirects mobile users to "m.myapp.com" (declare after DeviceResolverHandlerInterceptor) -->
  <bean class="org.springframework.mobile.device.switcher.SiteSwitcherHandlerInterceptor" 
      factory-method="mDot">
    <constructor-arg index="0" type="java.lang.String" value="myapp.com"/>
  </bean>
</interceptors>

Java-based configuration is also available:


@Bean
public DeviceResolverHandlerInterceptor deviceResolverHandlerInterceptor() {
    return new DeviceResolverHandlerInterceptor();
}

@Bean
public SiteSwitcherHandlerInterceptor siteSwitcherHandlerInterceptor() {
    return SiteSwitcherHandlerInterceptor.mDot("myapp.com", true);
}

@Override
public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(deviceResolverHandlerInterceptor());
    registry.addInterceptor(siteSwitcherHandlerInterceptor());
}

7. Device Aware View Management
ViewResolver provides a mapping between logical view name and actual view. Here we have used device aware view resolver ('LiteDeviceDelegatingViewResolver') that delegates to InternalResourceViewResolver allowing for resolution of device specific view names by adjusting view name by adding prefix (say 'm/' and 't/' for mobile and tablet) or suffix without the need for defining separate mapping for each device specific view.

7.1 Enabling Device Aware Views

XML configuration:
<bean class="org.springframework.mobile.device.view.LiteDeviceDelegatingViewResolver">
  <constructor-arg>
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
      <property name="prefix" value="/WEB-INF/views/" />
      <property name="suffix" value=".jsp" />
    </bean>
  </constructor-arg>
  <property name="mobilePrefix" value="mobile/" />
  <property name="tabletPrefix" value="tablet/" />
</bean>
   
Java-based configuration:
@Bean
public LiteDeviceDelegatingViewResolver liteDeviceAwareViewResolver() {
    InternalResourceViewResolver delegate = new InternalResourceViewResolver();
    delegate.setPrefix("/WEB-INF/views/");
    delegate.setSuffix(".jsp");
    LiteDeviceDelegatingViewResolver resolver = new LiteDeviceDelegatingViewResolver(delegate);
    resolver.setMobilePrefix("mobile/");
    resolver.setTabletPrefix("tablet/");
    return resolver;
}

7.2 Fallback View Resolution
There may be cases where device specific views for a particular page may not be available. There Fallback resolution ('enableFallback') comes into picture. If adjusted view name can not be resolved then original view is used by the ViewResolver.

XML configuration:
<bean class="org.springframework.mobile.device.view.LiteDeviceDelegatingViewResolver">
    ...
    <property name="enableFallback" value="true" />
    ...
</bean>
       
Java-based configuration:
@Bean
public LiteDeviceDelegatingViewResolver liteDeviceAwareViewResolver() {
    ...
    resolver.setEnableFallback(true);
    ...
    return resolver;
}

8. Sample Example for Spring Mobile Overview
In this section we discuss a sample web application with using Spring Mobile to detect device and accordingly rendering the views.

Source Code of Sample Application
You could find source code this application from GitHub.

sample-application-spring-mobile


9. Summary
In this article we have seen two different module to detecting compatible site to the device one is Device Resolution and another is SitePreference by these we could resolve device aware views. And also add one sample application for Spring Mobile.