This commit is contained in:
Keith Donald
2008-03-08 04:39:33 +00:00
parent f8f25ab7de
commit 1952fdea46
54 changed files with 626 additions and 257 deletions

View File

@@ -8,7 +8,7 @@
<classpathentry kind="lib" path="lib/global/commons-logging.jar"/>
<classpathentry kind="lib" path="lib/test/log4j.jar"/>
<classpathentry kind="lib" path="lib/global/spring-core.jar"/>
<classpathentry kind="lib" path="lib/global/spring-beans.jar"/>
<classpathentry kind="lib" path="lib/global/spring-beans.jar" sourcepath="/spring"/>
<classpathentry kind="lib" path="lib/global/ognl.jar"/>
<classpathentry kind="lib" path="lib/global/spring-context.jar"/>
<classpathentry kind="lib" path="lib/buildtime/el-api.jar"/>

View File

@@ -0,0 +1,74 @@
package org.springframework.binding.expression.el;
import javax.el.ExpressionFactory;
import org.springframework.beans.BeanInstantiationException;
import org.springframework.beans.BeanUtils;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
/**
* A helper for creating a new expression factory instance using the default expression factory class configured for the
* VM.
*
* @author Keith Donald
*/
public class DefaultExpressionFactoryUtils {
private static final String EXPRESSION_FACTORY_PROPERTY = "javax.el.ExpressionFactory";
static {
if (!System.getProperties().containsKey(EXPRESSION_FACTORY_PROPERTY)) {
// TODO - change default to Spring EL when it becomes available
setDefaultExpressionFactoryClassName("org.jboss.el.ExpressionFactoryImpl");
}
}
/**
* Returns the type of ExpressionFactory configured for this VM.
*/
public static String getDefaultExpressionFactoryClassName() {
return System.getProperty(EXPRESSION_FACTORY_PROPERTY);
}
/**
* Sets the type of ExpressionFactory configured for this VM.
*/
public static void setDefaultExpressionFactoryClassName(String expressionFactoryClassName) {
System.setProperty(EXPRESSION_FACTORY_PROPERTY, expressionFactoryClassName);
}
/**
* Creates a new instance of the expression factory configured for this VM.
* @throws IllegalStateException if the ExpressionFactory class cannot be found
* @throws RuntimeException if the ExpressionFactory cannot be instantiated
*/
public static ExpressionFactory createExpressionFactory() throws IllegalStateException, RuntimeException {
if (ReflectionUtils.findMethod(ExpressionFactory.class, "newInstance") != null) {
return ExpressionFactory.newInstance();
} else {
// Fallback in the case of using an older version of the EL API
try {
Class expressionFactoryClass = ClassUtils.forName(getDefaultExpressionFactoryClassName());
return (ExpressionFactory) BeanUtils.instantiateClass(expressionFactoryClass);
} catch (ClassNotFoundException e) {
throw new IllegalStateException(
"The default ExpressionFactory class '"
+ getDefaultExpressionFactoryClassName()
+ "' could not be found in the classpath. "
+ "Please add this to your classpath or set the default ExpressionFactory class name to something that is in the classpath.",
e);
} catch (NoClassDefFoundError e) {
throw new IllegalStateException(
"The default ExpressionFactory class '"
+ getDefaultExpressionFactoryClassName()
+ "' could not be found in the classpath. "
+ "Please add this to your classpath or set the default ExpressionFactory class name to something that is in the classpath.",
e);
} catch (BeanInstantiationException e) {
throw new RuntimeException("An instance of the default ExpressionFactory '"
+ getDefaultExpressionFactoryClassName()
+ "' could not be instantiated. Check your EL implementation configuration.", e);
}
}
}
}

View File

@@ -1,11 +1,28 @@
/*
* 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.faces.config;
import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
/**
* Namespace handler for the faces namespace.
* @author Jeremy Grelle
*/
public class FacesConfigNamespaceHandler extends NamespaceHandlerSupport {
public void init() {
registerBeanDefinitionParser("flow-builder-services", new FacesFlowBuilderServicesBeanDefinitionParser());
}
}

View File

@@ -1,8 +1,24 @@
/*
* 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.faces.config;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.binding.expression.el.DefaultExpressionFactoryUtils;
import org.springframework.faces.expression.LegacyJSFELExpressionParser;
import org.springframework.faces.model.converter.FacesConversionService;
import org.springframework.faces.webflow.JsfViewFactoryCreator;
@@ -11,6 +27,9 @@ import org.springframework.webflow.engine.builder.support.FlowBuilderServices;
import org.springframework.webflow.expression.el.WebFlowELExpressionParser;
import org.w3c.dom.Element;
/**
* Parser for the flow-builder-services tag.
*/
public class FacesFlowBuilderServicesBeanDefinitionParser extends AbstractSingleBeanDefinitionParser implements
BeanDefinitionParser {
@@ -34,7 +53,10 @@ public class FacesFlowBuilderServicesBeanDefinitionParser extends AbstractSingle
protected void doParse(Element element, BeanDefinitionBuilder definitionBuilder) {
boolean enableManagedBeans = parseEnableManagedBeans(element, definitionBuilder);
if (!enableManagedBeans) {
if (enableManagedBeans) {
definitionBuilder.addPropertyValue(EXPRESSION_PARSER_PROPERTY, new LegacyJSFELExpressionParser(
DefaultExpressionFactoryUtils.createExpressionFactory()));
} else {
parseExpressionParser(element, definitionBuilder);
}
parseViewFactoryCreator(element, definitionBuilder);
@@ -44,13 +66,10 @@ public class FacesFlowBuilderServicesBeanDefinitionParser extends AbstractSingle
private boolean parseEnableManagedBeans(Element element, BeanDefinitionBuilder definitionBuilder) {
String enableManagedBeans = element.getAttribute(ENABLE_MANAGED_BEANS_ATTRIBUTE);
if (StringUtils.hasText(enableManagedBeans)) {
boolean enabled = Boolean.parseBoolean(enableManagedBeans);
if (enabled) {
definitionBuilder.addPropertyValue(EXPRESSION_PARSER_PROPERTY, new LegacyJSFELExpressionParser());
}
return enabled;
return Boolean.valueOf(enableManagedBeans).booleanValue();
} else {
return false;
}
return false;
}
private void parseConversionService(Element element, BeanDefinitionBuilder definitionBuilder) {
@@ -76,7 +95,8 @@ public class FacesFlowBuilderServicesBeanDefinitionParser extends AbstractSingle
if (StringUtils.hasText(expressionParser)) {
definitionBuilder.addPropertyReference(EXPRESSION_PARSER_PROPERTY, expressionParser);
} else {
definitionBuilder.addPropertyValue(EXPRESSION_PARSER_PROPERTY, new WebFlowELExpressionParser());
definitionBuilder.addPropertyValue(EXPRESSION_PARSER_PROPERTY, new WebFlowELExpressionParser(
DefaultExpressionFactoryUtils.createExpressionFactory()));
}
}
}

View File

@@ -1,3 +1,18 @@
/*
* 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.faces.expression;
import javax.el.CompositeELResolver;

View File

@@ -1,3 +1,18 @@
/*
* 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.faces.expression;
import javax.el.CompositeELResolver;

View File

@@ -1,3 +1,18 @@
/*
* 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.faces.expression;
import javax.el.ELContext;

View File

@@ -1,3 +1,18 @@
/*
* 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.faces.expression;
import javax.el.ELContext;

View File

@@ -1,3 +1,18 @@
/*
* 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.faces.expression;
import java.util.Iterator;

View File

@@ -1,21 +1,33 @@
/*
* 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.faces.expression;
import java.util.ArrayList;
import java.util.List;
import javax.el.ELContext;
import javax.el.ELException;
import javax.el.ELResolver;
import javax.el.ExpressionFactory;
import javax.el.FunctionMapper;
import javax.el.VariableMapper;
import org.springframework.beans.BeanUtils;
import org.springframework.binding.expression.el.DefaultELResolver;
import org.springframework.binding.expression.el.ELContextFactory;
import org.springframework.binding.expression.el.ELExpressionParser;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.webflow.core.collection.MutableAttributeMap;
import org.springframework.webflow.execution.RequestContext;
import org.springframework.webflow.expression.el.ActionMethodELResolver;
@@ -33,46 +45,24 @@ import org.springframework.webflow.expression.el.SpringSecurityELResolver;
*/
public class LegacyJSFELExpressionParser extends ELExpressionParser {
private static final String EXPRESSION_FACTORY_PROPERTY = "javax.el.ExpressionFactory";
private static final String DEFAULT_EXPRESSION_FACTORY = "org.jboss.el.ExpressionFactoryImpl";
public LegacyJSFELExpressionParser(ExpressionFactory expressionFactory) {
super(expressionFactory);
putContextFactory(RequestContext.class, new RequestContextELContextFactory());
putContextFactory(MutableAttributeMap.class, new AttributeMapELContextFactory());
}
public LegacyJSFELExpressionParser() {
this(getDefaultExpressionFactory());
}
private static ExpressionFactory getDefaultExpressionFactory() {
if (!System.getProperties().containsKey(EXPRESSION_FACTORY_PROPERTY)) {
System.setProperty(EXPRESSION_FACTORY_PROPERTY, DEFAULT_EXPRESSION_FACTORY);
}
if (ReflectionUtils.findMethod(ExpressionFactory.class, "newInstance") != null) {
return ExpressionFactory.newInstance();
} else { // Fallback in case using an older version of el-api
try {
return (ExpressionFactory) BeanUtils.instantiateClass(Class.forName(DEFAULT_EXPRESSION_FACTORY));
} catch (Exception e) {
throw new ELException("Could not create the default ExpressionFactory", e);
}
}
}
private static class RequestContextELContextFactory implements ELContextFactory {
public ELContext getELContext(Object target) {
RequestContext context = (RequestContext) target;
List customResolvers = new ArrayList();
customResolvers.add(new RequestContextELResolver());
customResolvers.add(new RequestContextELResolver(context));
customResolvers.add(new ImplicitFlowVariableELResolver(context));
customResolvers.add(new ScopeSearchingELResolver(context));
customResolvers.add(new ActionMethodELResolver());
if (ClassUtils.isPresent("org.springframework.security.context.SecurityContextHolder")) {
customResolvers.add(new SpringSecurityELResolver());
}
customResolvers.add(new ImplicitFlowVariableELResolver());
customResolvers.add(new SpringBeanWebFlowELResolver());
customResolvers.add(new ActionMethodELResolver());
customResolvers.add(new ScopeSearchingELResolver());
customResolvers.add(new SpringBeanWebFlowELResolver(context));
customResolvers.add(new LegacyJSFBeanResolver());
ELResolver resolver = new DefaultELResolver(target, customResolvers);
return new WebFlowELContext(resolver);

View File

@@ -1,3 +1,18 @@
/*
* 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.faces.expression;
import javax.el.ELContext;

View File

@@ -1,3 +1,18 @@
/*
* 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.faces.model;
import java.util.ArrayList;

View File

@@ -1,3 +1,18 @@
/*
* 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.faces.model;
import java.util.ArrayList;

View File

@@ -1,6 +1,22 @@
/*
* 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.faces.model;
import java.util.List;
import javax.faces.model.DataModel;
/**

View File

@@ -1,3 +1,18 @@
/*
* 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.faces.model;
import javax.faces.component.UIComponent;

View File

@@ -1,3 +1,18 @@
/*
* 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.faces.model;
import java.io.Serializable;

View File

@@ -1,3 +1,18 @@
/*
* 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.faces.model.converter;
import java.lang.reflect.Constructor;

View File

@@ -1,3 +1,15 @@
/*
* Copyright 2004-2008 the original author or authimport org.springframework.binding.convert.ConversionService;
import org.springframework.binding.convert.support.DefaultConversionService;
import org.springframework.faces.model.OneSelectionTrackingListDataModel;
e.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.faces.model.converter;
import org.springframework.binding.convert.ConversionService;

View File

@@ -1,3 +1,18 @@
/*
* 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.faces.mvc;
import java.io.IOException;

View File

@@ -1,3 +1,18 @@
/*
* Copyright 2004-2008 the original authorimport javax.faces.event.PhaseEvent;
import javax.faces.event.PhaseId;
import javax.faces.event.PhaseListener;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
* 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.faces.support;
import javax.faces.event.PhaseEvent;

View File

@@ -1,3 +1,18 @@
/*
* 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.faces.ui.resource;
import java.io.IOException;

View File

@@ -1,3 +1,18 @@
/*
* 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.faces.ui.resource;
import java.io.IOException;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2004-2007 the original author or authors.
* 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.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2004-2007 the original author or authors.
* 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.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2004-2007 the original author or authors.
* 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.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2004-2007 the original author or authors.
* 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.

View File

@@ -1,3 +1,18 @@
/*
* 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.faces.webflow;
import java.io.IOException;

View File

@@ -1,49 +0,0 @@
/*
* Copyright 2004-2007 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.faces.webflow;
import javax.faces.component.UIViewRoot;
import org.springframework.webflow.engine.EndState;
import org.springframework.webflow.execution.Action;
import org.springframework.webflow.execution.Event;
import org.springframework.webflow.execution.RequestContext;
import org.springframework.webflow.execution.View;
/**
* Specialized {@link Action} implementation for rendering the JSF view in an {@link EndState}.
* <p>
* Before the final view is rendered, the {@link UIViewRoot} will be marked transient in order to bypass the JSF state
* saving process.
*
* @author Jeremy Grelle
*/
public class JsfFinalResponseAction implements Action {
private JsfViewFactory viewFactory;
public JsfFinalResponseAction(JsfViewFactory viewFactory) {
this.viewFactory = viewFactory;
}
public Event execute(RequestContext context) throws Exception {
View view = viewFactory.getView(context);
((JsfView) view).getViewRoot().setTransient(true);
view.render();
return new Event(this, "success");
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2004-2007 the original author or authors.
* 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.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2004-2007 the original author or authors.
* 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.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2004-2007 the original author or authors.
* 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.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2004-2007 the original author or authors.
* 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.

View File

@@ -29,6 +29,7 @@ import org.springframework.webflow.core.collection.LocalAttributeMap;
import org.springframework.webflow.core.collection.LocalParameterMap;
import org.springframework.webflow.execution.RequestContext;
import org.springframework.webflow.execution.RequestContextHolder;
import org.springframework.webflow.execution.View;
import org.springframework.webflow.expression.el.WebFlowELExpressionParser;
import org.springframework.webflow.test.MockExternalContext;
@@ -38,8 +39,6 @@ public class JsfFinalResponseActionTests extends TestCase {
private JsfViewFactory factory;
private JsfFinalResponseAction finalResponseAction;
private JSFMockHelper jsfMock = new JSFMockHelper();
private RequestContext context = (RequestContext) EasyMock.createMock(RequestContext.class);
@@ -73,7 +72,6 @@ public class JsfFinalResponseActionTests extends TestCase {
lifecycle = new TestLifecycle(jsfMock.lifecycle());
factory = new JsfViewFactory(parser.parseExpression("#{'" + VIEW_ID + "'}", new ParserContextImpl().template()
.eval(RequestContext.class).expect(String.class)), null, lifecycle);
finalResponseAction = new JsfFinalResponseAction(factory);
RequestContextHolder.setRequestContext(context);
MockExternalContext ext = new MockExternalContext();
ext.setNativeContext(new MockServletContext());
@@ -94,7 +92,9 @@ public class JsfFinalResponseActionTests extends TestCase {
EasyMock.replay(new Object[] { context });
finalResponseAction.execute(context);
View view = factory.getView(context);
((JsfView) view).getViewRoot().setTransient(true);
view.render();
assertTrue(newRoot.isTransient());
assertTrue(((NoRenderViewHandler) viewHandler).rendered);

View File

@@ -29,7 +29,7 @@
<li>Spring IDE tooling integration, with support for graphical flow modeling and visualization</li>
</ul>
<p align="right">
<a href="flows/main">Start your Spring Travel experience</a>
<a href="main">Start your Spring Travel experience</a>
</p>
</div>

View File

@@ -23,19 +23,29 @@
<!-- Activates annotation-based bean configuration -->
<context:annotation-config />
<!-- Instructs Spring to perfrom declarative transaction managemenet on annotated classes -->
<tx:annotation-driven />
<!-- Scans for application components to deploy -->
<!-- Scans for application @Components to deploy -->
<context:component-scan base-package="org.springframework.webflow.samples.booking" />
<!-- Handles requests to the Spring Web Flow system -->
<bean name="/flows/*" class="org.springframework.webflow.mvc.FlowController">
<!-- Maps request URIs to controllers -->
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<value>
/main=flowController
/booking=flowController
</value>
</property>
<property name="defaultHandler">
<!-- Handles requests mapped directly to facelet .xhtml view templates -->
<bean class="org.springframework.web.servlet.mvc.UrlFilenameViewController" />
</property>
</bean>
<!-- Handles requests mapped to the Spring Web Flow system -->
<bean id="flowController" class="org.springframework.webflow.mvc.FlowController">
<constructor-arg ref="flowExecutor" />
</bean>
<bean name="/*" class="org.springframework.web.servlet.mvc.UrlFilenameViewController"/>
<!-- Maps logical view names to Facelet templates (e.g. 'search' to '/WEB-INF/search.xhtml' -->
<bean id="jsfViewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="viewClass" value="org.springframework.faces.mvc.JsfView"/>
<property name="prefix" value="/WEB-INF/" />
@@ -54,7 +64,6 @@
<webflow:flow-registry id="flowRegistry" flow-builder-services="facesFlowBuilderServices">
<webflow:flow-location path="/WEB-INF/flows/main/main.xml" />
<webflow:flow-location path="/WEB-INF/flows/booking/booking.xml" />
<!-- TODO <webflow:flow-location path="/WEB-INF/flows/*/*.xml" /> -->
</webflow:flow-registry>
<!-- Configures the Spring Web Flow JSF integration -->
@@ -69,6 +78,9 @@
<!-- Installs a listener to apply Spring Security authorities -->
<bean id="securityFlowExecutionListener" class="org.springframework.webflow.security.SecurityFlowExecutionListener" />
<!-- Instructs Spring to perfrom declarative transaction managemenet on annotated classes -->
<tx:annotation-driven />
<!-- Drives transactions using local JPA APIs -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
@@ -120,5 +132,5 @@
<security:user name="scott" password="942f2339bf50796de535a384f0d1af3e" authorities="ROLE_USER" />
</security:user-service>
</security:authentication-provider>
</beans>

View File

@@ -6,21 +6,26 @@
<tiles:putAttribute name="content">
<div class="section">
<h1>Welcome to the Spring Web Flow + Spring MVC Sample Application</h1>
<h1>Welcome to Spring Travel</h1>
<p>
This reference application shows how to use Spring MVC and Web Flow together with JavaServerPages (JSP) and Tiles to develop web applications.
</p>
<p>
This hotel booking sample application illustrates Spring Web Flow in a Spring MVC environment.
The key features illustrated in this sample include:
</p>
<ul>
<li>A unified navigation model</li>
<li>A robust state management model</li>
<li>Modularization of web application functionality by domain responsibility</li>
<li>Flow-managed persistence contexts with the Java Persistence API (JPA)</li>
<li>OGNL Expression Language (EL) integration</li>
<li>Spring IDE integration, with support for graphical flow modeling</li>
<li>A declarative navigation model enabling full browser button support and dynamic navigation rules</li>
<li>A fine-grained state management model, including support for ConversationScope and ViewScope</li>
<li>Modularization of web application functionality by domain use case, illustrating project structure best-practices</li>
<li>Managed persistence contexts with the Java Persistence API (JPA)</li>
<li>Unified Expression Language (EL) integration</li>
<li>Spring Security integration</li>
<li>Applying reusable page layouts with Tiles</li>
<li>Exception handling support across all layers of the application</li>
<li>Spring IDE tooling integration, with support for graphical flow modeling and visualization</li>
</ul>
<p align="right">
<a href="main">Start your hotel booking experience</a>
<a href="main">Start your Spring Travel experience</a>
</p>
</div>

View File

@@ -14,41 +14,39 @@
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-2.0.xsd">
<bean id="handlerMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<!-- Maps request URIs to controllers -->
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<value>
/intro=urlFilenameController
/login=urlFilenameController
/logout-success=urlFilenameController
/main=flowController
/booking=flowController
</value>
</property>
<property name="defaultHandler" ref="flowController" />
<property name="defaultHandler">
<!-- Handles requests mapped directly to facelet .xhtml view templates -->
<bean class="org.springframework.web.servlet.mvc.UrlFilenameViewController" />
</property>
</bean>
<!-- Handles requests mapped to the Spring Web Flow system -->
<bean id="flowController" class="org.springframework.webflow.mvc.FlowController">
<constructor-arg ref="flowExecutor" />
</bean>
<!-- Executes flows: the central entry point into the Spring Web Flow system -->
<web:flow-executor id="flowExecutor" flow-registry="flowRegistry">
<web:flow-execution-listeners>
<web:listener ref="jpaFlowExecutionListener" criteria="*" />
<web:listener ref="securityFlowExecutionListener" criteria="*" />
</web:flow-execution-listeners>
</web:flow-executor>
<web:flow-registry id="flowRegistry" flow-builder-services="flowBuilderServices">
<!-- The registry of executable flow definitions -->
<web:flow-registry id="flowRegistry">
<web:flow-location path="WEB-INF/flows/main/main.xml" />
<web:flow-location path="WEB-INF/flows/booking/booking.xml" />
</web:flow-registry>
<web:flow-builder-services id="flowBuilderServices" expression-parser="expressionParser" />
<bean id="expressionParser" class="org.springframework.webflow.expression.el.WebFlowELExpressionParser">
<constructor-arg>
<bean class="org.jboss.el.ExpressionFactoryImpl" />
</constructor-arg>
</bean>
<!-- Installs a listener that manages JPA persistence contexts for flows that require them -->
<bean id="jpaFlowExecutionListener" class="org.springframework.webflow.persistence.JpaFlowExecutionListener">
<constructor-arg ref="entityManagerFactory" />
@@ -58,10 +56,7 @@
<!-- Installs a listener to apply Spring Security authorities -->
<bean id="securityFlowExecutionListener" class="org.springframework.webflow.security.SecurityFlowExecutionListener" />
<!-- Handles requests to render view templates directly: maps the requested path to a logical view name resolved by the resolver below -->
<bean id="urlFilenameController" class="org.springframework.web.servlet.mvc.UrlFilenameViewController" />
<!-- Maps logical view names selected by the url filename controller to .jsp view templates within the root webapp directory -->
<!-- Maps logical view names selected by the url filename controller to .jsp view templates within the /WEB-INF directory -->
<bean id="internalJspViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/" />
<property name="suffix" value=".jsp" />
@@ -72,7 +67,7 @@
<property name="formObjectClass" value="org.springframework.webflow.samples.booking.SearchCriteria" />
</bean>
<!-- Handels form binding and validation for the hotel booking -->
<!-- Handels form binding and validation for the hotel booking process -->
<bean id="bookingActions" class="org.springframework.webflow.action.FormAction">
<property name="formObjectClass" value="org.springframework.webflow.samples.booking.Booking" />
<property name="propertyEditorRegistrar">
@@ -103,7 +98,7 @@
</bean>
<!-- Executes transactions around @Transactional methods -->
<tx:annotation-driven transaction-manager="transactionManager" />
<tx:annotation-driven />
<!-- Drives transactions using local JPA APIs -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">

View File

@@ -10,13 +10,9 @@
<classpathentry kind="lib" path="lib/buildtime/asm-attrs.jar"/>
<classpathentry kind="lib" path="lib/buildtime/cglib.jar"/>
<classpathentry kind="lib" path="lib/test/clover.jar"/>
<classpathentry kind="lib" path="lib/buildtime/commons-beanutils.jar"/>
<classpathentry kind="lib" path="lib/test/commons-collections.jar"/>
<classpathentry kind="lib" path="lib/buildtime/commons-digester.jar"/>
<classpathentry kind="lib" path="lib/test/commons-lang.jar"/>
<classpathentry kind="lib" path="lib/buildtime/commons-fileupload.jar"/>
<classpathentry kind="lib" path="lib/buildtime/commons-logging.jar"/>
<classpathentry kind="lib" path="lib/buildtime/commons-validator.jar"/>
<classpathentry kind="lib" path="lib/buildtime/concurrent.jar"/>
<classpathentry kind="lib" path="lib/test/easymock.jar"/>
<classpathentry kind="lib" path="lib/buildtime/dom4j.jar"/>
@@ -30,7 +26,6 @@
<classpathentry kind="lib" path="lib/buildtime/junit.jar"/>
<classpathentry kind="lib" path="lib/global/ognl.jar"/>
<classpathentry kind="lib" path="lib/test/openjpa.jar"/>
<classpathentry kind="lib" path="lib/buildtime/oro.jar"/>
<classpathentry kind="lib" path="lib/buildtime/persistence-api.jar"/>
<classpathentry kind="lib" path="lib/buildtime/portlet-api.jar"/>
<classpathentry kind="lib" path="lib/test/serp.jar"/>
@@ -38,7 +33,7 @@
<classpathentry kind="lib" path="lib/test/spring-aop.jar"/>
<classpathentry kind="lib" path="lib/global/spring-beans.jar"/>
<classpathentry kind="lib" path="lib/global/spring-context.jar"/>
<classpathentry kind="lib" path="lib/global/spring-core.jar"/>
<classpathentry kind="lib" path="lib/global/spring-core.jar" sourcepath="/spring"/>
<classpathentry kind="lib" path="lib/test/spring-jdbc.jar"/>
<classpathentry kind="lib" path="lib/buildtime/spring-orm.jar"/>
<classpathentry kind="lib" path="lib/buildtime/spring-security-core.jar"/>
@@ -47,7 +42,5 @@
<classpathentry kind="lib" path="lib/global/spring-web.jar"/>
<classpathentry kind="lib" path="lib/buildtime/spring-webmvc.jar"/>
<classpathentry kind="lib" path="lib/buildtime/spring-webmvc-portlet.jar"/>
<classpathentry kind="lib" path="lib/buildtime/struts.jar"/>
<classpathentry kind="lib" path="lib/buildtime/xalan.jar"/>
<classpathentry kind="output" path="target/classes"/>
</classpath>

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2004-2007 the original author or authors.
* 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.

View File

@@ -35,7 +35,7 @@ public class DefaultTargetStateResolver implements TargetStateResolver {
/**
* The expression for the target state identifier.
*/
private Expression targetStateExpression;
private Expression targetStateIdExpression;
/**
* Creates a new target state resolver that always returns the same target state id.
@@ -47,15 +47,15 @@ public class DefaultTargetStateResolver implements TargetStateResolver {
/**
* Creates a new target state resolver.
* @param targetStateExpression the target state expression
* @param targetStateIdExpression the target state expression
*/
public DefaultTargetStateResolver(Expression targetStateExpression) {
Assert.notNull(targetStateExpression, "The target state expression is required");
this.targetStateExpression = targetStateExpression;
public DefaultTargetStateResolver(Expression targetStateIdExpression) {
Assert.notNull(targetStateIdExpression, "The target state id expression is required");
this.targetStateIdExpression = targetStateIdExpression;
}
public State resolveTargetState(Transition transition, State sourceState, RequestContext context) {
String targetStateId = (String) targetStateExpression.getValue(context);
String targetStateId = (String) targetStateIdExpression.getValue(context);
if (targetStateId != null) {
return ((Flow) context.getActiveFlow()).getStateInstance(targetStateId);
} else {
@@ -64,6 +64,6 @@ public class DefaultTargetStateResolver implements TargetStateResolver {
}
public String toString() {
return targetStateExpression.toString();
return targetStateIdExpression.toString();
}
}

View File

@@ -15,17 +15,26 @@
*/
package org.springframework.webflow.expression;
import javax.el.ExpressionFactory;
import org.springframework.binding.expression.Expression;
import org.springframework.binding.expression.ExpressionParser;
import org.springframework.binding.expression.ParserContext;
import org.springframework.binding.expression.ParserException;
import org.springframework.binding.expression.el.DefaultExpressionFactoryUtils;
import org.springframework.util.ClassUtils;
import org.springframework.webflow.expression.el.WebFlowELExpressionParser;
/**
* Static helper factory that creates instances of the default expression parser used by Spring Web Flow when requested.
* Marked final with a private constructor to prevent subclassing.
* Static factory that returns the default {@link ExpressionParser} for use by Spring Web Flow. Marked final with a
* private constructor to prevent subclassing.
* <p>
* The default is an OGNL based expression parser. Also asserts that OGNL is in the classpath the first time the parser
* is used.
* This factory employs the following algorithm when the returned ExpressionParser instance is used for the first time:
* <ul>
* <li>If a Unified EL implementation is configured for the VM, make the ELExpressionParser the default.
* <li>If no Unified EL implementation is configured and OGNL is configured, make the OgnlExpressionParser the default.
* <li>If neither Unified EL or OGNL are configured, throw an IllegalStateException.
* </ul>
*
* @author Keith Donald
* @author Erwin Vervaet
@@ -42,13 +51,13 @@ public final class DefaultExpressionParserFactory {
}
/**
* Returns the default expression parser. The returned expression parser is a thread-safe object.
* Returns the default expression parser for Spring Web Flow. The returned instance is a thread-safe object.
* @return the expression parser
*/
public static synchronized ExpressionParser getExpressionParser() {
// return a wrapper that will lazily load the default expression parser
// this prevents the default OGNL-based parser from being initialized until it is actually used
// which allows OGNL to be an optional dependency if the expression parser wrapper is replaced and never used
// this prevents the underlying parser from being initialized until it is actually used
// this allows the EL to be an optional dependency if the expression parser wrapper is replaced and never used
return new ExpressionParser() {
public Expression parseExpression(String expressionString, ParserContext context) throws ParserException {
return getDefaultExpressionParser().parseExpression(expressionString, context);
@@ -68,23 +77,24 @@ public final class DefaultExpressionParserFactory {
}
/**
* Create the default expression parser.
* @return the default expression parser
* Create the default expression parser. This implementation tries EL first, then OGNL if EL is not configured.
* @return the default Web Flow expression parser
*/
private static ExpressionParser createDefaultExpressionParser() throws IllegalStateException {
try {
Class.forName("ognl.Ognl");
return new WebFlowOgnlExpressionParser();
} catch (ClassNotFoundException e) {
throw new IllegalStateException(
"Unable to load the default expression parser: OGNL could not be found in the classpath. "
+ "Please add OGNL 2.x to your classpath or set the default ExpressionParser instance to something that is in the classpath. "
+ "Details: " + e.getMessage());
} catch (NoClassDefFoundError e) {
throw new IllegalStateException(
"Unable to construct the default expression parser: ognl.Ognl could not be instantiated. "
+ "Please add OGNL 2.x to your classpath or set the default ExpressionParser instance to something that is in the classpath. "
+ "Details: " + e);
ExpressionFactory elFactory = DefaultExpressionFactoryUtils.createExpressionFactory();
return new WebFlowELExpressionParser(elFactory);
} catch (Exception e) {
try {
ClassUtils.forName("ognl.Ognl");
return new WebFlowOgnlExpressionParser();
} catch (ClassNotFoundException ex) {
throw new IllegalStateException(
"Unable to create the default expression parser for Spring Web Flow: Neither a Unified EL implementation or OGNL could be found.");
} catch (NoClassDefFoundError ex) {
throw new IllegalStateException(
"Unable to create the default expression parser for Spring Web Flow: Neither a Unified EL implementation or OGNL could be found.");
}
}
}
}

View File

@@ -14,6 +14,15 @@ import org.springframework.webflow.execution.RequestContextHolder;
public class ImplicitFlowVariableELResolver extends ELResolver {
private RequestContext requestContext;
public ImplicitFlowVariableELResolver() {
}
public ImplicitFlowVariableELResolver(RequestContext requestContext) {
this.requestContext = requestContext;
}
public Class getCommonPropertyType(ELContext context, Object base) {
return Object.class;
}
@@ -23,10 +32,10 @@ public class ImplicitFlowVariableELResolver extends ELResolver {
}
public Class getType(ELContext context, Object base, Object property) {
if (base != null || RequestContextHolder.getRequestContext() == null) {
RequestContext requestContext = getRequestContext();
if (base != null || requestContext == null) {
return null;
}
RequestContext requestContext = RequestContextHolder.getRequestContext();
if (ImplicitVariables.matches(property)) {
context.setPropertyResolved(true);
return ImplicitVariables.value(context, requestContext, property).getClass();
@@ -36,10 +45,10 @@ public class ImplicitFlowVariableELResolver extends ELResolver {
}
public Object getValue(ELContext context, Object base, Object property) {
if (base != null || RequestContextHolder.getRequestContext() == null) {
RequestContext requestContext = getRequestContext();
if (base != null || requestContext == null) {
return null;
}
RequestContext requestContext = RequestContextHolder.getRequestContext();
if (ImplicitVariables.matches(property)) {
context.setPropertyResolved(true);
return ImplicitVariables.value(context, requestContext, property);
@@ -70,6 +79,10 @@ public class ImplicitFlowVariableELResolver extends ELResolver {
}
}
protected RequestContext getRequestContext() {
return requestContext != null ? requestContext : RequestContextHolder.getRequestContext();
}
private static final class ImplicitVariables {
private static final Set vars = new HashSet();
@@ -80,6 +93,8 @@ public class ImplicitFlowVariableELResolver extends ELResolver {
vars.add("flowScope");
vars.add("conversationScope");
vars.add("messageContext");
vars.add("flowExecutionContext");
vars.add("flowExecutionUrl");
}
private static final BeanELResolver internalResolver = new BeanELResolver();

View File

@@ -11,7 +11,7 @@ import org.springframework.webflow.execution.RequestContextHolder;
/**
* Custom EL resolver that resolves to a thread-bound RequestContext object for binding expressions prefixed with a
* {@link #REQUEST_CONTEXT_VARIABLE_NAME}. For instance "#{requestContext.conversationScope.myProperty}".
* {@link #REQUEST_CONTEXT_VARIABLE_NAME}. For instance "#{flowRequestContext.conversationScope.myProperty}".
* @author Jeremy Grelle
*/
public class RequestContextELResolver extends ELResolver {
@@ -19,7 +19,16 @@ public class RequestContextELResolver extends ELResolver {
/**
* Name of the request context variable.
*/
public static final String REQUEST_CONTEXT_VARIABLE_NAME = "requestContext";
public static final String REQUEST_CONTEXT_VARIABLE_NAME = "flowRequestContext";
private RequestContext context;
public RequestContextELResolver() {
}
public RequestContextELResolver(RequestContext context) {
this.context = context;
}
public Class getCommonPropertyType(ELContext elContext, Object base) {
return Object.class;
@@ -41,7 +50,7 @@ public class RequestContextELResolver extends ELResolver {
public Object getValue(ELContext elContext, Object base, Object property) {
if (base == null && REQUEST_CONTEXT_VARIABLE_NAME.equals(property)) {
elContext.setPropertyResolved(true);
return RequestContextHolder.getRequestContext();
return getRequestContext();
} else {
return null;
}
@@ -62,4 +71,9 @@ public class RequestContextELResolver extends ELResolver {
throw new PropertyNotWritableException("The RequestContext cannot be set with an expression.");
}
}
protected RequestContext getRequestContext() {
return context != null ? context : RequestContextHolder.getRequestContext();
}
}

View File

@@ -19,6 +19,15 @@ import org.springframework.webflow.execution.RequestContextHolder;
*/
public class ScopeSearchingELResolver extends ELResolver {
private RequestContext requestContext;
public ScopeSearchingELResolver() {
}
public ScopeSearchingELResolver(RequestContext requestContext) {
this.requestContext = requestContext;
}
public Class getCommonPropertyType(ELContext elContext, Object base) {
return Object.class;
}
@@ -28,10 +37,10 @@ public class ScopeSearchingELResolver extends ELResolver {
}
public Class getType(ELContext elContext, Object base, Object property) {
if (base != null || RequestContextHolder.getRequestContext() == null) {
RequestContext requestContext = getRequestContext();
if (base != null || requestContext == null) {
return null;
}
RequestContext requestContext = RequestContextHolder.getRequestContext();
String attributeName = property.toString();
if (requestContext.getRequestScope().contains(attributeName)) {
elContext.setPropertyResolved(true);
@@ -51,10 +60,10 @@ public class ScopeSearchingELResolver extends ELResolver {
}
public Object getValue(ELContext elContext, Object base, Object property) {
if (base != null || RequestContextHolder.getRequestContext() == null) {
RequestContext requestContext = getRequestContext();
if (base != null || requestContext == null) {
return null;
}
RequestContext requestContext = RequestContextHolder.getRequestContext();
String attributeName = property.toString();
if (requestContext.getRequestScope().contains(attributeName)) {
elContext.setPropertyResolved(true);
@@ -74,10 +83,10 @@ public class ScopeSearchingELResolver extends ELResolver {
}
public boolean isReadOnly(ELContext elContext, Object base, Object property) {
if (base != null || RequestContextHolder.getRequestContext() == null) {
RequestContext requestContext = getRequestContext();
if (base != null || requestContext == null) {
return false;
}
RequestContext requestContext = RequestContextHolder.getRequestContext();
String attributeName = property.toString();
if (requestContext.getRequestScope().contains(attributeName)) {
elContext.setPropertyResolved(true);
@@ -97,10 +106,10 @@ public class ScopeSearchingELResolver extends ELResolver {
}
public void setValue(ELContext elContext, Object base, Object property, Object value) {
if (base != null || RequestContextHolder.getRequestContext() == null) {
RequestContext requestContext = getRequestContext();
if (base != null || requestContext == null) {
return;
}
RequestContext requestContext = RequestContextHolder.getRequestContext();
String attributeName = property.toString();
if (requestContext.getRequestScope().contains(attributeName)) {
elContext.setPropertyResolved(true);
@@ -116,4 +125,9 @@ public class ScopeSearchingELResolver extends ELResolver {
requestContext.getConversationScope().put(attributeName, value);
}
}
protected RequestContext getRequestContext() {
return requestContext != null ? requestContext : RequestContextHolder.getRequestContext();
}
}

View File

@@ -16,14 +16,27 @@ public class SpringBeanWebFlowELResolver extends SpringBeanELResolver {
private static final BeanFactory EMPTY_BEAN_FACTORY = new StaticListableBeanFactory();
private RequestContext context;
public SpringBeanWebFlowELResolver() {
}
public SpringBeanWebFlowELResolver(RequestContext context) {
this.context = context;
}
protected BeanFactory getBeanFactory(ELContext elContext) {
RequestContext rc = RequestContextHolder.getRequestContext();
if (rc != null && rc.getActiveFlow().getBeanFactory() != null) {
BeanFactory factory = rc.getActiveFlow().getBeanFactory();
RequestContext requestContext = getRequestContext();
if (context != null && requestContext.getActiveFlow().getBeanFactory() != null) {
BeanFactory factory = requestContext.getActiveFlow().getBeanFactory();
return factory;
} else {
return EMPTY_BEAN_FACTORY;
}
}
protected RequestContext getRequestContext() {
return context != null ? context : RequestContextHolder.getRequestContext();
}
}

View File

@@ -42,7 +42,11 @@ public class SpringSecurityELResolver extends ELResolver {
public Object getValue(ELContext elContext, Object base, Object property) {
if (base == null && SECURITY_PRINCIPAL_VARIABLE_NAME.equals(property)) {
elContext.setPropertyResolved(true);
return SecurityContextHolder.getContext().getAuthentication();
if (SecurityContextHolder.getContext() != null) {
return SecurityContextHolder.getContext().getAuthentication();
} else {
return null;
}
} else {
return null;
}

View File

@@ -4,18 +4,15 @@ import java.util.ArrayList;
import java.util.List;
import javax.el.ELContext;
import javax.el.ELException;
import javax.el.ELResolver;
import javax.el.ExpressionFactory;
import javax.el.FunctionMapper;
import javax.el.VariableMapper;
import org.springframework.beans.BeanUtils;
import org.springframework.binding.expression.el.DefaultELResolver;
import org.springframework.binding.expression.el.ELContextFactory;
import org.springframework.binding.expression.el.ELExpressionParser;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.webflow.core.collection.MutableAttributeMap;
import org.springframework.webflow.execution.RequestContext;
@@ -28,46 +25,24 @@ import org.springframework.webflow.execution.RequestContext;
*/
public class WebFlowELExpressionParser extends ELExpressionParser {
private static final String EXPRESSION_FACTORY_PROPERTY = "javax.el.ExpressionFactory";
private static final String DEFAULT_EXPRESSION_FACTORY = "org.jboss.el.ExpressionFactoryImpl";
public WebFlowELExpressionParser(ExpressionFactory expressionFactory) {
super(expressionFactory);
putContextFactory(RequestContext.class, new RequestContextELContextFactory());
putContextFactory(MutableAttributeMap.class, new AttributeMapELContextFactory());
}
public WebFlowELExpressionParser() {
this(getDefaultExpressionFactory());
}
private static ExpressionFactory getDefaultExpressionFactory() {
if (!System.getProperties().containsKey(EXPRESSION_FACTORY_PROPERTY)) {
System.setProperty(EXPRESSION_FACTORY_PROPERTY, DEFAULT_EXPRESSION_FACTORY);
}
if (ReflectionUtils.findMethod(ExpressionFactory.class, "newInstance") != null) {
return ExpressionFactory.newInstance();
} else { // Fallback in case using an older version of el-api
try {
return (ExpressionFactory) BeanUtils.instantiateClass(Class.forName(DEFAULT_EXPRESSION_FACTORY));
} catch (Exception e) {
throw new ELException("Could not create the default ExpressionFactory", e);
}
}
}
private static class RequestContextELContextFactory implements ELContextFactory {
public ELContext getELContext(Object target) {
RequestContext context = (RequestContext) target;
List customResolvers = new ArrayList();
customResolvers.add(new RequestContextELResolver());
customResolvers.add(new RequestContextELResolver(context));
customResolvers.add(new ImplicitFlowVariableELResolver(context));
customResolvers.add(new ScopeSearchingELResolver(context));
customResolvers.add(new ActionMethodELResolver());
if (ClassUtils.isPresent("org.springframework.security.context.SecurityContextHolder")) {
customResolvers.add(new SpringSecurityELResolver());
}
customResolvers.add(new ImplicitFlowVariableELResolver());
customResolvers.add(new SpringBeanWebFlowELResolver());
customResolvers.add(new ActionMethodELResolver());
customResolvers.add(new ScopeSearchingELResolver());
customResolvers.add(new SpringBeanWebFlowELResolver(context));
ELResolver resolver = new DefaultELResolver(null, customResolvers);
return new WebFlowELContext(resolver);
}

View File

@@ -11,22 +11,16 @@ import org.springframework.webflow.expression.DefaultExpressionParserFactory;
* @author Keith Donald
*/
public class TestFlowBuilderServicesFactory {
private static FlowBuilderServices services;
private TestFlowBuilderServicesFactory() {
}
public static FlowBuilderServices getServices() {
if (services != null) {
return services;
} else {
services = new FlowBuilderServices();
services.setViewFactoryCreator(new MockViewFactoryCreator());
services.setConversionService(new DefaultConversionService());
services.setExpressionParser(DefaultExpressionParserFactory.getExpressionParser());
services.setResourceLoader(new DefaultResourceLoader());
services.setBeanFactory(new StaticListableBeanFactory());
return services;
}
FlowBuilderServices services = new FlowBuilderServices();
services.setViewFactoryCreator(new MockViewFactoryCreator());
services.setConversionService(new DefaultConversionService());
services.setExpressionParser(DefaultExpressionParserFactory.getExpressionParser());
services.setResourceLoader(new DefaultResourceLoader());
services.setBeanFactory(new StaticListableBeanFactory());
return services;
}
}

View File

@@ -13,7 +13,6 @@ import org.springframework.webflow.engine.builder.ViewFactoryCreator;
import org.springframework.webflow.engine.builder.support.FlowBuilderServices;
import org.springframework.webflow.execution.Action;
import org.springframework.webflow.execution.ViewFactory;
import org.springframework.webflow.expression.el.WebFlowELExpressionParser;
import org.springframework.webflow.mvc.MvcViewFactoryCreator;
public class FlowBuilderServicesBeanDefinitionParserTests extends TestCase {
@@ -36,7 +35,7 @@ public class FlowBuilderServicesBeanDefinitionParserTests extends TestCase {
public void testFlowBuilderServicesCustomized() {
builderServices = (FlowBuilderServices) context.getBean("flowBuilderServicesCustom");
assertNotNull(builderServices);
assertTrue(builderServices.getExpressionParser() instanceof WebFlowELExpressionParser);
assertNotNull(builderServices.getExpressionParser());
assertTrue(builderServices.getViewFactoryCreator() instanceof TestViewFactoryCreator);
assertTrue(builderServices.getConversionService() instanceof TestConversionService);
}

View File

@@ -15,7 +15,7 @@
view-factory-creator="customViewFactoryCreator"
conversion-service="customConversionService"/>
<bean id="customExpressionParser" class="org.springframework.webflow.expression.el.WebFlowELExpressionParser"/>
<bean id="customExpressionParser" class="org.springframework.webflow.expression.DefaultExpressionParserFactory" factory-method="getExpressionParser"/>
<bean id="customViewFactoryCreator" class="org.springframework.webflow.config.FlowBuilderServicesBeanDefinitionParserTests$TestViewFactoryCreator"/>

View File

@@ -39,7 +39,7 @@ public class TextToTargetStateResolverTests extends TestCase {
}
public void testDynamic() {
String expression = "${flowScope.lastState}";
String expression = "#{flowScope.lastState}";
TargetStateResolver resolver = (TargetStateResolver) converter.convert(expression);
MockRequestContext context = new MockRequestContext();
context.getFlowScope().put("lastState", "mockState");

View File

@@ -17,6 +17,11 @@ package org.springframework.webflow.engine.builder.support;
import junit.framework.TestCase;
import org.springframework.binding.expression.Expression;
import org.springframework.binding.expression.ExpressionParser;
import org.springframework.binding.expression.ParserContext;
import org.springframework.binding.expression.ParserException;
import org.springframework.binding.expression.support.StaticExpression;
import org.springframework.webflow.engine.Flow;
import org.springframework.webflow.engine.TransitionCriteria;
import org.springframework.webflow.engine.WildcardTransitionCriteria;
@@ -74,8 +79,12 @@ public class TextToTransitionCriteriaTests extends TestCase {
}
public void testNullExpressionEvaluation() throws Exception {
String expression = "${null}";
TransitionCriteria criterion = (TransitionCriteria) converter.convert(expression);
serviceLocator.getFlowBuilderServices().setExpressionParser(new ExpressionParser() {
public Expression parseExpression(String expressionString, ParserContext context) throws ParserException {
return new StaticExpression(null);
}
});
TransitionCriteria criterion = (TransitionCriteria) converter.convert("doesnt matter");
RequestContext ctx = getRequestContext();
assertFalse("Criterion should evaluate to false", criterion.test(ctx));
}

View File

@@ -18,7 +18,6 @@ package org.springframework.webflow.expression;
import junit.framework.TestCase;
import org.springframework.binding.expression.ExpressionParser;
import org.springframework.webflow.expression.DefaultExpressionParserFactory;
/**
* Unit tests for {@link DefaultExpressionParserFactory}.

View File

@@ -26,7 +26,6 @@ import org.springframework.webflow.context.ExternalContext;
import org.springframework.webflow.core.collection.AttributeMap;
import org.springframework.webflow.engine.EndState;
import org.springframework.webflow.engine.Flow;
import org.springframework.webflow.expression.el.WebFlowELExpressionParser;
import org.springframework.webflow.test.execution.AbstractXmlFlowExecutionTests;
/**
@@ -68,7 +67,6 @@ public class SearchFlowExecutionTests extends AbstractXmlFlowExecutionTests {
}
protected void configureFlowBuilderContext(MockFlowBuilderContext builderContext) {
builderContext.getFlowBuilderServices().setExpressionParser(new WebFlowELExpressionParser());
Flow mockDetailFlow = new Flow("detail-flow");
mockDetailFlow.setInputMapper(new AttributeMapper() {
public void map(Object source, Object target, MappingContext context) {