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:[email protected]">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 <[email protected]> + * @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: + * <bean class="org.demo.MyTextProvider" name="myTextProvider" type="com.opensymphony.xwork2.TextProvider" /> + * <constant name="struts.xworkTextProvider" value="myTextProvider" /> + * <p/> + * if you want to also use your implementation for framework's messages define another constant (remember to put + * into it all framework messages) + * <constant name="system" value="myTextProvider" /> + * <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(); + +}
