MethodConfigurationProviderpublic class MethodConfigurationProvider extends Object implements com.opensymphony.xwork2.config.ConfigurationProviderMethodConfigurationProvider creates ActionConfigs for potential action
methods that lack a corresponding action mapping,
so that these methods can be invoked without extra or redundant configuration.
As a dynamic method, the behavior of this class could be represented as:
int bang = name.indexOf('!');
if (bang != -1) {
String method = name.substring(bang + 1);
mapping.setMethod(method);
name = name.substring(0, bang);
}
If the action URL is "foo!bar", the the "foo" action is invoked,
calling "bar" instead of "execute".
Instead of scanning each request at runtime, the provider creates action mappings
for each method that could be matched using a dynamic approach.
Advantages over a dynamic approach are that:
The "dynamic" methods are not a special case, but just another action mapping,
with all the features of a hardcoded mapping.
When needed, a manual action can be provided for a method and invoked with the same
syntax as an automatic action.
The ConfigBrowser can display all potential actions.
|
Fields Summary |
---|
private com.opensymphony.xwork2.config.Configuration | configurationStores configuration property. | boolean | reloadStore needsReload property. | com.opensymphony.xwork2.ObjectFactory | factoryStores ObjectFactory property. |
Methods Summary |
---|
protected boolean | addDynamicMethods(java.util.Map actions, java.lang.String actionName, com.opensymphony.xwork2.config.entities.ActionConfig actionConfig)Scans class for potential Action mehods,
automatically generating and registering ActionConfigs as needed.
The system iterates over the set of namespaces and the set of actionNames
in a Configuration and retrieves each ActionConfig.
For each ActionConfig that invokes the default "execute" method,
the provider inspects the className class for other non-void,
no-argument methods that do not begin with "getX" or "isX".
For each qualifying method, the provider looks for another actionName in
the same namespace that equals action.name + "!" + method.name.
If that actionName is not found, System copies the ActionConfig,
changes the method property, and adds it to the package configuration
under the new actionName (action!method).
The system ignores ActionConfigs with a method property set so as to
avoid creating alias methods for alias methods.
The system ignores "getX" and "isX" methods since these would appear to be
JavaBeans property and would not be intended as action methods.
(The X represents any upper character or non-letter.)
String configMethod = actionConfig.getMethodName();
boolean hasMethod = (configMethod != null) && (configMethod.length() > 0);
if (hasMethod) return false;
String className = actionConfig.getClassName();
Set actionMethods = new HashSet();
Class actionClass;
ObjectFactory factory = getObjectFactory();
try {
actionClass = factory.getClassInstance(className);
} catch (ClassNotFoundException e) {
throw new ConfigurationException(e);
}
Method[] methods = actionClass.getMethods();
for (Method method : methods) {
String returnString = method.getReturnType().getName();
boolean isString = "java.lang.String".equals(returnString);
if (isString) {
Class[] parameterTypes = method.getParameterTypes();
boolean noParameters = (parameterTypes.length == 0);
String methodString = method.getName();
boolean notGetMethod = !((methodString.startsWith("get")) && upperAt(3, methodString));
boolean notIsMethod = !((methodString.startsWith("is")) && upperAt(2, methodString));
boolean notToString = !("toString".equals(methodString));
boolean notExecute = !("execute".equals(methodString));
boolean qualifies = noParameters && notGetMethod && notIsMethod && notToString && notExecute;
if (qualifies) {
actionMethods.add(methodString);
}
}
}
for (Object actionMethod : actionMethods) {
String methodName = (String) actionMethod;
StringBuilder sb = new StringBuilder();
sb.append(actionName);
sb.append("!"); // TODO: Make "!" a configurable character
sb.append(methodName);
String newActionName = sb.toString();
boolean haveAction = actions.containsKey(newActionName);
if (haveAction) continue;
ActionConfig newActionConfig = new ActionConfig(
newActionName,
actionConfig.getClassName(),
actionConfig.getParams(),
actionConfig.getResults(),
actionConfig.getInterceptors(),
actionConfig.getExceptionMappings());
newActionConfig.setMethodName(methodName);
String packageName = actionConfig.getPackageName();
newActionConfig.setPackageName(packageName);
PackageConfig packageConfig = configuration.getPackageConfig(packageName);
packageConfig.addActionConfig(newActionName, actionConfig);
}
return (actionMethods.size() > 0);
| public void | destroy()
// Override to provide functionality
| private com.opensymphony.xwork2.ObjectFactory | getObjectFactory()Provides ObjectFactory property.
if (factory == null) {
factory = ObjectFactory.getObjectFactory();
if (factory == null) throw new
ConfigurationException("MethodConfigurationProvider.getObjectFactory: ObjectFactory==null");
}
return factory;
| public void | init(com.opensymphony.xwork2.config.Configuration configuration)
setConfiguration(configuration);
configuration.rebuildRuntimeConfiguration();
| public void | loadPackages()
Set namespaces = Collections.EMPTY_SET;
RuntimeConfiguration rc = configuration.getRuntimeConfiguration();
Map allActionConfigs = rc.getActionConfigs();
if (allActionConfigs != null) {
namespaces = allActionConfigs.keySet();
}
if (namespaces.size() == 0) {
throw new ConfigurationException("MethodConfigurationProvider.loadPackages: namespaces.size == 0");
}
boolean added = false;
for (Object namespace : namespaces) {
Map actions = (Map) allActionConfigs.get(namespace);
Set actionNames = actions.keySet();
for (Object actionName : actionNames) {
ActionConfig actionConfig = (ActionConfig) actions.get(actionName);
added = added | addDynamicMethods(actions, (String) actionName, actionConfig);
}
}
reload = added;
| public boolean | needsReload()
return reload;
| public void | register(com.opensymphony.xwork2.inject.ContainerBuilder containerBuilder, com.opensymphony.xwork2.util.location.LocatableProperties locatableProperties)
// Override to provide functionality
| public void | setConfiguration(com.opensymphony.xwork2.config.Configuration configuration)Updates configuration property.
this.configuration = configuration;
| public void | setObjectFactory(com.opensymphony.xwork2.ObjectFactory factory)Updates ObjectFactory property.
this.factory = factory;
| private boolean | upperAt(int pos, java.lang.String string)Verifies that character at a String position is upper case.
int len = string.length();
if (len < pos) return false;
String ch = string.substring(pos, pos+1);
return ch.equals(ch.toUpperCase());
|
|