/* * Copyright 2010-2014 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.mobile.device.view; import javax.servlet.http.HttpServletRequest; import org.springframework.mobile.device.Device; import org.springframework.mobile.device.DeviceUtils; import org.springframework.mobile.device.site.SitePreference; import org.springframework.mobile.device.site.SitePreferenceUtils; import org.springframework.mobile.device.util.ResolverUtils; import org.springframework.util.Assert; import org.springframework.web.context.request.RequestAttributes; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import org.springframework.web.servlet.ViewResolver; import org.springframework.web.servlet.view.ContentNegotiatingViewResolver; /** * A lightweight {@link AbstractDeviceDelegatingViewResolver} for adjusting a * view based on the combination of resolved {@link Device} and specified * {@link SitePreference}. View names can be augmented with a specified prefix * or suffix. * * <p>Specify the prefix for the different device types. Default prefixes are * empty strings. For the requested view name of "home", the following table * illustrates how the view name will be adjusted based on device type.</p> * * <table border=1 cellpadding=3 cellspacing=0> * <tr> * <td>Resolved Device</td> * <td>Method</td> * <td>Prefix</td> * <td>Adjusted View</td> * </tr> * <tr> * <td>Normal</td> * <td>{@link #setNormalPrefix(String)}</td> * <td>"normal/"</td> * <td>"normal/home"</td> * </tr> * <tr> * <td>Mobile</td> * <td>{@link #setMobilePrefix(String)}</td> * <td>"mobile/"</td> * <td>"mobile/home"</td> * </tr> * <tr> * <td>Tablet</td> * <td>{@link #setTabletPrefix(String)}</td> * <td>"tablet/"</td> * <td>"tablet/home"</td> * </tr> * </table> * * <p>Alternatively, you may want to have the views adjusted to use a suffix * for each device type. Again, using the requested view name of "home", the * following table shows the adjusted view names.</p> * * <table border=1 cellpadding=3 cellspacing=0> * <tr> * <td>Resolved Device</td> * <td>Method</td> * <td>Suffix</td> * <td>Adjusted View</td> * </tr> * <tr> * <td>Normal</td> * <td>{@link #setNormalSuffix(String)}</td> * <td>".normal"</td> * <td>"home.normal"</td> * </tr> * <tr> * <td>Mobile</td> * <td>{@link #setMobileSuffix(String)}</td> * <td>".mobile"</td> * <td>"home.mobile"</td> * </tr> * <tr> * <td>Tablet</td> * <td>{@link #setTabletSuffix(String)}</td> * <td>".tablet"</td> * <td>"home.tablet"</td> * </tr> * </table> * * <p>It is also possible to use a combination of prefix and suffix. The view * resolver will apply both to the adjusted view.</p> * * @author Scott Rossillo * @author Roy Clarkson * @since 1.1 * @see ViewResolver * @see ContentNegotiatingViewResolver */ public class LiteDeviceDelegatingViewResolver extends AbstractDeviceDelegatingViewResolver { private String normalPrefix = ""; private String mobilePrefix = ""; private String tabletPrefix = ""; private String normalSuffix = ""; private String mobileSuffix = ""; private String tabletSuffix = ""; /** * Creates a new LiteDeviceDelegatingViewResolver * @param delegate the ViewResolver in which to delegate */ public LiteDeviceDelegatingViewResolver(ViewResolver delegate) { super(delegate); } /** * Set the prefix that gets prepended to view names for normal devices. */ public void setNormalPrefix(String normalPrefix) { this.normalPrefix = (normalPrefix != null ? normalPrefix : ""); } /** * Return the prefix that gets prepended to view names for normal devices */ protected String getNormalPrefix() { return this.normalPrefix; } /** * Set the prefix that gets prepended to view names for mobile devices. */ public void setMobilePrefix(String mobilePrefix) { this.mobilePrefix = (mobilePrefix != null ? mobilePrefix : ""); } /** * Return the prefix that gets prepended to view names for mobile devices */ protected String getMobilePrefix() { return this.mobilePrefix; } /** * Set the prefix that gets prepended to view names for tablet devices. */ public void setTabletPrefix(String tabletPrefix) { this.tabletPrefix = (tabletPrefix != null ? tabletPrefix : ""); } /** * Return the prefix that gets prepended to view names for tablet devices */ protected String getTabletPrefix() { return this.tabletPrefix; } /** * Set the suffix that gets appended to view names for normal devices. */ public void setNormalSuffix(String normalSuffix) { this.normalSuffix = (normalSuffix != null ? normalSuffix : ""); } /** * Return the suffix that gets appended to view names for normal devices */ protected String getNormalSuffix() { return this.normalSuffix; } /** * Set the suffix that gets appended to view names for mobile devices */ public void setMobileSuffix(String mobileSuffix) { this.mobileSuffix = (mobileSuffix != null ? mobileSuffix : ""); } /** * Return the suffix that gets appended to view names for mobile devices */ protected String getMobileSuffix() { return this.mobileSuffix; } /** * Set the suffix that gets appended to view names for tablet devices */ public void setTabletSuffix(String tabletSuffix) { this.tabletSuffix = (tabletSuffix != null ? tabletSuffix : ""); } /** * Return the suffix that gets appended to view names for tablet devices */ protected String getTabletSuffix() { return this.tabletSuffix; } @Override protected String getDeviceViewNameInternal(String viewName) { RequestAttributes attrs = RequestContextHolder.getRequestAttributes(); Assert.isInstanceOf(ServletRequestAttributes.class, attrs); HttpServletRequest request = ((ServletRequestAttributes) attrs).getRequest(); Device device = DeviceUtils.getCurrentDevice(request); SitePreference sitePreference = SitePreferenceUtils.getCurrentSitePreference(request); String resolvedViewName = viewName; if (ResolverUtils.isNormal(device, sitePreference)) { resolvedViewName = getNormalPrefix() + viewName + getNormalSuffix(); } else if (ResolverUtils.isMobile(device, sitePreference)) { resolvedViewName = getMobilePrefix() + viewName + getMobileSuffix(); } else if (ResolverUtils.isTablet(device, sitePreference)) { resolvedViewName = getTabletPrefix() + viewName + getTabletSuffix(); } // MOBILE-63 "redirect:/" and "forward:/" can result in the view name containing multiple trailing slashes return stripTrailingSlash(resolvedViewName); } private String stripTrailingSlash(String viewName) { if (viewName.endsWith("//")) { return viewName.substring(0, viewName.length() - 1); } return viewName; } }