/*
* 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 java.util.Locale;
import javax.servlet.ServletContext;
import org.springframework.core.Ordered;
import org.springframework.util.Assert;
import org.springframework.web.context.support.WebApplicationObjectSupport;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
/**
* Abstract {@link ViewResolver} implementation, providing a device
* aware {@link ViewResolver} wrapper that delegates to another view resolver
* implementation, allowing for resolution of device specific view names without
* the need for a dedicated mapping to be defined for each view.</p>
* @author Roy Clarkson
* @since 1.1
* @see LiteDeviceDelegatingViewResolver
*/
public abstract class AbstractDeviceDelegatingViewResolver extends
WebApplicationObjectSupport implements ViewResolver, Ordered {
/**
* Prefix for special view names that specify a redirect URL (usually
* to a controller after a form has been submitted and processed).
*/
public static final String REDIRECT_URL_PREFIX = "redirect:";
/**
* Prefix for special view names that specify a forward URL (usually
* to a controller after a form has been submitted and processed).
*/
public static final String FORWARD_URL_PREFIX = "forward:";
private final ViewResolver delegate;
private int order = Ordered.LOWEST_PRECEDENCE;
private boolean enableFallback = false;
/**
* Creates a new AbstractDeviceDelegatingViewResolver
* @param delegate the ViewResolver in which to delegate
*/
protected AbstractDeviceDelegatingViewResolver(ViewResolver delegate) {
Assert.notNull(delegate, "delegate is required");
this.delegate = delegate;
}
/**
* Returns the delegate view resolver
*/
public ViewResolver getViewResolver() {
return this.delegate;
}
public void setOrder(int order) {
this.order = order;
}
@Override
public int getOrder() {
return this.order;
}
/**
* Enables support for fallback resolution, meaning if the adjusted view
* name cannot be resolved, and attempt will be made to resolve the
* original view name. This may be helpful in situations where not all
* views within a web site have device specific implementations.
*
* <p>Note: fallback resolution will only work when delegating to a view
* resolver which returns null from
* {@link #resolveViewName(String, Locale)} if it cannot resolve a view.
* For example, {@link InternalResourceViewResolver} never returns null,
* so fallback resolution will not be available.
*/
public void setEnableFallback(boolean enableFallback) {
this.enableFallback = enableFallback;
}
/**
* Return whether fallback view resolution is enabled
* @see #setEnableFallback(boolean)
*/
protected boolean getEnableFallback() {
return this.enableFallback;
}
public View resolveViewName(String viewName, Locale locale) throws Exception {
String deviceViewName = getDeviceViewName(viewName);
View view = delegate.resolveViewName(deviceViewName, locale);
if (enableFallback && view == null) {
view = delegate.resolveViewName(viewName, locale);
}
if (logger.isDebugEnabled() && view != null) {
logger.debug("Resolved View: " + view.toString());
}
return view;
}
/**
* Returns the adjusted view name as determined by subclass implementation.
* In the case where a requested URL is prefixed with "redirect:" or
* "forward:", the view name will not be adjusted.
* @param viewName the name of the view before device resolution
* @return the adjusted view name
* @see #getDeviceViewNameInternal(String)
*/
protected String getDeviceViewName(String viewName) {
// Check for special "redirect:" prefix.
if (viewName.startsWith(REDIRECT_URL_PREFIX)) {
return viewName;
}
// Check for special "forward:" prefix.
if (viewName.startsWith(FORWARD_URL_PREFIX)) {
return viewName;
}
return getDeviceViewNameInternal(viewName);
}
/**
* Subclasses must implement this method, adjusting the device view name
* based on device resolution used within the subclass.
* @param viewName the name of the view before device resolution
* @return the adjusted view name
* @see #getDeviceViewName(String)
*/
protected abstract String getDeviceViewNameInternal(String viewName);
@Override
protected void initServletContext(ServletContext servletContext) {
String name = delegate.getClass().getName();
getApplicationContext().getAutowireCapableBeanFactory().initializeBean(delegate, name);
}
}