addressed cyclical dependency with view package

This commit is contained in:
Keith Donald
2008-04-25 00:54:49 +00:00
parent bcef26dd4a
commit 7acf169250
23 changed files with 443 additions and 445 deletions

View File

@@ -26,7 +26,7 @@ import org.springframework.binding.format.registry.DefaultFormatterRegistry;
import org.springframework.util.StringUtils;
import org.springframework.webflow.engine.builder.support.FlowBuilderServices;
import org.springframework.webflow.expression.DefaultExpressionParserFactory;
import org.springframework.webflow.mvc.view.MvcViewFactoryCreator;
import org.springframework.webflow.mvc.builder.MvcViewFactoryCreator;
import org.w3c.dom.Element;
/**

View File

@@ -30,12 +30,12 @@ public interface ViewFactoryCreator {
/**
* Create a view factory capable of creating {@link View} objects that can render the view template with the
* provided identifier.
* @param viewIdExpression an expression that resolves the id of the view template
* @param viewName an expression that resolves the name of the view template
* @param expressionParser an optional expression parser to use to resolve view expressions
* @param formatterRegistry an optional formatter registry to use to format text values
* @return the view factory
*/
public ViewFactory createViewFactory(Expression viewIdExpression, ExpressionParser expressionParser,
public ViewFactory createViewFactory(Expression viewName, ExpressionParser expressionParser,
FormatterRegistry formatterRegistry);
/**
@@ -43,5 +43,5 @@ public interface ViewFactoryCreator {
* @param viewStateId the view state id
* @return the default view id
*/
public String getViewIdByConvention(String viewStateId);
public String getViewNameByConvention(String viewStateId);
}

View File

@@ -588,7 +588,7 @@ public class FlowModelFlowBuilder extends AbstractFlowBuilder {
if (endState) {
return null;
} else {
view = getLocalContext().getViewFactoryCreator().getViewIdByConvention(stateId);
view = getLocalContext().getViewFactoryCreator().getViewNameByConvention(stateId);
Expression viewId = getLocalContext().getExpressionParser().parseExpression(view,
new FluentParserContext().template().evaluate(RequestContext.class).expectResult(String.class));
return createViewFactory(viewId);

View File

@@ -0,0 +1,59 @@
/*
* Copyright 2004-2008 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.webflow.mvc.builder;
import java.util.Iterator;
import java.util.List;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.webflow.execution.RequestContext;
import org.springframework.webflow.mvc.view.FlowViewResolver;
/**
* View factory implementation that delegates to the Spring-configured view resolver chain to resolve the Spring MVC
* view implementation to render.
*
* @author Keith Donald
*/
public class DelegatingFlowViewResolver implements FlowViewResolver {
private List viewResolvers;
/**
* Creates a new flow view resolver that delegates to
* @param viewResolvers
*/
public DelegatingFlowViewResolver(List viewResolvers) {
this.viewResolvers = viewResolvers;
}
public View resolveView(String viewName, RequestContext context) {
for (Iterator it = viewResolvers.iterator(); it.hasNext();) {
ViewResolver viewResolver = (ViewResolver) it.next();
try {
View view = viewResolver.resolveViewName(viewName, context.getExternalContext().getLocale());
if (view != null) {
return view;
}
} catch (Exception e) {
throw new IllegalStateException("Exception resolving view with name '" + viewName + "'", e);
}
}
return null;
}
}

View File

@@ -13,56 +13,36 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.webflow.mvc.view;
package org.springframework.webflow.mvc.builder;
import org.springframework.binding.expression.Expression;
import org.springframework.binding.expression.ExpressionParser;
import org.springframework.binding.format.FormatterRegistry;
import org.springframework.context.ApplicationContext;
import org.springframework.core.io.ContextResource;
import org.springframework.core.io.Resource;
import org.springframework.util.ClassUtils;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.view.InternalResourceView;
import org.springframework.web.servlet.view.JstlView;
import org.springframework.webflow.context.portlet.PortletExternalContext;
import org.springframework.webflow.execution.RequestContext;
import org.springframework.webflow.execution.View;
import org.springframework.webflow.execution.ViewFactory;
import org.springframework.webflow.mvc.portlet.PortletMvcView;
import org.springframework.webflow.mvc.servlet.ServletMvcView;
import org.springframework.webflow.mvc.view.FlowViewResolver;
/**
* View factory implementation that creates a Spring-MVC Internal Resource view to render a flow-relative view resource
* such as a JSP or Velocity template.
* @author Keith Donald
*/
class InternalFlowResourceMvcViewFactory implements ViewFactory {
public class InternalResourceFlowViewResolver implements FlowViewResolver {
private static final boolean JSTL_PRESENT = ClassUtils.isPresent("javax.servlet.jsp.jstl.fmt.LocalizationContext");
private Expression viewIdExpression;
private ExpressionParser expressionParser;
private FormatterRegistry formatterRegistry;
public InternalFlowResourceMvcViewFactory(Expression viewIdExpression, ExpressionParser expressionParser,
FormatterRegistry formatterRegistry) {
this.viewIdExpression = viewIdExpression;
this.expressionParser = expressionParser;
this.formatterRegistry = formatterRegistry;
}
public View getView(RequestContext context) {
String viewId = (String) viewIdExpression.getValue(context);
if (viewId.startsWith("/")) {
return getViewInternal(viewId, context, context.getActiveFlow().getApplicationContext());
public View resolveView(String viewName, RequestContext context) {
if (viewName.startsWith("/")) {
return getViewInternal(viewName, context, context.getActiveFlow().getApplicationContext());
} else {
ApplicationContext flowContext = context.getActiveFlow().getApplicationContext();
if (flowContext == null) {
throw new IllegalStateException("A Flow ApplicationContext is required to resolve Flow View Resources");
}
Resource viewResource = flowContext.getResource(viewId);
Resource viewResource = flowContext.getResource(viewName);
if (!(viewResource instanceof ContextResource)) {
throw new IllegalStateException(
"A ContextResource is required to get relative view paths within this context");
@@ -76,27 +56,14 @@ class InternalFlowResourceMvcViewFactory implements ViewFactory {
if (JSTL_PRESENT) {
JstlView view = new JstlView(viewPath);
view.setApplicationContext(flowContext);
return createMvcView(view, context);
return view;
} else {
InternalResourceView view = new InternalResourceView(viewPath);
view.setApplicationContext(flowContext);
return createMvcView(view, context);
return view;
}
} else {
throw new IllegalArgumentException("Unsupported view type " + viewPath + " only types supported are [.jsp]");
}
}
private MvcView createMvcView(org.springframework.web.servlet.View view, RequestContext context) {
MvcView mvcView;
if (context.getExternalContext() instanceof PortletExternalContext) {
mvcView = new PortletMvcView(view, context);
} else {
mvcView = new ServletMvcView(view, context);
}
mvcView.setExpressionParser(expressionParser);
mvcView.setFormatterRegistry(formatterRegistry);
return mvcView;
}
}

View File

@@ -0,0 +1,41 @@
/*
* Copyright 2004-2008 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.webflow.mvc.builder;
import org.springframework.core.enums.StaticLabeledEnum;
/**
* Supported Spring Web MVC environments.
*
* @author Keith Donald
*/
public class MvcEnvironment extends StaticLabeledEnum {
/**
* Servlet MVC.
*/
public static final MvcEnvironment SERVLET = new MvcEnvironment(0, "servlet");
/**
* Portlet MVC.
*/
public static final MvcEnvironment PORTLET = new MvcEnvironment(0, "portlet");
private MvcEnvironment(int code, String label) {
super(code, label);
}
}

View File

@@ -0,0 +1,118 @@
/*
* Copyright 2004-2008 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.webflow.mvc.builder;
import java.util.List;
import org.springframework.binding.expression.Expression;
import org.springframework.binding.expression.ExpressionParser;
import org.springframework.binding.format.FormatterRegistry;
import org.springframework.web.servlet.View;
import org.springframework.webflow.engine.builder.ViewFactoryCreator;
import org.springframework.webflow.execution.ViewFactory;
import org.springframework.webflow.mvc.portlet.PortletMvcViewFactory;
import org.springframework.webflow.mvc.servlet.ServletMvcViewFactory;
import org.springframework.webflow.mvc.view.FlowViewResolver;
/**
* View factory creator implementation that produces View Factories that create native Spring MVC-based views.
*
* This class is used by a flow builder in a Spring MVC environment to configure view factories on flows that render
* Spring MVC-based views.
*
* This class supports rendering views resolved by existing Spring MVC-based resolver infrastructure, or, if no such
* infrastructure is configured, JSP resources relative to the flow definition being built.
*
* @author Keith Donald
* @author Scott Andrews
*/
public class MvcViewFactoryCreator implements ViewFactoryCreator {
private MvcEnvironment environment;
private String defaultViewSuffix = ".jsp";
private FlowViewResolver flowViewResolver = new InternalResourceFlowViewResolver();
/**
* Returns the configured mvc environment.
* @return the mvc environment
*/
public MvcEnvironment getEnvironment() {
return environment;
}
/**
* Sets the configured mvc environment.
* @param environment the mvc environment.
*/
public void setEnvironment(MvcEnvironment environment) {
this.environment = environment;
}
/**
* Returns the default view suffix when selecting views by convention. Default is .jsp.
* @return the default view suffix
*/
public String getDefaultViewSuffix() {
return defaultViewSuffix;
}
/**
* Sets the default suffix for view names when selecting views by convention. Default is .jsp.
* @param defaultViewSuffix the default view suffix
*/
public void setDefaultViewSuffix(String defaultViewSuffix) {
this.defaultViewSuffix = defaultViewSuffix;
}
/**
* Sets the view resolvers that will be used to resolve views selected by flows. If multiple resolvers are to be
* used, the resolvers should be ordered in the manner they should be applied.
* @param viewResolvers the view resolver list
*/
public void setViewResolvers(List viewResolvers) {
this.flowViewResolver = new DelegatingFlowViewResolver(viewResolvers);
}
/**
* Set to fully customize how the flow system resolves Spring MVC {@link View} objects.
* @param flowViewResolver the flow view resolver
*/
public void setFlowViewResolver(FlowViewResolver flowViewResolver) {
this.flowViewResolver = flowViewResolver;
}
public ViewFactory createViewFactory(Expression viewName, ExpressionParser expressionParser,
FormatterRegistry formatterRegistry) {
if (environment == null || environment == MvcEnvironment.SERVLET) {
return new ServletMvcViewFactory(viewName, flowViewResolver, expressionParser, formatterRegistry);
} else if (environment == MvcEnvironment.PORTLET) {
return new PortletMvcViewFactory(viewName, flowViewResolver, expressionParser, formatterRegistry);
} else {
throw new IllegalStateException("Environment not supported " + environment);
}
}
public String getViewNameByConvention(String viewStateId) {
if (flowViewResolver instanceof DelegatingFlowViewResolver) {
return viewStateId;
} else {
return viewStateId + defaultViewSuffix;
}
}
}

View File

@@ -26,14 +26,15 @@ import org.springframework.web.servlet.View;
import org.springframework.web.servlet.ViewRendererServlet;
import org.springframework.webflow.context.ExternalContext;
import org.springframework.webflow.execution.RequestContext;
import org.springframework.webflow.mvc.view.MvcView;
import org.springframework.webflow.mvc.view.AbstractMvcView;
/**
* Spring Web Portlet MVC view implementation.
*
* @author Keith Donald
* @author Scott Andrews
*/
public class PortletMvcView extends MvcView {
public class PortletMvcView extends AbstractMvcView {
/**
* Creates a new portlet view.
@@ -44,7 +45,7 @@ public class PortletMvcView extends MvcView {
super(view, context);
}
public void doRender(Map model) throws Exception {
protected void doRender(Map model) throws Exception {
RequestContext context = getRequestContext();
ExternalContext externalContext = context.getExternalContext();
View view = getView();

View File

@@ -0,0 +1,46 @@
/*
* Copyright 2004-2008 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.webflow.mvc.portlet;
import org.springframework.binding.expression.Expression;
import org.springframework.binding.expression.ExpressionParser;
import org.springframework.binding.format.FormatterRegistry;
import org.springframework.web.servlet.View;
import org.springframework.webflow.execution.RequestContext;
import org.springframework.webflow.mvc.view.AbstractMvcView;
import org.springframework.webflow.mvc.view.AbstractMvcViewFactory;
import org.springframework.webflow.mvc.view.FlowViewResolver;
/**
* Creates Portlet MVC views.
*
* @author Keith Donald
*/
public class PortletMvcViewFactory extends AbstractMvcViewFactory {
public PortletMvcViewFactory(Expression viewName, FlowViewResolver viewResolver, ExpressionParser expressionParser,
FormatterRegistry formatterRegistry) {
super(viewName, viewResolver, expressionParser, formatterRegistry);
}
protected AbstractMvcView createMvcView(View view, RequestContext context) {
PortletMvcView mvcView = new PortletMvcView(view, context);
mvcView.setExpressionParser(getExpressionParser());
mvcView.setFormatterRegistry(getFormatterRegistry());
return mvcView;
}
}

View File

@@ -22,13 +22,13 @@ import javax.servlet.http.HttpServletResponse;
import org.springframework.webflow.context.ExternalContext;
import org.springframework.webflow.execution.RequestContext;
import org.springframework.webflow.mvc.view.MvcView;
import org.springframework.webflow.mvc.view.AbstractMvcView;
/**
* Creates a new Spring Web Servlet MVC view.
* @author Keith Donald
*/
public class ServletMvcView extends MvcView {
public class ServletMvcView extends AbstractMvcView {
/**
* Creates a new servlet view.
@@ -39,7 +39,7 @@ public class ServletMvcView extends MvcView {
super(view, context);
}
public void doRender(Map model) throws Exception {
protected void doRender(Map model) throws Exception {
RequestContext context = getRequestContext();
ExternalContext externalContext = context.getExternalContext();
HttpServletRequest request = (HttpServletRequest) externalContext.getNativeRequest();

View File

@@ -0,0 +1,46 @@
/*
* Copyright 2004-2008 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.webflow.mvc.servlet;
import org.springframework.binding.expression.Expression;
import org.springframework.binding.expression.ExpressionParser;
import org.springframework.binding.format.FormatterRegistry;
import org.springframework.web.servlet.View;
import org.springframework.webflow.execution.RequestContext;
import org.springframework.webflow.mvc.view.AbstractMvcView;
import org.springframework.webflow.mvc.view.AbstractMvcViewFactory;
import org.springframework.webflow.mvc.view.FlowViewResolver;
/**
* Creates Servlet MVC views.
*
* @author Keith Donald
*/
public class ServletMvcViewFactory extends AbstractMvcViewFactory {
public ServletMvcViewFactory(Expression viewName, FlowViewResolver viewResolver, ExpressionParser expressionParser,
FormatterRegistry formatterRegistry) {
super(viewName, viewResolver, expressionParser, formatterRegistry);
}
protected AbstractMvcView createMvcView(View view, RequestContext context) {
ServletMvcView mvcView = new ServletMvcView(view, context);
mvcView.setExpressionParser(getExpressionParser());
mvcView.setFormatterRegistry(getFormatterRegistry());
return mvcView;
}
}

View File

@@ -58,7 +58,7 @@ import org.springframework.webflow.expression.DefaultExpressionParserFactory;
*
* @author Keith Donald
*/
public abstract class MvcView implements View {
public abstract class AbstractMvcView implements View {
private static final MappingResultsCriteria PROPERTY_NOT_FOUND_ERROR = new PropertyNotFoundError();
@@ -83,7 +83,7 @@ public abstract class MvcView implements View {
* @param view the Spring MVC view to render
* @param requestContext the current flow request context
*/
public MvcView(org.springframework.web.servlet.View view, RequestContext requestContext) {
public AbstractMvcView(org.springframework.web.servlet.View view, RequestContext requestContext) {
this.view = view;
this.requestContext = requestContext;
}

View File

@@ -0,0 +1,64 @@
/*
* Copyright 2004-2008 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.webflow.mvc.view;
import org.springframework.binding.expression.Expression;
import org.springframework.binding.expression.ExpressionParser;
import org.springframework.binding.format.FormatterRegistry;
import org.springframework.webflow.execution.RequestContext;
import org.springframework.webflow.execution.View;
import org.springframework.webflow.execution.ViewFactory;
/**
* Base class for mvc view factories.
*
* @author Keith Donald
*/
public abstract class AbstractMvcViewFactory implements ViewFactory {
private Expression viewName;
private FlowViewResolver viewResolver;
private ExpressionParser expressionParser;
private FormatterRegistry formatterRegistry;
public AbstractMvcViewFactory(Expression viewName, FlowViewResolver viewResolver,
ExpressionParser expressionParser, FormatterRegistry formatterRegistry) {
this.viewName = viewName;
this.viewResolver = viewResolver;
this.expressionParser = expressionParser;
this.formatterRegistry = formatterRegistry;
}
protected ExpressionParser getExpressionParser() {
return expressionParser;
}
protected FormatterRegistry getFormatterRegistry() {
return formatterRegistry;
}
public View getView(RequestContext context) {
String viewName = (String) this.viewName.getValue(context);
org.springframework.web.servlet.View view = viewResolver.resolveView(viewName, context);
return createMvcView(view, context);
}
protected abstract AbstractMvcView createMvcView(org.springframework.web.servlet.View view, RequestContext context);
}

View File

@@ -43,7 +43,7 @@ import org.springframework.validation.ObjectError;
*
* This class is a Spring Errors adapter, basically, for use with spring form and bind tags.
*
* @see MvcView
* @see AbstractMvcView
*
* @author Keith Donald
*/
@@ -82,7 +82,7 @@ public class BindingModel extends AbstractErrors {
/**
* Sets the results of a data mapping attempt onto the bound model object from the view.
* @see MvcView#processUserEvent()
* @see AbstractMvcView#processUserEvent()
* @param results
*/
public void setMappingResults(MappingResults results) {

View File

@@ -0,0 +1,30 @@
/*
* Copyright 2004-2008 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.webflow.mvc.view;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.webflow.execution.RequestContext;
/**
* A Web Flow version of the View Resolver interface. Used to resolve a MVC view from flow state.
*
* @author Keith Donald
* @see ViewResolver
*/
public interface FlowViewResolver {
public View resolveView(String viewName, RequestContext context);
}

View File

@@ -1,68 +0,0 @@
/*
* Copyright 2004-2008 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.webflow.mvc.view;
import java.util.List;
import org.springframework.binding.expression.Expression;
import org.springframework.binding.expression.ExpressionParser;
import org.springframework.binding.format.FormatterRegistry;
import org.springframework.webflow.engine.builder.ViewFactoryCreator;
import org.springframework.webflow.execution.ViewFactory;
/**
* View factory creator implementation that produces View Factories that create native Spring MVC-based views.
*
* This class is used by a flow builder in a Spring MVC environment to configure view factories on flows that render
* Spring MVC-based views.
*
* This class supports rendering views resolved by existing Spring MVC-based resolver infrastructure, or, if no such
* infrastructure is configured, JSP resources relative to the flow definition being built.
*
* @author Keith Donald
* @author Scott Andrews
*/
public class MvcViewFactoryCreator implements ViewFactoryCreator {
private List viewResolvers;
/**
* Sets the view resolvers that will be used to resolve views selected by flows. If multiple resolvers are to be
* used, the resolvers should be ordered in the manner they should be applied.
* @param viewResolvers the view resolver list
*/
public void setViewResolvers(List viewResolvers) {
this.viewResolvers = viewResolvers;
}
public ViewFactory createViewFactory(Expression viewIdExpression, ExpressionParser expressionParser,
FormatterRegistry formatterRegistry) {
if (viewResolvers != null) {
return new ViewResolvingMvcViewFactory(viewIdExpression, expressionParser, formatterRegistry, viewResolvers);
} else {
return new InternalFlowResourceMvcViewFactory(viewIdExpression, expressionParser, formatterRegistry);
}
}
public String getViewIdByConvention(String viewStateId) {
if (viewResolvers != null) {
return viewStateId;
} else {
return viewStateId + ".jsp";
}
}
}

View File

@@ -1,85 +0,0 @@
/*
* Copyright 2004-2008 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.webflow.mvc.view;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import org.springframework.binding.expression.Expression;
import org.springframework.binding.expression.ExpressionParser;
import org.springframework.binding.format.FormatterRegistry;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.webflow.context.portlet.PortletExternalContext;
import org.springframework.webflow.execution.RequestContext;
import org.springframework.webflow.execution.View;
import org.springframework.webflow.execution.ViewFactory;
import org.springframework.webflow.mvc.portlet.PortletMvcView;
import org.springframework.webflow.mvc.servlet.ServletMvcView;
/**
* View factory implementation that delegates to the Spring-configured view resolver chain to resolve the Spring MVC
* view implementation to render.
* @author Keith Donald
*/
class ViewResolvingMvcViewFactory implements ViewFactory {
private Expression viewIdExpression;
private ExpressionParser expressionParser;
private FormatterRegistry formatterRegistry;
private List viewResolvers;
public ViewResolvingMvcViewFactory(Expression viewIdExpression, ExpressionParser expressionParser,
FormatterRegistry formatterRegistry, List viewResolvers) {
this.viewIdExpression = viewIdExpression;
this.expressionParser = expressionParser;
this.formatterRegistry = formatterRegistry;
this.viewResolvers = viewResolvers;
}
public View getView(RequestContext context) {
String viewName = (String) viewIdExpression.getValue(context);
MvcView view;
if (context.getExternalContext() instanceof PortletExternalContext) {
view = new PortletMvcView(resolveView(viewName), context);
} else {
view = new ServletMvcView(resolveView(viewName), context);
}
view.setExpressionParser(expressionParser);
view.setFormatterRegistry(formatterRegistry);
return view;
}
protected org.springframework.web.servlet.View resolveView(String viewName) {
for (Iterator it = viewResolvers.iterator(); it.hasNext();) {
ViewResolver viewResolver = (ViewResolver) it.next();
try {
Locale locale = LocaleContextHolder.getLocale();
org.springframework.web.servlet.View view = viewResolver.resolveViewName(viewName, locale);
if (view != null) {
return view;
}
} catch (Exception e) {
throw new IllegalStateException("Exception resolving view with name '" + viewName + "'", e);
}
}
return null;
}
}

View File

@@ -39,7 +39,7 @@ class MockViewFactoryCreator implements ViewFactoryCreator {
return new MockViewFactory(viewIdExpression);
}
public String getViewIdByConvention(String viewStateId) {
public String getViewNameByConvention(String viewStateId) {
return viewStateId;
}

View File

@@ -14,7 +14,7 @@ import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.webflow.engine.builder.ViewFactoryCreator;
import org.springframework.webflow.engine.builder.support.FlowBuilderServices;
import org.springframework.webflow.execution.ViewFactory;
import org.springframework.webflow.mvc.view.MvcViewFactoryCreator;
import org.springframework.webflow.mvc.builder.MvcViewFactoryCreator;
public class FlowBuilderServicesBeanDefinitionParserTests extends TestCase {
@@ -49,7 +49,7 @@ public class FlowBuilderServicesBeanDefinitionParserTests extends TestCase {
throw new UnsupportedOperationException("Auto-generated method stub");
}
public String getViewIdByConvention(String viewStateId) {
public String getViewNameByConvention(String viewStateId) {
return viewStateId;
}

View File

@@ -15,7 +15,7 @@ import org.springframework.mock.web.portlet.MockPortletContext;
import org.springframework.mock.web.portlet.MockRenderRequest;
import org.springframework.mock.web.portlet.MockRenderResponse;
import org.springframework.web.servlet.ViewRendererServlet;
import org.springframework.webflow.mvc.view.MvcView;
import org.springframework.webflow.mvc.view.AbstractMvcView;
import org.springframework.webflow.test.MockFlowExecutionKey;
import org.springframework.webflow.test.MockRequestContext;
@@ -39,7 +39,7 @@ public class PortletMvcViewTests extends TestCase {
context.getMockFlowExecutionContext().setKey(new MockFlowExecutionKey("c1v1"));
org.springframework.web.servlet.View mvcView = (org.springframework.web.servlet.View) EasyMock
.createMock(org.springframework.web.servlet.View.class);
MvcView view = new PortletMvcView(mvcView, context);
AbstractMvcView view = new PortletMvcView(mvcView, context);
view.setFormatterRegistry(formatterRegistry);
view.render();
assertNotNull(request.getAttribute(ViewRendererServlet.VIEW_ATTRIBUTE));

View File

@@ -19,7 +19,7 @@ import org.springframework.mock.web.MockServletContext;
import org.springframework.validation.BindingResult;
import org.springframework.web.servlet.View;
import org.springframework.webflow.mvc.servlet.ServletMvcView;
import org.springframework.webflow.mvc.view.MvcView;
import org.springframework.webflow.mvc.view.AbstractMvcView;
import org.springframework.webflow.test.MockFlowExecutionKey;
import org.springframework.webflow.test.MockRequestContext;
@@ -50,7 +50,7 @@ public class ServletMvcViewTests extends TestCase {
context.getMockExternalContext().setNativeResponse(new MockHttpServletResponse());
context.getMockFlowExecutionContext().setKey(new MockFlowExecutionKey("c1v1"));
org.springframework.web.servlet.View mvcView = new MockView();
MvcView view = new ServletMvcView(mvcView, context);
AbstractMvcView view = new ServletMvcView(mvcView, context);
view.setFormatterRegistry(formatterRegistry);
view.render();
assertTrue(renderCalled);

View File

@@ -1,221 +0,0 @@
package org.springframework.webflow.mvc.view;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collections;
import java.util.Locale;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import junit.framework.TestCase;
import org.springframework.binding.expression.Expression;
import org.springframework.binding.expression.support.StaticExpression;
import org.springframework.context.support.StaticApplicationContext;
import org.springframework.core.io.AbstractResource;
import org.springframework.core.io.ContextResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.util.ClassUtils;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.webflow.execution.Event;
import org.springframework.webflow.execution.View;
import org.springframework.webflow.execution.ViewFactory;
import org.springframework.webflow.test.GeneratedFlowExecutionKey;
import org.springframework.webflow.test.MockExternalContext;
import org.springframework.webflow.test.MockRequestContext;
public class MvcViewFactoryTests extends TestCase {
private MvcViewFactoryCreator creator;
private StaticApplicationContext applicationContext;
protected void setUp() {
creator = new MvcViewFactoryCreator();
applicationContext = new StaticApplicationContext();
applicationContext.refresh();
}
public void testGetViewNoFlowApplicationContext() {
Expression viewId = new StaticExpression("flowrelativeview.jsp");
InternalFlowResourceMvcViewFactory factory = new InternalFlowResourceMvcViewFactory(viewId, null, null);
MockRequestContext context = new MockRequestContext();
try {
factory.getView(context);
fail("Expected illegal state");
} catch (IllegalStateException e) {
// expected;
}
}
public void testGetViewNoFlowApplicationContextAbsolutePath() {
Expression viewId = new StaticExpression("/absoluteview.jsp");
InternalFlowResourceMvcViewFactory factory = new InternalFlowResourceMvcViewFactory(viewId, null, null);
MockRequestContext context = new MockRequestContext();
assertNotNull(factory.getView(context));
}
public void testNoResolversGetResource() throws Exception {
ResourceLoader viewResourceLoader = new ResourceLoader() {
public ClassLoader getClassLoader() {
return ClassUtils.getDefaultClassLoader();
}
public Resource getResource(String name) {
return new TestContextResource("/parent/" + name);
}
};
applicationContext.setResourceLoader(viewResourceLoader);
Expression viewId = new StaticExpression("myview.jsp");
ViewFactory viewFactory = creator.createViewFactory(viewId, null, null);
MockRequestContext context = new MockRequestContext();
context.getRootFlow().setApplicationContext(applicationContext);
MockExternalContext externalContext = new MockExternalContext();
MockHttpServletRequest request = new MockHttpServletRequest();
MockHttpServletResponse response = new MockHttpServletResponse();
externalContext.setNativeRequest(request);
externalContext.setNativeResponse(response);
context.setExternalContext(externalContext);
context.getMockFlowExecutionContext().setKey(new GeneratedFlowExecutionKey());
View view = viewFactory.getView(context);
assertEquals(false, view.hasFlowEvent());
view.render();
assertEquals("/parent/myview.jsp", response.getForwardedUrl());
}
public void testViewResolversGetResource() throws Exception {
MockViewResolver viewResolver = new MockViewResolver("myview");
creator.setViewResolvers(Collections.singletonList(viewResolver));
Expression viewId = new StaticExpression("myview");
ViewFactory viewFactory = creator.createViewFactory(viewId, null, null);
MockRequestContext context = new MockRequestContext();
MockExternalContext externalContext = new MockExternalContext();
MockHttpServletRequest request = new MockHttpServletRequest();
MockHttpServletResponse response = new MockHttpServletResponse();
externalContext.setNativeRequest(request);
externalContext.setNativeResponse(response);
context.setExternalContext(externalContext);
context.getMockFlowExecutionContext().setKey(new GeneratedFlowExecutionKey());
View view = viewFactory.getView(context);
assertEquals(false, view.hasFlowEvent());
view.render();
assertEquals("myview", response.getForwardedUrl());
}
public void testRestoreView() throws Exception {
ResourceLoader viewResourceLoader = new ResourceLoader() {
public ClassLoader getClassLoader() {
return ClassUtils.getDefaultClassLoader();
}
public Resource getResource(String name) {
return new TestContextResource("/parent/" + name);
}
};
applicationContext.setResourceLoader(viewResourceLoader);
Expression viewId = new StaticExpression("myview.jsp");
ViewFactory viewFactory = creator.createViewFactory(viewId, null, null);
MockRequestContext context = new MockRequestContext();
context.getRootFlow().setApplicationContext(applicationContext);
MockExternalContext externalContext = new MockExternalContext();
MockHttpServletRequest request = new MockHttpServletRequest();
MockHttpServletResponse response = new MockHttpServletResponse();
externalContext.putRequestParameter("_eventId", "foo");
externalContext.setNativeRequest(request);
externalContext.setNativeResponse(response);
context.setExternalContext(externalContext);
context.getMockFlowExecutionContext().setKey(new GeneratedFlowExecutionKey());
View view = viewFactory.getView(context);
view.processUserEvent();
assertEquals(true, view.hasFlowEvent());
Event e = view.getFlowEvent();
assertEquals(view, e.getSource());
assertEquals("foo", e.getId());
view.render();
assertEquals("/parent/myview.jsp", response.getForwardedUrl());
}
public void testRestoreViewButtonEventIdFormat() throws Exception {
ResourceLoader viewResourceLoader = new ResourceLoader() {
public ClassLoader getClassLoader() {
return ClassUtils.getDefaultClassLoader();
}
public Resource getResource(String name) {
return new TestContextResource("/parent/" + name);
}
};
applicationContext.setResourceLoader(viewResourceLoader);
Expression viewId = new StaticExpression("myview.jsp");
ViewFactory viewFactory = creator.createViewFactory(viewId, null, null);
MockRequestContext context = new MockRequestContext();
context.getRootFlow().setApplicationContext(applicationContext);
MockExternalContext externalContext = new MockExternalContext();
MockHttpServletRequest request = new MockHttpServletRequest();
MockHttpServletResponse response = new MockHttpServletResponse();
externalContext.putRequestParameter("_eventId_foo", "true");
externalContext.setNativeRequest(request);
externalContext.setNativeResponse(response);
context.setExternalContext(externalContext);
context.getMockFlowExecutionContext().setKey(new GeneratedFlowExecutionKey());
View view = viewFactory.getView(context);
view.processUserEvent();
assertEquals(true, view.hasFlowEvent());
Event e = view.getFlowEvent();
assertEquals(view, e.getSource());
assertEquals("foo", e.getId());
view.render();
assertEquals("/parent/myview.jsp", response.getForwardedUrl());
}
private static class MockViewResolver implements ViewResolver {
private String expectedViewName;
public MockViewResolver(String expectedViewName) {
this.expectedViewName = expectedViewName;
}
public org.springframework.web.servlet.View resolveViewName(String viewName, Locale arg1) throws Exception {
assertEquals(expectedViewName, viewName);
return new MockView();
}
class MockView implements org.springframework.web.servlet.View {
boolean renderCalled;
public String getContentType() {
return "text/html";
}
public void render(Map model, HttpServletRequest request, HttpServletResponse response) throws Exception {
request.getRequestDispatcher(expectedViewName).forward(request, response);
renderCalled = true;
}
}
}
private static class TestContextResource extends AbstractResource implements ContextResource {
private String path;
public TestContextResource(String path) {
this.path = path;
}
public String getDescription() {
return "test context resource";
}
public InputStream getInputStream() throws IOException {
throw new UnsupportedOperationException("Auto-generated method stub");
}
public String getPathWithinContext() {
return path;
}
}
}

View File

@@ -54,7 +54,7 @@ public class MvcViewTests extends TestCase {
context.getMockExternalContext().setNativeResponse(new MockHttpServletResponse());
context.getMockFlowExecutionContext().setKey(new MockFlowExecutionKey("c1v1"));
org.springframework.web.servlet.View mvcView = new MockView();
MvcView view = new MockMvcView(mvcView, context);
AbstractMvcView view = new MockMvcView(mvcView, context);
view.setFormatterRegistry(formatterRegistry);
view.render();
assertTrue(renderCalled);
@@ -82,7 +82,7 @@ public class MvcViewTests extends TestCase {
context.getMockExternalContext().setNativeResponse(new MockHttpServletResponse());
context.getMockFlowExecutionContext().setKey(new MockFlowExecutionKey("c1v1"));
org.springframework.web.servlet.View mvcView = new MockView();
MvcView view = new MockMvcView(mvcView, context);
AbstractMvcView view = new MockMvcView(mvcView, context);
view.setFormatterRegistry(formatterRegistry);
view.render();
assertEquals(context.getFlowScope().get("bindBean"), model.get("bindBean"));
@@ -100,7 +100,7 @@ public class MvcViewTests extends TestCase {
context.getMockExternalContext().setNativeResponse(new MockHttpServletResponse());
context.getMockFlowExecutionContext().setKey(new MockFlowExecutionKey("c1v1"));
org.springframework.web.servlet.View mvcView = new MockView();
MvcView view = new MockMvcView(mvcView, context);
AbstractMvcView view = new MockMvcView(mvcView, context);
view.processUserEvent();
assertFalse(view.hasFlowEvent());
assertNull(view.getFlowEvent());
@@ -114,7 +114,7 @@ public class MvcViewTests extends TestCase {
context.getMockExternalContext().setNativeResponse(new MockHttpServletResponse());
context.getMockFlowExecutionContext().setKey(new MockFlowExecutionKey("c1v1"));
org.springframework.web.servlet.View mvcView = new MockView();
MvcView view = new MockMvcView(mvcView, context);
AbstractMvcView view = new MockMvcView(mvcView, context);
view.setFormatterRegistry(formatterRegistry);
view.processUserEvent();
assertTrue(view.hasFlowEvent());
@@ -138,7 +138,7 @@ public class MvcViewTests extends TestCase {
context.getMockExternalContext().setNativeResponse(new MockHttpServletResponse());
context.getMockFlowExecutionContext().setKey(new MockFlowExecutionKey("c1v1"));
org.springframework.web.servlet.View mvcView = new MockView();
MvcView view = new MockMvcView(mvcView, context);
AbstractMvcView view = new MockMvcView(mvcView, context);
view.setFormatterRegistry(formatterRegistry);
view.processUserEvent();
assertTrue(view.hasFlowEvent());
@@ -152,7 +152,7 @@ public class MvcViewTests extends TestCase {
assertEquals("foo", bindBean.getBeanProperty().getName());
}
private class MockMvcView extends MvcView {
private class MockMvcView extends AbstractMvcView {
public MockMvcView(View view, RequestContext context) {
super(view, context);