struts-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From lukaszlen...@apache.org
Subject [49/57] [partial] struts git commit: Merges xwork packages into struts
Date Wed, 17 Jun 2015 21:09:49 GMT
http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/DefaultActionProxy.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/DefaultActionProxy.java b/core/src/main/java/com/opensymphony/xwork2/DefaultActionProxy.java
new file mode 100644
index 0000000..544fbf3
--- /dev/null
+++ b/core/src/main/java/com/opensymphony/xwork2/DefaultActionProxy.java
@@ -0,0 +1,216 @@
+/*
+ * $Id$
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.entities.ActionConfig;
+import com.opensymphony.xwork2.inject.Inject;
+import com.opensymphony.xwork2.util.LocalizedTextUtil;
+import com.opensymphony.xwork2.util.profiling.UtilTimerStack;
+import org.apache.commons.lang3.StringEscapeUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import java.io.Serializable;
+import java.util.Locale;
+
+
+/**
+ * The Default ActionProxy implementation
+ *
+ * @author Rainer Hermanns
+ * @author Revised by <a href="mailto:hu_pengfei@yahoo.com.cn">Henry Hu</a>
+ * @author tmjee
+ * @version $Date$ $Id$
+ * @since 2005-8-6
+ */
+public class DefaultActionProxy implements ActionProxy, Serializable {
+
+    private static final long serialVersionUID = 3293074152487468527L;
+
+    private static final Logger LOG = LogManager.getLogger(DefaultActionProxy.class);
+
+    protected Configuration configuration;
+    protected ActionConfig config;
+    protected ActionInvocation invocation;
+    protected UnknownHandlerManager unknownHandlerManager;
+    protected String actionName;
+    protected String namespace;
+    protected String method;
+    protected boolean executeResult;
+    protected boolean cleanupContext;
+
+    protected ObjectFactory objectFactory;
+
+    protected ActionEventListener actionEventListener;
+
+    private boolean methodSpecified = true;
+
+    /**
+     * This constructor is private so the builder methods (create*) should be used to create an DefaultActionProxy.
+     * <p/>
+     * The reason for the builder methods is so that you can use a subclass to create your own DefaultActionProxy instance
+     * (like a RMIActionProxy).
+     */
+    protected DefaultActionProxy(ActionInvocation inv, String namespace, String actionName, String methodName, boolean executeResult, boolean cleanupContext) {
+
+        this.invocation = inv;
+        this.cleanupContext = cleanupContext;
+        LOG.debug("Creating an DefaultActionProxy for namespace [{}] and action name [{}]", namespace, actionName);
+
+        this.actionName = StringEscapeUtils.escapeHtml4(actionName);
+        this.namespace = namespace;
+        this.executeResult = executeResult;
+        this.method = StringEscapeUtils.escapeEcmaScript(StringEscapeUtils.escapeHtml4(methodName));
+    }
+
+    @Inject
+    public void setObjectFactory(ObjectFactory factory) {
+        this.objectFactory = factory;
+    }
+
+    @Inject
+    public void setConfiguration(Configuration config) {
+        this.configuration = config;
+    }
+
+    @Inject
+    public void setUnknownHandler(UnknownHandlerManager unknownHandlerManager) {
+        this.unknownHandlerManager = unknownHandlerManager;
+    }
+
+    @Inject(required = false)
+    public void setActionEventListener(ActionEventListener listener) {
+        this.actionEventListener = listener;
+    }
+
+    public Object getAction() {
+        return invocation.getAction();
+    }
+
+    public String getActionName() {
+        return actionName;
+    }
+
+    public ActionConfig getConfig() {
+        return config;
+    }
+
+    public void setExecuteResult(boolean executeResult) {
+        this.executeResult = executeResult;
+    }
+
+    public boolean getExecuteResult() {
+        return executeResult;
+    }
+
+    public ActionInvocation getInvocation() {
+        return invocation;
+    }
+
+    public String getNamespace() {
+        return namespace;
+    }
+
+    public String execute() throws Exception {
+        ActionContext nestedContext = ActionContext.getContext();
+        ActionContext.setContext(invocation.getInvocationContext());
+
+        String retCode = null;
+
+        String profileKey = "execute: ";
+        try {
+            UtilTimerStack.push(profileKey);
+
+            retCode = invocation.invoke();
+        } finally {
+            if (cleanupContext) {
+                ActionContext.setContext(nestedContext);
+            }
+            UtilTimerStack.pop(profileKey);
+        }
+
+        return retCode;
+    }
+
+
+    public String getMethod() {
+        return method;
+    }
+
+    private void resolveMethod() {
+        // if the method is set to null, use the one from the configuration
+        // if the one from the configuration is also null, use "execute"
+        if (StringUtils.isEmpty(this.method)) {
+            this.method = config.getMethodName();
+            if (StringUtils.isEmpty(this.method)) {
+                this.method = ActionConfig.DEFAULT_METHOD;
+            }
+            methodSpecified = false;
+        }
+    }
+
+    protected void prepare() {
+        String profileKey = "create DefaultActionProxy: ";
+        try {
+            UtilTimerStack.push(profileKey);
+            config = configuration.getRuntimeConfiguration().getActionConfig(namespace, actionName);
+
+            if (config == null && unknownHandlerManager.hasUnknownHandlers()) {
+                config = unknownHandlerManager.handleUnknownAction(namespace, actionName);
+            }
+            if (config == null) {
+                throw new ConfigurationException(getErrorMessage());
+            }
+
+            resolveMethod();
+
+            if (!config.isAllowedMethod(method)) {
+                throw new ConfigurationException("Invalid method: " + method + " for action " + actionName);
+            }
+
+            invocation.init(this);
+
+        } finally {
+            UtilTimerStack.pop(profileKey);
+        }
+    }
+
+    protected String getErrorMessage() {
+        if ((namespace != null) && (namespace.trim().length() > 0)) {
+            return LocalizedTextUtil.findDefaultText(
+                    XWorkMessages.MISSING_PACKAGE_ACTION_EXCEPTION,
+                    Locale.getDefault(),
+                    new String[]{namespace, actionName});
+        } else {
+            return LocalizedTextUtil.findDefaultText(
+                    XWorkMessages.MISSING_ACTION_EXCEPTION,
+                    Locale.getDefault(),
+                    new String[]{actionName});
+        }
+    }
+
+    public boolean isMethodSpecified() {
+        return methodSpecified;
+    }
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/DefaultActionProxyFactory.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/DefaultActionProxyFactory.java b/core/src/main/java/com/opensymphony/xwork2/DefaultActionProxyFactory.java
new file mode 100644
index 0000000..5c7db7a
--- /dev/null
+++ b/core/src/main/java/com/opensymphony/xwork2/DefaultActionProxyFactory.java
@@ -0,0 +1,79 @@
+/*
+ * 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.inject.Container;
+import com.opensymphony.xwork2.inject.Inject;
+
+import java.util.Map;
+
+
+/**
+ * Default factory for {@link com.opensymphony.xwork2.ActionProxyFactory}.
+ *
+ * @author Jason Carreira
+ */
+public class DefaultActionProxyFactory implements ActionProxyFactory {
+
+    protected Container container;
+    
+    public DefaultActionProxyFactory() {
+        super();
+    }
+    
+    @Inject
+    public void setContainer(Container container) {
+        this.container = container;
+    }
+    
+    public ActionProxy createActionProxy(String namespace, String actionName, Map<String, Object> extraContext) {
+        return createActionProxy(namespace, actionName, null, extraContext, true, true);
+    }
+
+    public ActionProxy createActionProxy(String namespace, String actionName, String methodName, Map<String, Object> extraContext) {
+        return createActionProxy(namespace, actionName, methodName, extraContext, true, true);
+    }
+
+    public ActionProxy createActionProxy(String namespace, String actionName, Map<String, Object> extraContext, boolean executeResult, boolean cleanupContext) {
+        return createActionProxy(namespace, actionName, null, extraContext, executeResult, cleanupContext);
+    }
+
+    public ActionProxy createActionProxy(String namespace, String actionName, String methodName, Map<String, Object> extraContext, boolean executeResult, boolean cleanupContext) {
+        
+        ActionInvocation inv = new DefaultActionInvocation(extraContext, true);
+        container.inject(inv);
+        return createActionProxy(inv, namespace, actionName, methodName, executeResult, cleanupContext);
+    }
+    
+    public ActionProxy createActionProxy(ActionInvocation inv, String namespace, String actionName, boolean executeResult, boolean cleanupContext) {
+        
+        return createActionProxy(inv, namespace, actionName, null, executeResult, cleanupContext);
+    }
+
+    public ActionProxy createActionProxy(ActionInvocation inv, String namespace, String actionName, String methodName, boolean executeResult, boolean cleanupContext) {
+
+        DefaultActionProxy proxy = new DefaultActionProxy(inv, namespace, actionName, methodName, executeResult, cleanupContext);
+        container.inject(proxy);
+        proxy.prepare();
+        return proxy;
+    }
+
+    @Override
+    public String toString() {
+        return getClass().getSimpleName();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/DefaultLocaleProvider.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/DefaultLocaleProvider.java b/core/src/main/java/com/opensymphony/xwork2/DefaultLocaleProvider.java
new file mode 100644
index 0000000..09a4daa
--- /dev/null
+++ b/core/src/main/java/com/opensymphony/xwork2/DefaultLocaleProvider.java
@@ -0,0 +1,25 @@
+package com.opensymphony.xwork2;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import java.util.Locale;
+
+/**
+ * Default implementation of {@link LocaleProvider}
+ */
+public class DefaultLocaleProvider implements LocaleProvider {
+
+    private final static Logger LOG = LogManager.getLogger(DefaultLocaleProvider.class);
+
+    public Locale getLocale() {
+        ActionContext ctx = ActionContext.getContext();
+        if (ctx != null) {
+            return ctx.getLocale();
+        } else {
+            LOG.debug("Action context not initialized");
+            return null;
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/DefaultTextProvider.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/DefaultTextProvider.java b/core/src/main/java/com/opensymphony/xwork2/DefaultTextProvider.java
new file mode 100644
index 0000000..eb57deb
--- /dev/null
+++ b/core/src/main/java/com/opensymphony/xwork2/DefaultTextProvider.java
@@ -0,0 +1,146 @@
+/*
+ * 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.util.LocalizedTextUtil;
+import com.opensymphony.xwork2.util.ValueStack;
+
+import java.io.Serializable;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.ResourceBundle;
+
+/**
+ * DefaultTextProvider gets texts from only the default resource bundles associated with the
+ * LocalizedTextUtil.
+ *
+ * @author Jason Carreira <jcarreira@gmail.com>
+ * @author Rainer Hermanns
+ * @see LocalizedTextUtil#addDefaultResourceBundle(String)
+ */
+public class DefaultTextProvider implements TextProvider, Serializable, Unchainable {
+
+    private static final Object[] EMPTY_ARGS = new Object[0];
+
+    public DefaultTextProvider() {
+    }
+
+    public boolean hasKey(String key) {
+        return getText(key) != null;
+    }
+
+    public String getText(String key) {
+        return LocalizedTextUtil.findDefaultText(key, ActionContext.getContext().getLocale());
+    }
+
+    public String getText(String key, String defaultValue) {
+        String text = getText(key);
+        if (text == null) {
+            return defaultValue;
+        }
+        return text;
+    }
+
+    public String getText(String key, List<?> args) {
+        Object[] params;
+        if (args != null) {
+            params = args.toArray();
+        } else {
+            params = EMPTY_ARGS;
+        }
+
+        return LocalizedTextUtil.findDefaultText(key, ActionContext.getContext().getLocale(), params);
+    }
+
+    public String getText(String key, String[] args) {
+        Object[] params;
+        if (args != null) {
+            params = args;
+        } else {
+            params = EMPTY_ARGS;
+        }
+
+        return LocalizedTextUtil.findDefaultText(key, ActionContext.getContext().getLocale(), params);
+    }
+
+    public String getText(String key, String defaultValue, List<?> args) {
+        String text = getText(key, args);
+        if(text == null && defaultValue == null) {
+            defaultValue = key;
+        }
+        if (text == null && defaultValue != null) {
+
+            MessageFormat format = new MessageFormat(defaultValue);
+            format.setLocale(ActionContext.getContext().getLocale());
+            format.applyPattern(defaultValue);
+
+            Object[] params;
+            if (args != null) {
+                params = args.toArray();
+            } else {
+                params = EMPTY_ARGS;
+            }
+
+            return format.format(params);
+        }
+        return text;        
+    }
+
+    public String getText(String key, String defaultValue, String[] args) {
+        String text = getText(key, args);
+        if (text == null) {
+            MessageFormat format = new MessageFormat(defaultValue);
+            format.setLocale(ActionContext.getContext().getLocale());
+            format.applyPattern(defaultValue);
+
+            if (args == null) {
+                return format.format(EMPTY_ARGS);
+            }
+
+            return format.format(args);
+        }
+        return text;
+    }
+
+
+    public String getText(String key, String defaultValue, String obj) {
+        List<Object> args = new ArrayList<>(1);
+        args.add(obj);
+        return getText(key, defaultValue, args);
+    }
+
+    public String getText(String key, String defaultValue, List<?> args, ValueStack stack) {
+        //we're not using the value stack here
+        return getText(key, defaultValue, args);
+    }
+
+    public String getText(String key, String defaultValue, String[] args, ValueStack stack) {
+        //we're not using the value stack here
+        List<Object> values = new ArrayList<Object>(Arrays.asList(args));
+        return getText(key, defaultValue, values);
+    }
+
+    public ResourceBundle getTexts(String bundleName) {
+        return LocalizedTextUtil.findResourceBundle(bundleName, ActionContext.getContext().getLocale());
+    }
+
+    public ResourceBundle getTexts() {
+        return null;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/DefaultUnknownHandlerManager.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/DefaultUnknownHandlerManager.java b/core/src/main/java/com/opensymphony/xwork2/DefaultUnknownHandlerManager.java
new file mode 100644
index 0000000..92f7ba7
--- /dev/null
+++ b/core/src/main/java/com/opensymphony/xwork2/DefaultUnknownHandlerManager.java
@@ -0,0 +1,131 @@
+/*
+ * 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.entities.ActionConfig;
+import com.opensymphony.xwork2.config.entities.UnknownHandlerConfig;
+import com.opensymphony.xwork2.inject.Container;
+import com.opensymphony.xwork2.inject.Inject;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Default implementation of UnknownHandlerManager
+ *
+ * @see com.opensymphony.xwork2.UnknownHandlerManager
+ */
+public class DefaultUnknownHandlerManager implements UnknownHandlerManager {
+
+    private Container container;
+
+    protected ArrayList<UnknownHandler> unknownHandlers;
+
+    @Inject
+    public void setContainer(Container container) {
+        this.container = container;
+        try {
+            build();
+        } catch (Exception e) {
+            throw new ConfigurationException(e);
+        }
+    }
+
+    /**
+     * Builds a list of UnknownHandlers in the order specified by the configured "unknown-handler-stack".
+     * If "unknown-handler-stack" was not configured, all UnknownHandlers will be returned, in no specific order
+     */
+    protected void build() throws Exception {
+        Configuration configuration = container.getInstance(Configuration.class);
+        ObjectFactory factory = container.getInstance(ObjectFactory.class);
+
+        if (configuration != null && container != null) {
+            List<UnknownHandlerConfig> unkownHandlerStack = configuration.getUnknownHandlerStack();
+            unknownHandlers = new ArrayList<>();
+
+            if (unkownHandlerStack != null && !unkownHandlerStack.isEmpty()) {
+                //get UnknownHandlers in the specified order
+                for (UnknownHandlerConfig unknownHandlerConfig : unkownHandlerStack) {
+                    UnknownHandler uh = factory.buildUnknownHandler(unknownHandlerConfig.getName(), new HashMap<String, Object>());
+                    unknownHandlers.add(uh);
+                }
+            } else {
+                //add all available UnknownHandlers
+                Set<String> unknownHandlerNames = container.getInstanceNames(UnknownHandler.class);
+                for (String unknownHandlerName : unknownHandlerNames) {
+                    UnknownHandler uh = container.getInstance(UnknownHandler.class, unknownHandlerName);
+                    unknownHandlers.add(uh);
+                }
+            }
+        }
+    }
+
+    /**
+     * Iterate over UnknownHandlers and return the result of the first one that can handle it
+     */
+    public Result handleUnknownResult(ActionContext actionContext, String actionName, ActionConfig actionConfig, String resultCode) {
+        for (UnknownHandler unknownHandler : unknownHandlers) {
+            Result result = unknownHandler.handleUnknownResult(actionContext, actionName, actionConfig, resultCode);
+            if (result != null) {
+                return result;
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Iterate over UnknownHandlers and return the result of the first one that can handle it
+     *
+     * @throws NoSuchMethodException
+     */
+    public Object handleUnknownMethod(Object action, String methodName) throws NoSuchMethodException {
+        for (UnknownHandler unknownHandler : unknownHandlers) {
+            Object result = unknownHandler.handleUnknownActionMethod(action, methodName);
+            if (result != null) {
+                return result;
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Iterate over UnknownHandlers and return the result of the first one that can handle it
+     */
+    public ActionConfig handleUnknownAction(String namespace, String actionName) {
+        for (UnknownHandler unknownHandler : unknownHandlers) {
+            ActionConfig result = unknownHandler.handleUnknownAction(namespace, actionName);
+            if (result != null) {
+                return result;
+            }
+        }
+
+        return null;
+    }
+
+    public boolean hasUnknownHandlers() {
+        return unknownHandlers != null && !unknownHandlers.isEmpty();
+    }
+
+    public List<UnknownHandler> getUnknownHandlers() {
+        return unknownHandlers;
+    }
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/FileManager.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/FileManager.java b/core/src/main/java/com/opensymphony/xwork2/FileManager.java
new file mode 100644
index 0000000..5c6806b
--- /dev/null
+++ b/core/src/main/java/com/opensymphony/xwork2/FileManager.java
@@ -0,0 +1,75 @@
+package com.opensymphony.xwork2;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Collection;
+
+/**
+ * Basic interface to access file on the File System and to monitor changes
+ */
+public interface FileManager {
+
+    /**
+     * Enables configs reloading when config file changed
+     *
+     * @param reloadingConfigs {@link XWorkConstants#RELOAD_XML_CONFIGURATION}
+     */
+    void setReloadingConfigs(boolean reloadingConfigs);
+
+    /**
+     * Checks if given file changed and must be reloaded if {@link #setReloadingConfigs(boolean)} is true
+     *
+     * @param fileName to check
+     * @return true if file changed
+     */
+    boolean fileNeedsReloading(String fileName);
+
+    /**
+     * Checks if file represented by provided URL should be reloaded
+     *
+     * @param fileUrl url to a file
+     * @return true if file exists and should be reloaded, if url is null return false
+     */
+    boolean fileNeedsReloading(URL fileUrl);
+
+    /**
+     * Loads opens the named file and returns the InputStream
+     *
+     * @param fileUrl - the URL of the file to open
+     * @return an InputStream of the file contents or null
+     * @throws IllegalArgumentException if there is no file with the given file name
+     */
+    InputStream loadFile(URL fileUrl);
+
+    /**
+     * Adds file to list of monitored files if {@link #setReloadingConfigs(boolean)} is true
+     *
+     * @param fileUrl {@link URL} to file to be monitored
+     */
+    void monitorFile(URL fileUrl);
+
+    /**
+     * Convert URLs to URLs with "file" protocol
+     * @param url URL to convert to a jar url
+     * @return a URL to a file, or null if the URL external form cannot be parsed
+     */
+    URL normalizeToFileProtocol(URL url);
+
+    /**
+     * Indicate if given implementation supports current OS File System
+     *
+     * @return true if supports current OS File System
+     */
+    boolean support();
+
+    /**
+     * User's implementation should return false as then it will be taken in first place
+     *
+     * @return true if it's a framework provided implementation
+     */
+    boolean internal();
+
+    Collection<? extends URL> getAllPhysicalUrls(URL url) throws IOException;
+
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/FileManagerFactory.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/FileManagerFactory.java b/core/src/main/java/com/opensymphony/xwork2/FileManagerFactory.java
new file mode 100644
index 0000000..f0eafc0
--- /dev/null
+++ b/core/src/main/java/com/opensymphony/xwork2/FileManagerFactory.java
@@ -0,0 +1,12 @@
+package com.opensymphony.xwork2;
+
+/**
+ * Factory that creates FileManager, default to {@link com.opensymphony.xwork2.util.fs.DefaultFileManager}
+ */
+public interface FileManagerFactory {
+
+    void setReloadingConfigs(String reloadingConfigs);
+
+    FileManager getFileManager();
+
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/InvalidMetadataException.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/InvalidMetadataException.java b/core/src/main/java/com/opensymphony/xwork2/InvalidMetadataException.java
new file mode 100644
index 0000000..eb556f5
--- /dev/null
+++ b/core/src/main/java/com/opensymphony/xwork2/InvalidMetadataException.java
@@ -0,0 +1,34 @@
+/*
+ * 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;
+
+/**
+ * <code>InvalidMetadataException</code>
+ *
+ * @author Rainer Hermanns
+ * @version $Id$
+ */
+public class InvalidMetadataException extends RuntimeException {
+
+    /**
+	 * Create a new <code>InvalidMetadataException</code> with the supplied error message.
+     * 
+	 * @param msg the error message
+	 */
+	public InvalidMetadataException(String msg) {
+		super(msg);
+	}
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/LocaleProvider.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/LocaleProvider.java b/core/src/main/java/com/opensymphony/xwork2/LocaleProvider.java
new file mode 100644
index 0000000..6fc4ea9
--- /dev/null
+++ b/core/src/main/java/com/opensymphony/xwork2/LocaleProvider.java
@@ -0,0 +1,40 @@
+/*
+ * 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.util.Locale;
+
+
+/**
+ * Indicates that the implementing class can provide its own {@link Locale}.
+ * <p/>
+ * This is useful for when an action may wish override the default locale. All that is
+ * needed is to implement this interface and return your own custom locale.
+ * The {@link TextProvider} interface uses this interface heavily for retrieving
+ * internationalized messages from resource bundles.
+ *
+ * @author Jason Carreira
+ */
+public interface LocaleProvider {
+
+    /**
+     * Gets the provided locale.
+     *
+     * @return  the locale.
+     */
+    Locale getLocale();
+
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/MockActionInvocation.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/MockActionInvocation.java b/core/src/main/java/com/opensymphony/xwork2/MockActionInvocation.java
new file mode 100644
index 0000000..3eea89b
--- /dev/null
+++ b/core/src/main/java/com/opensymphony/xwork2/MockActionInvocation.java
@@ -0,0 +1,26 @@
+/*
+ * 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;
+
+/**
+ * Mock for an {@link ActionInvocation}.
+ *
+ * @author plightbo
+ * @deprecated Please use @see com.opensymphony.xwork2.mock.MockActionInvocation instead
+ */
+@Deprecated public class MockActionInvocation extends com.opensymphony.xwork2.mock.MockActionInvocation {
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/ModelDriven.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/ModelDriven.java b/core/src/main/java/com/opensymphony/xwork2/ModelDriven.java
new file mode 100644
index 0000000..2f5f6c7
--- /dev/null
+++ b/core/src/main/java/com/opensymphony/xwork2/ModelDriven.java
@@ -0,0 +1,34 @@
+/*
+ * 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;
+
+
+/**
+ * ModelDriven Actions provide a model object to be pushed onto the ValueStack
+ * in addition to the Action itself, allowing a FormBean type approach like Struts.
+ *
+ * @author Jason Carreira
+ */
+public interface ModelDriven<T> {
+
+    /**
+     * Gets the model to be pushed onto the ValueStack instead of the Action itself.
+     *
+     * @return the model
+     */
+    T getModel();
+
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/ObjectFactory.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/ObjectFactory.java b/core/src/main/java/com/opensymphony/xwork2/ObjectFactory.java
new file mode 100644
index 0000000..f1a6c7f
--- /dev/null
+++ b/core/src/main/java/com/opensymphony/xwork2/ObjectFactory.java
@@ -0,0 +1,251 @@
+/*
+ * 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.ConfigurationException;
+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.*;
+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.validator.Validator;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import java.io.Serializable;
+import java.util.Map;
+
+
+/**
+ * ObjectFactory is responsible for building the core framework objects. Users may register their 
+ * own implementation of the ObjectFactory to control instantiation of these Objects.
+ * <p/>
+ * This default implementation uses the {@link #buildBean(Class,java.util.Map) buildBean} 
+ * method to create all classes (interceptors, actions, results, etc).
+ * <p/>
+ *
+ * @author Jason Carreira
+ */
+public class ObjectFactory implements Serializable {
+
+    private static final Logger LOG = LogManager.getLogger(ObjectFactory.class);
+
+    private transient ClassLoader ccl;
+    private Container container;
+
+    private ActionFactory actionFactory;
+    private ResultFactory resultFactory;
+    private InterceptorFactory interceptorFactory;
+    private ValidatorFactory validatorFactory;
+    private ConverterFactory converterFactory;
+    private UnknownHandlerFactory unknownHandlerFactory;
+
+    @Inject(value="objectFactory.classloader", required=false)
+    public void setClassLoader(ClassLoader cl) {
+        this.ccl = cl;
+    }
+    
+    @Inject
+    public void setContainer(Container container) {
+        this.container = container;
+    }
+
+    @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;
+    }
+
+    @Inject
+    public void setUnknownHandlerFactory(UnknownHandlerFactory unknownHandlerFactory) {
+        this.unknownHandlerFactory = unknownHandlerFactory;
+    }
+
+    /**
+     * @deprecated Since 2.1
+     */
+    @Deprecated public static ObjectFactory getObjectFactory() {
+        return ActionContext.getContext().getContainer().getInstance(ObjectFactory.class);
+    }
+
+    /**
+     * Allows for ObjectFactory implementations that support
+     * Actions without no-arg constructors.
+     *
+     * @return true if no-arg constructor is required, false otherwise
+     */
+    public boolean isNoArgConstructorRequired() {
+        return true;
+    }
+
+    /**
+     * Utility method to obtain the class matched to className. Caches look ups so that subsequent
+     * lookups will be faster.
+     *
+     * @param className The fully qualified name of the class to return
+     * @return The class itself
+     * @throws ClassNotFoundException
+     */
+    public Class getClassInstance(String className) throws ClassNotFoundException {
+        if (ccl != null) {
+            return ccl.loadClass(className);
+        }
+
+        return ClassLoaderUtil.loadClass(className, this.getClass());
+    }
+
+    /**
+     * Build an instance of the action class to handle a particular request (eg. web request)
+     * @param actionName the name the action configuration is set up with in the configuration
+     * @param namespace the namespace the action is configured in
+     * @param config the action configuration found in the config for the actionName / namespace
+     * @param extraContext a Map of extra context which uses the same keys as the {@link com.opensymphony.xwork2.ActionContext}
+     * @return instance of the action class to handle a web request
+     * @throws Exception
+     */
+    public Object buildAction(String actionName, String namespace, ActionConfig config, Map<String, Object> extraContext) throws Exception {
+        return actionFactory.buildAction(actionName, namespace, config, extraContext);
+    }
+
+    /**
+     * Build a generic Java object of the given type.
+     *
+     * @param clazz the type of Object to build
+     * @param extraContext a Map of extra context which uses the same keys as the {@link com.opensymphony.xwork2.ActionContext}
+     */
+    public Object buildBean(Class clazz, Map<String, Object> extraContext) throws Exception {
+        return clazz.newInstance();
+    }
+
+    /**
+     * @param obj
+     */
+    protected Object injectInternalBeans(Object obj) {
+        if (obj != null && container != null) {
+            container.inject(obj);
+        }
+        return obj;
+    }
+
+    /**
+     * Build a generic Java object of the given type.
+     *
+     * @param className the type of Object to build
+     * @param extraContext a Map of extra context which uses the same keys as the {@link com.opensymphony.xwork2.ActionContext}
+     */
+    public Object buildBean(String className, Map<String, Object> extraContext) throws Exception {
+        return buildBean(className, extraContext, true);
+    }
+    
+    /**
+     * Build a generic Java object of the given type.
+     *
+     * @param className the type of Object to build
+     * @param extraContext a Map of extra context which uses the same keys as the {@link com.opensymphony.xwork2.ActionContext}
+     */
+    public Object buildBean(String className, Map<String, Object> extraContext, boolean injectInternal) throws Exception {
+        Class clazz = getClassInstance(className);
+        Object obj = buildBean(clazz, extraContext);
+        if (injectInternal) {
+            injectInternalBeans(obj);
+        }
+        return obj;
+    }
+
+    /**
+     * 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
+     */
+    public Interceptor buildInterceptor(InterceptorConfig interceptorConfig, Map<String, String> interceptorRefParams) throws ConfigurationException {
+        return interceptorFactory.buildInterceptor(interceptorConfig, interceptorRefParams);
+    }
+
+    /**
+     * Build a Result using the type in the ResultConfig and set the parameters in the ResultConfig.
+     *
+     * @param resultConfig the ResultConfig found for the action with the result code returned
+     * @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 {
+        return resultFactory.buildResult(resultConfig, extraContext);
+    }
+
+    /**
+     * 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}
+     */
+    public Validator buildValidator(String className, Map<String, Object> params, Map<String, Object> extraContext) throws Exception {
+        return validatorFactory.buildValidator(className, params, extraContext);
+    }
+
+    /**
+     * 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, Map<String, Object> extraContext) throws Exception {
+        return converterFactory.buildConverter(converterClass, extraContext);
+    }
+
+    /**
+     * Builds unknown handler
+     *
+     * @param unknownHandlerName
+     * @param extraContext
+     * @return
+     * @throws Exception
+     */
+    public UnknownHandler buildUnknownHandler(String unknownHandlerName, Map<String, Object> extraContext) throws Exception {
+        return unknownHandlerFactory.buildUnknownHandler(unknownHandlerName, extraContext);
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/Preparable.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/Preparable.java b/core/src/main/java/com/opensymphony/xwork2/Preparable.java
new file mode 100644
index 0000000..58a2412
--- /dev/null
+++ b/core/src/main/java/com/opensymphony/xwork2/Preparable.java
@@ -0,0 +1,35 @@
+/*
+ * 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;
+
+
+/**
+ * Preparable Actions will have their <code>prepare()</code> method called if the {@link com.opensymphony.xwork2.interceptor.PrepareInterceptor}
+ * is applied to the ActionConfig.
+ *
+ * @author Jason Carreira
+ * @see com.opensymphony.xwork2.interceptor.PrepareInterceptor
+ */
+public interface Preparable {
+
+    /**
+     * This method is called to allow the action to prepare itself.
+     *
+     * @throws Exception thrown if a system level exception occurs.
+     */
+    void prepare() throws Exception;
+    
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/ResourceBundleTextProvider.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/ResourceBundleTextProvider.java b/core/src/main/java/com/opensymphony/xwork2/ResourceBundleTextProvider.java
new file mode 100644
index 0000000..1415e71
--- /dev/null
+++ b/core/src/main/java/com/opensymphony/xwork2/ResourceBundleTextProvider.java
@@ -0,0 +1,48 @@
+/*
+ * 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.ResourceBundle;
+
+/**
+ * Extension Interface for TextProvider to help supporting ResourceBundles.
+ *
+ * @author Rene Gielen
+ */
+public interface ResourceBundleTextProvider extends TextProvider {
+
+    /**
+     * Set the resource bundle to use.
+     *
+     * @param bundle the bundle to use.
+     */
+    void setBundle(ResourceBundle bundle);
+
+    /**
+     * Set the class to use for reading the resource bundle.
+     *
+     * @param clazz the class to use for loading.
+     */
+    void setClazz(Class clazz);
+
+    /**
+     * Set the LocaleProvider to use.
+     *
+     * @param localeProvider the LocaleProvider to use.
+     */
+    void setLocaleProvider(LocaleProvider localeProvider);
+
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/Result.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/Result.java b/core/src/main/java/com/opensymphony/xwork2/Result.java
new file mode 100644
index 0000000..3d65377
--- /dev/null
+++ b/core/src/main/java/com/opensymphony/xwork2/Result.java
@@ -0,0 +1,45 @@
+/*
+ * 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.io.Serializable;
+
+
+/**
+ * All results (except for <code>Action.NONE</code>) of an {@link Action} are mapped to a View implementation.
+ * <p/>
+ * Examples of Views might be:
+ * <ul>
+ * <li>SwingPanelView - pops up a new Swing panel</li>
+ * <li>ActionChainView - executes another action</li>
+ * <li>SerlvetRedirectView - redirects the HTTP response to a URL</li>
+ * <li>ServletDispatcherView - dispatches the HTTP response to a URL</li>
+ * </ul>
+ *
+ * @author plightbo
+ */
+public interface Result extends Serializable {
+
+    /**
+     * Represents a generic interface for all action execution results.
+     * Whether that be displaying a webpage, generating an email, sending a JMS message, etc.
+     *
+     * @param invocation  the invocation context.
+     * @throws Exception can be thrown.
+     */
+    public void execute(ActionInvocation invocation) throws Exception;
+
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/TestNGXWorkTestCase.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/TestNGXWorkTestCase.java b/core/src/main/java/com/opensymphony/xwork2/TestNGXWorkTestCase.java
new file mode 100644
index 0000000..823e764
--- /dev/null
+++ b/core/src/main/java/com/opensymphony/xwork2/TestNGXWorkTestCase.java
@@ -0,0 +1,62 @@
+/*
+ * 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.config.ConfigurationProvider;
+import com.opensymphony.xwork2.config.impl.MockConfiguration;
+import com.opensymphony.xwork2.inject.Container;
+import com.opensymphony.xwork2.util.XWorkTestCaseHelper;
+import org.testng.annotations.AfterTest;
+import org.testng.annotations.BeforeTest;
+
+/**
+ * Base test class for TestNG unit tests.  Provides common XWork variables
+ * and performs XWork setup and teardown processes
+ */
+public class TestNGXWorkTestCase {
+
+    protected ConfigurationManager configurationManager;
+    protected Configuration configuration;
+    protected Container container;
+    protected ActionProxyFactory actionProxyFactory;
+
+    @BeforeTest
+    protected void setUp() throws Exception {
+        configurationManager = XWorkTestCaseHelper.setUp();
+        configuration = new MockConfiguration();
+        ((MockConfiguration) configuration).selfRegister();
+        container = configuration.getContainer();
+        actionProxyFactory = container.getInstance(ActionProxyFactory.class);
+    }
+
+    @AfterTest
+    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);
+    }
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/TextProvider.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/TextProvider.java b/core/src/main/java/com/opensymphony/xwork2/TextProvider.java
new file mode 100644
index 0000000..aed8479
--- /dev/null
+++ b/core/src/main/java/com/opensymphony/xwork2/TextProvider.java
@@ -0,0 +1,180 @@
+/*
+ * 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.util.ValueStack;
+
+import java.util.List;
+import java.util.ResourceBundle;
+
+
+/**
+ * Provides access to {@link ResourceBundle}s and their underlying text messages.
+ * Implementing classes can delegate {@link TextProviderSupport}. Messages will be
+ * searched in multiple resource bundles, starting with the one associated with
+ * this particular class (action in most cases), continuing to try the message
+ * bundle associated with each superclass as well. It will stop once a bundle is
+ * found that contains the given text. This gives a cascading style that allow
+ * global texts to be defined for an application base class.
+ * <p/>
+ * You can override {@link LocaleProvider#getLocale()} to change the behaviour of how
+ * to choose locale for the bundles that are returned. Typically you would
+ * use the {@link LocaleProvider} interface to get the users configured locale.
+ * <p/>
+ * When you want to use your own implementation for Struts 2 project you have to define following
+ * bean and constant in struts.xml:
+ * &lt;bean class=&quot;org.demo.MyTextProvider&quot; name=&quot;myTextProvider&quot; type=&quot;com.opensymphony.xwork2.TextProvider&quot; /&gt;
+ * &lt;constant name=&quot;struts.xworkTextProvider&quot; value=&quot;myTextProvider&quot; /&gt;
+ * <p/>
+ * if you want to also use your implementation for framework's messages define another constant (remember to put
+ * into it all framework messages)
+ * &lt;constant name=&quot;system&quot; value=&quot;myTextProvider&quot; /&gt;
+ * <p/>
+ * Take a look on {@link com.opensymphony.xwork2.ActionSupport} for example TextProvider implemntation.
+ *
+ * @author Jason Carreira
+ * @author Rainer Hermanns
+ * @see LocaleProvider
+ * @see TextProviderSupport
+ */
+public interface TextProvider {
+
+    /**
+     * Checks if a message key exists.
+     *
+     * @param key message key to check for
+     * @return boolean true if key exists, false otherwise.
+     */
+    boolean hasKey(String key);
+
+    /**
+     * Gets a message based on a message key or if no message is found the provided key
+     * is returned.
+     *
+     * @param key the resource bundle key that is to be searched for
+     * @return the message as found in the resource bundle, or the provided key if none is found.
+     */
+    String getText(String key);
+
+    /**
+     * Gets a message based on a key, or, if the message is not found, a supplied
+     * default value is returned.
+     *
+     * @param key          the resource bundle key that is to be searched for
+     * @param defaultValue the default value which will be returned if no message is found
+     * @return the message as found in the resource bundle, or defaultValue if none is found
+     */
+    String getText(String key, String defaultValue);
+
+    /**
+     * Gets a message based on a key using the supplied obj, as defined in
+     * {@link java.text.MessageFormat}, or, if the message is not found, a supplied
+     * default value is returned.
+     *
+     * @param key          the resource bundle key that is to be searched for
+     * @param defaultValue the default value which will be returned if no message is found
+     * @param obj          obj to be used in a {@link java.text.MessageFormat} message
+     * @return the message as found in the resource bundle, or defaultValue if none is found
+     */
+    String getText(String key, String defaultValue, String obj);
+
+    /**
+     * Gets a message based on a key using the supplied args, as defined in
+     * {@link java.text.MessageFormat} or the provided key if no message is found.
+     *
+     * @param key  the resource bundle key that is to be searched for
+     * @param args a list args to be used in a {@link java.text.MessageFormat} message
+     * @return the message as found in the resource bundle, or the provided key if none is found.
+     */
+    String getText(String key, List<?> args);
+
+    /**
+     * Gets a message based on a key using the supplied args, as defined in
+     * {@link java.text.MessageFormat}, or the provided key if no message is found.
+     *
+     * @param key  the resource bundle key that is to be searched for
+     * @param args an array args to be used in a {@link java.text.MessageFormat} message
+     * @return the message as found in the resource bundle, or the provided key if none is found.
+     */
+    String getText(String key, String[] args);
+
+    /**
+     * Gets a message based on a key using the supplied args, as defined in
+     * {@link java.text.MessageFormat}, or, if the message is not found, a supplied
+     * default value is returned.
+     *
+     * @param key          the resource bundle key that is to be searched for
+     * @param defaultValue the default value which will be returned if no message is found
+     * @param args         a list args to be used in a {@link java.text.MessageFormat} message
+     * @return the message as found in the resource bundle, or defaultValue if none is found
+     */
+    String getText(String key, String defaultValue, List<?> args);
+
+    /**
+     * Gets a message based on a key using the supplied args, as defined in
+     * {@link java.text.MessageFormat}, or, if the message is not found, a supplied
+     * default value is returned.
+     *
+     * @param key          the resource bundle key that is to be searched for
+     * @param defaultValue the default value which will be returned if no message is found
+     * @param args         an array args to be used in a {@link java.text.MessageFormat} message
+     * @return the message as found in the resource bundle, or defaultValue if none is found
+     */
+    String getText(String key, String defaultValue, String[] args);
+
+    /**
+     * Gets a message based on a key using the supplied args, as defined in
+     * {@link java.text.MessageFormat}, or, if the message is not found, a supplied
+     * default value is returned. Instead of using the value stack in the ActionContext
+     * this version of the getText() method uses the provided value stack.
+     *
+     * @param key          the resource bundle key that is to be searched for
+     * @param defaultValue the default value which will be returned if no message is found
+     * @param args         a list args to be used in a {@link java.text.MessageFormat} message
+     * @param stack        the value stack to use for finding the text
+     * @return the message as found in the resource bundle, or defaultValue if none is found
+     */
+    String getText(String key, String defaultValue, List<?> args, ValueStack stack);
+
+    /**
+     * Gets a message based on a key using the supplied args, as defined in
+     * {@link java.text.MessageFormat}, or, if the message is not found, a supplied
+     * default value is returned. Instead of using the value stack in the ActionContext
+     * this version of the getText() method uses the provided value stack.
+     *
+     * @param key          the resource bundle key that is to be searched for
+     * @param defaultValue the default value which will be returned if no message is found
+     * @param args         an array args to be used in a {@link java.text.MessageFormat} message
+     * @param stack        the value stack to use for finding the text
+     * @return the message as found in the resource bundle, or defaultValue if none is found
+     */
+    String getText(String key, String defaultValue, String[] args, ValueStack stack);
+
+    /**
+     * Get the named bundle, such as "com/acme/Foo".
+     *
+     * @param bundleName the name of the resource bundle, such as <code>"com/acme/Foo"</code>.
+     * @return the bundle
+     */
+    ResourceBundle getTexts(String bundleName);
+
+    /**
+     * Get the resource bundle associated with the implementing class (usually an action).
+     *
+     * @return the bundle
+     */
+    ResourceBundle getTexts();
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/TextProviderFactory.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/TextProviderFactory.java b/core/src/main/java/com/opensymphony/xwork2/TextProviderFactory.java
new file mode 100644
index 0000000..331d534
--- /dev/null
+++ b/core/src/main/java/com/opensymphony/xwork2/TextProviderFactory.java
@@ -0,0 +1,71 @@
+/*
+ * 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.inject.Inject;
+
+import java.util.ResourceBundle;
+
+/**
+ * This factory enables users to provide and correctly initialize a custom TextProvider.
+ *
+ * @author Oleg Gorobets
+ * @author Rene Gielen
+ */
+public class TextProviderFactory {
+
+    private TextProvider textProvider;
+
+    @Inject
+    public void setTextProvider(TextProvider textProvider) {
+        this.textProvider = textProvider;
+    }
+
+    public TextProvider createInstance(Class clazz, LocaleProvider provider) {
+        TextProvider instance = getTextProvider(clazz, provider);
+        if (instance instanceof ResourceBundleTextProvider) {
+            ((ResourceBundleTextProvider) instance).setClazz(clazz);
+            ((ResourceBundleTextProvider) instance).setLocaleProvider(provider);
+        }
+        return instance;
+    }
+
+    public TextProvider createInstance(ResourceBundle bundle, LocaleProvider provider) {
+        TextProvider instance = getTextProvider(bundle, provider);
+        if (instance instanceof ResourceBundleTextProvider) {
+            ((ResourceBundleTextProvider) instance).setBundle(bundle);
+            ((ResourceBundleTextProvider) instance).setLocaleProvider(provider);
+        }
+        return instance;
+    }
+
+    protected TextProvider getTextProvider(Class clazz, LocaleProvider provider) {
+        if (this.textProvider == null) {
+            return new TextProviderSupport(clazz, provider);
+        } else {
+            return textProvider;
+        }
+    }
+
+    private TextProvider getTextProvider(ResourceBundle bundle, LocaleProvider provider) {
+        if (this.textProvider == null) {
+            return new TextProviderSupport(bundle, provider);
+        } else {
+            return textProvider;
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/TextProviderSupport.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/TextProviderSupport.java b/core/src/main/java/com/opensymphony/xwork2/TextProviderSupport.java
new file mode 100644
index 0000000..8b641a4
--- /dev/null
+++ b/core/src/main/java/com/opensymphony/xwork2/TextProviderSupport.java
@@ -0,0 +1,329 @@
+/*
+ * 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.inject.Inject;
+import com.opensymphony.xwork2.util.LocalizedTextUtil;
+import com.opensymphony.xwork2.util.ValueStack;
+
+import java.util.*;
+
+
+/**
+ * Default TextProvider implementation.
+ *
+ * @author Jason Carreira
+ * @author Rainer Hermanns
+ */
+public class TextProviderSupport implements ResourceBundleTextProvider {
+
+    private Class clazz;
+    private LocaleProvider localeProvider;
+    private ResourceBundle bundle;
+
+    /**
+     * Default constructor
+     */
+    public TextProviderSupport() {
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param clazz    a clazz to use for reading the resource bundle.
+     * @param provider a locale provider.
+     */
+    public TextProviderSupport(Class clazz, LocaleProvider provider) {
+        this.clazz = clazz;
+        this.localeProvider = provider;
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param bundle   the resource bundle.
+     * @param provider a locale provider.
+     */
+    public TextProviderSupport(ResourceBundle bundle, LocaleProvider provider) {
+        this.bundle = bundle;
+        this.localeProvider = provider;
+    }
+
+    /**
+     * @param bundle the resource bundle.
+     */
+    public void setBundle(ResourceBundle bundle) {
+        this.bundle = bundle;
+    }
+
+    /**
+     * @param clazz a clazz to use for reading the resource bundle.
+     */
+    public void setClazz(Class clazz) {
+        this.clazz = clazz;
+    }
+
+
+    /**
+     * @param localeProvider a locale provider.
+     */
+    @Inject
+    public void setLocaleProvider(LocaleProvider localeProvider) {
+        this.localeProvider = localeProvider;
+    }
+
+
+    /**
+     * Checks if a key is available in the resource bundles associated with this action.
+     * The resource bundles are searched, starting with the one associated
+     * with this particular action, and testing all its superclasses' bundles.
+     * It will stop once a bundle is found that contains the given text. This gives
+     * a cascading style that allow global texts to be defined for an application base
+     * class.
+     */
+    public boolean hasKey(String key) {
+    	String message;
+    	if (clazz != null) {
+            message =  LocalizedTextUtil.findText(clazz, key, getLocale(), null, new Object[0] );
+        } else {
+            message = LocalizedTextUtil.findText(bundle, key, getLocale(), null, new Object[0]);
+        }
+    	return message != null;
+    }
+
+    /**
+     * Get a text from the resource bundles associated with this action.
+     * The resource bundles are searched, starting with the one associated
+     * with this particular action, and testing all its superclasses' bundles.
+     * It will stop once a bundle is found that contains the given text. This gives
+     * a cascading style that allow global texts to be defined for an application base
+     * class.
+     *
+     * @param key name of text to be found
+     * @return value of named text or the provided key if no value is found
+     */
+    public String getText(String key) {
+        return getText(key, key, Collections.emptyList());
+    }
+
+    /**
+     * Get a text from the resource bundles associated with this action.
+     * The resource bundles are searched, starting with the one associated
+     * with this particular action, and testing all its superclasses' bundles.
+     * It will stop once a bundle is found that contains the given text. This gives
+     * a cascading style that allow global texts to be defined for an application base
+     * class. If no text is found for this text name, the default value is returned.
+     *
+     * @param key    name of text to be found
+     * @param defaultValue the default value which will be returned if no text is found
+     * @return value of named text or the provided defaultValue if no value is found
+     */
+    public String getText(String key, String defaultValue) {
+        return getText(key, defaultValue, Collections.emptyList());
+    }
+
+    /**
+     * Get a text from the resource bundles associated with this action.
+     * The resource bundles are searched, starting with the one associated
+     * with this particular action, and testing all its superclasses' bundles.
+     * It will stop once a bundle is found that contains the given text. This gives
+     * a cascading style that allow global texts to be defined for an application base
+     * class. If no text is found for this text name, the default value is returned.
+     *
+     * @param key    name of text to be found
+     * @param defaultValue the default value which will be returned if no text is found
+     * @return value of named text or the provided defaultValue if no value is found
+     */
+    public String getText(String key, String defaultValue, String arg) {
+        List<Object> args = new ArrayList<>();
+        args.add(arg);
+        return getText(key, defaultValue, args);
+    }
+
+    /**
+     * Get a text from the resource bundles associated with this action.
+     * The resource bundles are searched, starting with the one associated
+     * with this particular action, and testing all its superclasses' bundles.
+     * It will stop once a bundle is found that contains the given text. This gives
+     * a cascading style that allow global texts to be defined for an application base
+     * class. If no text is found for this text name, the default value is returned.
+     *
+     * @param key name of text to be found
+     * @param args      a List of args to be used in a MessageFormat message
+     * @return value of named text or the provided key if no value is found
+     */
+    public String getText(String key, List<?> args) {
+        return getText(key, key, args);
+    }
+
+    /**
+     * Get a text from the resource bundles associated with this action.
+     * The resource bundles are searched, starting with the one associated
+     * with this particular action, and testing all its superclasses' bundles.
+     * It will stop once a bundle is found that contains the given text. This gives
+     * a cascading style that allow global texts to be defined for an application base
+     * class. If no text is found for this text name, the default value is returned.
+     *
+     * @param key name of text to be found
+     * @param args      an array of args to be used in a MessageFormat message
+     * @return value of named text or the provided key if no value is found
+     */
+    public String getText(String key, String[] args) {
+        return getText(key, key, args);
+    }
+
+    /**
+     * Get a text from the resource bundles associated with this action.
+     * The resource bundles are searched, starting with the one associated
+     * with this particular action, and testing all its superclasses' bundles.
+     * It will stop once a bundle is found that contains the given text. This gives
+     * a cascading style that allow global texts to be defined for an application base
+     * class. If no text is found for this text name, the default value is returned.
+     *
+     * @param key    name of text to be found
+     * @param defaultValue the default value which will be returned if no text is found
+     * @param args         a List of args to be used in a MessageFormat message
+     * @return value of named text or the provided defaultValue if no value is found
+     */
+    public String getText(String key, String defaultValue, List<?> args) {
+        Object[] argsArray = ((args != null && !args.equals(Collections.emptyList())) ? args.toArray() : null);
+        if (clazz != null) {
+            return LocalizedTextUtil.findText(clazz, key, getLocale(), defaultValue, argsArray);
+        } else {
+            return LocalizedTextUtil.findText(bundle, key, getLocale(), defaultValue, argsArray);
+        }
+    }
+
+    /**
+     * Get a text from the resource bundles associated with this action.
+     * The resource bundles are searched, starting with the one associated
+     * with this particular action, and testing all its superclasses' bundles.
+     * It will stop once a bundle is found that contains the given text. This gives
+     * a cascading style that allow global texts to be defined for an application base
+     * class. If no text is found for this text name, the default value is returned.
+     *
+     * @param key          name of text to be found
+     * @param defaultValue the default value which will be returned if no text is found
+     * @param args         an array of args to be used in a MessageFormat message
+     * @return value of named text or the provided defaultValue if no value is found
+     */
+    public String getText(String key, String defaultValue, String[] args) {
+        if (clazz != null) {
+            return LocalizedTextUtil.findText(clazz, key, getLocale(), defaultValue, args);
+        } else {
+            return LocalizedTextUtil.findText(bundle, key, getLocale(), defaultValue, args);
+        }
+    }
+
+    /**
+     * Gets a message based on a key using the supplied args, as defined in
+     * {@link java.text.MessageFormat}, or, if the message is not found, a supplied
+     * default value is returned. Instead of using the value stack in the ActionContext
+     * this version of the getText() method uses the provided value stack.
+     *
+     * @param key    the resource bundle key that is to be searched for
+     * @param defaultValue the default value which will be returned if no message is found
+     * @param args         a list args to be used in a {@link java.text.MessageFormat} message
+     * @param stack        the value stack to use for finding the text
+     * @return the message as found in the resource bundle, or defaultValue if none is found
+     */
+    public String getText(String key, String defaultValue, List<?> args, ValueStack stack) {
+        Object[] argsArray = ((args != null) ? args.toArray() : null);
+        Locale locale;
+        if (stack == null){
+        	locale = getLocale();
+        }else{
+        	locale = (Locale) stack.getContext().get(ActionContext.LOCALE);
+        }
+        if (locale == null) {
+            locale = getLocale();
+        }
+        if (clazz != null) {
+            return LocalizedTextUtil.findText(clazz, key, locale, defaultValue, argsArray, stack);
+        } else {
+            return LocalizedTextUtil.findText(bundle, key, locale, defaultValue, argsArray, stack);
+        }
+    }
+
+
+    /**
+     * Gets a message based on a key using the supplied args, as defined in
+     * {@link java.text.MessageFormat}, or, if the message is not found, a supplied
+     * default value is returned. Instead of using the value stack in the ActionContext
+     * this version of the getText() method uses the provided value stack.
+     *
+     * @param key          the resource bundle key that is to be searched for
+     * @param defaultValue the default value which will be returned if no message is found
+     * @param args         an array args to be used in a {@link java.text.MessageFormat} message
+     * @param stack        the value stack to use for finding the text
+     * @return the message as found in the resource bundle, or defaultValue if none is found
+     */
+    public String getText(String key, String defaultValue, String[] args, ValueStack stack) {
+        Locale locale;
+        if (stack == null){
+        	locale = getLocale();
+        }else{
+        	locale = (Locale) stack.getContext().get(ActionContext.LOCALE);
+        }
+        if (locale == null) {
+            locale = getLocale();
+        }
+        if (clazz != null) {
+            return LocalizedTextUtil.findText(clazz, key, locale, defaultValue, args, stack);
+        } else {
+            return LocalizedTextUtil.findText(bundle, key, locale, defaultValue, args, stack);
+        }
+
+    }
+
+    /**
+     * Get the named bundle.
+     * <p/>
+     * You can override the getLocale() methodName to change the behaviour of how
+     * to choose locale for the bundles that are returned. Typically you would
+     * use the TextProvider interface to get the users configured locale, or use
+     * your own methodName to allow the user to select the locale and store it in
+     * the session (by using the SessionAware interface).
+     *
+     * @param aBundleName bundle name
+     * @return a resource bundle
+     */
+    public ResourceBundle getTexts(String aBundleName) {
+        return LocalizedTextUtil.findResourceBundle(aBundleName, getLocale());
+    }
+
+    /**
+     * Get the resource bundle associated with this action.
+     * This will be based on the actual subclass that is used.
+     *
+     * @return resouce bundle
+     */
+    public ResourceBundle getTexts() {
+        if (clazz != null) {
+            return getTexts(clazz.getName());
+        }
+        return bundle;
+    }
+
+    /**
+     * Get's the locale from the localeProvider.
+     *
+     * @return the locale from the localeProvider.
+     */
+    private Locale getLocale() {
+        return localeProvider.getLocale();
+    }
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/Unchainable.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/Unchainable.java b/core/src/main/java/com/opensymphony/xwork2/Unchainable.java
new file mode 100644
index 0000000..19d88ef
--- /dev/null
+++ b/core/src/main/java/com/opensymphony/xwork2/Unchainable.java
@@ -0,0 +1,25 @@
+/*
+ * 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;
+
+/**
+ * Simple marker interface to indicate an object should <b>not</b> have its properties copied during chaining.
+ *
+ * @see com.opensymphony.xwork2.interceptor.ChainingInterceptor
+ */
+public interface Unchainable {
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/UnknownHandler.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/UnknownHandler.java b/core/src/main/java/com/opensymphony/xwork2/UnknownHandler.java
new file mode 100644
index 0000000..faabfc0
--- /dev/null
+++ b/core/src/main/java/com/opensymphony/xwork2/UnknownHandler.java
@@ -0,0 +1,63 @@
+/*
+ * 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.config.entities.ActionConfig;
+
+/**
+ * Handles cases when the result or action is unknown.
+ * <p/>
+ * This allows other classes like Struts plugins to provide intelligent defaults easier.
+ */
+public interface UnknownHandler {
+    
+    /**
+     * Handles the case when an action configuration is unknown.  Implementations can return a new ActionConfig
+     * to be used to process the request.
+     * 
+     * @param namespace The namespace
+     * @param actionName The action name
+     * @return An generated ActionConfig, can return <tt>null</tt>
+     * @throws XWorkException
+     */
+    public ActionConfig handleUnknownAction(String namespace, String actionName) throws XWorkException;
+    
+    /**
+     * Handles the case when a result cannot be found for an action and result code. 
+     * 
+     * @param actionContext The action context
+     * @param actionName The action name
+     * @param actionConfig The action config
+     * @param resultCode The returned result code
+     * @return A result to be executed, can return <tt>null</tt>
+     * @throws XWorkException
+     */
+    public Result handleUnknownResult(ActionContext actionContext, String actionName, ActionConfig actionConfig, String resultCode) throws XWorkException;
+    
+    /**
+     * Handles the case when an action method cannot be found.  This method is responsible both for finding the method and executing it.
+     * 
+     * @since 2.1
+     * @param action The action object
+     * @param methodName The method name to call
+     * @return The result returned from invoking the action method, can return <tt>null</tt>
+     * @deprecated @throws NoSuchMethodException If the method cannot be found should return null instead,
+     *                                           don't throw exception as other UnknownHandles won't be invoked
+     *                                           'throws NoSuchMethodException' signature will be removed with next
+     *                                           major release
+     */
+	public Object handleUnknownActionMethod(Object action, String methodName) throws NoSuchMethodException;
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/UnknownHandlerManager.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/UnknownHandlerManager.java b/core/src/main/java/com/opensymphony/xwork2/UnknownHandlerManager.java
new file mode 100644
index 0000000..325c0ff
--- /dev/null
+++ b/core/src/main/java/com/opensymphony/xwork2/UnknownHandlerManager.java
@@ -0,0 +1,37 @@
+/*
+ * 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.entities.ActionConfig;
+
+import java.util.List;
+
+/**
+ * An unknown handler manager contains a list of UnknownHandler and iterates on them by order
+ *
+ * @see com.opensymphony.xwork2.DefaultUnknownHandlerManager
+ */
+public interface UnknownHandlerManager {
+    Result handleUnknownResult(ActionContext actionContext, String actionName, ActionConfig actionConfig, String resultCode);
+
+    Object handleUnknownMethod(Object action, String methodName) throws NoSuchMethodException;
+
+    ActionConfig handleUnknownAction(String namespace, String actionName);
+
+    boolean hasUnknownHandlers();
+
+    List<UnknownHandler> getUnknownHandlers();
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/Validateable.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/Validateable.java b/core/src/main/java/com/opensymphony/xwork2/Validateable.java
new file mode 100644
index 0000000..889a284
--- /dev/null
+++ b/core/src/main/java/com/opensymphony/xwork2/Validateable.java
@@ -0,0 +1,33 @@
+/*
+ * 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;
+
+
+/**
+ * Provides an interface in which a call for a validation check can be done.
+ *
+ * @author Jason Carreira
+ * @see ActionSupport
+ * @see com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor
+ */
+public interface Validateable {
+
+    /**
+     * Performs validation.
+     */
+    void validate();
+
+}


Mime
View raw message