You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@struts.apache.org by lu...@apache.org on 2015/06/17 23:09:48 UTC

[48/57] [partial] struts git commit: Merges xwork packages into struts

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/ValidationAware.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/ValidationAware.java b/core/src/main/java/com/opensymphony/xwork2/ValidationAware.java
new file mode 100644
index 0000000..4ae5e84
--- /dev/null
+++ b/core/src/main/java/com/opensymphony/xwork2/ValidationAware.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2002-2007,2009 The Apache Software Foundation.
+ * 
+ * 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 com.opensymphony.xwork2;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * ValidationAware classes can accept Action (class level) or field level error messages. Action level messages are kept
+ * in a Collection. Field level error messages are kept in a Map from String field name to a List of field error msgs.
+ *
+ * @author plightbo 
+ */
+public interface ValidationAware {
+
+    /**
+     * Set the Collection of Action-level String error messages.
+     *
+     * @param errorMessages Collection of String error messages
+     */
+    void setActionErrors(Collection<String> errorMessages);
+
+    /**
+     * Get the Collection of Action-level error messages for this action. Error messages should not
+     * be added directly here, as implementations are free to return a new Collection or an
+     * Unmodifiable Collection.
+     *
+     * @return Collection of String error messages
+     */
+    Collection<String> getActionErrors();
+
+    /**
+     * Set the Collection of Action-level String messages (not errors).
+     *
+     * @param messages Collection of String messages (not errors).
+     */
+    void setActionMessages(Collection<String> messages);
+
+    /**
+     * Get the Collection of Action-level messages for this action. Messages should not be added
+     * directly here, as implementations are free to return a new Collection or an Unmodifiable
+     * Collection.
+     *
+     * @return Collection of String messages
+     */
+    Collection<String> getActionMessages();
+
+    /**
+     * Set the field error map of fieldname (String) to Collection of String error messages.
+     *
+     * @param errorMap field error map
+     */
+    void setFieldErrors(Map<String, List<String>> errorMap);
+
+    /**
+     * Get the field specific errors associated with this action. Error messages should not be added
+     * directly here, as implementations are free to return a new Collection or an Unmodifiable
+     * Collection.
+     *
+     * @return Map with errors mapped from fieldname (String) to Collection of String error messages
+     */
+    Map<String, List<String>> getFieldErrors();
+
+    /**
+     * Add an Action-level error message to this Action.
+     *
+     * @param anErrorMessage  the error message
+     */
+    void addActionError(String anErrorMessage);
+
+    /**
+     * Add an Action-level message to this Action.
+     *
+     * @param aMessage  the message
+     */
+    void addActionMessage(String aMessage);
+
+    /**
+     * Add an error message for a given field.
+     *
+     * @param fieldName    name of field
+     * @param errorMessage the error message
+     */
+    void addFieldError(String fieldName, String errorMessage);
+
+    /**
+     * Check whether there are any Action-level error messages.
+     *
+     * @return true if any Action-level error messages have been registered
+     */
+    boolean hasActionErrors();
+
+    /**
+     * Checks whether there are any Action-level messages.
+     *
+     * @return true if any Action-level messages have been registered
+     */
+    boolean hasActionMessages();
+
+    /**
+     * Checks whether there are any action errors or field errors.
+     * <p/>
+     * <b>Note</b>: that this does not have the same meaning as in WW 1.x.
+     *
+     * @return <code>(hasActionErrors() || hasFieldErrors())</code>
+     */
+    boolean hasErrors();
+
+    /**
+     * Check whether there are any field errors associated with this action.
+     *
+     * @return whether there are any field errors
+     */
+    boolean hasFieldErrors();
+
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/ValidationAwareSupport.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/ValidationAwareSupport.java b/core/src/main/java/com/opensymphony/xwork2/ValidationAwareSupport.java
new file mode 100644
index 0000000..520513b
--- /dev/null
+++ b/core/src/main/java/com/opensymphony/xwork2/ValidationAwareSupport.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright 2002-2006,2009 The Apache Software Foundation.
+ * 
+ * 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 com.opensymphony.xwork2;
+
+import java.io.Serializable;
+import java.util.*;
+
+/**
+ * Provides a default implementation of ValidationAware. Returns new collections for
+ * errors and messages (defensive copy).
+ *
+ * @author Jason Carreira
+ * @author tm_jee
+ * @version $Date$ $Id$
+ */
+public class ValidationAwareSupport implements ValidationAware, Serializable {
+
+    private Collection<String> actionErrors;
+    private Collection<String> actionMessages;
+    private Map<String, List<String>> fieldErrors;
+
+
+    public synchronized void setActionErrors(Collection<String> errorMessages) {
+        this.actionErrors = errorMessages;
+    }
+
+    public synchronized Collection<String> getActionErrors() {
+        return new LinkedList<>(internalGetActionErrors());
+    }
+
+    public synchronized void setActionMessages(Collection<String> messages) {
+        this.actionMessages = messages;
+    }
+
+    public synchronized Collection<String> getActionMessages() {
+        return new LinkedList<>(internalGetActionMessages());
+    }
+
+    public synchronized void setFieldErrors(Map<String, List<String>> errorMap) {
+        this.fieldErrors = errorMap;
+    }
+
+    public synchronized Map<String, List<String>> getFieldErrors() {
+        return new LinkedHashMap<>(internalGetFieldErrors());
+    }
+
+    public synchronized void addActionError(String anErrorMessage) {
+        internalGetActionErrors().add(anErrorMessage);
+    }
+
+    public synchronized void addActionMessage(String aMessage) {
+        internalGetActionMessages().add(aMessage);
+    }
+
+    public synchronized void addFieldError(String fieldName, String errorMessage) {
+        final Map<String, List<String>> errors = internalGetFieldErrors();
+        List<String> thisFieldErrors = errors.get(fieldName);
+
+        if (thisFieldErrors == null) {
+            thisFieldErrors = new ArrayList<>();
+            errors.put(fieldName, thisFieldErrors);
+        }
+
+        thisFieldErrors.add(errorMessage);
+    }
+
+    public synchronized boolean hasActionErrors() {
+        return (actionErrors != null) && !actionErrors.isEmpty();
+    }
+
+    public synchronized boolean hasActionMessages() {
+        return (actionMessages != null) && !actionMessages.isEmpty();
+    }
+
+    public synchronized boolean hasErrors() {
+        return (hasActionErrors() || hasFieldErrors());
+    }
+
+    public synchronized boolean hasFieldErrors() {
+        return (fieldErrors != null) && !fieldErrors.isEmpty();
+    }
+
+    private Collection<String> internalGetActionErrors() {
+        if (actionErrors == null) {
+            actionErrors = new ArrayList<>();
+        }
+
+        return actionErrors;
+    }
+
+    private Collection<String> internalGetActionMessages() {
+        if (actionMessages == null) {
+            actionMessages = new ArrayList<>();
+        }
+
+        return actionMessages;
+    }
+
+    private Map<String, List<String>> internalGetFieldErrors() {
+        if (fieldErrors == null) {
+            fieldErrors = new LinkedHashMap<>();
+        }
+
+        return fieldErrors;
+    }
+
+    /**
+     * Clears field errors map.
+     * <p/>
+     * Will clear the map that contains field errors.
+     */
+    public synchronized void clearFieldErrors() {
+        internalGetFieldErrors().clear();
+    }
+
+    /**
+     * Clears action errors list.
+     * <p/>
+     * Will clear the list that contains action errors.
+     */
+    public synchronized void clearActionErrors() {
+        internalGetActionErrors().clear();
+    }
+
+    /**
+     * Clears messages list.
+     * <p/>
+     * Will clear the list that contains action messages.
+     */
+    public synchronized void clearMessages() {
+        internalGetActionMessages().clear();
+    }
+
+    /**
+     * Clears all error list/maps.
+     * <p/>
+     * Will clear the map and list that contain
+     * field errors and action errors.
+     */
+    public synchronized void clearErrors() {
+        internalGetFieldErrors().clear();
+        internalGetActionErrors().clear();
+    }
+
+    /**
+     * Clears all error and messages list/maps.
+     * <p/>
+     * Will clear the maps/lists that contain
+     * field errors, action errors and action messages.
+     */
+    public synchronized void clearErrorsAndMessages() {
+        internalGetFieldErrors().clear();
+        internalGetActionErrors().clear();
+        internalGetActionMessages().clear();
+    }
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/XWork.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/XWork.java b/core/src/main/java/com/opensymphony/xwork2/XWork.java
new file mode 100644
index 0000000..fddc75b
--- /dev/null
+++ b/core/src/main/java/com/opensymphony/xwork2/XWork.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2002-2006,2009 The Apache Software Foundation.
+ * 
+ * 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 com.opensymphony.xwork2;
+
+import com.opensymphony.xwork2.config.Configuration;
+import com.opensymphony.xwork2.config.ConfigurationManager;
+import com.opensymphony.xwork2.util.logging.LoggerFactory;
+
+import java.util.Collections;
+import java.util.Map;
+
+/**
+ * Simple facade to make using XWork standalone easier
+ */
+public class XWork {
+    
+    ConfigurationManager configurationManager;
+    
+    public XWork() {
+        this(new ConfigurationManager());
+    }
+    
+    public XWork(ConfigurationManager mgr) {
+        this.configurationManager = mgr;
+    }
+    
+    public void setLoggerFactory(LoggerFactory factory) {
+        LoggerFactory.setLoggerFactory(factory);
+    }
+    
+    /**
+     * Executes an action
+     * 
+     * @param namespace The namespace
+     * @param name The action name
+     * @param method The method name
+     * @throws Exception If anything goes wrong
+     */
+    public void executeAction(String namespace, String name, String method) throws XWorkException {
+        Map<String, Object> extraContext = Collections.emptyMap();
+        executeAction(namespace, name, method, extraContext);
+    }
+    
+    /**
+     * Executes an action with extra context information
+     * 
+     * @param namespace The namespace
+     * @param name The action name
+     * @param method The method name
+     * @param extraContext A map of extra context information
+     * @throws Exception If anything goes wrong
+     */
+    public void executeAction(String namespace, String name, String method, Map<String, Object> extraContext) throws XWorkException {
+        Configuration config = configurationManager.getConfiguration();
+        try {
+            ActionProxy proxy = config.getContainer().getInstance(ActionProxyFactory.class).createActionProxy(
+                    namespace, name, method, extraContext, true, false);
+        
+            proxy.execute();
+        } catch (Exception e) {
+            throw new XWorkException(e);
+        } finally {
+            ActionContext.setContext(null);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/XWorkConstants.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/XWorkConstants.java b/core/src/main/java/com/opensymphony/xwork2/XWorkConstants.java
new file mode 100644
index 0000000..433b005
--- /dev/null
+++ b/core/src/main/java/com/opensymphony/xwork2/XWorkConstants.java
@@ -0,0 +1,30 @@
+package com.opensymphony.xwork2;
+
+/**
+ * Constants used across framework
+ */
+public final class XWorkConstants {
+
+    public static final String COLLECTION_CONVERTER = "collectionConverter";
+    public static final String DATE_CONVERTER = "dateConverter";
+    public static final String NUMBER_CONVERTER = "numberConverter";
+    public static final String STRING_CONVERTER = "stringConverter";
+    public static final String ARRAY_CONVERTER = "arrayConverter";
+    public static final String DEV_MODE = "devMode";
+    public static final String LOG_MISSING_PROPERTIES = "logMissingProperties";
+    public static final String ENABLE_OGNL_EXPRESSION_CACHE = "enableOGNLExpressionCache";
+    public static final String ENABLE_OGNL_EVAL_EXPRESSION = "enableOGNLEvalExpression";
+    public static final String RELOAD_XML_CONFIGURATION = "reloadXmlConfiguration";
+    public static final String ALLOW_STATIC_METHOD_ACCESS = "allowStaticMethodAccess";
+    public static final String XWORK_LOGGER_FACTORY = "xwork.loggerFactory";
+
+    public static final String OGNL_EXCLUDED_CLASSES = "ognlExcludedClasses";
+    public static final String OGNL_EXCLUDED_PACKAGE_NAME_PATTERNS = "ognlExcludedPackageNamePatterns";
+
+    public static final String ADDITIONAL_EXCLUDED_PATTERNS = "additionalExcludedPatterns";
+    public static final String ADDITIONAL_ACCEPTED_PATTERNS = "additionalAcceptedPatterns";
+
+    public static final String OVERRIDE_EXCLUDED_PATTERNS = "overrideExcludedPatterns";
+    public static final String OVERRIDE_ACCEPTED_PATTERNS = "overrideAcceptedPatterns";
+
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/XWorkException.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/XWorkException.java b/core/src/main/java/com/opensymphony/xwork2/XWorkException.java
new file mode 100644
index 0000000..8445a1c
--- /dev/null
+++ b/core/src/main/java/com/opensymphony/xwork2/XWorkException.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright 2002-2007,2009 The Apache Software Foundation.
+ * 
+ * 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 com.opensymphony.xwork2;
+
+import com.opensymphony.xwork2.util.location.Locatable;
+import com.opensymphony.xwork2.util.location.Location;
+import com.opensymphony.xwork2.util.location.LocationUtils;
+
+
+/**
+ * A generic runtime exception that optionally contains Location information 
+ *
+ * @author Jason Carreira
+ */
+public class XWorkException extends RuntimeException implements Locatable {
+
+    private Location location;
+
+
+    /**
+     * Constructs a <code>XWorkException</code> with no detail message.
+     */
+    public XWorkException() {
+    }
+
+    /**
+     * Constructs a <code>XWorkException</code> with the specified
+     * detail message.
+     *
+     * @param s the detail message.
+     */
+    public XWorkException(String s) {
+        this(s, null, null);
+    }
+    
+    /**
+     * Constructs a <code>XWorkException</code> with the specified
+     * detail message and target.
+     *
+     * @param s the detail message.
+     * @param target the target of the exception.
+     */
+    public XWorkException(String s, Object target) {
+        this(s, null, target);
+    }
+
+    /**
+     * Constructs a <code>XWorkException</code> with the root cause
+     *
+     * @param cause The wrapped exception
+     */
+    public XWorkException(Throwable cause) {
+        this(null, cause, null);
+    }
+    
+    /**
+     * Constructs a <code>XWorkException</code> with the root cause and target
+     *
+     * @param cause The wrapped exception
+     * @param target The target of the exception
+     */
+    public XWorkException(Throwable cause, Object target) {
+        this(null, cause, target);
+    }
+
+    /**
+     * Constructs a <code>XWorkException</code> with the specified
+     * detail message and exception cause.
+     *
+     * @param s the detail message.
+     * @param cause the wrapped exception
+     */
+    public XWorkException(String s, Throwable cause) {
+        this(s, cause, null);
+    }
+    
+    
+     /**
+     * Constructs a <code>XWorkException</code> with the specified
+     * detail message, cause, and target
+     *
+     * @param s the detail message.
+     * @param cause The wrapped exception
+     * @param target The target of the exception
+     */
+    public XWorkException(String s, Throwable cause, Object target) {
+        super(s, cause);
+        
+        this.location = LocationUtils.getLocation(target);
+        if (this.location == Location.UNKNOWN) {
+            this.location = LocationUtils.getLocation(cause);
+        }
+    }
+
+
+    /**
+     * Gets the underlying cause
+     * 
+     * @return the underlying cause, <tt>null</tt> if no cause
+     * @deprecated Use {@link #getCause()} 
+     */
+    @Deprecated public Throwable getThrowable() {
+        return getCause();
+    }
+
+
+    /**
+     * Gets the location of the error, if available
+     *
+     * @return the location, <tt>null</tt> if not available 
+     */
+    public Location getLocation() {
+        return this.location;
+    }
+    
+    
+    /**
+     * Returns a short description of this throwable object, including the 
+     * location. If no detailed message is available, it will use the message
+     * of the underlying exception if available.
+     *
+     * @return a string representation of this <code>Throwable</code>.
+     */
+    @Override
+    public String toString() {
+        String msg = getMessage();
+        if (msg == null && getCause() != null) {
+            msg = getCause().getMessage();
+        }
+
+        if (location != null) {
+            if (msg != null) {
+                return msg + " - " + location.toString();
+            } else {
+                return location.toString();
+            }
+        } else {
+            return msg;
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/XWorkJUnit4TestCase.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/XWorkJUnit4TestCase.java b/core/src/main/java/com/opensymphony/xwork2/XWorkJUnit4TestCase.java
new file mode 100644
index 0000000..90b53d2
--- /dev/null
+++ b/core/src/main/java/com/opensymphony/xwork2/XWorkJUnit4TestCase.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2002-2006,2009 The Apache Software Foundation.
+ *
+ * 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 com.opensymphony.xwork2;
+
+import com.opensymphony.xwork2.config.Configuration;
+import com.opensymphony.xwork2.config.ConfigurationException;
+import com.opensymphony.xwork2.config.ConfigurationManager;
+import com.opensymphony.xwork2.config.ConfigurationProvider;
+import com.opensymphony.xwork2.inject.*;
+import com.opensymphony.xwork2.test.StubConfigurationProvider;
+import com.opensymphony.xwork2.util.XWorkTestCaseHelper;
+import com.opensymphony.xwork2.util.location.LocatableProperties;
+import org.junit.After;
+import org.junit.Before;
+
+public abstract class XWorkJUnit4TestCase {
+
+    protected ConfigurationManager configurationManager;
+    protected Configuration configuration;
+    protected Container container;
+    protected ActionProxyFactory actionProxyFactory;
+
+    @Before
+    public void setUp() throws Exception {
+        configurationManager = XWorkTestCaseHelper.setUp();
+        configuration = configurationManager.getConfiguration();
+        container = configuration.getContainer();
+        actionProxyFactory = container.getInstance(ActionProxyFactory.class);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        XWorkTestCaseHelper.tearDown(configurationManager);
+        configurationManager = null;
+        configuration = null;
+        container = null;
+        actionProxyFactory = null;
+    }
+
+    protected void loadConfigurationProviders(ConfigurationProvider... providers) {
+        configurationManager = XWorkTestCaseHelper.loadConfigurationProviders(configurationManager, providers);
+        configuration = configurationManager.getConfiguration();
+        container = configuration.getContainer();
+        actionProxyFactory = container.getInstance(ActionProxyFactory.class);
+    }
+
+    protected void loadButAdd(final Class<?> type, final Object impl) {
+        loadButAdd(type, Container.DEFAULT_NAME, impl);
+    }
+
+    protected void loadButAdd(final Class<?> type, final String name, final Object impl) {
+        loadConfigurationProviders(new StubConfigurationProvider() {
+            @Override
+            public void register(ContainerBuilder builder,
+                                 LocatableProperties props) throws ConfigurationException {
+                builder.factory(type, name, new Factory() {
+                    public Object create(Context context) throws Exception {
+                        return impl;
+                    }
+
+                }, Scope.SINGLETON);
+            }
+        });
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/XWorkMessages.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/XWorkMessages.java b/core/src/main/java/com/opensymphony/xwork2/XWorkMessages.java
new file mode 100644
index 0000000..d187acc
--- /dev/null
+++ b/core/src/main/java/com/opensymphony/xwork2/XWorkMessages.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2002-2006,2009 The Apache Software Foundation.
+ * 
+ * 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 com.opensymphony.xwork2;
+
+
+/**
+ * Contains constants for some default XWork messages.
+ *
+ * @author Jason Carreira
+ */
+public interface XWorkMessages {
+
+    public static final String ACTION_EXECUTION_ERROR             = "xwork.error.action.execution";
+    public static final String MISSING_ACTION_EXCEPTION           = "xwork.exception.missing-action";
+    public static final String MISSING_PACKAGE_ACTION_EXCEPTION   = "xwork.exception.missing-package-action";
+    public static final String DEFAULT_INVALID_FIELDVALUE         = "xwork.default.invalid.fieldvalue";
+
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/XWorkTestCase.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/XWorkTestCase.java b/core/src/main/java/com/opensymphony/xwork2/XWorkTestCase.java
new file mode 100644
index 0000000..c9b4e32
--- /dev/null
+++ b/core/src/main/java/com/opensymphony/xwork2/XWorkTestCase.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2002-2006,2009 The Apache Software Foundation.
+ * 
+ * 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 com.opensymphony.xwork2;
+
+import com.opensymphony.xwork2.config.Configuration;
+import com.opensymphony.xwork2.config.ConfigurationException;
+import com.opensymphony.xwork2.config.ConfigurationManager;
+import com.opensymphony.xwork2.config.ConfigurationProvider;
+import com.opensymphony.xwork2.inject.*;
+import com.opensymphony.xwork2.test.StubConfigurationProvider;
+import com.opensymphony.xwork2.util.XWorkTestCaseHelper;
+import com.opensymphony.xwork2.util.location.LocatableProperties;
+import junit.framework.TestCase;
+
+
+/**
+ * Base JUnit TestCase to extend for XWork specific JUnit tests. Uses 
+ * the generic test setup for logic.
+ *
+ * @author plightbo
+ */
+public abstract class XWorkTestCase extends TestCase {
+    
+    protected ConfigurationManager configurationManager;
+    protected Configuration configuration;
+    protected Container container;
+    protected ActionProxyFactory actionProxyFactory;
+    
+    public XWorkTestCase() {
+        super();
+    }
+    
+    @Override
+    protected void setUp() throws Exception {
+        configurationManager = XWorkTestCaseHelper.setUp();
+        configuration = configurationManager.getConfiguration();
+        container = configuration.getContainer();
+        actionProxyFactory = container.getInstance(ActionProxyFactory.class);
+    }
+    
+    @Override
+    protected void tearDown() throws Exception {
+        XWorkTestCaseHelper.tearDown(configurationManager);
+        configurationManager = null;
+        configuration = null;
+        container = null;
+        actionProxyFactory = null;
+    }
+    
+    protected void loadConfigurationProviders(ConfigurationProvider... providers) {
+        configurationManager = XWorkTestCaseHelper.loadConfigurationProviders(configurationManager, providers);
+        configuration = configurationManager.getConfiguration();
+        container = configuration.getContainer();
+        actionProxyFactory = container.getInstance(ActionProxyFactory.class);
+    }
+    
+    protected void loadButAdd(final Class<?> type, final Object impl) {
+        loadButAdd(type, Container.DEFAULT_NAME, impl);
+    }
+    
+    protected void loadButAdd(final Class<?> type, final String name, final Object impl) {
+        loadConfigurationProviders(new StubConfigurationProvider() {
+            @Override
+            public void register(ContainerBuilder builder,
+                    LocatableProperties props) throws ConfigurationException {
+                builder.factory(type, name, new Factory() {
+                    public Object create(Context context) throws Exception {
+                        return impl;
+                    }
+                    
+                }, Scope.SINGLETON);
+            }
+        });
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/config/BeanSelectionProvider.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/config/BeanSelectionProvider.java b/core/src/main/java/com/opensymphony/xwork2/config/BeanSelectionProvider.java
new file mode 100644
index 0000000..d6cef8b
--- /dev/null
+++ b/core/src/main/java/com/opensymphony/xwork2/config/BeanSelectionProvider.java
@@ -0,0 +1,8 @@
+package com.opensymphony.xwork2.config;
+
+/**
+ * When implemented allows to alias already existing beans
+ */
+public interface BeanSelectionProvider extends ConfigurationProvider {
+
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/config/Configuration.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/config/Configuration.java b/core/src/main/java/com/opensymphony/xwork2/config/Configuration.java
new file mode 100644
index 0000000..be1359d
--- /dev/null
+++ b/core/src/main/java/com/opensymphony/xwork2/config/Configuration.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2002-2006,2009 The Apache Software Foundation.
+ * 
+ * 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 com.opensymphony.xwork2.config;
+
+import com.opensymphony.xwork2.config.entities.PackageConfig;
+import com.opensymphony.xwork2.config.entities.UnknownHandlerConfig;
+import com.opensymphony.xwork2.inject.Container;
+
+import java.io.Serializable;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+
+/**
+ * XWork configuration.
+ *
+ * @author Mike
+ */
+public interface Configuration extends Serializable {
+
+    void rebuildRuntimeConfiguration();
+
+    PackageConfig getPackageConfig(String name);
+
+    Set<String> getPackageConfigNames();
+
+    Map<String, PackageConfig> getPackageConfigs();
+
+    /**
+     * The current runtime configuration. Currently, if changes have been made to the Configuration since the last
+     * time buildRuntimeConfiguration() was called, you'll need to make sure to.
+     *
+     * @return the current runtime configuration
+     */
+    RuntimeConfiguration getRuntimeConfiguration();
+
+    void addPackageConfig(String name, PackageConfig packageConfig);
+
+    /**
+     * Removes a package from the the list of packages. Changes to the configuration won't take effect until buildRuntimeConfiguration
+     * is called.
+     * @param packageName the name of the package to remove
+     * @return the package removed (if any)
+     */
+    PackageConfig removePackageConfig(String packageName);
+
+    /**
+     * Allow the Configuration to clean up any resources that have been used.
+     */
+    void destroy();
+
+    /**
+     * @deprecated Since 2.1
+     * @param providers
+     * @throws ConfigurationException
+     */
+    @Deprecated void reload(List<ConfigurationProvider> providers) throws ConfigurationException;
+    
+    /**
+     * @since 2.1
+     * @param containerProviders
+     * @throws ConfigurationException
+     */
+    List<PackageProvider> reloadContainer(List<ContainerProvider> containerProviders) throws ConfigurationException;
+
+    /**
+     * @return the container
+     */
+    Container getContainer();
+
+    Set<String> getLoadedFileNames();
+
+    /**
+     * @since 2.1
+     * @return list of unknown handlers
+     */
+    List<UnknownHandlerConfig> getUnknownHandlerStack();
+
+    /**
+     * @since 2.1
+     * @param unknownHandlerStack
+     */
+    void setUnknownHandlerStack(List<UnknownHandlerConfig> unknownHandlerStack);
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/config/ConfigurationException.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/config/ConfigurationException.java b/core/src/main/java/com/opensymphony/xwork2/config/ConfigurationException.java
new file mode 100644
index 0000000..fcbb11b
--- /dev/null
+++ b/core/src/main/java/com/opensymphony/xwork2/config/ConfigurationException.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2002-2006,2009 The Apache Software Foundation.
+ * 
+ * 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 com.opensymphony.xwork2.config;
+
+import com.opensymphony.xwork2.XWorkException;
+
+
+/**
+ * ConfigurationException
+ *
+ * @author Jason Carreira
+ */
+public class ConfigurationException extends XWorkException {
+
+    /**
+     * Constructs a <code>ConfigurationException</code> with no detail message.
+     */
+    public ConfigurationException() {
+    }
+
+    /**
+     * Constructs a <code>ConfigurationException</code> with the specified
+     * detail message.
+     *
+     * @param s the detail message.
+     */
+    public ConfigurationException(String s) {
+        super(s);
+    }
+    
+    /**
+     * Constructs a <code>ConfigurationException</code> with the specified
+     * detail message.
+     *
+     * @param s the detail message.
+     */
+    public ConfigurationException(String s, Object target) {
+        super(s, target);
+    }
+
+    /**
+     * Constructs a <code>ConfigurationException</code> with no detail message.
+     */
+    public ConfigurationException(Throwable cause) {
+        super(cause);
+    }
+    
+    /**
+     * Constructs a <code>ConfigurationException</code> with no detail message.
+     */
+    public ConfigurationException(Throwable cause, Object target) {
+        super(cause, target);
+    }
+
+    /**
+     * Constructs a <code>ConfigurationException</code> with the specified
+     * detail message.
+     *
+     * @param s the detail message.
+     */
+    public ConfigurationException(String s, Throwable cause) {
+        super(s, cause);
+    }
+    
+    /**
+     * Constructs a <code>ConfigurationException</code> with the specified
+     * detail message.
+     *
+     * @param s the detail message.
+     */
+    public ConfigurationException(String s, Throwable cause, Object target) {
+        super(s, cause, target);
+    }
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/config/ConfigurationManager.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/config/ConfigurationManager.java b/core/src/main/java/com/opensymphony/xwork2/config/ConfigurationManager.java
new file mode 100644
index 0000000..38920f7
--- /dev/null
+++ b/core/src/main/java/com/opensymphony/xwork2/config/ConfigurationManager.java
@@ -0,0 +1,232 @@
+/*
+ * Copyright 2002-2006,2009 The Apache Software Foundation.
+ * 
+ * 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 com.opensymphony.xwork2.config;
+
+import com.opensymphony.xwork2.XWorkConstants;
+import com.opensymphony.xwork2.config.impl.DefaultConfiguration;
+import com.opensymphony.xwork2.config.providers.XWorkConfigurationProvider;
+import com.opensymphony.xwork2.config.providers.XmlConfigurationProvider;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+
+/**
+ * ConfigurationManager - central for XWork Configuration management, including
+ * its ConfigurationProvider.
+ *
+ * @author Jason Carreira
+ * @author tm_jee
+ * @version $Date$ $Id$
+ */
+public class ConfigurationManager {
+
+    protected static final Logger LOG = LogManager.getLogger(ConfigurationManager.class);
+    protected Configuration configuration;
+    protected Lock providerLock = new ReentrantLock();
+    private List<ContainerProvider> containerProviders = new CopyOnWriteArrayList<>();
+    private List<PackageProvider> packageProviders = new CopyOnWriteArrayList<>();
+    protected String defaultFrameworkBeanName;
+    private boolean providersChanged = false;
+    private boolean reloadConfigs = true; // for the first time
+
+    public ConfigurationManager() {
+        this("xwork");
+    }
+    
+    public ConfigurationManager(String name) {
+        this.defaultFrameworkBeanName = name;
+    }
+
+    /**
+     * Get the current XWork configuration object.  By default an instance of DefaultConfiguration will be returned
+     *
+     * @see com.opensymphony.xwork2.config.impl.DefaultConfiguration
+     */
+    public synchronized Configuration getConfiguration() {
+        if (configuration == null) {
+            setConfiguration(createConfiguration(defaultFrameworkBeanName));
+            try {
+                configuration.reloadContainer(getContainerProviders());
+            } catch (ConfigurationException e) {
+                setConfiguration(null);
+                throw new ConfigurationException("Unable to load configuration.", e);
+            }
+        } else {
+            conditionalReload();
+        }
+
+        return configuration;
+    }
+
+    protected Configuration createConfiguration(String beanName) {
+        return new DefaultConfiguration(beanName);
+    }
+
+    public synchronized void setConfiguration(Configuration configuration) {
+        this.configuration = configuration;
+    }
+
+    /**
+     * Get the current list of ConfigurationProviders. If no custom ConfigurationProviders have been added, this method
+     * will return a list containing only the default ConfigurationProvider, XMLConfigurationProvider.  if a custom
+     * ConfigurationProvider has been added, then the XmlConfigurationProvider must be added by hand.
+     * </p>
+     * <p/>
+     * TODO: the lazy instantiation of XmlConfigurationProvider should be refactored to be elsewhere.  the behavior described above seems unintuitive.
+     *
+     * @return the list of registered ConfigurationProvider objects
+     * @see ConfigurationProvider
+     */
+    public List<ContainerProvider> getContainerProviders() {
+        providerLock.lock();
+        try {
+            if (containerProviders.size() == 0) {
+                containerProviders.add(new XWorkConfigurationProvider());
+                containerProviders.add(new XmlConfigurationProvider("xwork.xml", false));
+            }
+
+            return containerProviders;
+        } finally {
+            providerLock.unlock();
+        }
+    }
+
+    /**
+     * Set the list of configuration providers
+     *
+     * @param containerProviders list of {@link ConfigurationProvider} to be set
+     */
+    public void setContainerProviders(List<ContainerProvider> containerProviders) {
+        providerLock.lock();
+        try {
+            this.containerProviders = new CopyOnWriteArrayList<>(containerProviders);
+            providersChanged = true;
+        } finally {
+            providerLock.unlock();
+        }
+    }
+
+    /**
+     * adds a configuration provider to the List of ConfigurationProviders.  a given ConfigurationProvider may be added
+     * more than once
+     *
+     * @param provider the ConfigurationProvider to register
+     */
+    public void addContainerProvider(ContainerProvider provider) {
+        if (!containerProviders.contains(provider)) {
+            containerProviders.add(provider);
+            providersChanged = true;
+        }
+    }
+
+    public void clearContainerProviders() {
+        for (ContainerProvider containerProvider : containerProviders) {
+            clearContainerProvider(containerProvider);
+        }
+        containerProviders.clear();
+        providersChanged = true;
+    }
+
+    private void clearContainerProvider(ContainerProvider containerProvider) {
+        try {
+            containerProvider.destroy();
+        } catch (Exception e) {
+            LOG.warn("Error while destroying container provider [{}]", containerProvider.toString(), e);
+        }
+    }
+
+    /**
+     * Destroy its managing Configuration instance
+     */
+    public synchronized void destroyConfiguration() {
+        clearContainerProviders(); // let's destroy the ConfigurationProvider first
+        containerProviders = new CopyOnWriteArrayList<ContainerProvider>();
+        if (configuration != null)
+            configuration.destroy(); // let's destroy it first, before nulling it.
+        configuration = null;
+    }
+
+
+    /**
+     * Reloads the Configuration files if the configuration files indicate that they need to be reloaded.
+     */
+    public synchronized void conditionalReload() {
+        if (reloadConfigs || providersChanged) {
+            LOG.debug("Checking ConfigurationProviders for reload.");
+            List<ContainerProvider> providers = getContainerProviders();
+            boolean reload = needReloadContainerProviders(providers);
+            if (!reload) {
+                reload = needReloadPackageProviders();
+            }
+            if (reload) {
+                reloadProviders(providers);
+            }
+            updateReloadConfigsFlag();
+            providersChanged = false;
+        }
+    }
+
+    private void updateReloadConfigsFlag() {
+        reloadConfigs = Boolean.parseBoolean(configuration.getContainer().getInstance(String.class, XWorkConstants.RELOAD_XML_CONFIGURATION));
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("Updating [{}], current value is [{}], new value [{}]",
+                    XWorkConstants.RELOAD_XML_CONFIGURATION, String.valueOf(reloadConfigs), String.valueOf(reloadConfigs));
+        }
+    }
+
+    private boolean needReloadPackageProviders() {
+        if (packageProviders != null) {
+            for (PackageProvider provider : packageProviders) {
+                if (provider.needsReload()) {
+                    LOG.info("Detected package provider [{}] needs to be reloaded. Reloading all providers.", provider);
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    private boolean needReloadContainerProviders(List<ContainerProvider> providers) {
+        for (ContainerProvider provider : providers) {
+            if (provider.needsReload()) {
+                LOG.info("Detected container provider [{}] needs to be reloaded. Reloading all providers.", provider);
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private void reloadProviders(List<ContainerProvider> providers) {
+        for (ContainerProvider containerProvider : containerProviders) {
+            try {
+                containerProvider.destroy();
+            } catch (Exception e) {
+                LOG.warn("error while destroying configuration provider [{}]", containerProvider, e);
+            }
+        }
+        packageProviders = this.configuration.reloadContainer(providers);
+    }
+
+    public synchronized void reload() {
+        packageProviders = getConfiguration().reloadContainer(getContainerProviders());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/config/ConfigurationProvider.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/config/ConfigurationProvider.java b/core/src/main/java/com/opensymphony/xwork2/config/ConfigurationProvider.java
new file mode 100644
index 0000000..146532b
--- /dev/null
+++ b/core/src/main/java/com/opensymphony/xwork2/config/ConfigurationProvider.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2002-2006,2009 The Apache Software Foundation.
+ * 
+ * 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 com.opensymphony.xwork2.config;
+
+/**
+ * Interface to be implemented by all forms of XWork configuration classes.
+ */
+public interface ConfigurationProvider extends ContainerProvider, PackageProvider {
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/config/ConfigurationUtil.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/config/ConfigurationUtil.java b/core/src/main/java/com/opensymphony/xwork2/config/ConfigurationUtil.java
new file mode 100644
index 0000000..e7ba7a6
--- /dev/null
+++ b/core/src/main/java/com/opensymphony/xwork2/config/ConfigurationUtil.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2002-2006,2009 The Apache Software Foundation.
+ * 
+ * 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 com.opensymphony.xwork2.config;
+
+import com.opensymphony.xwork2.config.entities.PackageConfig;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.StringTokenizer;
+
+/**
+ * ConfigurationUtil
+ * 
+ * @author Jason Carreira Created May 23, 2003 11:22:49 PM
+ */
+public class ConfigurationUtil {
+
+    private static final Logger LOG = LogManager.getLogger(ConfigurationUtil.class);
+
+    private ConfigurationUtil() {
+    }
+
+    /**
+     * Get the {@link PackageConfig} elements with the specified names.
+     * @param configuration Configuration from which to find the package elements
+     * @param parent Comma separated list of parent package names
+     * @return The package elements that correspond to the names in the {@code parent} parameter.
+     */
+    public static List<PackageConfig> buildParentsFromString(Configuration configuration, String parent) {
+        List<String> parentPackageNames = buildParentListFromString(parent);
+        List<PackageConfig> parentPackageConfigs = new ArrayList<>();
+        for (String parentPackageName : parentPackageNames) {
+            PackageConfig parentPackageContext = configuration.getPackageConfig(parentPackageName);
+
+            if (parentPackageContext != null) {
+                parentPackageConfigs.add(parentPackageContext);
+            }
+        }
+
+        return parentPackageConfigs;
+    }
+
+    /**
+     * Splits the string into a list using a comma as the token separator.
+     * @param parent The comma separated string.
+     * @return A list of tokens from the specified string.
+     */
+    public static List<String> buildParentListFromString(String parent) {
+        if (StringUtils.isEmpty(parent)) {
+            return Collections.emptyList();
+        }
+
+        StringTokenizer tokenizer = new StringTokenizer(parent, ",");
+        List<String> parents = new ArrayList<>();
+
+        while (tokenizer.hasMoreTokens()) {
+            String parentName = tokenizer.nextToken().trim();
+
+            if (StringUtils.isNotEmpty(parentName)) {
+                parents.add(parentName);
+            }
+        }
+
+        return parents;
+    }
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/config/ContainerProvider.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/config/ContainerProvider.java b/core/src/main/java/com/opensymphony/xwork2/config/ContainerProvider.java
new file mode 100644
index 0000000..de943f0
--- /dev/null
+++ b/core/src/main/java/com/opensymphony/xwork2/config/ContainerProvider.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2002-2006,2009 The Apache Software Foundation.
+ * 
+ * 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 com.opensymphony.xwork2.config;
+
+import com.opensymphony.xwork2.inject.ContainerBuilder;
+import com.opensymphony.xwork2.util.location.LocatableProperties;
+
+
+/**
+ * Provides beans and constants/properties for the Container
+ * 
+ * @since 2.1
+ */
+public interface ContainerProvider {
+
+    /**
+     * Called before removed from the configuration manager
+     */
+    public void destroy();
+    
+    /**
+     * Initializes with the configuration
+     * @param configuration The configuration
+     * @throws ConfigurationException If anything goes wrong
+     */
+    public void init(Configuration configuration) throws ConfigurationException;
+    
+    /**
+     * Tells whether the ContainerProvider should reload its configuration
+     *
+     * @return <tt>true</tt>, whether the ContainerProvider should reload its configuration, <tt>false</tt>otherwise.
+     */
+    public boolean needsReload();
+    
+    /**
+     * Registers beans and properties for the Container
+     * 
+     * @param builder The builder to register beans with
+     * @param props The properties to register constants with
+     * @throws ConfigurationException If anything goes wrong
+     */
+    public void register(ContainerBuilder builder, LocatableProperties props) throws ConfigurationException;
+    
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/config/FileManagerFactoryProvider.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/config/FileManagerFactoryProvider.java b/core/src/main/java/com/opensymphony/xwork2/config/FileManagerFactoryProvider.java
new file mode 100644
index 0000000..392b138
--- /dev/null
+++ b/core/src/main/java/com/opensymphony/xwork2/config/FileManagerFactoryProvider.java
@@ -0,0 +1,33 @@
+package com.opensymphony.xwork2.config;
+
+import com.opensymphony.xwork2.FileManagerFactory;
+import com.opensymphony.xwork2.inject.ContainerBuilder;
+import com.opensymphony.xwork2.inject.Scope;
+import com.opensymphony.xwork2.util.location.LocatableProperties;
+
+/**
+ * Allows to specify custom {@link FileManagerFactory}
+ */
+public class FileManagerFactoryProvider implements ContainerProvider {
+
+    private Class<? extends FileManagerFactory> factoryClass;
+
+    public FileManagerFactoryProvider(Class<? extends FileManagerFactory> factoryClass) {
+        this.factoryClass = factoryClass;
+    }
+
+    public void destroy() {
+    }
+
+    public void init(Configuration configuration) throws ConfigurationException {
+    }
+
+    public boolean needsReload() {
+        return false;
+    }
+
+    public void register(ContainerBuilder builder, LocatableProperties props) throws ConfigurationException {
+        builder.factory(FileManagerFactory.class, factoryClass.getSimpleName(), factoryClass, Scope.SINGLETON);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/config/FileManagerProvider.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/config/FileManagerProvider.java b/core/src/main/java/com/opensymphony/xwork2/config/FileManagerProvider.java
new file mode 100644
index 0000000..100f458
--- /dev/null
+++ b/core/src/main/java/com/opensymphony/xwork2/config/FileManagerProvider.java
@@ -0,0 +1,35 @@
+package com.opensymphony.xwork2.config;
+
+import com.opensymphony.xwork2.FileManager;
+import com.opensymphony.xwork2.inject.ContainerBuilder;
+import com.opensymphony.xwork2.inject.Scope;
+import com.opensymphony.xwork2.util.location.LocatableProperties;
+
+/**
+ * Allows to specify custom {@link FileManager} by user
+ */
+public class FileManagerProvider implements ContainerProvider {
+
+    private Class<? extends FileManager> fileManagerClass;
+    private String name;
+
+    public FileManagerProvider(Class<? extends FileManager> fileManagerClass, String name) {
+        this.fileManagerClass = fileManagerClass;
+        this.name = name;
+    }
+
+    public void destroy() {
+    }
+
+    public void init(Configuration configuration) throws ConfigurationException {
+    }
+
+    public boolean needsReload() {
+        return false;
+    }
+
+    public void register(ContainerBuilder builder, LocatableProperties props) throws ConfigurationException {
+        builder.factory(FileManager.class, name, fileManagerClass, Scope.SINGLETON);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/config/PackageProvider.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/config/PackageProvider.java b/core/src/main/java/com/opensymphony/xwork2/config/PackageProvider.java
new file mode 100644
index 0000000..dd0dfae
--- /dev/null
+++ b/core/src/main/java/com/opensymphony/xwork2/config/PackageProvider.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2002-2006,2009 The Apache Software Foundation.
+ * 
+ * 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 com.opensymphony.xwork2.config;
+
+/**
+ * Provides configuration packages.  The separate init and loadPackages calls are due to the need to 
+ * preserve backwards compatibility with the 2.0 {@link ConfigurationProvider} interface
+ * 
+ * @since 2.1
+ */
+public interface PackageProvider {
+    
+    /**
+     * Initializes with the configuration
+     * @param configuration The configuration
+     * @throws ConfigurationException If anything goes wrong
+     */
+    public void init(Configuration configuration) throws ConfigurationException;
+    
+    /**
+     * Tells whether the PackageProvider should reload its configuration
+     *
+     * @return <tt>true</tt>, whether the PackageProvider should reload its configuration, <tt>false</tt>otherwise.
+     */
+    public boolean needsReload();
+
+    /**
+     * Loads the packages for the configuration.
+     * @throws ConfigurationException
+     */
+    public void loadPackages() throws ConfigurationException;
+    
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/config/ReferenceResolverException.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/config/ReferenceResolverException.java b/core/src/main/java/com/opensymphony/xwork2/config/ReferenceResolverException.java
new file mode 100644
index 0000000..00f1adb
--- /dev/null
+++ b/core/src/main/java/com/opensymphony/xwork2/config/ReferenceResolverException.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2002-2006,2009 The Apache Software Foundation.
+ * 
+ * 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 com.opensymphony.xwork2.config;
+
+import com.opensymphony.xwork2.XWorkException;
+
+
+/**
+ * Exception when a reference can't be resolved.
+ *
+ * @author Mike
+ */
+public class ReferenceResolverException extends XWorkException {
+
+    public ReferenceResolverException() {
+        super();
+    }
+
+    public ReferenceResolverException(String s) {
+        super(s);
+    }
+
+    public ReferenceResolverException(String s, Throwable cause) {
+        super(s, cause);
+    }
+
+    public ReferenceResolverException(Throwable cause) {
+        super(cause);
+    }
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/config/RuntimeConfiguration.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/config/RuntimeConfiguration.java b/core/src/main/java/com/opensymphony/xwork2/config/RuntimeConfiguration.java
new file mode 100644
index 0000000..f24c766
--- /dev/null
+++ b/core/src/main/java/com/opensymphony/xwork2/config/RuntimeConfiguration.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2002-2006,2009 The Apache Software Foundation.
+ * 
+ * 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 com.opensymphony.xwork2.config;
+
+import com.opensymphony.xwork2.config.entities.ActionConfig;
+
+import java.io.Serializable;
+import java.util.Map;
+
+
+/**
+ * RuntimeConfiguration
+ *
+ * @author Jason Carreira
+ *         Created Feb 25, 2003 10:56:02 PM
+ */
+public interface RuntimeConfiguration extends Serializable {
+
+    /**
+     * get the fully expanded ActionConfig for a specified namespace and (action) name
+     *
+     * @param namespace the namespace of the Action.  if this is null, then the empty namespace, "", will be used
+     * @param name      the name of the Action.  may not be null.
+     * @return the requested ActionConfig or null if there was no ActionConfig associated with the specified namespace
+     *         and name
+     */
+    ActionConfig getActionConfig(String namespace, String name);
+
+    /**
+     * returns a Map of all the registered ActionConfigs.  Again, these ActionConfigs are fully expanded so that any
+     * inherited interceptors, results, etc. will be included
+     *
+     * @return a Map of Map keyed by namespace and name respectively such that
+     *         <pre>
+     *                 ActionConfig config = (ActionConfig)((Map)getActionConfigs.get(namespace)).get(name);
+     *                 </pre>
+     *         should return a valid config for valid namespace/name pairs
+     */
+    Map<String, Map<String, ActionConfig>> getActionConfigs();
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/config/entities/ActionConfig.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/config/entities/ActionConfig.java b/core/src/main/java/com/opensymphony/xwork2/config/entities/ActionConfig.java
new file mode 100644
index 0000000..d796c02
--- /dev/null
+++ b/core/src/main/java/com/opensymphony/xwork2/config/entities/ActionConfig.java
@@ -0,0 +1,351 @@
+/*
+ * Copyright 2002-2006,2009 The Apache Software Foundation.
+ *
+ * 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 com.opensymphony.xwork2.config.entities;
+
+import com.opensymphony.xwork2.util.location.Located;
+import com.opensymphony.xwork2.util.location.Location;
+import org.apache.commons.lang3.StringUtils;
+
+import java.io.Serializable;
+import java.util.*;
+
+
+/**
+ * Contains everything needed to configure and execute an action:
+ * <ul>
+ * <li>methodName - the method name to execute on the action. If this is null, the Action will be cast to the Action
+ * Interface and the execute() method called</li>
+ * <li>clazz - the class name for the action</li>
+ * <li>params - the params to be set for this action just before execution</li>
+ * <li>results - the result map {String -> View class}</li>
+ * <li>resultParameters - params for results {String -> Map}</li>
+ * <li>typeConverter - the Ognl TypeConverter to use when getting/setting properties</li>
+ * </ul>
+ *
+ * @author Mike
+ * @author Rainer Hermanns
+ * @version $Revision$
+ */
+public class ActionConfig extends Located implements Serializable {
+
+    public static final String DEFAULT_METHOD = "execute";
+    public static final String WILDCARD = "*";
+
+    protected List<InterceptorMapping> interceptors; // a list of interceptorMapping Objects eg. List<InterceptorMapping>
+    protected Map<String,String> params;
+    protected Map<String, ResultConfig> results;
+    protected List<ExceptionMappingConfig> exceptionMappings;
+    protected String className;
+    protected String methodName;
+    protected String packageName;
+    protected String name;
+    protected Set<String> allowedMethods;
+
+    protected ActionConfig(String packageName, String name, String className) {
+        this.packageName = packageName;
+        this.name = name;
+        this.className = className;
+        params = new LinkedHashMap<String, String>();
+        results = new LinkedHashMap<String, ResultConfig>();
+        interceptors = new ArrayList<InterceptorMapping>();
+        exceptionMappings = new ArrayList<ExceptionMappingConfig>();
+        allowedMethods = new HashSet<String>();
+    }
+
+    /**
+     * Clones an ActionConfig, copying data into new maps and lists
+     * @param orig The ActionConfig to clone
+     * @Since 2.1
+     */
+    protected ActionConfig(ActionConfig orig) {
+        this.name = orig.name;
+        this.className = orig.className;
+        this.methodName = orig.methodName;
+        this.packageName = orig.packageName;
+        this.params = new LinkedHashMap<>(orig.params);
+        this.interceptors = new ArrayList<>(orig.interceptors);
+        this.results = new LinkedHashMap<>(orig.results);
+        this.exceptionMappings = new ArrayList<>(orig.exceptionMappings);
+        this.allowedMethods = new HashSet<>(orig.allowedMethods);
+        this.location = orig.location;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public String getClassName() {
+        return className;
+    }
+
+    public List<ExceptionMappingConfig> getExceptionMappings() {
+        return exceptionMappings;
+    }
+
+    public List<InterceptorMapping> getInterceptors() {
+        return interceptors;
+    }
+
+    public Set<String> getAllowedMethods() {
+        return allowedMethods;
+    }
+
+    /**
+     * Returns name of the action method
+     *
+     * @return name of the method to execute
+     */
+    public String getMethodName() {
+        return methodName;
+    }
+
+    /**
+     * @return Returns the packageName.
+     */
+    public String getPackageName() {
+        return packageName;
+    }
+
+    public Map<String, String> getParams() {
+        return params;
+    }
+
+    public Map<String, ResultConfig> getResults() {
+        return results;
+    }
+
+    public boolean isAllowedMethod(String method) {
+        if (allowedMethods.size() == 1 && WILDCARD.equals(allowedMethods.iterator().next())) {
+            return true;
+        } else {
+            return method.equals(methodName != null ? methodName : DEFAULT_METHOD) || allowedMethods.contains(method);
+        }
+    }
+
+    @Override public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+
+        if (!(o instanceof ActionConfig)) {
+            return false;
+        }
+
+        final ActionConfig actionConfig = (ActionConfig) o;
+
+        if ((className != null) ? (!className.equals(actionConfig.className)) : (actionConfig.className != null)) {
+            return false;
+        }
+
+        if ((name != null) ? (!name.equals(actionConfig.name)) : (actionConfig.name != null)) {
+            return false;
+        }
+
+        if ((interceptors != null) ? (!interceptors.equals(actionConfig.interceptors)) : (actionConfig.interceptors != null))
+        {
+            return false;
+        }
+
+        if ((methodName != null) ? (!methodName.equals(actionConfig.methodName)) : (actionConfig.methodName != null)) {
+            return false;
+        }
+
+        if ((params != null) ? (!params.equals(actionConfig.params)) : (actionConfig.params != null)) {
+            return false;
+        }
+
+        if ((results != null) ? (!results.equals(actionConfig.results)) : (actionConfig.results != null)) {
+            return false;
+        }
+
+        if ((allowedMethods != null) ? (!allowedMethods.equals(actionConfig.allowedMethods)) : (actionConfig.allowedMethods != null)) {
+            return false;
+        }
+
+        return true;
+    }
+
+    @Override public int hashCode() {
+        int result;
+        result = (interceptors != null ? interceptors.hashCode() : 0);
+        result = 31 * result + (params != null ? params.hashCode() : 0);
+        result = 31 * result + (results != null ? results.hashCode() : 0);
+        result = 31 * result + (exceptionMappings != null ? exceptionMappings.hashCode() : 0);
+        result = 31 * result + (className != null ? className.hashCode() : 0);
+        result = 31 * result + (methodName != null ? methodName.hashCode() : 0);
+        result = 31 * result + (packageName != null ? packageName.hashCode() : 0);
+        result = 31 * result + (name != null ? name.hashCode() : 0);
+        result = 31 * result + (allowedMethods != null ? allowedMethods.hashCode() : 0);
+        return result;
+    }
+
+    @Override public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("{ActionConfig ");
+        sb.append(name).append(" (");
+        sb.append(className);
+        if (methodName != null) {
+            sb.append(".").append(methodName).append("()");
+        }
+        sb.append(")");
+        sb.append(" - ").append(location);
+        sb.append("}");
+        return sb.toString();
+    }
+
+    /**
+     * The builder for this object.  An instance of this object is the only way to construct a new instance.  The
+     * purpose is to enforce the immutability of the object.  The methods are structured in a way to support chaining.
+     * After setting any values you need, call the {@link #build()} method to create the object.
+     */
+    public static class Builder implements InterceptorListHolder{
+
+        protected ActionConfig target;
+        private boolean gotMethods;
+
+        public Builder(ActionConfig toClone) {
+            target = new ActionConfig(toClone);
+            addAllowedMethod(toClone.getAllowedMethods());
+        }
+
+        public Builder(String packageName, String name, String className) {
+            target = new ActionConfig(packageName, name, className);
+        }
+
+        public Builder packageName(String name) {
+            target.packageName = name;
+            return this;
+        }
+
+        public Builder name(String name) {
+            target.name = name;
+            return this;
+        }
+
+        public Builder className(String name) {
+            target.className = name;
+            return this;
+        }
+
+        public Builder defaultClassName(String name) {
+            if (StringUtils.isEmpty(target.className)) {
+                target.className = name;
+            }
+            return this;
+        }
+
+        public Builder methodName(String method) {
+            target.methodName = method;
+            return this;
+        }
+
+        public Builder addExceptionMapping(ExceptionMappingConfig exceptionMapping) {
+            target.exceptionMappings.add(exceptionMapping);
+            return this;
+        }
+
+        public Builder addExceptionMappings(Collection<? extends ExceptionMappingConfig> mappings) {
+            target.exceptionMappings.addAll(mappings);
+            return this;
+        }
+
+        public Builder exceptionMappings(Collection<? extends ExceptionMappingConfig> mappings) {
+            target.exceptionMappings.clear();
+            target.exceptionMappings.addAll(mappings);
+            return this;
+        }
+
+        public Builder addInterceptor(InterceptorMapping interceptor) {
+            target.interceptors.add(interceptor);
+            return this;
+        }
+
+        public Builder addInterceptors(List<InterceptorMapping> interceptors) {
+            target.interceptors.addAll(interceptors);
+            return this;
+        }
+
+        public Builder interceptors(List<InterceptorMapping> interceptors) {
+            target.interceptors.clear();
+            target.interceptors.addAll(interceptors);
+            return this;
+        }
+
+        public Builder addParam(String name, String value) {
+            target.params.put(name, value);
+            return this;
+        }
+
+        public Builder addParams(Map<String,String> params) {
+            target.params.putAll(params);
+            return this;
+        }
+
+        public Builder addResultConfig(ResultConfig resultConfig) {
+            target.results.put(resultConfig.getName(), resultConfig);
+            return this;
+        }
+
+        public Builder addResultConfigs(Collection<ResultConfig> configs) {
+            for (ResultConfig rc : configs) {
+                target.results.put(rc.getName(), rc);
+            }
+            return this;
+        }
+
+        public Builder addResultConfigs(Map<String,ResultConfig> configs) {
+            target.results.putAll(configs);
+            return this;
+        }
+
+        public Builder addAllowedMethod(String methodName) {
+            target.allowedMethods.add(methodName);
+            return this;
+        }
+
+        public Builder addAllowedMethod(Collection<String> methods) {
+            if (methods != null) {
+                gotMethods = true;
+                target.allowedMethods.addAll(methods);
+            }
+            return this;
+        }
+
+        public Builder location(Location loc) {
+            target.location = loc;
+            return this;
+        }
+
+        public ActionConfig build() {
+            embalmTarget();
+            ActionConfig result = target;
+            target = new ActionConfig(target);
+            return result;
+        }
+
+        protected void embalmTarget() {
+            if (!gotMethods && target.allowedMethods.isEmpty()) {
+                target.allowedMethods.add(WILDCARD);
+            }
+
+            target.params = Collections.unmodifiableMap(target.params);
+            target.results = Collections.unmodifiableMap(target.results);
+            target.interceptors = Collections.unmodifiableList(target.interceptors);
+            target.exceptionMappings = Collections.unmodifiableList(target.exceptionMappings);
+            target.allowedMethods = Collections.unmodifiableSet(target.allowedMethods);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/config/entities/ExceptionMappingConfig.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/config/entities/ExceptionMappingConfig.java b/core/src/main/java/com/opensymphony/xwork2/config/entities/ExceptionMappingConfig.java
new file mode 100644
index 0000000..21a791e
--- /dev/null
+++ b/core/src/main/java/com/opensymphony/xwork2/config/entities/ExceptionMappingConfig.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright 2002-2006,2009 The Apache Software Foundation.
+ * 
+ * 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 com.opensymphony.xwork2.config.entities;
+
+import com.opensymphony.xwork2.util.location.Located;
+import com.opensymphony.xwork2.util.location.Location;
+
+import java.io.Serializable;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * Configuration for exception mapping.
+ *
+ * @author Rainer Hermanns
+ * @author Matthew E. Porter (matthew dot porter at metissian dot com)
+ */
+public class ExceptionMappingConfig extends Located implements Serializable {
+
+    protected String name;
+    protected String exceptionClassName;
+    protected String result;
+    protected Map<String,String> params;
+
+    protected ExceptionMappingConfig(String name, String exceptionClassName, String result) {
+        this.name = name;
+        this.exceptionClassName = exceptionClassName;
+        this.result = result;
+        this.params = new LinkedHashMap<>();
+    }
+
+    protected ExceptionMappingConfig(ExceptionMappingConfig target) {
+        this.name = target.name;
+        this.exceptionClassName = target.exceptionClassName;
+        this.result = target.result;
+        this.params = new LinkedHashMap<>(target.params);
+        this.location = target.location;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public String getExceptionClassName() {
+        return exceptionClassName;
+    }
+
+    public String getResult() {
+        return result;
+    }
+
+    public Map<String,String> getParams() {
+        return params;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+
+        if (!(o instanceof ExceptionMappingConfig)) {
+            return false;
+        }
+
+        final ExceptionMappingConfig exceptionMappingConfig = (ExceptionMappingConfig) o;
+
+        if ((name != null) ? (!name.equals(exceptionMappingConfig.name)) : (exceptionMappingConfig.name != null)) {
+            return false;
+        }
+
+        if ((exceptionClassName != null) ? (!exceptionClassName.equals(exceptionMappingConfig.exceptionClassName)) : (exceptionMappingConfig.exceptionClassName != null))
+        {
+            return false;
+        }
+
+        if ((result != null) ? (!result.equals(exceptionMappingConfig.result)) : (exceptionMappingConfig.result != null))
+        {
+            return false;
+        }
+
+        if ((params != null) ? (!params.equals(exceptionMappingConfig.params)) : (exceptionMappingConfig.params != null))
+        {
+            return false;
+        }
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int hashCode;
+        hashCode = ((name != null) ? name.hashCode() : 0);
+        hashCode = (29 * hashCode) + ((exceptionClassName != null) ? exceptionClassName.hashCode() : 0);
+        hashCode = (29 * hashCode) + ((result != null) ? result.hashCode() : 0);
+        hashCode = (29 * hashCode) + ((params != null) ? params.hashCode() : 0);
+
+        return hashCode;
+    }
+
+    @Override
+    public String toString() {
+        return "ExceptionMappingConfig: [" + name + "] handle ["
+                + exceptionClassName + "] to result [" + result + "] with params " + params;
+    }
+
+    /**
+     * The builder for this object.  An instance of this object is the only way to construct a new instance.  The
+     * purpose is to enforce the immutability of the object.  The methods are structured in a way to support chaining.
+     * After setting any values you need, call the {@link #build()} method to create the object.
+     */
+    public static class Builder{
+
+        protected ExceptionMappingConfig target;
+
+        public Builder(ExceptionMappingConfig toClone) {
+            target = new ExceptionMappingConfig(toClone);
+        }
+
+        public Builder(String name, String exceptionClassName, String result) {
+            target = new ExceptionMappingConfig(name, exceptionClassName, result);
+        }
+
+        public Builder name(String name) {
+            target.name = name;
+            return this;
+        }
+
+        public Builder exceptionClassName(String name) {
+            target.exceptionClassName = name;
+            return this;
+        }
+
+        public Builder result(String result) {
+            target.result = result;
+            return this;
+        }
+
+        public Builder addParam(String name, String value) {
+            target.params.put(name, value);
+            return this;
+        }
+
+        public Builder addParams(Map<String,String> params) {
+            target.params.putAll(params);
+            return this;
+        }
+
+        public Builder location(Location loc) {
+            target.location = loc;
+            return this;
+        }
+
+        public ExceptionMappingConfig build() {
+            embalmTarget();
+            ExceptionMappingConfig result = target;
+            target = new ExceptionMappingConfig(target);
+            return result;
+        }
+
+        protected void embalmTarget() {
+            target.params = Collections.unmodifiableMap(target.params);
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/config/entities/InterceptorConfig.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/config/entities/InterceptorConfig.java b/core/src/main/java/com/opensymphony/xwork2/config/entities/InterceptorConfig.java
new file mode 100644
index 0000000..b04bbd9
--- /dev/null
+++ b/core/src/main/java/com/opensymphony/xwork2/config/entities/InterceptorConfig.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright 2002-2006,2009 The Apache Software Foundation.
+ * 
+ * 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 com.opensymphony.xwork2.config.entities;
+
+import com.opensymphony.xwork2.util.location.Located;
+import com.opensymphony.xwork2.util.location.Location;
+
+import java.io.Serializable;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * Configuration for Interceptors.
+ * <p/>
+ * In the xml configuration file this is defined as the <code>interceptors</code> tag.
+ *
+ * @author Mike
+ */
+public class InterceptorConfig extends Located implements Serializable {
+
+    protected Map<String,String> params;
+    protected String className;
+    protected String name;
+
+    protected InterceptorConfig(String name, String className) {
+        this.params = new LinkedHashMap<>();
+        this.name = name;
+        this.className = className;
+    }
+
+    protected InterceptorConfig(InterceptorConfig orig) {
+        this.name = orig.name;
+        this.className = orig.className;
+        this.params = new LinkedHashMap<>(orig.params);
+        this.location = orig.location;
+    }
+
+    public String getClassName() {
+        return className;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public Map<String,String> getParams() {
+        return params;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+
+        if (!(o instanceof InterceptorConfig)) {
+            return false;
+        }
+
+        final InterceptorConfig interceptorConfig = (InterceptorConfig) o;
+
+        if ((className != null) ? (!className.equals(interceptorConfig.className)) : (interceptorConfig.className != null)) {
+            return false;
+        }
+
+        if ((name != null) ? (!name.equals(interceptorConfig.name)) : (interceptorConfig.name != null)) {
+            return false;
+        }
+
+        if ((params != null) ? (!params.equals(interceptorConfig.params)) : (interceptorConfig.params != null)) {
+            return false;
+        }
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result;
+        result = ((name != null) ? name.hashCode() : 0);
+        result = (29 * result) + ((className != null) ? className.hashCode() : 0);
+        result = (29 * result) + ((params != null) ? params.hashCode() : 0);
+
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return "InterceptorConfig: [" + name + "] => [" + className + "] with params " + params;
+    }
+
+    /**
+     * The builder for this object.  An instance of this object is the only way to construct a new instance.  The
+     * purpose is to enforce the immutability of the object.  The methods are structured in a way to support chaining.
+     * After setting any values you need, call the {@link #build()} method to create the object.
+     */
+    public static final class Builder {
+        protected InterceptorConfig target;
+
+        public Builder(String name, String className) {
+            target = new InterceptorConfig(name, className);
+        }
+
+        public Builder(InterceptorConfig orig) {
+            target = new InterceptorConfig(orig);
+        }
+
+        public Builder name(String name) {
+            target.name = name;
+            return this;
+        }
+
+        public Builder className(String name) {
+            target.className = name;
+            return this;
+        }
+
+        public Builder addParam(String name, String value) {
+            target.params.put(name, value);
+            return this;
+        }
+
+        public Builder addParams(Map<String,String> params) {
+            target.params.putAll(params);
+            return this;
+        }
+
+        public Builder location(Location loc) {
+            target.location = loc;
+            return this;
+        }
+
+        public InterceptorConfig build() {
+            embalmTarget();
+            InterceptorConfig result = target;
+            target = new InterceptorConfig(target);
+            return result;
+        }
+
+        protected void embalmTarget() {
+            target.params = Collections.unmodifiableMap(target.params);
+        }
+    }
+}