WW-4158 Defines new factory interfaces with default implementations and uses them in ObjectFactory, docs updated as well

git-svn-id: https://svn.apache.org/repos/asf/struts/struts2/trunk@1508392 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Lukasz Lenart
2013-07-30 11:27:46 +00:00
parent 49d339f8f3
commit fce9681270
23 changed files with 498 additions and 151 deletions
@@ -64,8 +64,16 @@ public final class StrutsConstants {
/** The com.opensymphony.xwork2.ObjectFactory implementation class */
public static final String STRUTS_OBJECTFACTORY = "struts.objectFactory";
public static final String STRUTS_OBJECTFACTORY_ACTIONFACTORY = "struts.objectFactory.actionFactory";
public static final String STRUTS_OBJECTFACTORY_RESULTFACTORY = "struts.objectFactory.resultFactory";
public static final String STRUTS_OBJECTFACTORY_CONVERTERFACTORY = "struts.objectFactory.converterFactory";
public static final String STRUTS_OBJECTFACTORY_INTERCEPTORFACTORY = "struts.objectFactory.interceptorFactory";
public static final String STRUTS_OBJECTFACTORY_VALIDATORFACTORY = "struts.objectFactory.validatorFactory";
/** The com.opensymphony.xwork2.util.FileManager implementation class */
public static final String STRUTS_FILE_MANAGER_FACTORY = "struts.fileManagerFactory";
@@ -44,12 +44,21 @@ import com.opensymphony.xwork2.conversion.impl.DateConverter;
import com.opensymphony.xwork2.conversion.impl.NumberConverter;
import com.opensymphony.xwork2.conversion.impl.StringConverter;
import com.opensymphony.xwork2.conversion.impl.XWorkConverter;
import com.opensymphony.xwork2.factory.ActionFactory;
import com.opensymphony.xwork2.factory.ConverterFactory;
import com.opensymphony.xwork2.factory.InterceptorFactory;
import com.opensymphony.xwork2.factory.ResultFactory;
import com.opensymphony.xwork2.factory.ValidatorFactory;
import com.opensymphony.xwork2.inject.Container;
import com.opensymphony.xwork2.inject.ContainerBuilder;
import com.opensymphony.xwork2.inject.Context;
import com.opensymphony.xwork2.inject.Factory;
import com.opensymphony.xwork2.inject.Scope;
import com.opensymphony.xwork2.util.*;
import com.opensymphony.xwork2.util.ClassLoaderUtil;
import com.opensymphony.xwork2.util.LocalizedTextUtil;
import com.opensymphony.xwork2.util.PatternMatcher;
import com.opensymphony.xwork2.util.TextParser;
import com.opensymphony.xwork2.util.ValueStackFactory;
import com.opensymphony.xwork2.util.location.LocatableProperties;
import com.opensymphony.xwork2.util.logging.Logger;
import com.opensymphony.xwork2.util.logging.LoggerFactory;
@@ -61,7 +70,6 @@ import org.apache.struts2.components.UrlRenderer;
import org.apache.struts2.dispatcher.StaticContentLoader;
import org.apache.struts2.dispatcher.mapper.ActionMapper;
import org.apache.struts2.dispatcher.multipart.MultiPartRequest;
import com.opensymphony.xwork2.factory.ResultFactory;
import org.apache.struts2.views.freemarker.FreemarkerManager;
import org.apache.struts2.views.util.UrlHelper;
import org.apache.struts2.views.velocity.VelocityManager;
@@ -93,12 +101,36 @@ import java.util.StringTokenizer;
* <td>Creates actions, results, and interceptors</td>
* </tr>
* <tr>
* <td>com.opensymphony.xwork2.factory.ActionFactory</td>
* <td>struts.objectFactory.actionFactory</td>
* <td>singleton</td>
* <td>Dedicated factory used to create Actions, you can implement/extend existing one instead of defining new ObjectFactory</td>
* </tr>
* <tr>
* <td>com.opensymphony.xwork2.factory.ResultFactory</td>
* <td>struts.objectFactory.resultFactory</td>
* <td>singleton</td>
* <td>Dedicated factory used to create Results, you can implement/extend existing one instead of defining new ObjectFactory</td>
* </tr>
* <tr>
* <td>com.opensymphony.xwork2.factory.InterceptorFactory</td>
* <td>struts.objectFactory.interceptorFactory</td>
* <td>singleton</td>
* <td>Dedicated factory used to create Interceptors, you can implement/extend existing one instead of defining new ObjectFactory</td>
* </tr>
* <tr>
* <td>com.opensymphony.xwork2.factory.ConverterFactory</td>
* <td>struts.objectFactory.converterFactory</td>
* <td>singleton</td>
* <td>Dedicated factory used to create TypeConverters, you can implement/extend existing one instead of defining new ObjectFactory</td>
* </tr>
* <tr>
* <td>com.opensymphony.xwork2.factory.ValidatorFactory</td>
* <td>struts.objectFactory.validatorFactory</td>
* <td>singleton</td>
* <td>Dedicated factory used to create Validators, you can implement/extend existing one instead of defining new ObjectFactory</td>
* </tr>
* <tr>
* <td>com.opensymphony.xwork2.ActionProxyFactory</td>
* <td>struts.actionProxyFactory</td>
* <td>singleton</td>
@@ -332,7 +364,11 @@ public class BeanSelectionProvider implements ConfigurationProvider {
public void register(ContainerBuilder builder, LocatableProperties props) {
alias(ObjectFactory.class, StrutsConstants.STRUTS_OBJECTFACTORY, builder, props);
alias(ActionFactory.class, StrutsConstants.STRUTS_OBJECTFACTORY_ACTIONFACTORY, builder, props);
alias(ResultFactory.class, StrutsConstants.STRUTS_OBJECTFACTORY_RESULTFACTORY, builder, props);
alias(ConverterFactory.class, StrutsConstants.STRUTS_OBJECTFACTORY_CONVERTERFACTORY, builder, props);
alias(InterceptorFactory.class, StrutsConstants.STRUTS_OBJECTFACTORY_INTERCEPTORFACTORY, builder, props);
alias(ValidatorFactory.class, StrutsConstants.STRUTS_OBJECTFACTORY_INTERCEPTORFACTORY, builder, props);
alias(FileManagerFactory.class, StrutsConstants.STRUTS_FILE_MANAGER_FACTORY, builder, props, Scope.SINGLETON);
@@ -60,7 +60,7 @@ public class StrutsResultFactory implements ResultFactory {
protected void setParameter(Result result, String name, String value, Map<String, Object> extraContext) {
if (result instanceof ParamNameAwareResult) {
if (((ParamNameAwareResult) result).acceptParamName(name, value)) {
if (((ParamNameAwareResult) result).acceptableParameterName(name, value)) {
reflectionProvider.setProperty(name, value, result, extraContext, true);
}
} else {
@@ -24,17 +24,31 @@
package org.apache.struts2.impl;
import com.opensymphony.xwork2.ObjectFactory;
import com.opensymphony.xwork2.Result;
import com.opensymphony.xwork2.config.ConfigurationException;
import com.opensymphony.xwork2.config.entities.InterceptorConfig;
import com.opensymphony.xwork2.config.entities.ResultConfig;
import com.opensymphony.xwork2.inject.Inject;
import com.opensymphony.xwork2.interceptor.Interceptor;
import com.opensymphony.xwork2.util.reflection.ReflectionProvider;
import java.util.HashMap;
import java.util.Map;
/**
* Instead of overriding the whole class a new {@link com.opensymphony.xwork2.factory.InterceptorFactory}
* should be defined, thus should be solved in Struts 2.5
*
* @deprecated since version 2.3.16
*/
@Deprecated
public class StrutsObjectFactory extends ObjectFactory {
private ReflectionProvider reflectionProvider;
@Inject
public void setReflectionProvider(ReflectionProvider reflectionProvider) {
this.reflectionProvider = reflectionProvider;
}
public Interceptor buildInterceptor(InterceptorConfig interceptorConfig, Map refParams)
throws ConfigurationException {
String className = interceptorConfig.getClassName();
@@ -28,9 +28,22 @@
<struts>
<bean class="com.opensymphony.xwork2.ObjectFactory" name="xwork" />
<bean type="com.opensymphony.xwork2.ObjectFactory" name="struts" class="org.apache.struts2.impl.StrutsObjectFactory" />
<bean type="com.opensymphony.xwork2.factory.ResultFactory" name="xwork" class="org.apache.struts2.factory.StrutsResultFactory" />
<bean type="com.opensymphony.xwork2.factory.ResultFactory" name="struts" class="org.apache.struts2.factory.StrutsResultFactory" />
<bean type="com.opensymphony.xwork2.factory.ActionFactory" name="xwork" class="com.opensymphony.xwork2.factory.DefaultActionFactory" />
<bean type="com.opensymphony.xwork2.factory.ActionFactory" name="struts" class="com.opensymphony.xwork2.factory.DefaultActionFactory" />
<bean type="com.opensymphony.xwork2.factory.ConverterFactory" name="xwork" class="com.opensymphony.xwork2.factory.DefaultConverterFactory" />
<bean type="com.opensymphony.xwork2.factory.ConverterFactory" name="struts" class="com.opensymphony.xwork2.factory.DefaultConverterFactory" />
<bean type="com.opensymphony.xwork2.factory.InterceptorFactory" name="xwork" class="com.opensymphony.xwork2.factory.DefaultInterceptorFactory" />
<bean type="com.opensymphony.xwork2.factory.InterceptorFactory" name="struts" class="com.opensymphony.xwork2.factory.DefaultInterceptorFactory" />
<bean type="com.opensymphony.xwork2.factory.ValidatorFactory" name="xwork" class="com.opensymphony.xwork2.factory.DefaultValidatorFactory" />
<bean type="com.opensymphony.xwork2.factory.ValidatorFactory" name="struts" class="com.opensymphony.xwork2.factory.DefaultValidatorFactory" />
<bean type="com.opensymphony.xwork2.FileManager" class="com.opensymphony.xwork2.util.fs.DefaultFileManager" name="system" scope="singleton"/>
<bean type="com.opensymphony.xwork2.FileManagerFactory" class="com.opensymphony.xwork2.util.fs.DefaultFileManagerFactory" name="xwork" scope="singleton"/>
@@ -47,7 +47,7 @@ public class StrutsResultFactoryTest extends StrutsTestCase {
private String accept;
private String reject = "ok";
public boolean acceptParamName(String name, String value) {
public boolean acceptableParameterName(String name, String value) {
return "accept".equals(name);
}
@@ -36,6 +36,8 @@ import com.opensymphony.xwork2.config.entities.PackageConfig;
import com.opensymphony.xwork2.config.entities.ResultConfig;
import com.opensymphony.xwork2.config.entities.ResultTypeConfig;
import com.opensymphony.xwork2.config.impl.DefaultConfiguration;
import com.opensymphony.xwork2.factory.DefaultInterceptorFactory;
import com.opensymphony.xwork2.factory.DefaultResultFactory;
import com.opensymphony.xwork2.inject.Container;
import com.opensymphony.xwork2.inject.Scope.Strategy;
import com.opensymphony.xwork2.ognl.OgnlReflectionProvider;
@@ -754,7 +756,7 @@ public class PackageBasedActionConfigBuilderTest extends TestCase {
}
T obj = type.newInstance();
if (obj instanceof ObjectFactory) {
((ObjectFactory)obj).setReflectionProvider(new OgnlReflectionProvider() {
OgnlReflectionProvider rp = new OgnlReflectionProvider() {
@Override
public void setProperties(Map<String, ?> properties, Object o) {
@@ -762,17 +764,27 @@ public class PackageBasedActionConfigBuilderTest extends TestCase {
public void setProperties(Map<String, ?> properties, Object o, Map<String, Object> context, boolean throwPropertyExceptions) throws ReflectionException {
if (o instanceof ActionChainResult) {
((ActionChainResult)o).setActionName(String.valueOf(properties.get("actionName")));
((ActionChainResult) o).setActionName(String.valueOf(properties.get("actionName")));
}
}
@Override
public void setProperty(String name, Object value, Object o, Map<String, Object> context, boolean throwPropertyExceptions) {
if (o instanceof ActionChainResult) {
((ActionChainResult)o).setActionName((String)value);
((ActionChainResult) o).setActionName((String) value);
}
}
});
};
DefaultInterceptorFactory dif = new DefaultInterceptorFactory();
dif.setObjectFactory((ObjectFactory) obj);
dif.setReflectionProvider(rp);
DefaultResultFactory drf = new DefaultResultFactory();
drf.setObjectFactory((ObjectFactory) obj);
drf.setReflectionProvider(rp);
((ObjectFactory) obj).setInterceptorFactory(dif);
((ObjectFactory) obj).setResultFactory(drf);
}
return obj;
} catch (Exception e) {
@@ -21,13 +21,6 @@
package org.apache.struts2.plexus;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletContext;
import org.codehaus.plexus.PlexusContainer;
import com.opensymphony.xwork2.Action;
import com.opensymphony.xwork2.ObjectFactory;
import com.opensymphony.xwork2.Result;
@@ -39,7 +32,13 @@ import com.opensymphony.xwork2.inject.Inject;
import com.opensymphony.xwork2.interceptor.Interceptor;
import com.opensymphony.xwork2.util.logging.Logger;
import com.opensymphony.xwork2.util.logging.LoggerFactory;
import com.opensymphony.xwork2.util.reflection.ReflectionProvider;
import com.opensymphony.xwork2.validator.Validator;
import org.codehaus.plexus.PlexusContainer;
import javax.servlet.ServletContext;
import java.util.HashMap;
import java.util.Map;
/**
* Plexus integartion. You need three optional files: plexus-request.xml, plexus-session.xml, and
@@ -71,13 +70,18 @@ import com.opensymphony.xwork2.validator.Validator;
* @author <a href="mailto:evenisse@apache.org">Emmanuel Venisse</a>
*/
public class PlexusObjectFactory extends ObjectFactory {
private static final Logger LOG = LoggerFactory.getLogger(PlexusObjectFactory.class);
private static final String PLEXUS_COMPONENT_TYPE = "plexus.component.type";
private PlexusContainer base;
private ReflectionProvider reflectionProvider;
@Inject
public void setReflectionProvider(ReflectionProvider reflectionProvider) {
this.reflectionProvider = reflectionProvider;
}
@Inject
public void setServletConfig(ServletContext servletContext) {
@@ -20,20 +20,20 @@ import com.opensymphony.xwork2.config.entities.ActionConfig;
import com.opensymphony.xwork2.config.entities.InterceptorConfig;
import com.opensymphony.xwork2.config.entities.ResultConfig;
import com.opensymphony.xwork2.conversion.TypeConverter;
import com.opensymphony.xwork2.factory.ActionFactory;
import com.opensymphony.xwork2.factory.ConverterFactory;
import com.opensymphony.xwork2.factory.InterceptorFactory;
import com.opensymphony.xwork2.factory.ResultFactory;
import com.opensymphony.xwork2.factory.ValidatorFactory;
import com.opensymphony.xwork2.inject.Container;
import com.opensymphony.xwork2.inject.Inject;
import com.opensymphony.xwork2.interceptor.Interceptor;
import com.opensymphony.xwork2.util.ClassLoaderUtil;
import com.opensymphony.xwork2.util.logging.Logger;
import com.opensymphony.xwork2.util.logging.LoggerFactory;
import com.opensymphony.xwork2.util.reflection.ReflectionException;
import com.opensymphony.xwork2.util.reflection.ReflectionExceptionHandler;
import com.opensymphony.xwork2.util.reflection.ReflectionProvider;
import com.opensymphony.xwork2.validator.Validator;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
@@ -48,41 +48,53 @@ import java.util.Map;
* @author Jason Carreira
*/
public class ObjectFactory implements Serializable {
private static final Logger LOG = LoggerFactory.getLogger(ObjectFactory.class);
private transient ClassLoader ccl;
private Container container;
protected ReflectionProvider reflectionProvider;
private ActionFactory actionFactory;
private ResultFactory resultFactory;
private InterceptorFactory interceptorFactory;
private ValidatorFactory validatorFactory;
private ConverterFactory converterFactory;
@Inject(value="objectFactory.classloader", required=false)
public void setClassLoader(ClassLoader cl) {
this.ccl = cl;
}
@Inject
public void setReflectionProvider(ReflectionProvider prov) {
this.reflectionProvider = prov;
}
public ObjectFactory() {
}
public ObjectFactory(ReflectionProvider prov) {
this.reflectionProvider = prov;
}
@Inject
public void setContainer(Container container) {
this.container = container;
}
@Inject(required = false)
@Inject
public void setActionFactory(ActionFactory actionFactory) {
this.actionFactory = actionFactory;
}
@Inject
public void setResultFactory(ResultFactory resultFactory) {
this.resultFactory = resultFactory;
}
@Inject
public void setInterceptorFactory(InterceptorFactory interceptorFactory) {
this.interceptorFactory = interceptorFactory;
}
@Inject
public void setValidatorFactory(ValidatorFactory validatorFactory) {
this.validatorFactory = validatorFactory;
}
@Inject
public void setConverterFactory(ConverterFactory converterFactory) {
this.converterFactory = converterFactory;
}
/**
* @deprecated Since 2.1
*/
@@ -126,7 +138,7 @@ public class ObjectFactory implements Serializable {
* @throws Exception
*/
public Object buildAction(String actionName, String namespace, ActionConfig config, Map<String, Object> extraContext) throws Exception {
return buildBean(config.getClassName(), extraContext);
return actionFactory.buildAction(actionName, namespace, config, extraContext);
}
/**
@@ -187,39 +199,7 @@ public class ObjectFactory implements Serializable {
* Action mapping or InterceptorStack definition
*/
public Interceptor buildInterceptor(InterceptorConfig interceptorConfig, Map<String, String> interceptorRefParams) throws ConfigurationException {
String interceptorClassName = interceptorConfig.getClassName();
Map<String, String> thisInterceptorClassParams = interceptorConfig.getParams();
Map<String, String> params = (thisInterceptorClassParams == null) ? new HashMap<String, String>() : new HashMap<String, String>(thisInterceptorClassParams);
params.putAll(interceptorRefParams);
String message;
Throwable cause;
try {
// interceptor instances are long-lived and used across user sessions, so don't try to pass in any extra context
Interceptor interceptor = (Interceptor) buildBean(interceptorClassName, null);
reflectionProvider.setProperties(params, interceptor);
interceptor.init();
return interceptor;
} catch (InstantiationException e) {
cause = e;
message = "Unable to instantiate an instance of Interceptor class [" + interceptorClassName + "].";
} catch (IllegalAccessException e) {
cause = e;
message = "IllegalAccessException while attempting to instantiate an instance of Interceptor class [" + interceptorClassName + "].";
} catch (ClassCastException e) {
cause = e;
message = "Class [" + interceptorClassName + "] does not implement com.opensymphony.xwork2.interceptor.Interceptor";
} catch (Exception e) {
cause = e;
message = "Caught Exception while registering Interceptor class " + interceptorClassName;
} catch (NoClassDefFoundError e) {
cause = e;
message = "Could not load class " + interceptorClassName + ". Perhaps it exists but certain dependencies are not available?";
}
throw new ConfigurationException(message, cause, interceptorConfig);
return interceptorFactory.buildInterceptor(interceptorConfig, interceptorRefParams);
}
/**
@@ -229,29 +209,7 @@ public class ObjectFactory implements Serializable {
* @param extraContext a Map of extra context which uses the same keys as the {@link com.opensymphony.xwork2.ActionContext}
*/
public Result buildResult(ResultConfig resultConfig, Map<String, Object> extraContext) throws Exception {
if (resultFactory != null) {
return resultFactory.buildResult(resultConfig, extraContext);
}
String resultClassName = resultConfig.getClassName();
Result result = null;
if (resultClassName != null) {
result = (Result) buildBean(resultClassName, extraContext);
Map<String, String> params = resultConfig.getParams();
if (params != null) {
for (Map.Entry<String, String> paramEntry : params.entrySet()) {
try {
reflectionProvider.setProperty(paramEntry.getKey(), paramEntry.getValue(), result, extraContext, true);
} catch (ReflectionException ex) {
if (result instanceof ReflectionExceptionHandler) {
((ReflectionExceptionHandler) result).handle(ex);
}
}
}
}
}
return result;
return resultFactory.buildResult(resultConfig, extraContext);
}
/**
@@ -262,57 +220,18 @@ public class ObjectFactory implements Serializable {
* @param extraContext a Map of extra context which uses the same keys as the {@link com.opensymphony.xwork2.ActionContext}
*/
public Validator buildValidator(String className, Map<String, Object> params, Map<String, Object> extraContext) throws Exception {
Validator validator = (Validator) buildBean(className, extraContext);
reflectionProvider.setProperties(params, validator, extraContext);
return validator;
return validatorFactory.buildValidator(className, params, extraContext);
}
/**
* Build converter of given type - it must be registered with {@link Container} first
* Build converter of given type
*
* @param converterClass to instantiate
* @param extraContext a Map of extra context which uses the same keys as the {@link com.opensymphony.xwork2.ActionContext}
* @return instance of converterClass with inject dependencies
*/
public TypeConverter buildConverter(Class<? extends TypeConverter> converterClass) {
if (LOG.isDebugEnabled()) {
LOG.debug("Creating converter of type [#0]", converterClass.getCanonicalName());
}
return container.getInstance(converterClass);
public TypeConverter buildConverter(Class<? extends TypeConverter> converterClass, Map<String, Object> extraContext) throws Exception {
return converterFactory.buildConverter(converterClass, extraContext);
}
/**
* Build converter of given type - it must be registered with {@link Container} first
*
* @param converterClass to instantiate
* @param name name of converter to use
* @return instance of converterClass with inject dependencies
*/
public TypeConverter buildConverter(Class<? extends TypeConverter> converterClass, String name) {
if (LOG.isDebugEnabled()) {
LOG.debug("Creating converter of type [#0] with name [#1]", converterClass.getCanonicalName(), name);
}
return container.getInstance(converterClass, name);
}
/**
* Build converter of given type - it must be registered with {@link Container} first
*
* @param name name of converter to use
* @return instance of converterClass with inject dependencies
*/
public TypeConverter buildConverter(String name) {
if (LOG.isDebugEnabled()) {
LOG.debug("Creating converter with name [#0]", name);
}
TypeConverter instance = container.getInstance(TypeConverter.class, name);
if (LOG.isDebugEnabled()) {
LOG.debug("Converter of Type [#0] with name [#1], created!", instance.getClass().getCanonicalName(), name);
}
return instance;
}
static class ContinuationsClassLoader extends ClassLoader {
}
}
@@ -57,6 +57,14 @@ import com.opensymphony.xwork2.conversion.impl.NumberConverter;
import com.opensymphony.xwork2.conversion.impl.StringConverter;
import com.opensymphony.xwork2.conversion.impl.XWorkBasicConverter;
import com.opensymphony.xwork2.conversion.impl.XWorkConverter;
import com.opensymphony.xwork2.factory.ActionFactory;
import com.opensymphony.xwork2.factory.ConverterFactory;
import com.opensymphony.xwork2.factory.DefaultActionFactory;
import com.opensymphony.xwork2.factory.DefaultConverterFactory;
import com.opensymphony.xwork2.factory.DefaultInterceptorFactory;
import com.opensymphony.xwork2.factory.DefaultResultFactory;
import com.opensymphony.xwork2.factory.InterceptorFactory;
import com.opensymphony.xwork2.factory.ResultFactory;
import com.opensymphony.xwork2.inject.Container;
import com.opensymphony.xwork2.inject.ContainerBuilder;
import com.opensymphony.xwork2.inject.Context;
@@ -293,6 +301,13 @@ public class DefaultConfiguration implements Configuration {
}
}
builder.factory(ObjectFactory.class, Scope.SINGLETON);
builder.factory(ActionFactory.class, DefaultActionFactory.class, Scope.SINGLETON);
builder.factory(ResultFactory.class, DefaultResultFactory.class, Scope.SINGLETON);
builder.factory(InterceptorFactory.class, DefaultInterceptorFactory.class, Scope.SINGLETON);
builder.factory(com.opensymphony.xwork2.factory.ValidatorFactory.class, com.opensymphony.xwork2.factory.DefaultValidatorFactory.class, Scope.SINGLETON);
builder.factory(ConverterFactory.class, DefaultConverterFactory.class, Scope.SINGLETON);
builder.factory(FileManager.class, "system", DefaultFileManager.class, Scope.SINGLETON);
if (!fmFactoryRegistered) {
builder.factory(FileManagerFactory.class, DefaultFileManagerFactory.class, Scope.SINGLETON);
@@ -8,6 +8,7 @@ import com.opensymphony.xwork2.DefaultUnknownHandlerManager;
import com.opensymphony.xwork2.FileManager;
import com.opensymphony.xwork2.FileManagerFactory;
import com.opensymphony.xwork2.LocaleProvider;
import com.opensymphony.xwork2.ObjectFactory;
import com.opensymphony.xwork2.TextProvider;
import com.opensymphony.xwork2.TextProviderSupport;
import com.opensymphony.xwork2.UnknownHandlerManager;
@@ -36,6 +37,14 @@ import com.opensymphony.xwork2.conversion.impl.NumberConverter;
import com.opensymphony.xwork2.conversion.impl.StringConverter;
import com.opensymphony.xwork2.conversion.impl.XWorkBasicConverter;
import com.opensymphony.xwork2.conversion.impl.XWorkConverter;
import com.opensymphony.xwork2.factory.ActionFactory;
import com.opensymphony.xwork2.factory.ConverterFactory;
import com.opensymphony.xwork2.factory.DefaultActionFactory;
import com.opensymphony.xwork2.factory.DefaultConverterFactory;
import com.opensymphony.xwork2.factory.DefaultInterceptorFactory;
import com.opensymphony.xwork2.factory.DefaultResultFactory;
import com.opensymphony.xwork2.factory.InterceptorFactory;
import com.opensymphony.xwork2.factory.ResultFactory;
import com.opensymphony.xwork2.inject.ContainerBuilder;
import com.opensymphony.xwork2.inject.Scope;
import com.opensymphony.xwork2.ognl.ObjectProxy;
@@ -52,7 +61,12 @@ import com.opensymphony.xwork2.ognl.accessor.XWorkIteratorPropertyAccessor;
import com.opensymphony.xwork2.ognl.accessor.XWorkListPropertyAccessor;
import com.opensymphony.xwork2.ognl.accessor.XWorkMapPropertyAccessor;
import com.opensymphony.xwork2.ognl.accessor.XWorkMethodAccessor;
import com.opensymphony.xwork2.util.*;
import com.opensymphony.xwork2.util.CompoundRoot;
import com.opensymphony.xwork2.util.OgnlTextParser;
import com.opensymphony.xwork2.util.PatternMatcher;
import com.opensymphony.xwork2.util.TextParser;
import com.opensymphony.xwork2.util.ValueStackFactory;
import com.opensymphony.xwork2.util.WildcardHelper;
import com.opensymphony.xwork2.util.fs.DefaultFileManager;
import com.opensymphony.xwork2.util.fs.DefaultFileManagerFactory;
import com.opensymphony.xwork2.util.location.LocatableProperties;
@@ -96,7 +110,14 @@ public class XWorkConfigurationProvider implements ConfigurationProvider {
public void register(ContainerBuilder builder, LocatableProperties props)
throws ConfigurationException {
builder.factory(com.opensymphony.xwork2.ObjectFactory.class)
builder
.factory(ObjectFactory.class)
.factory(ActionFactory.class, DefaultActionFactory.class)
.factory(ResultFactory.class, DefaultResultFactory.class)
.factory(InterceptorFactory.class, DefaultInterceptorFactory.class)
.factory(com.opensymphony.xwork2.factory.ValidatorFactory.class, com.opensymphony.xwork2.factory.DefaultValidatorFactory.class)
.factory(ConverterFactory.class, DefaultConverterFactory.class)
.factory(ActionProxyFactory.class, DefaultActionProxyFactory.class, Scope.SINGLETON)
.factory(ObjectTypeDeterminer.class, DefaultObjectTypeDeterminer.class, Scope.SINGLETON)
@@ -15,10 +15,10 @@
*/
package com.opensymphony.xwork2.conversion.impl;
import com.opensymphony.xwork2.ObjectFactory;
import com.opensymphony.xwork2.XWorkConstants;
import com.opensymphony.xwork2.XWorkException;
import com.opensymphony.xwork2.conversion.TypeConverter;
import com.opensymphony.xwork2.inject.Container;
import com.opensymphony.xwork2.inject.Inject;
import java.lang.reflect.Member;
@@ -56,11 +56,11 @@ import java.util.Map;
*/
public class XWorkBasicConverter extends DefaultTypeConverter {
private ObjectFactory objectFactory;
private Container container;
@Inject
public void setObjectFactory(ObjectFactory fac) {
this.objectFactory = fac;
public void setContainer(Container container) {
this.container = container;
}
@Override
@@ -170,7 +170,7 @@ public class XWorkBasicConverter extends DefaultTypeConverter {
}
private Object doConvertToCollection(Map<String, Object> context, Object o, Member member, String prop, Object value, Class toType) {
TypeConverter converter = objectFactory.buildConverter(CollectionConverter.class);
TypeConverter converter = container.getInstance(CollectionConverter.class);
if (converter == null) {
throw new XWorkException("TypeConverter with name [#0] must be registered first!", XWorkConstants.COLLECTION_CONVERTER);
}
@@ -178,7 +178,7 @@ public class XWorkBasicConverter extends DefaultTypeConverter {
}
private Object doConvertToArray(Map<String, Object> context, Object o, Member member, String prop, Object value, Class toType) {
TypeConverter converter = objectFactory.buildConverter(ArrayConverter.class);
TypeConverter converter = container.getInstance(ArrayConverter.class);
if (converter == null) {
throw new XWorkException("TypeConverter with name [#0] must be registered first!", XWorkConstants.ARRAY_CONVERTER);
}
@@ -186,7 +186,7 @@ public class XWorkBasicConverter extends DefaultTypeConverter {
}
private Object doConvertToDate(Map<String, Object> context, Object value, Class toType) {
TypeConverter converter = objectFactory.buildConverter(DateConverter.class);
TypeConverter converter = container.getInstance(DateConverter.class);
if (converter == null) {
throw new XWorkException("TypeConverter with name [#0] must be registered first!", XWorkConstants.DATE_CONVERTER);
}
@@ -194,7 +194,7 @@ public class XWorkBasicConverter extends DefaultTypeConverter {
}
private Object doConvertToNumber(Map<String, Object> context, Object value, Class toType) {
TypeConverter converter = objectFactory.buildConverter(NumberConverter.class);
TypeConverter converter = container.getInstance(NumberConverter.class);
if (converter == null) {
throw new XWorkException("TypeConverter with name [#0] must be registered first!", XWorkConstants.NUMBER_CONVERTER);
}
@@ -202,10 +202,11 @@ public class XWorkBasicConverter extends DefaultTypeConverter {
}
private Object doConvertToString(Map<String, Object> context, Object value) {
TypeConverter converter = objectFactory.buildConverter(StringConverter.class);
TypeConverter converter = container.getInstance(StringConverter.class);
if (converter == null) {
throw new XWorkException("TypeConverter with name [#0] must be registered first!", XWorkConstants.STRING_CONVERTER);
}
return converter.convertValue(context, null, null, null, value, null);
}
}
@@ -0,0 +1,18 @@
package com.opensymphony.xwork2.factory;
import com.opensymphony.xwork2.config.entities.ActionConfig;
import java.util.Map;
/**
* Used by {@link com.opensymphony.xwork2.ObjectFactory} to build actions
*/
public interface ActionFactory {
/**
* Builds action instance
*/
Object buildAction(String actionName, String namespace, ActionConfig config, Map<String, Object> extraContext) throws Exception;
}
@@ -0,0 +1,21 @@
package com.opensymphony.xwork2.factory;
import com.opensymphony.xwork2.conversion.TypeConverter;
import java.util.Map;
/**
* Dedicated interface used by {@link com.opensymphony.xwork2.ObjectFactory} to build {@link TypeConverter}
*/
public interface ConverterFactory {
/**
* Build converter of given type
*
* @param converterClass to instantiate
* @param extraContext a Map of extra context which uses the same keys as the {@link com.opensymphony.xwork2.ActionContext}
* @return instance of converterClass with inject dependencies
*/
TypeConverter buildConverter(Class<? extends TypeConverter> converterClass, Map<String, Object> extraContext) throws Exception;
}
@@ -0,0 +1,25 @@
package com.opensymphony.xwork2.factory;
import com.opensymphony.xwork2.ObjectFactory;
import com.opensymphony.xwork2.config.entities.ActionConfig;
import com.opensymphony.xwork2.inject.Inject;
import java.util.Map;
/**
* Default implementation
*/
public class DefaultActionFactory implements ActionFactory {
private ObjectFactory objectFactory;
@Inject
public void setObjectFactory(ObjectFactory objectFactory) {
this.objectFactory = objectFactory;
}
public Object buildAction(String actionName, String namespace, ActionConfig config, Map<String, Object> extraContext) throws Exception {
return objectFactory.buildBean(config.getClassName(), extraContext);
}
}
@@ -0,0 +1,32 @@
package com.opensymphony.xwork2.factory;
import com.opensymphony.xwork2.conversion.TypeConverter;
import com.opensymphony.xwork2.inject.Container;
import com.opensymphony.xwork2.inject.Inject;
import com.opensymphony.xwork2.util.logging.Logger;
import com.opensymphony.xwork2.util.logging.LoggerFactory;
import java.util.Map;
/**
* Default implementation
*/
public class DefaultConverterFactory implements ConverterFactory {
private static final Logger LOG = LoggerFactory.getLogger(DefaultConverterFactory.class);
private Container container;
@Inject
public void setContainer(Container container) {
this.container = container;
}
public TypeConverter buildConverter(Class<? extends TypeConverter> converterClass, Map<String, Object> extraContext) throws Exception {
if (LOG.isDebugEnabled()) {
LOG.debug("Creating converter of type [#0]", converterClass.getCanonicalName());
}
return container.getInstance(converterClass);
}
}
@@ -0,0 +1,67 @@
package com.opensymphony.xwork2.factory;
import com.opensymphony.xwork2.ObjectFactory;
import com.opensymphony.xwork2.config.ConfigurationException;
import com.opensymphony.xwork2.config.entities.InterceptorConfig;
import com.opensymphony.xwork2.inject.Inject;
import com.opensymphony.xwork2.interceptor.Interceptor;
import com.opensymphony.xwork2.util.reflection.ReflectionProvider;
import java.util.HashMap;
import java.util.Map;
/**
* Default implementation
*/
public class DefaultInterceptorFactory implements InterceptorFactory {
private ObjectFactory objectFactory;
private ReflectionProvider reflectionProvider;
@Inject
public void setObjectFactory(ObjectFactory objectFactory) {
this.objectFactory = objectFactory;
}
@Inject
public void setReflectionProvider(ReflectionProvider reflectionProvider) {
this.reflectionProvider = reflectionProvider;
}
public Interceptor buildInterceptor(InterceptorConfig interceptorConfig, Map<String, String> interceptorRefParams) throws ConfigurationException {
String interceptorClassName = interceptorConfig.getClassName();
Map<String, String> thisInterceptorClassParams = interceptorConfig.getParams();
Map<String, String> params = (thisInterceptorClassParams == null) ? new HashMap<String, String>() : new HashMap<String, String>(thisInterceptorClassParams);
params.putAll(interceptorRefParams);
String message;
Throwable cause;
try {
// interceptor instances are long-lived and used across user sessions, so don't try to pass in any extra context
Interceptor interceptor = (Interceptor) objectFactory.buildBean(interceptorClassName, null);
reflectionProvider.setProperties(params, interceptor);
interceptor.init();
return interceptor;
} catch (InstantiationException e) {
cause = e;
message = "Unable to instantiate an instance of Interceptor class [" + interceptorClassName + "].";
} catch (IllegalAccessException e) {
cause = e;
message = "IllegalAccessException while attempting to instantiate an instance of Interceptor class [" + interceptorClassName + "].";
} catch (ClassCastException e) {
cause = e;
message = "Class [" + interceptorClassName + "] does not implement com.opensymphony.xwork2.interceptor.Interceptor";
} catch (Exception e) {
cause = e;
message = "Caught Exception while registering Interceptor class " + interceptorClassName;
} catch (NoClassDefFoundError e) {
cause = e;
message = "Could not load class " + interceptorClassName + ". Perhaps it exists but certain dependencies are not available?";
}
throw new ConfigurationException(message, cause, interceptorConfig);
}
}
@@ -0,0 +1,54 @@
package com.opensymphony.xwork2.factory;
import com.opensymphony.xwork2.ObjectFactory;
import com.opensymphony.xwork2.Result;
import com.opensymphony.xwork2.config.entities.ResultConfig;
import com.opensymphony.xwork2.inject.Inject;
import com.opensymphony.xwork2.util.reflection.ReflectionException;
import com.opensymphony.xwork2.util.reflection.ReflectionExceptionHandler;
import com.opensymphony.xwork2.util.reflection.ReflectionProvider;
import java.util.Map;
/**
* Default implementation
*/
public class DefaultResultFactory implements ResultFactory {
private ObjectFactory objectFactory;
private ReflectionProvider reflectionProvider;
@Inject
public void setObjectFactory(ObjectFactory objectFactory) {
this.objectFactory = objectFactory;
}
@Inject
public void setReflectionProvider(ReflectionProvider reflectionProvider) {
this.reflectionProvider = reflectionProvider;
}
public Result buildResult(ResultConfig resultConfig, Map<String, Object> extraContext) throws Exception {
String resultClassName = resultConfig.getClassName();
Result result = null;
if (resultClassName != null) {
result = (Result) objectFactory.buildBean(resultClassName, extraContext);
Map<String, String> params = resultConfig.getParams();
if (params != null) {
for (Map.Entry<String, String> paramEntry : params.entrySet()) {
try {
reflectionProvider.setProperty(paramEntry.getKey(), paramEntry.getValue(), result, extraContext, true);
} catch (ReflectionException ex) {
if (result instanceof ReflectionExceptionHandler) {
((ReflectionExceptionHandler) result).handle(ex);
}
}
}
}
}
return result;
}
}
@@ -0,0 +1,34 @@
package com.opensymphony.xwork2.factory;
import com.opensymphony.xwork2.ObjectFactory;
import com.opensymphony.xwork2.inject.Inject;
import com.opensymphony.xwork2.util.reflection.ReflectionProvider;
import com.opensymphony.xwork2.validator.Validator;
import java.util.Map;
/**
* Default implementation
*/
public class DefaultValidatorFactory implements ValidatorFactory {
private ObjectFactory objectFactory;
private ReflectionProvider reflectionProvider;
@Inject
public void setObjectFactory(ObjectFactory objectFactory) {
this.objectFactory = objectFactory;
}
@Inject
public void setReflectionProvider(ReflectionProvider reflectionProvider) {
this.reflectionProvider = reflectionProvider;
}
public Validator buildValidator(String className, Map<String, Object> params, Map<String, Object> extraContext) throws Exception {
Validator validator = (Validator) objectFactory.buildBean(className, extraContext);
reflectionProvider.setProperties(params, validator, extraContext);
return validator;
}
}
@@ -0,0 +1,28 @@
package com.opensymphony.xwork2.factory;
import com.opensymphony.xwork2.config.ConfigurationException;
import com.opensymphony.xwork2.config.entities.InterceptorConfig;
import com.opensymphony.xwork2.interceptor.Interceptor;
import java.util.Map;
/**
* Dedicated interface used by {@link com.opensymphony.xwork2.ObjectFactory} to build {@link com.opensymphony.xwork2.interceptor.Interceptor}
*/
public interface InterceptorFactory {
/**
* Builds an Interceptor from the InterceptorConfig and the Map of
* parameters from the interceptor reference. Implementations of this method
* should ensure that the Interceptor is parameterized with both the
* parameters from the Interceptor config and the interceptor ref Map (the
* interceptor ref params take precedence), and that the Interceptor.init()
* method is called on the Interceptor instance before it is returned.
*
* @param interceptorConfig the InterceptorConfig from the configuration
* @param interceptorRefParams a Map of params provided in the Interceptor reference in the
* Action mapping or InterceptorStack definition
*/
Interceptor buildInterceptor(InterceptorConfig interceptorConfig, Map<String, String> interceptorRefParams) throws ConfigurationException;
}
@@ -0,0 +1,21 @@
package com.opensymphony.xwork2.factory;
import com.opensymphony.xwork2.validator.Validator;
import java.util.Map;
/**
* Dedicated interface used by {@link com.opensymphony.xwork2.ObjectFactory} to build {@link Validator}
*/
public interface ValidatorFactory {
/**
* Build a Validator of the given type and set the parameters on it
*
* @param className the type of Validator to build
* @param params property name -> value Map to set onto the Validator instance
* @param extraContext a Map of extra context which uses the same keys as the {@link com.opensymphony.xwork2.ActionContext}
*/
Validator buildValidator(String className, Map<String, Object> params, Map<String, Object> extraContext) throws Exception;
}
@@ -5,6 +5,6 @@ package com.opensymphony.xwork2.result;
*/
public interface ParamNameAwareResult {
boolean acceptParamName(String name, String value);
boolean acceptableParameterName(String name, String value);
}
@@ -206,7 +206,7 @@ public class XWorkList extends ArrayList {
if (LOG.isDebugEnabled()) {
LOG.debug("Converting from " + element.getClass().getName() + " to " + clazz.getName());
}
TypeConverter conv = getObjectFactory().buildConverter(XWorkConverter.class);
TypeConverter conv = getTypeConverter();
Map<String, Object> context = ActionContext.getContext().getContextMap();
element = conv.convertValue(context, null, null, null, element, clazz);
}
@@ -214,6 +214,10 @@ public class XWorkList extends ArrayList {
return element;
}
private TypeConverter getTypeConverter() {
return ActionContext.getContext().getContainer().getInstance(XWorkConverter.class);
}
@Override
public boolean contains(Object element) {
element = convert(element);