2014. 10. 13.

Configuring SiteMesh3 with DeviceResolver - Java based configuration

web.xml
<filter>
    <filter-name>deviceResolverHandlerFilter</filter-name>
    <filter-class>org.springframework.mobile.device.DeviceResolverRequestFilter</filter-class>
</filter>

<filter>
    <filter-name>sitemesh</filter-name>
    <filter-class>com.yoursite.common.filter.SiteMeshFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>sitemesh</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

SiteMeshFilter.java
package com.yoursite.common.filter;

import com.yoursite.common.SiteMeshDecoratorSelector;

import org.sitemesh.builder.SiteMeshFilterBuilder;
import org.sitemesh.config.ConfigurableSiteMeshFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * sitemesh 설정
 * 
 * @author ysh3342
 * @since 2014.10.07
 *
 */
public class SiteMeshFilter extends ConfigurableSiteMeshFilter {
 private static final Logger logger = LoggerFactory
   .getLogger(SiteMeshFilter.class);

 @Override
 protected void applyCustomConfiguration(SiteMeshFilterBuilder builder) {
  logger.debug("applyCustomConfiguration");

  final String path = "/WEB-INF/vm/_decorators/";
  SiteMeshDecoratorSelector decoratorSelector = new SiteMeshDecoratorSelector();

  decoratorSelector.putMapping(SiteMeshDecoratorSelector.DEFAULT, path
    + "default.vm");
  decoratorSelector.putMapping(SiteMeshDecoratorSelector.MOBILE, path
    + "mobile.vm");

  decoratorSelector.put("/popup/*", path + "popup.vm");
  decoratorSelector.put("/ajax/*", path + "null.vm"); // TEST

  decoratorSelector.setUseCookie(true);

  // Assign
  builder.setCustomDecoratorSelector(decoratorSelector)
    .addExcludedPath("/jsp/*").addExcludedPath("/*.jsp");
 }

}

SiteMeshDecoratorSelector.java
package com.yoursite.common;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import org.sitemesh.config.PathBasedDecoratorSelector;
import org.sitemesh.content.Content;
import org.sitemesh.content.ContentChunk;
import org.sitemesh.webapp.WebAppContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.mobile.device.site.SitePreference;
import org.springframework.mobile.device.site.SitePreferenceHandler;

/**
 * 상황별 데코레이터를 선택한다
 * 
 * @author ysh3342
 * @since 2014.10.07
 */
public class SiteMeshDecoratorSelector extends
  PathBasedDecoratorSelector<WebAppContext> {

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

 public static final String DEFAULT = "default";
 public static final String MOBILE = "mobile";
 public static final String TABLET = "tablet";

 private final Map<String, String> mappings = new HashMap<String, String>();

 private boolean useCookie = false;
 private String cookieName = "PC";

 @Override
 public String[] selectDecoratorPaths(Content content,
   WebAppContext siteMeshContext) throws IOException {
  logger.debug("selectDecoratorPaths(Content content, WebAppContext siteMeshContext)");

  // If page contains <meta name='decorator'
  // content='/some/dec.html,/another/dec.html'>
  ContentChunk decoratorMetaTag = content.getExtractedProperties()
    .getChild("meta.decorator");
  if (decoratorMetaTag.hasValue()) {
   logger.debug("decoratorMetaTag : {}", decoratorMetaTag.getValue());
   return decoratorMetaTag.getValue().split(",");
  }

  // request path 기준으로 매핑된 decorator path를 가져온다
  String[] pathDecorator = super.getPathMapper().get(
    siteMeshContext.getPath());
  if (pathDecorator != null) {
   logger.debug("pathDecorator : {}", (Object[]) pathDecorator);
   return pathDecorator;
  }

  String decorator;
  final SitePreference sitePreference = (SitePreference) siteMeshContext
    .getRequest()
    .getAttribute(
      SitePreferenceHandler.CURRENT_SITE_PREFERENCE_ATTRIBUTE);

  if (sitePreference.isMobile()) {
   logger.debug("Mobile");
   decorator = mappings.get(MOBILE);
  } else if (sitePreference.isTablet()) {
   logger.debug("Tablet");
   decorator = mappings.get(TABLET);
  } else {
   logger.debug("PC");
   decorator = mappings.get(DEFAULT);
  }

  if (decorator == null) {
   decorator = "/WEB-INF/vm/_decorators/default.vm";
   logger.info("Fail to load decorator path.");
   logger.info("Using decorator path [{}] instead.", decorator);

   // String[] empty = {};
   // return empty;
  }
  logger.debug("decorator : {}", decorator);

  return decorator.split(",");
 }

 public void putMapping(String pattern, String value) {
  if (value != null) {
   mappings.put(pattern, value);
  }
 }

 public boolean isUseCookie() {
  return useCookie;
 }

 public void setUseCookie(boolean useCookie) {
  this.useCookie = useCookie;
 }

 public String getCookieName() {
  return cookieName;
 }

 public void setCookieName(String cookieName) {
  this.cookieName = cookieName;
 }

}

2014. 10. 8.

Mobile version of sitemesh decorator

pom.xml

    org.springframework.mobile
    spring-mobile-device
    1.1.2.RELEASE


Spring interceptor
<mvc:interceptors>
    <!-- request.setAttribute(DeviceUtils.CURRENT_DEVICE_ATTRIBUTE = "currentDevice", org.springframework.mobile.device.Device); -->
    <bean class="org.springframework.mobile.device.DeviceResolverHandlerInterceptor" />
    <!-- request.setAttribute(SitePreferenceHandler.CURRENT_SITE_PREFERENCE_ATTRIBUTE = "currentSitePreference", org.springframework.mobile.device.site.SitePreference); -->
    <bean class="org.springframework.mobile.device.site.SitePreferenceHandlerInterceptor" />
</mvc:interceptors>

SpringMobileParameterDecoratorMapper.java
package com.yoursite.common.mapper;

import java.util.Properties;

import javax.servlet.http.HttpServletRequest;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.mobile.device.site.SitePreference;
import org.springframework.mobile.device.site.SitePreferenceUtils;

import com.opensymphony.module.sitemesh.Config;
import com.opensymphony.module.sitemesh.Decorator;
import com.opensymphony.module.sitemesh.DecoratorMapper;
import com.opensymphony.module.sitemesh.Page;
import com.opensymphony.module.sitemesh.mapper.ConfigDecoratorMapper;

/**
 * sitemesh 2.4 용 DecoratorMapper
 * @author ysh3342
 *
 */
public class SpringMobileParameterDecoratorMapper extends ConfigDecoratorMapper {
 private static final Logger logger = LoggerFactory
   .getLogger(SpringMobileParameterDecoratorMapper.class);
 // private String decoratorName = null;

 private static final String MOBILE_DECORATORNAME = "mobile";
 private static final String TABLET_DECORATORNAME = "tablet";

 public void init(Config config, Properties properties,
   DecoratorMapper parent) throws InstantiationException {
  super.init(config, properties, parent);
  // decoratorName = properties.getProperty("decorator.name", "mobile");
  // logger.debug("init decoratorName : {}", decoratorName);
 }

 public Decorator getDecorator(final HttpServletRequest request,
   final Page page) {
  SitePreference sitePreference = SitePreferenceUtils
    .getCurrentSitePreference(request);
  if (sitePreference != null) {
   logger.debug("sitePreference.isNormal() : {}",
     sitePreference.isNormal());
   logger.debug("sitePreference.isMobile() : {}",
     sitePreference.isMobile());
   logger.debug("sitePreference.isTablet() : {}",
     sitePreference.isTablet());
   if (sitePreference.isMobile()) {
    return getNamedDecorator(request, MOBILE_DECORATORNAME);
   } else if (sitePreference.isTablet()) {
    return getNamedDecorator(request, TABLET_DECORATORNAME);
   } else {
    return super.getDecorator(request, page);
   }
  }
  logger.debug("super.getDecorator(request, page);");
  return super.getDecorator(request, page);
 }
}

sitemesh.xml
<property name="decorators-file" value="/WEB-INF/decorators.xml"/>
<decorator-mappers>
    <mapper class="com.yoursite.common.mapper.SpringMobileParameterDecoratorMapper">
        <param name="config" value="${decorators-file}"/>
    </mapper>
</decorator-mappers>