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); + } + } +}
