http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/interceptor/ScopedModelDrivenInterceptor.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/com/opensymphony/xwork2/interceptor/ScopedModelDrivenInterceptor.java b/core/src/main/java/com/opensymphony/xwork2/interceptor/ScopedModelDrivenInterceptor.java new file mode 100644 index 0000000..9d32fbe --- /dev/null +++ b/core/src/main/java/com/opensymphony/xwork2/interceptor/ScopedModelDrivenInterceptor.java @@ -0,0 +1,164 @@ +/* + * 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.interceptor; + +import com.opensymphony.xwork2.ActionContext; +import com.opensymphony.xwork2.ActionInvocation; +import com.opensymphony.xwork2.ObjectFactory; +import com.opensymphony.xwork2.XWorkException; +import com.opensymphony.xwork2.config.entities.ActionConfig; +import com.opensymphony.xwork2.inject.Inject; + +import java.lang.reflect.Method; +import java.util.Map; + +/** + * <!-- START SNIPPET: description --> + * + * An interceptor that enables scoped model-driven actions. + * + * <p/>This interceptor only activates on actions that implement the {@link ScopedModelDriven} interface. If + * detected, it will retrieve the model class from the configured scope, then provide it to the Action. + * + * <!-- END SNIPPET: description --> + * + * <p/> <u>Interceptor parameters:</u> + * + * <!-- START SNIPPET: parameters --> + * + * <ul> + * + * <li>className - The model class name. Defaults to the class name of the object returned by the getModel() method.</li> + * + * <li>name - The key to use when storing or retrieving the instance in a scope. Defaults to the model + * class name.</li> + * + * <li>scope - The scope to store and retrieve the model. Defaults to 'request' but can also be 'session'.</li> + * </ul> + * + * <!-- END SNIPPET: parameters --> + * + * <p/> <u>Extending the interceptor:</u> + * + * <p/> + * + * <!-- START SNIPPET: extending --> + * + * There are no known extension points for this interceptor. + * + * <!-- END SNIPPET: extending --> + * + * <p/> <u>Example code:</u> + * + * <pre> + * <!-- START SNIPPET: example --> + * + * <-- Basic usage --> + * <interceptor name="scopedModelDriven" class="com.opensymphony.interceptor.ScopedModelDrivenInterceptor" /> + * + * <-- Using all available parameters --> + * <interceptor name="gangsterForm" class="com.opensymphony.interceptor.ScopedModelDrivenInterceptor"> + * <param name="scope">session</param> + * <param name="name">gangsterForm</param> + * <param name="className">com.opensymphony.example.GangsterForm</param> + * </interceptor> + * + * <!-- END SNIPPET: example --> + * </pre> + */ +public class ScopedModelDrivenInterceptor extends AbstractInterceptor { + + private static final Class[] EMPTY_CLASS_ARRAY = new Class[0]; + + private static final String GET_MODEL = "getModel"; + private String scope; + private String name; + private String className; + private ObjectFactory objectFactory; + + @Inject + public void setObjectFactory(ObjectFactory factory) { + this.objectFactory = factory; + } + + protected Object resolveModel(ObjectFactory factory, ActionContext actionContext, String modelClassName, String modelScope, String modelName) throws Exception { + Object model; + Map<String, Object> scopeMap = actionContext.getContextMap(); + if ("session".equals(modelScope)) { + scopeMap = actionContext.getSession(); + } + + model = scopeMap.get(modelName); + if (model == null) { + model = factory.buildBean(modelClassName, null); + scopeMap.put(modelName, model); + } + return model; + } + + @Override + public String intercept(ActionInvocation invocation) throws Exception { + Object action = invocation.getAction(); + + if (action instanceof ScopedModelDriven) { + ScopedModelDriven modelDriven = (ScopedModelDriven) action; + if (modelDriven.getModel() == null) { + ActionContext ctx = ActionContext.getContext(); + ActionConfig config = invocation.getProxy().getConfig(); + + String cName = className; + if (cName == null) { + try { + Method method = action.getClass().getMethod(GET_MODEL, EMPTY_CLASS_ARRAY); + Class cls = method.getReturnType(); + cName = cls.getName(); + } catch (NoSuchMethodException e) { + throw new XWorkException("The " + GET_MODEL + "() is not defined in action " + action.getClass() + "", config); + } + } + String modelName = name; + if (modelName == null) { + modelName = cName; + } + Object model = resolveModel(objectFactory, ctx, cName, scope, modelName); + modelDriven.setModel(model); + modelDriven.setScopeKey(modelName); + } + } + return invocation.invoke(); + } + + /** + * @param className the className to set + */ + public void setClassName(String className) { + this.className = className; + } + + /** + * @param name the name to set + */ + public void setName(String name) { + this.name = name; + } + + /** + * @param scope the scope to set + */ + public void setScope(String scope) { + this.scope = scope; + } +}
http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/interceptor/StaticParametersInterceptor.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/com/opensymphony/xwork2/interceptor/StaticParametersInterceptor.java b/core/src/main/java/com/opensymphony/xwork2/interceptor/StaticParametersInterceptor.java new file mode 100644 index 0000000..25fd8d6 --- /dev/null +++ b/core/src/main/java/com/opensymphony/xwork2/interceptor/StaticParametersInterceptor.java @@ -0,0 +1,240 @@ +/* + * 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.interceptor; + +import com.opensymphony.xwork2.ActionContext; +import com.opensymphony.xwork2.ActionInvocation; +import com.opensymphony.xwork2.ValidationAware; +import com.opensymphony.xwork2.XWorkConstants; +import com.opensymphony.xwork2.config.entities.ActionConfig; +import com.opensymphony.xwork2.config.entities.Parameterizable; +import com.opensymphony.xwork2.inject.Inject; +import com.opensymphony.xwork2.util.*; +import com.opensymphony.xwork2.util.reflection.ReflectionContextState; +import org.apache.commons.lang3.BooleanUtils; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.util.Collections; +import java.util.Map; +import java.util.TreeMap; + + +/** + * <!-- START SNIPPET: description --> + * + * This interceptor populates the action with the static parameters defined in the action configuration. If the action + * implements {@link Parameterizable}, a map of the static parameters will be also be passed directly to the action. + * The static params will be added to the request params map, unless "merge" is set to false. + * + * <p/> Parameters are typically defined with <param> elements within xwork.xml. + * + * <!-- END SNIPPET: description --> + * + * <p/> <u>Interceptor parameters:</u> + * + * <!-- START SNIPPET: parameters --> + * + * <ul> + * + * <li>None</li> + * + * </ul> + * + * <!-- END SNIPPET: parameters --> + * + * <p/> <u>Extending the interceptor:</u> + * + * <!-- START SNIPPET: extending --> + * + * <p/>There are no extension points to this interceptor. + * + * <!-- END SNIPPET: extending --> + * + * <p/> <u>Example code:</u> + * + * <pre> + * <!-- START SNIPPET: example --> + * <action name="someAction" class="com.examples.SomeAction"> + * <interceptor-ref name="staticParams"> + * <param name="parse">true</param> + * <param name="overwrite">false</param> + * </interceptor-ref> + * <result name="success">good_result.ftl</result> + * </action> + * <!-- END SNIPPET: example --> + * </pre> + * + * @author Patrick Lightbody + */ +public class StaticParametersInterceptor extends AbstractInterceptor { + + private boolean parse; + private boolean overwrite; + private boolean merge = true; + private boolean devMode = false; + + private static final Logger LOG = LogManager.getLogger(StaticParametersInterceptor.class); + + private ValueStackFactory valueStackFactory; + + @Inject + public void setValueStackFactory(ValueStackFactory valueStackFactory) { + this.valueStackFactory = valueStackFactory; + } + + @Inject(XWorkConstants.DEV_MODE) + public void setDevMode(String mode) { + devMode = BooleanUtils.toBoolean(mode); + } + + public void setParse(String value) { + this.parse = BooleanUtils.toBoolean(value); + } + + public void setMerge(String value) { + this.merge = BooleanUtils.toBoolean(value); + } + + /** + * Overwrites already existing parameters from other sources. + * Static parameters are the successor over previously set parameters, if true. + * + * @param value + */ + public void setOverwrite(String value) { + this.overwrite = BooleanUtils.toBoolean(value); + } + + @Override + public String intercept(ActionInvocation invocation) throws Exception { + ActionConfig config = invocation.getProxy().getConfig(); + Object action = invocation.getAction(); + + final Map<String, String> parameters = config.getParams(); + + LOG.debug("Setting static parameters: {}", parameters); + + // for actions marked as Parameterizable, pass the static parameters directly + if (action instanceof Parameterizable) { + ((Parameterizable) action).setParams(parameters); + } + + if (parameters != null) { + ActionContext ac = ActionContext.getContext(); + Map<String, Object> contextMap = ac.getContextMap(); + try { + ReflectionContextState.setCreatingNullObjects(contextMap, true); + ReflectionContextState.setReportingConversionErrors(contextMap, true); + final ValueStack stack = ac.getValueStack(); + + ValueStack newStack = valueStackFactory.createValueStack(stack); + boolean clearableStack = newStack instanceof ClearableValueStack; + if (clearableStack) { + //if the stack's context can be cleared, do that to prevent OGNL + //from having access to objects in the stack, see XW-641 + ((ClearableValueStack)newStack).clearContextValues(); + Map<String, Object> context = newStack.getContext(); + ReflectionContextState.setCreatingNullObjects(context, true); + ReflectionContextState.setDenyMethodExecution(context, true); + ReflectionContextState.setReportingConversionErrors(context, true); + + //keep locale from original context + context.put(ActionContext.LOCALE, stack.getContext().get(ActionContext.LOCALE)); + } + + for (Map.Entry<String, String> entry : parameters.entrySet()) { + Object val = entry.getValue(); + if (parse && val instanceof String) { + val = TextParseUtil.translateVariables(val.toString(), stack); + } + try { + newStack.setValue(entry.getKey(), val); + } catch (RuntimeException e) { + if (devMode) { + String developerNotification = LocalizedTextUtil.findText(ParametersInterceptor.class, "devmode.notification", ActionContext.getContext().getLocale(), "Developer Notification:\n{0}", new Object[]{ + "Unexpected Exception caught setting '" + entry.getKey() + "' on '" + action.getClass() + ": " + e.getMessage() + }); + LOG.error(developerNotification); + if (action instanceof ValidationAware) { + ((ValidationAware) action).addActionMessage(developerNotification); + } + } + } + } + + if (clearableStack && (stack.getContext() != null) && (newStack.getContext() != null)) + stack.getContext().put(ActionContext.CONVERSION_ERRORS, newStack.getContext().get(ActionContext.CONVERSION_ERRORS)); + + if (merge) + addParametersToContext(ac, parameters); + } finally { + ReflectionContextState.setCreatingNullObjects(contextMap, false); + ReflectionContextState.setReportingConversionErrors(contextMap, false); + } + } + return invocation.invoke(); + } + + + /** + * @param ac The action context + * @return the parameters from the action mapping in the context. If none found, returns + * an empty map. + */ + protected Map<String, String> retrieveParameters(ActionContext ac) { + ActionConfig config = ac.getActionInvocation().getProxy().getConfig(); + if (config != null) { + return config.getParams(); + } else { + return Collections.emptyMap(); + } + } + + /** + * Adds the parameters into context's ParameterMap. + * As default, static parameters will not overwrite existing paramaters from other sources. + * If you want the static parameters as successor over already existing parameters, set overwrite to <tt>true</tt>. + * + * @param ac The action context + * @param newParams The parameter map to apply + */ + protected void addParametersToContext(ActionContext ac, Map<String, ?> newParams) { + Map<String, Object> previousParams = ac.getParameters(); + + Map<String, Object> combinedParams; + if ( overwrite ) { + if (previousParams != null) { + combinedParams = new TreeMap<>(previousParams); + } else { + combinedParams = new TreeMap<>(); + } + if ( newParams != null) { + combinedParams.putAll(newParams); + } + } else { + if (newParams != null) { + combinedParams = new TreeMap<>(newParams); + } else { + combinedParams = new TreeMap<>(); + } + if ( previousParams != null) { + combinedParams.putAll(previousParams); + } + } + ac.setParameters(combinedParams); + } +} http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/interceptor/TimerInterceptor.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/com/opensymphony/xwork2/interceptor/TimerInterceptor.java b/core/src/main/java/com/opensymphony/xwork2/interceptor/TimerInterceptor.java new file mode 100644 index 0000000..7cc4918 --- /dev/null +++ b/core/src/main/java/com/opensymphony/xwork2/interceptor/TimerInterceptor.java @@ -0,0 +1,244 @@ +/* + * 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.interceptor; + +import com.opensymphony.xwork2.ActionInvocation; +import org.apache.commons.lang3.StringUtils; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +/** + * <!-- START SNIPPET: description --> + * This interceptor logs the amount of time in milliseconds. In order for this interceptor to work properly, the + * logging framework must be set to at least the <tt>INFO</tt> level. + * This interceptor relies on the <a href="http://jakarta.apache.org/commons/logging/">Commons Logging API</a> to + * report its execution-time value. + * <!-- END SNIPPET: description --> + * + * <!-- START SNIPPET: parameters --> + * + * <ul> + * + * <li>logLevel (optional) - what log level should we use (<code>trace, debug, info, warn, error, fatal</code>)? - defaut is <code>info</code></li> + * + * <li>logCategory (optional) - If provided we would use this category (eg. <code>com.mycompany.app</code>). + * Default is to use <code>com.opensymphony.xwork2.interceptor.TimerInterceptor</code>.</li> + * + * </ul> + * + * The parameters above enables us to log all action execution times in our own logfile. + * + * <!-- END SNIPPET: parameters --> + * + * <!-- START SNIPPET: extending --> + * This interceptor can be extended to provide custom message format. Users should override the + * <code>invokeUnderTiming</code> method. + * <!-- END SNIPPET: extending --> + * + * <pre> + * <!-- START SNIPPET: example --> + * <!-- records only the action's execution time --> + * <action name="someAction" class="com.examples.SomeAction"> + * <interceptor-ref name="completeStack"/> + * <interceptor-ref name="timer"/> + * <result name="success">good_result.ftl</result> + * </action> + * + * <!-- records action's execution time as well as other interceptors--> + * <action name="someAction" class="com.examples.SomeAction"> + * <interceptor-ref name="timer"/> + * <interceptor-ref name="completeStack"/> + * <result name="success">good_result.ftl</result> + * </action> + * <!-- END SNIPPET: example --> + * </pre> + * + * This second example uses our own log category at debug level. + * + * <pre> + * <!-- START SNIPPET: example2 --> + * <!-- records only the action's execution time --> + * <action name="someAction" class="com.examples.SomeAction"> + * <interceptor-ref name="completeStack"/> + * <interceptor-ref name="timer"> + * <param name="logLevel">debug</param> + * <param name="logCategory">com.mycompany.myapp.actiontime</param> + * <interceptor-ref/> + * <result name="success">good_result.ftl</result> + * </action> + * + * <!-- records action's execution time as well as other interceptors--> + * <action name="someAction" class="com.examples.SomeAction"> + * <interceptor-ref name="timer"/> + * <interceptor-ref name="completeStack"/> + * <result name="success">good_result.ftl</result> + * </action> + * <!-- END SNIPPET: example2 --> + * </pre> + * + * @author Jason Carreira + * @author Claus Ibsen + */ +public class TimerInterceptor extends AbstractInterceptor { + protected static final Logger LOG = LogManager.getLogger(TimerInterceptor.class); + + protected Logger categoryLogger; + protected String logCategory; + protected String logLevel; + + public String getLogCategory() { + return logCategory; + } + + public void setLogCategory(String logCatgory) { + this.logCategory = logCatgory; + } + + public String getLogLevel() { + return logLevel; + } + + public void setLogLevel(String logLevel) { + this.logLevel = logLevel; + } + + @Override + public String intercept(ActionInvocation invocation) throws Exception { + if (! shouldLog()) { + return invocation.invoke(); + } else { + return invokeUnderTiming(invocation); + } + } + + /** + * Is called to invoke the action invocation and time the execution time. + * + * @param invocation the action invocation. + * @return the result of the action execution. + * @throws Exception can be thrown from the action. + */ + protected String invokeUnderTiming(ActionInvocation invocation) throws Exception { + long startTime = System.currentTimeMillis(); + String result = invocation.invoke(); + long executionTime = System.currentTimeMillis() - startTime; + + StringBuilder message = new StringBuilder(100); + message.append("Executed action ["); + String namespace = invocation.getProxy().getNamespace(); + if (StringUtils.isNotBlank(namespace)) { + message.append(namespace).append("/"); + } + message.append(invocation.getProxy().getActionName()); + message.append("!"); + message.append(invocation.getProxy().getMethod()); + message.append("] took ").append(executionTime).append(" ms."); + + doLog(getLoggerToUse(), message.toString()); + + return result; + } + + /** + * Determines if we should log the time. + * + * @return true to log, false to not log. + */ + protected boolean shouldLog() { + // default check first + if (logLevel == null && logCategory == null) { + return LOG.isInfoEnabled(); + } + + // okay user have set some parameters + return isLoggerEnabled(getLoggerToUse(), logLevel); + } + + /** + * Get's the logger to use. + * + * @return the logger to use. + */ + protected Logger getLoggerToUse() { + if (logCategory != null) { + if (categoryLogger == null) { + // init category logger + categoryLogger = LogManager.getLogger(logCategory); + if (logLevel == null) { + logLevel = "info"; // use info as default if not provided + } + } + return categoryLogger; + } + + return LOG; + } + + /** + * Performs the actual logging. + * + * @param logger the provided logger to use. + * @param message the message to log. + */ + protected void doLog(Logger logger, String message) { + if (logLevel == null) { + logger.info(message); + return; + } + + if ("debug".equalsIgnoreCase(logLevel)) { + logger.debug(message); + } else if ("info".equalsIgnoreCase(logLevel)) { + logger.info(message); + } else if ("warn".equalsIgnoreCase(logLevel)) { + logger.warn(message); + } else if ("error".equalsIgnoreCase(logLevel)) { + logger.error(message); + } else if ("fatal".equalsIgnoreCase(logLevel)) { + logger.fatal(message); + } else if ("trace".equalsIgnoreCase(logLevel)) { + logger.trace(message); + } else { + throw new IllegalArgumentException("LogLevel [" + logLevel + "] is not supported"); + } + } + + /** + * Is the given logger enalbed at the given level? + * + * @param logger the logger. + * @param level the level to check if <code>isXXXEnabled</code>. + * @return <tt>true</tt> if enabled, <tt>false</tt> if not. + */ + private static boolean isLoggerEnabled(Logger logger, String level) { + if ("debug".equalsIgnoreCase(level)) { + return logger.isDebugEnabled(); + } else if ("info".equalsIgnoreCase(level)) { + return logger.isInfoEnabled(); + } else if ("warn".equalsIgnoreCase(level)) { + return logger.isWarnEnabled(); + } else if ("error".equalsIgnoreCase(level)) { + return logger.isErrorEnabled(); + } else if ("fatal".equalsIgnoreCase(level)) { + return logger.isFatalEnabled(); + } else if ("trace".equalsIgnoreCase(level)) { + return logger.isTraceEnabled(); + } else { + throw new IllegalArgumentException("LogLevel [" + level + "] is not supported"); + } + } + +} http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/interceptor/ValidationErrorAware.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/com/opensymphony/xwork2/interceptor/ValidationErrorAware.java b/core/src/main/java/com/opensymphony/xwork2/interceptor/ValidationErrorAware.java new file mode 100644 index 0000000..5d0fd6b --- /dev/null +++ b/core/src/main/java/com/opensymphony/xwork2/interceptor/ValidationErrorAware.java @@ -0,0 +1,38 @@ +/* + * 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.interceptor; + +/** + * ValidationErrorAware classes can be notified about validation errors + * before {@link com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor} will return 'inputResultName' result + * to allow change or not the result name + * + * This interface can be only applied to action which already implements {@link com.opensymphony.xwork2.ValidationAware} interface! + * + * @since 2.3.15 + */ +public interface ValidationErrorAware { + + /** + * Allows to notify action about occurred action/field errors + * + * @param currentResultName current result name, action can change it or return the same + * @return new result name or passed currentResultName + */ + String actionErrorOccurred(final String currentResultName); + +} http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/interceptor/ValidationWorkflowAware.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/com/opensymphony/xwork2/interceptor/ValidationWorkflowAware.java b/core/src/main/java/com/opensymphony/xwork2/interceptor/ValidationWorkflowAware.java new file mode 100644 index 0000000..51bdf71 --- /dev/null +++ b/core/src/main/java/com/opensymphony/xwork2/interceptor/ValidationWorkflowAware.java @@ -0,0 +1,12 @@ +package com.opensymphony.xwork2.interceptor; + +/** + * ValidationWorkflowAware classes can programmatically change result name when errors occurred + * + * This interface can be only applied to action which already implements {@link com.opensymphony.xwork2.ValidationAware} interface! + */ +public interface ValidationWorkflowAware { + + String getInputResultName(); + +} http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/interceptor/annotations/After.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/com/opensymphony/xwork2/interceptor/annotations/After.java b/core/src/main/java/com/opensymphony/xwork2/interceptor/annotations/After.java new file mode 100644 index 0000000..3fc2fcd --- /dev/null +++ b/core/src/main/java/com/opensymphony/xwork2/interceptor/annotations/After.java @@ -0,0 +1,81 @@ +/* + * 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.interceptor.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * <!-- START SNIPPET: description --> + * Marks a action method that needs to be called after the main action method and the result was + * executed. Return value is ignored. + * <!-- END SNIPPET: description --> + * + * <p/> <u>Annotation usage:</u> + * + * <!-- START SNIPPET: usage --> + * The After annotation can be applied at method level. + * + * <!-- END SNIPPET: usage --> + * + * <p/> <u>Annotation parameters:</u> + * + * <!-- START SNIPPET: parameters --> + * <table class='confluenceTable'> + * <tr> + * <th class='confluenceTh'> Parameter </th> + * <th class='confluenceTh'> Required </th> + * <th class='confluenceTh'> Default </th> + * <th class='confluenceTh'> Notes </th> + * </tr> + * <tr> + * <td class='confluenceTd'>priority</td> + * <td class='confluenceTd'>no</td> + * <td class='confluenceTd'>10</td> + * <td class='confluenceTd'>Priority order of method execution</td> + * </tr> + * </table> + * <!-- END SNIPPET: parameters --> + * + * <p/> <u>Example code:</u> + * + * <pre> + * <!-- START SNIPPET: example --> + * public class SampleAction extends ActionSupport { + * + * @After + * public void isValid() throws ValidationException { + * // validate model object, throw exception if failed + * } + * + * public String execute() { + * // perform action + * return SUCCESS; + * } + * } + * <!-- END SNIPPET: example --> + * </pre> + * + * @author Zsolt Szasz, zsolt at lorecraft dot com + * @author Rainer Hermanns + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.METHOD}) +public @interface After { + int priority() default 10; +} http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/interceptor/annotations/Allowed.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/com/opensymphony/xwork2/interceptor/annotations/Allowed.java b/core/src/main/java/com/opensymphony/xwork2/interceptor/annotations/Allowed.java new file mode 100644 index 0000000..4263344 --- /dev/null +++ b/core/src/main/java/com/opensymphony/xwork2/interceptor/annotations/Allowed.java @@ -0,0 +1,18 @@ +package com.opensymphony.xwork2.interceptor.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Declares that it is permitted for the field be mutated through + * a HttpRequest parameter. + * + * @author martin.gilday + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface Allowed { + +} http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/interceptor/annotations/AnnotationParameterFilterIntereptor.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/com/opensymphony/xwork2/interceptor/annotations/AnnotationParameterFilterIntereptor.java b/core/src/main/java/com/opensymphony/xwork2/interceptor/annotations/AnnotationParameterFilterIntereptor.java new file mode 100644 index 0000000..f978e46 --- /dev/null +++ b/core/src/main/java/com/opensymphony/xwork2/interceptor/annotations/AnnotationParameterFilterIntereptor.java @@ -0,0 +1,95 @@ +package com.opensymphony.xwork2.interceptor.annotations; + + +import com.opensymphony.xwork2.Action; +import com.opensymphony.xwork2.ActionInvocation; +import com.opensymphony.xwork2.interceptor.AbstractInterceptor; +import com.opensymphony.xwork2.interceptor.Interceptor; +import com.opensymphony.xwork2.interceptor.ParameterFilterInterceptor; +import com.opensymphony.xwork2.interceptor.ParametersInterceptor; +import com.opensymphony.xwork2.util.AnnotationUtils; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Map; + +/** + * Annotation based version of {@link ParameterFilterInterceptor}. + * <p/> + * This {@link Interceptor} must be placed in the stack before the {@link ParametersInterceptor} + * When a parameter matches a field that is marked {@link Blocked} then it is removed from + * the parameter map. + * <p/> + * If an {@link Action} class is marked with {@link BlockByDefault} then all parameters are + * removed unless a field on the Action exists and is marked with {@link Allowed} + * + * @author martin.gilday + */ +public class AnnotationParameterFilterIntereptor extends AbstractInterceptor { + + /* (non-Javadoc) + * @see com.opensymphony.xwork2.interceptor.AbstractInterceptor#intercept(com.opensymphony.xwork2.ActionInvocation) + */ + @Override public String intercept(ActionInvocation invocation) throws Exception { + + final Object action = invocation.getAction(); + Map<String, Object> parameters = invocation.getInvocationContext().getParameters(); + + Object model = invocation.getStack().peek(); + if (model == action) { + model = null; + } + + boolean blockByDefault = action.getClass().isAnnotationPresent(BlockByDefault.class); + List<Field> annotatedFields = new ArrayList<>(); + HashSet<String> paramsToRemove = new HashSet<>(); + + if (blockByDefault) { + AnnotationUtils.addAllFields(Allowed.class, action.getClass(), annotatedFields); + if (model != null) { + AnnotationUtils.addAllFields(Allowed.class, model.getClass(), annotatedFields); + } + + for (String paramName : parameters.keySet()) { + boolean allowed = false; + + for (Field field : annotatedFields) { + //TODO only matches exact field names. need to change to it matches start of ognl expression + //i.e take param name up to first . (period) and match against that + if (field.getName().equals(paramName)) { + allowed = true; + break; + } + } + + if (!allowed) { + paramsToRemove.add(paramName); + } + } + } else { + AnnotationUtils.addAllFields(Blocked.class, action.getClass(), annotatedFields); + if (model != null) { + AnnotationUtils.addAllFields(Blocked.class, model.getClass(), annotatedFields); + } + + for (String paramName : parameters.keySet()) { + for (Field field : annotatedFields) { + //TODO only matches exact field names. need to change to it matches start of ognl expression + //i.e take param name up to first . (period) and match against that + if (field.getName().equals(paramName)) { + paramsToRemove.add(paramName); + } + } + } + } + + for (String aParamsToRemove : paramsToRemove) { + parameters.remove(aParamsToRemove); + } + + return invocation.invoke(); + } + +} http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/interceptor/annotations/AnnotationWorkflowInterceptor.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/com/opensymphony/xwork2/interceptor/annotations/AnnotationWorkflowInterceptor.java b/core/src/main/java/com/opensymphony/xwork2/interceptor/annotations/AnnotationWorkflowInterceptor.java new file mode 100644 index 0000000..665ed1c --- /dev/null +++ b/core/src/main/java/com/opensymphony/xwork2/interceptor/annotations/AnnotationWorkflowInterceptor.java @@ -0,0 +1,192 @@ +/* + * 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.interceptor.annotations; + +import com.opensymphony.xwork2.ActionInvocation; +import com.opensymphony.xwork2.XWorkException; +import com.opensymphony.xwork2.interceptor.AbstractInterceptor; +import com.opensymphony.xwork2.interceptor.PreResultListener; +import com.opensymphony.xwork2.util.AnnotationUtils; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +/** + * <!-- START SNIPPET: javadoc --> + * <p>Invokes any annotated methods on the action. Specifically, it supports the following + * annotations: + * <ul> + * <li> @{@link Before} - will be invoked before the action method. If the returned value is not null, it is + * returned as the action result code</li> + * <li> @{@link BeforeResult} - will be invoked after the action method but before the result execution</li> + * <li> @{@link After} - will be invoked after the action method and result execution</li> + * </ul> + * </p> + * <p/> + * <p>There can be multiple methods marked with the same annotations, but the order of their execution + * is not guaranteed. However, the annotated methods on the superclass chain are guaranteed to be invoked before the + * annotated method in the current class in the case of a {@link Before} annotations and after, if the annotations is + * {@link After}.</p> + * <!-- END SNIPPET: javadoc --> + * <p/> + * <pre> + * <!-- START SNIPPET: javacode --> + * public class BaseAnnotatedAction { + * protected String log = ""; + * <p/> + * @Before + * public String baseBefore() { + * log = log + "baseBefore-"; + * return null; + * } + * } + * <p/> + * public class AnnotatedAction extends BaseAnnotatedAction { + * @Before + * public String before() { + * log = log + "before"; + * return null; + * } + * <p/> + * public String execute() { + * log = log + "-execute"; + * return Action.SUCCESS; + * } + * <p/> + * @BeforeResult + * public void beforeResult() throws Exception { + * log = log +"-beforeResult"; + * } + * <p/> + * @After + * public void after() { + * log = log + "-after"; + * } + * } + * <!-- END SNIPPET: javacode --> + * </pre> + * <p/> + * <!-- START SNIPPET: example --> + * <p>With the interceptor applied and the action executed on <code>AnnotatedAction</code> the log + * instance variable will contain <code>baseBefore-before-execute-beforeResult-after</code>.</p> + * <!-- END SNIPPET: example --> + * <p/> + * <p/>Configure a stack in xwork.xml that replaces the PrepareInterceptor with the AnnotationWorkflowInterceptor: + * <pre> + * <!-- START SNIPPET: stack --> + * <interceptor-stack name="annotatedStack"> + * <interceptor-ref name="staticParams"/> + * <interceptor-ref name="params"/> + * <interceptor-ref name="conversionError"/> + * <interceptor-ref name="annotationWorkflow"/> + * </interceptor-stack> + * <!-- END SNIPPET: stack --> + * </pre> + * + * @author Zsolt Szasz, zsolt at lorecraft dot com + * @author Rainer Hermanns + * @author Dan Oxlade, dan d0t oxlade at gmail d0t c0m + */ +public class AnnotationWorkflowInterceptor extends AbstractInterceptor implements PreResultListener { + + /** + * Discovers annotated methods on the action and calls them according to the workflow + * + * @see com.opensymphony.xwork2.interceptor.Interceptor#intercept(com.opensymphony.xwork2.ActionInvocation) + */ + public String intercept(ActionInvocation invocation) throws Exception { + final Object action = invocation.getAction(); + invocation.addPreResultListener(this); + List<Method> methods = new ArrayList<>(AnnotationUtils.getAnnotatedMethods(action.getClass(), Before.class)); + if (methods.size() > 0) { + // methods are only sorted by priority + Collections.sort(methods, new Comparator<Method>() { + public int compare(Method method1, Method method2) { + return comparePriorities(method1.getAnnotation(Before.class).priority(), + method2.getAnnotation(Before.class).priority()); + } + }); + for (Method m : methods) { + final String resultCode = (String) m.invoke(action, (Object[]) null); + if (resultCode != null) { + // shortcircuit execution + return resultCode; + } + } + } + + String invocationResult = invocation.invoke(); + + // invoke any @After methods + methods = new ArrayList<Method>(AnnotationUtils.getAnnotatedMethods(action.getClass(), After.class)); + + if (methods.size() > 0) { + // methods are only sorted by priority + Collections.sort(methods, new Comparator<Method>() { + public int compare(Method method1, Method method2) { + return comparePriorities(method1.getAnnotation(After.class).priority(), + method2.getAnnotation(After.class).priority()); + } + }); + for (Method m : methods) { + m.invoke(action, (Object[]) null); + } + } + + return invocationResult; + } + + protected static int comparePriorities(int val1, int val2) { + if (val2 < val1) { + return -1; + } else if (val2 > val1) { + return 1; + } else { + return 0; + } + } + + /** + * Invokes any @BeforeResult annotated methods + * + * @see com.opensymphony.xwork2.interceptor.PreResultListener#beforeResult(com.opensymphony.xwork2.ActionInvocation,String) + */ + public void beforeResult(ActionInvocation invocation, String resultCode) { + Object action = invocation.getAction(); + List<Method> methods = new ArrayList<Method>(AnnotationUtils.getAnnotatedMethods(action.getClass(), BeforeResult.class)); + + if (methods.size() > 0) { + // methods are only sorted by priority + Collections.sort(methods, new Comparator<Method>() { + public int compare(Method method1, Method method2) { + return comparePriorities(method1.getAnnotation(BeforeResult.class).priority(), + method2.getAnnotation(BeforeResult.class).priority()); + } + }); + for (Method m : methods) { + try { + m.invoke(action, (Object[]) null); + } catch (Exception e) { + throw new XWorkException(e); + } + } + } + } + +} http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/interceptor/annotations/Before.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/com/opensymphony/xwork2/interceptor/annotations/Before.java b/core/src/main/java/com/opensymphony/xwork2/interceptor/annotations/Before.java new file mode 100644 index 0000000..cb0e555 --- /dev/null +++ b/core/src/main/java/com/opensymphony/xwork2/interceptor/annotations/Before.java @@ -0,0 +1,80 @@ +/* + * 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.interceptor.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * <!-- START SNIPPET: description --> + * Marks a action method that needs to be executed before the main action method. + * <!-- END SNIPPET: description --> + * + * <p/> <u>Annotation usage:</u> + * + * <!-- START SNIPPET: usage --> + * The Before annotation can be applied at method level. + * + * <!-- END SNIPPET: usage --> + * + * <p/> <u>Annotation parameters:</u> + * + * <!-- START SNIPPET: parameters --> + * <table class='confluenceTable'> + * <tr> + * <th class='confluenceTh'> Parameter </th> + * <th class='confluenceTh'> Required </th> + * <th class='confluenceTh'> Default </th> + * <th class='confluenceTh'> Notes </th> + * </tr> + * <tr> + * <td class='confluenceTd'>priority</td> + * <td class='confluenceTd'>no</td> + * <td class='confluenceTd'>10</td> + * <td class='confluenceTd'>Priority order of method execution</td> + * </tr> + * </table> + * <!-- END SNIPPET: parameters --> + * + * <p/> <u>Example code:</u> + * + * <pre> + * <!-- START SNIPPET: example --> + * public class SampleAction extends ActionSupport { + * + * @Before + * public void isAuthorized() throws AuthenticationException { + * // authorize request, throw exception if failed + * } + * + * public String execute() { + * // perform secure action + * return SUCCESS; + * } + * } + * <!-- END SNIPPET: example --> + * </pre> + * + * @author Zsolt Szasz, zsolt at lorecraft dot com + * @author Rainer Hermanns + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.METHOD}) +public @interface Before { + int priority() default 10; +} http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/interceptor/annotations/BeforeResult.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/com/opensymphony/xwork2/interceptor/annotations/BeforeResult.java b/core/src/main/java/com/opensymphony/xwork2/interceptor/annotations/BeforeResult.java new file mode 100644 index 0000000..faeb400 --- /dev/null +++ b/core/src/main/java/com/opensymphony/xwork2/interceptor/annotations/BeforeResult.java @@ -0,0 +1,80 @@ +/* + * 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.interceptor.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * <!-- START SNIPPET: description --> + * Marks a action method that needs to be executed before the result. Return value is ignored. + * <!-- END SNIPPET: description --> + * + * <p/> <u>Annotation usage:</u> + * + * <!-- START SNIPPET: usage --> + * The BeforeResult annotation can be applied at method level. + * + * <!-- END SNIPPET: usage --> + * + * <p/> <u>Annotation parameters:</u> + * + * <!-- START SNIPPET: parameters --> + * <table class='confluenceTable'> + * <tr> + * <th class='confluenceTh'> Parameter </th> + * <th class='confluenceTh'> Required </th> + * <th class='confluenceTh'> Default </th> + * <th class='confluenceTh'> Notes </th> + * </tr> + * <tr> + * <td class='confluenceTd'>priority</td> + * <td class='confluenceTd'>no</td> + * <td class='confluenceTd'>10</td> + * <td class='confluenceTd'>Priority order of method execution</td> + * </tr> + * </table> + * <!-- END SNIPPET: parameters --> + * + * <p/> <u>Example code:</u> + * + * <pre> + * <!-- START SNIPPET: example --> + * public class SampleAction extends ActionSupport { + * + * @BeforeResult + * public void isValid() throws ValidationException { + * // validate model object, throw exception if failed + * } + * + * public String execute() { + * // perform action + * return SUCCESS; + * } + * } + * <!-- END SNIPPET: example --> + * </pre> + * + * @author Zsolt Szasz, zsolt at lorecraft dot com + * @author Rainer Hermanns + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.METHOD}) +public @interface BeforeResult { + int priority() default 10; +} http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/interceptor/annotations/BlockByDefault.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/com/opensymphony/xwork2/interceptor/annotations/BlockByDefault.java b/core/src/main/java/com/opensymphony/xwork2/interceptor/annotations/BlockByDefault.java new file mode 100644 index 0000000..a87ac0b --- /dev/null +++ b/core/src/main/java/com/opensymphony/xwork2/interceptor/annotations/BlockByDefault.java @@ -0,0 +1,21 @@ +package com.opensymphony.xwork2.interceptor.annotations; + +import com.opensymphony.xwork2.Action; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Declares that by default fields on the {@link Action} class + * are NOT permitted to be set from HttpRequest parameters. + * To allow access to a field it must be annotated with {@link Allowed} + * + * @author martin.gilday + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface BlockByDefault { + +} http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/interceptor/annotations/Blocked.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/com/opensymphony/xwork2/interceptor/annotations/Blocked.java b/core/src/main/java/com/opensymphony/xwork2/interceptor/annotations/Blocked.java new file mode 100644 index 0000000..e9a2885 --- /dev/null +++ b/core/src/main/java/com/opensymphony/xwork2/interceptor/annotations/Blocked.java @@ -0,0 +1,18 @@ +package com.opensymphony.xwork2.interceptor.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Declares that the given field should NOT be able to be mutated through + * a HttpRequest parameter. + * + * @author martin.gilday + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface Blocked { + +} http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/interceptor/annotations/InputConfig.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/com/opensymphony/xwork2/interceptor/annotations/InputConfig.java b/core/src/main/java/com/opensymphony/xwork2/interceptor/annotations/InputConfig.java new file mode 100644 index 0000000..5d70744 --- /dev/null +++ b/core/src/main/java/com/opensymphony/xwork2/interceptor/annotations/InputConfig.java @@ -0,0 +1,92 @@ +/* + * Copyright 2002-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.interceptor.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import com.opensymphony.xwork2.Action; + +/** + * <!-- START SNIPPET: description --> + * Marks a action method that if it's not validated by ValidationInterceptor then execute input method or input result. + * <!-- END SNIPPET: description --> + * + * <p/> <u>Annotation usage:</u> + * + * <!-- START SNIPPET: usage --> + * The InputConfig annotation can be applied at method level. + * + * <!-- END SNIPPET: usage --> + * + * <p/> <u>Annotation parameters:</u> + * + * <!-- START SNIPPET: parameters --> + * <table class='confluenceTable'> + * <tr> + * <th class='confluenceTh'> Parameter </th> + * <th class='confluenceTh'> Required </th> + * <th class='confluenceTh'> Default </th> + * <th class='confluenceTh'> Notes </th> + * </tr> + * <tr> + * <td class='confluenceTd'>methodName</td> + * <td class='confluenceTd'>no</td> + * <td class='confluenceTd'></td> + * <td class='confluenceTd'>execute this method if specific</td> + * </tr> + * <tr> + * <td class='confluenceTd'>resultName</td> + * <td class='confluenceTd'>no</td> + * <td class='confluenceTd'></td> + * <td class='confluenceTd'>return this result if methodName not specific</td> + * </tr> + * </table> + * <!-- END SNIPPET: parameters --> + * + * <p/> <u>Example code:</u> + * + * <pre> + * <!-- START SNIPPET: example --> + * public class SampleAction extends ActionSupport { + * + * public void isValid() throws ValidationException { + * // validate model object, throw exception if failed + * } + * + * @InputConfig(methodName="input") + * public String execute() { + * // perform action + * return SUCCESS; + * } + * public String input() { + * // perform some data filling + * return INPUT; + * } + * } + * <!-- END SNIPPET: example --> + * </pre> + * + * @author zhouyanming, [email protected] + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.METHOD}) +public @interface InputConfig { + String methodName() default ""; + String resultName() default Action.INPUT; +} http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/interceptor/annotations/package.html ---------------------------------------------------------------------- diff --git a/core/src/main/java/com/opensymphony/xwork2/interceptor/annotations/package.html b/core/src/main/java/com/opensymphony/xwork2/interceptor/annotations/package.html new file mode 100644 index 0000000..8ac50a8 --- /dev/null +++ b/core/src/main/java/com/opensymphony/xwork2/interceptor/annotations/package.html @@ -0,0 +1 @@ +<body>Interceptor annotations.</body> http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/interceptor/package.html ---------------------------------------------------------------------- diff --git a/core/src/main/java/com/opensymphony/xwork2/interceptor/package.html b/core/src/main/java/com/opensymphony/xwork2/interceptor/package.html new file mode 100644 index 0000000..505d814 --- /dev/null +++ b/core/src/main/java/com/opensymphony/xwork2/interceptor/package.html @@ -0,0 +1 @@ +<body>Interceptor classes.</body> http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/mock/MockActionInvocation.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/com/opensymphony/xwork2/mock/MockActionInvocation.java b/core/src/main/java/com/opensymphony/xwork2/mock/MockActionInvocation.java new file mode 100644 index 0000000..0749689 --- /dev/null +++ b/core/src/main/java/com/opensymphony/xwork2/mock/MockActionInvocation.java @@ -0,0 +1,133 @@ +/* + * 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; + +import com.opensymphony.xwork2.*; +import com.opensymphony.xwork2.interceptor.PreResultListener; +import com.opensymphony.xwork2.util.ValueStack; + +import java.util.ArrayList; +import java.util.List; + +/** + * Mock for an {@link ActionInvocation}. + * + * @author plightbo + * @author Rainer Hermanns + * @author tm_jee + * @version $Id$ + */ +public class MockActionInvocation implements ActionInvocation { + + private Object action; + private ActionContext invocationContext; + private ActionEventListener actionEventListener; + private ActionProxy proxy; + private Result result; + private String resultCode; + private ValueStack stack; + + private List<PreResultListener> preResultListeners = new ArrayList<>(); + + public Object getAction() { + return action; + } + + public void setAction(Object action) { + this.action = action; + } + + public ActionContext getInvocationContext() { + return invocationContext; + } + + public void setInvocationContext(ActionContext invocationContext) { + this.invocationContext = invocationContext; + } + + public ActionProxy getProxy() { + return proxy; + } + + public void setProxy(ActionProxy proxy) { + this.proxy = proxy; + } + + public Result getResult() { + return result; + } + + public void setResult(Result result) { + this.result = result; + } + + public String getResultCode() { + return resultCode; + } + + public void setResultCode(String resultCode) { + this.resultCode = resultCode; + } + + public ValueStack getStack() { + return stack; + } + + public void setStack(ValueStack stack) { + this.stack = stack; + } + + public boolean isExecuted() { + return false; + } + + public void addPreResultListener(PreResultListener listener) { + preResultListeners.add(listener); + } + + public String invoke() throws Exception { + for (Object preResultListener : preResultListeners) { + PreResultListener listener = (PreResultListener) preResultListener; + listener.beforeResult(this, resultCode); + } + return resultCode; + } + + public String invokeActionOnly() throws Exception { + return resultCode; + } + + public void setActionEventListener(ActionEventListener listener) { + this.actionEventListener = listener; + } + + public ActionEventListener getActionEventListener() { + return this.actionEventListener; + } + + public void init(ActionProxy proxy) { + } + + public ActionInvocation serialize() { + return this; + } + + public ActionInvocation deserialize(ActionContext actionContext) { + return this; + } + +} http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/mock/MockActionProxy.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/com/opensymphony/xwork2/mock/MockActionProxy.java b/core/src/main/java/com/opensymphony/xwork2/mock/MockActionProxy.java new file mode 100644 index 0000000..f373591 --- /dev/null +++ b/core/src/main/java/com/opensymphony/xwork2/mock/MockActionProxy.java @@ -0,0 +1,127 @@ +/* + * 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; + +import com.opensymphony.xwork2.ActionInvocation; +import com.opensymphony.xwork2.ActionProxy; +import com.opensymphony.xwork2.config.Configuration; +import com.opensymphony.xwork2.config.entities.ActionConfig; +import org.apache.commons.lang3.StringUtils; + +/** + * Mock for an {@link ActionProxy}. + * + * @author Patrick Lightbody (plightbo at gmail dot com) + */ +public class MockActionProxy implements ActionProxy { + + Object action; + String actionName; + ActionConfig config; + boolean executeResult; + ActionInvocation invocation; + String namespace; + String method; + boolean executedCalled; + String returnedResult; + Configuration configuration; + boolean methodSpecified; + + public void prepare() throws Exception {} + + public String execute() throws Exception { + executedCalled = true; + + return returnedResult; + } + + public void setReturnedResult(String returnedResult) { + this.returnedResult = returnedResult; + } + + public boolean isExecutedCalled() { + return executedCalled; + } + + public Object getAction() { + return action; + } + + public void setAction(Object action) { + this.action = action; + } + + public String getActionName() { + return actionName; + } + + public void setActionName(String actionName) { + this.actionName = actionName; + } + + public ActionConfig getConfig() { + return config; + } + + public void setConfig(ActionConfig config) { + this.config = config; + } + + public boolean getExecuteResult() { + return executeResult; + } + + public void setExecuteResult(boolean executeResult) { + this.executeResult = executeResult; + } + + public ActionInvocation getInvocation() { + return invocation; + } + + public void setInvocation(ActionInvocation invocation) { + this.invocation = invocation; + } + + public String getNamespace() { + return namespace; + } + + public void setNamespace(String namespace) { + this.namespace = namespace; + } + + public String getMethod() { + return method; + } + + public void setMethod(String method) { + this.method = method; + methodSpecified = StringUtils.isNotEmpty(method); + } + + public boolean isMethodSpecified() + { + return methodSpecified; + } + + public void setMethodSpecified(boolean methodSpecified) + { + this.methodSpecified = methodSpecified; + } + +} http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/mock/MockContainer.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/com/opensymphony/xwork2/mock/MockContainer.java b/core/src/main/java/com/opensymphony/xwork2/mock/MockContainer.java new file mode 100644 index 0000000..bcad8a9 --- /dev/null +++ b/core/src/main/java/com/opensymphony/xwork2/mock/MockContainer.java @@ -0,0 +1,41 @@ +package com.opensymphony.xwork2.mock; + +import com.opensymphony.xwork2.inject.Container; +import com.opensymphony.xwork2.inject.Scope; + +import java.util.Set; + +/** + * Mock implementation to be used in unittests + */ +public class MockContainer implements Container { + + public void inject(Object o) { + + } + + public <T> T inject(Class<T> implementation) { + return null; + } + + public <T> T getInstance(Class<T> type, String name) { + return null; + } + + public <T> T getInstance(Class<T> type) { + return null; + } + + public Set<String> getInstanceNames(Class<?> type) { + return null; + } + + public void setScopeStrategy(Scope.Strategy scopeStrategy) { + + } + + public void removeScopeStrategy() { + + } + +} http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/mock/MockInterceptor.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/com/opensymphony/xwork2/mock/MockInterceptor.java b/core/src/main/java/com/opensymphony/xwork2/mock/MockInterceptor.java new file mode 100644 index 0000000..c244770 --- /dev/null +++ b/core/src/main/java/com/opensymphony/xwork2/mock/MockInterceptor.java @@ -0,0 +1,122 @@ +/* + * 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; + +import com.opensymphony.xwork2.ActionInvocation; +import com.opensymphony.xwork2.interceptor.Interceptor; +import junit.framework.Assert; + + +/** + * Mock for an {@link com.opensymphony.xwork2.interceptor.Interceptor}. + * + * @author Jason Carreira + */ +public class MockInterceptor implements Interceptor { + + private static final long serialVersionUID = 2692551676567227756L; + + public static final String DEFAULT_FOO_VALUE = "fooDefault"; + + + private String expectedFoo = DEFAULT_FOO_VALUE; + private String foo = DEFAULT_FOO_VALUE; + private boolean executed = false; + + + public boolean isExecuted() { + return executed; + } + + public void setExpectedFoo(String expectedFoo) { + this.expectedFoo = expectedFoo; + } + + public String getExpectedFoo() { + return expectedFoo; + } + + public void setFoo(String foo) { + this.foo = foo; + } + + public String getFoo() { + return foo; + } + + /** + * Called to let an interceptor clean up any resources it has allocated. + */ + public void destroy() { + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + + if (!(o instanceof MockInterceptor)) { + return false; + } + + final MockInterceptor testInterceptor = (MockInterceptor) o; + + if (executed != testInterceptor.executed) { + return false; + } + + if ((expectedFoo != null) ? (!expectedFoo.equals(testInterceptor.expectedFoo)) : (testInterceptor.expectedFoo != null)) + { + return false; + } + + if ((foo != null) ? (!foo.equals(testInterceptor.foo)) : (testInterceptor.foo != null)) { + return false; + } + + return true; + } + + @Override + public int hashCode() { + int result; + result = ((expectedFoo != null) ? expectedFoo.hashCode() : 0); + result = (29 * result) + ((foo != null) ? foo.hashCode() : 0); + result = (29 * result) + (executed ? 1 : 0); + + return result; + } + + /** + * Called after an Interceptor is created, but before any requests are processed using the intercept() methodName. This + * gives the Interceptor a chance to initialize any needed resources. + */ + public void init() { + } + + /** + * Allows the Interceptor to do some processing on the request before and/or after the rest of the processing of the + * request by the DefaultActionInvocation or to short-circuit the processing and just return a String return code. + */ + public String intercept(ActionInvocation invocation) throws Exception { + executed = true; + Assert.assertNotSame(DEFAULT_FOO_VALUE, foo); + Assert.assertEquals(expectedFoo, foo); + + return invocation.invoke(); + } +} http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/mock/MockObjectTypeDeterminer.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/com/opensymphony/xwork2/mock/MockObjectTypeDeterminer.java b/core/src/main/java/com/opensymphony/xwork2/mock/MockObjectTypeDeterminer.java new file mode 100644 index 0000000..605aaf2 --- /dev/null +++ b/core/src/main/java/com/opensymphony/xwork2/mock/MockObjectTypeDeterminer.java @@ -0,0 +1,125 @@ +/* + * 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; + +import com.opensymphony.xwork2.conversion.ObjectTypeDeterminer; +import ognl.OgnlException; +import ognl.OgnlRuntime; + +import java.util.Map; + +/** + * Mocks the function of an ObjectTypeDeterminer for testing purposes. + * + * @author Gabe + */ +public class MockObjectTypeDeterminer implements ObjectTypeDeterminer { + + private Class keyClass; + private Class elementClass; + private String keyProperty; + private boolean shouldCreateIfNew; + + public MockObjectTypeDeterminer() {} + + + /** + * @param keyClass + * @param elementClass + * @param keyProperty + * @param shouldCreateIfNew + */ + public MockObjectTypeDeterminer(Class keyClass, Class elementClass, + String keyProperty, boolean shouldCreateIfNew) { + super(); + this.keyClass = keyClass; + this.elementClass = elementClass; + this.keyProperty = keyProperty; + this.shouldCreateIfNew = shouldCreateIfNew; + } + + public Class getKeyClass(Class parentClass, String property) { + return getKeyClass(); + } + + public Class getElementClass(Class parentClass, String property, Object key) { + return getElementClass(); + } + + public String getKeyProperty(Class parentClass, String property) { + return getKeyProperty(); + } + + public boolean shouldCreateIfNew(Class parentClass, String property, + Object target, String keyProperty, boolean isIndexAccessed) { + try { + System.out.println("ognl:"+OgnlRuntime.getPropertyAccessor(Map.class)+" this:"+this); + } catch (OgnlException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return isShouldCreateIfNew(); + } + + /** + * @return Returns the elementClass. + */ + public Class getElementClass() { + return elementClass; + } + /** + * @param elementClass The elementClass to set. + */ + public void setElementClass(Class elementClass) { + this.elementClass = elementClass; + } + /** + * @return Returns the keyClass. + */ + public Class getKeyClass() { + return keyClass; + } + /** + * @param keyClass The keyClass to set. + */ + public void setKeyClass(Class keyClass) { + this.keyClass = keyClass; + } + /** + * @return Returns the keyProperty. + */ + public String getKeyProperty() { + return keyProperty; + } + /** + * @param keyProperty The keyProperty to set. + */ + public void setKeyProperty(String keyProperty) { + this.keyProperty = keyProperty; + } + /** + * @return Returns the shouldCreateIfNew. + */ + public boolean isShouldCreateIfNew() { + return shouldCreateIfNew; + } + /** + * @param shouldCreateIfNew The shouldCreateIfNew to set. + */ + public void setShouldCreateIfNew(boolean shouldCreateIfNew) { + this.shouldCreateIfNew = shouldCreateIfNew; + } +} http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/mock/MockResult.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/com/opensymphony/xwork2/mock/MockResult.java b/core/src/main/java/com/opensymphony/xwork2/mock/MockResult.java new file mode 100644 index 0000000..571469c --- /dev/null +++ b/core/src/main/java/com/opensymphony/xwork2/mock/MockResult.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.mock; + +import com.opensymphony.xwork2.ActionInvocation; +import com.opensymphony.xwork2.Result; + +/** + * Mock for a {@link Result}. + * + * @author Mike + * @author Rainer Hermanns + */ +public class MockResult implements Result { + + public static final String DEFAULT_PARAM = "foo"; + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + + return o instanceof MockResult; + } + + public void execute(ActionInvocation invocation) throws Exception { + // no op + } + + @Override + public int hashCode() { + return 10; + } + + public void setFoo(String foo) { + // no op + } + +} http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/mock/package.html ---------------------------------------------------------------------- diff --git a/core/src/main/java/com/opensymphony/xwork2/mock/package.html b/core/src/main/java/com/opensymphony/xwork2/mock/package.html new file mode 100644 index 0000000..61bdf48 --- /dev/null +++ b/core/src/main/java/com/opensymphony/xwork2/mock/package.html @@ -0,0 +1 @@ +<body>XWork specific mock classes.</body> http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/ognl/ErrorMessageBuilder.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/com/opensymphony/xwork2/ognl/ErrorMessageBuilder.java b/core/src/main/java/com/opensymphony/xwork2/ognl/ErrorMessageBuilder.java new file mode 100644 index 0000000..e136241 --- /dev/null +++ b/core/src/main/java/com/opensymphony/xwork2/ognl/ErrorMessageBuilder.java @@ -0,0 +1,58 @@ +package com.opensymphony.xwork2.ognl; + +/** + * Helper class to build error messages. + */ +public class ErrorMessageBuilder { + + private StringBuilder message = new StringBuilder(); + + public static ErrorMessageBuilder create() { + return new ErrorMessageBuilder(); + } + + private ErrorMessageBuilder() { + } + + public ErrorMessageBuilder errorSettingExpressionWithValue(String expr, Object value) { + appenExpression(expr); + if (value instanceof Object[]) { + appendValueAsArray((Object[]) value, message); + } else { + appendValue(value); + } + return this; + } + + private void appenExpression(String expr) { + message.append("Error setting expression '"); + message.append(expr); + message.append("' with value "); + } + + private void appendValue(Object value) { + message.append("'"); + message.append(value); + message.append("'"); + } + + private void appendValueAsArray(Object[] valueArray, StringBuilder msg) { + msg.append("["); + for (int index = 0; index < valueArray.length; index++) { + appendValue(valueArray[index]); + if (hasMoreElements(valueArray, index)) { + msg.append(", "); + } + } + msg.append("]"); + } + + private boolean hasMoreElements(Object[] valueArray, int index) { + return index < (valueArray.length + 1); + } + + public String build() { + return message.toString(); + } + +} http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/ognl/ObjectProxy.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/com/opensymphony/xwork2/ognl/ObjectProxy.java b/core/src/main/java/com/opensymphony/xwork2/ognl/ObjectProxy.java new file mode 100644 index 0000000..b01fd67 --- /dev/null +++ b/core/src/main/java/com/opensymphony/xwork2/ognl/ObjectProxy.java @@ -0,0 +1,55 @@ +/* + * 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.ognl; + +/** + * An Object to use within OGNL to proxy other Objects + * usually Collections that you set in a different place + * on the ValueStack but want to retain the context information + * about where they previously were. + * + * @author Gabe + */ +public class ObjectProxy { + private Object value; + private Class lastClassAccessed; + private String lastPropertyAccessed; + + public Class getLastClassAccessed() { + return lastClassAccessed; + } + + public void setLastClassAccessed(Class lastClassAccessed) { + this.lastClassAccessed = lastClassAccessed; + } + + public String getLastPropertyAccessed() { + return lastPropertyAccessed; + } + + public void setLastPropertyAccessed(String lastPropertyAccessed) { + this.lastPropertyAccessed = lastPropertyAccessed; + } + + public Object getValue() { + return value; + } + + public void setValue(Object value) { + this.value = value; + } +} http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/ognl/OgnlNullHandlerWrapper.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/com/opensymphony/xwork2/ognl/OgnlNullHandlerWrapper.java b/core/src/main/java/com/opensymphony/xwork2/ognl/OgnlNullHandlerWrapper.java new file mode 100644 index 0000000..95a0e35 --- /dev/null +++ b/core/src/main/java/com/opensymphony/xwork2/ognl/OgnlNullHandlerWrapper.java @@ -0,0 +1,24 @@ +package com.opensymphony.xwork2.ognl; + +import com.opensymphony.xwork2.conversion.NullHandler; + +import java.util.Map; + +public class OgnlNullHandlerWrapper implements ognl.NullHandler { + + private NullHandler wrapped; + + public OgnlNullHandlerWrapper(NullHandler target) { + this.wrapped = target; + } + + public Object nullMethodResult(Map context, Object target, + String methodName, Object[] args) { + return wrapped.nullMethodResult(context, target, methodName, args); + } + + public Object nullPropertyValue(Map context, Object target, Object property) { + return wrapped.nullPropertyValue(context, target, property); + } + +} http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/ognl/OgnlReflectionContextFactory.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/com/opensymphony/xwork2/ognl/OgnlReflectionContextFactory.java b/core/src/main/java/com/opensymphony/xwork2/ognl/OgnlReflectionContextFactory.java new file mode 100644 index 0000000..03a5537 --- /dev/null +++ b/core/src/main/java/com/opensymphony/xwork2/ognl/OgnlReflectionContextFactory.java @@ -0,0 +1,14 @@ +package com.opensymphony.xwork2.ognl; + +import com.opensymphony.xwork2.util.reflection.ReflectionContextFactory; +import ognl.Ognl; + +import java.util.Map; + +public class OgnlReflectionContextFactory implements ReflectionContextFactory { + + public Map createDefaultContext(Object root) { + return Ognl.createDefaultContext(root); + } + +} http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/ognl/OgnlReflectionProvider.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/com/opensymphony/xwork2/ognl/OgnlReflectionProvider.java b/core/src/main/java/com/opensymphony/xwork2/ognl/OgnlReflectionProvider.java new file mode 100644 index 0000000..34f3043 --- /dev/null +++ b/core/src/main/java/com/opensymphony/xwork2/ognl/OgnlReflectionProvider.java @@ -0,0 +1,125 @@ +package com.opensymphony.xwork2.ognl; + +import com.opensymphony.xwork2.inject.Inject; +import com.opensymphony.xwork2.util.reflection.ReflectionException; +import com.opensymphony.xwork2.util.reflection.ReflectionProvider; +import ognl.Ognl; +import ognl.OgnlException; +import ognl.OgnlRuntime; + +import java.beans.IntrospectionException; +import java.beans.PropertyDescriptor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.Collection; +import java.util.Map; + +public class OgnlReflectionProvider implements ReflectionProvider { + + private OgnlUtil ognlUtil; + + @Inject + public void setOgnlUtil(OgnlUtil ognlUtil) { + this.ognlUtil = ognlUtil; + } + + public Field getField(Class inClass, String name) { + return OgnlRuntime.getField(inClass, name); + } + + public Method getGetMethod(Class targetClass, String propertyName) + throws IntrospectionException, ReflectionException { + try { + return OgnlRuntime.getGetMethod(null, targetClass, propertyName); + } catch (OgnlException e) { + throw new ReflectionException(e); + } + } + + public Method getSetMethod(Class targetClass, String propertyName) + throws IntrospectionException, ReflectionException { + try { + return OgnlRuntime.getSetMethod(null, targetClass, propertyName); + } catch (OgnlException e) { + throw new ReflectionException(e); + } + } + + public void setProperties(Map<String, ?> props, Object o, Map<String, Object> context) { + ognlUtil.setProperties(props, o, context); + } + + public void setProperties(Map<String, ?> props, Object o, Map<String, Object> context, boolean throwPropertyExceptions) throws ReflectionException{ + ognlUtil.setProperties(props, o, context, throwPropertyExceptions); + + } + + public void setProperties(Map<String, ?> properties, Object o) { + ognlUtil.setProperties(properties, o); + } + + public PropertyDescriptor getPropertyDescriptor(Class targetClass, + String propertyName) throws IntrospectionException, + ReflectionException { + try { + return OgnlRuntime.getPropertyDescriptor(targetClass, propertyName); + } catch (OgnlException e) { + throw new ReflectionException(e); + } + } + + public void copy(Object from, Object to, Map<String, Object> context, + Collection<String> exclusions, Collection<String> inclusions) { + ognlUtil.copy(from, to, context, exclusions, inclusions); + } + + public Object getRealTarget(String property, Map<String, Object> context, Object root) + throws ReflectionException { + try { + return ognlUtil.getRealTarget(property, context, root); + } catch (OgnlException e) { + throw new ReflectionException(e); + } + } + + public void setProperty(String name, Object value, Object o, Map<String, Object> context) { + ognlUtil.setProperty(name, value, o, context); + } + + public void setProperty(String name, Object value, Object o, Map<String, Object> context, boolean throwPropertyExceptions) { + ognlUtil.setProperty(name, value, o, context, throwPropertyExceptions); + } + + public Map getBeanMap(Object source) throws IntrospectionException, + ReflectionException { + try { + return ognlUtil.getBeanMap(source); + } catch (OgnlException e) { + throw new ReflectionException(e); + } + } + + public Object getValue(String expression, Map<String, Object> context, Object root) + throws ReflectionException { + try { + return ognlUtil.getValue(expression, context, root); + } catch (OgnlException e) { + throw new ReflectionException(e); + } + } + + public void setValue(String expression, Map<String, Object> context, Object root, + Object value) throws ReflectionException { + try { + Ognl.setValue(expression, context, root, value); + } catch (OgnlException e) { + throw new ReflectionException(e); + } + } + + public PropertyDescriptor[] getPropertyDescriptors(Object source) + throws IntrospectionException { + return ognlUtil.getPropertyDescriptors(source); + } + +}
