com.opensymphony.xwork2.util.CompoundRootAccessor Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of xwork Show documentation
Show all versions of xwork Show documentation
XWork is an command-pattern framework that is used to power WebWork
as well as other applications. XWork provides an Inversion of Control
container, a powerful expression language, data type conversion,
validation, and pluggable configuration.
/*
* Copyright (c) 2002-2006 by OpenSymphony
* All rights reserved.
*/
package com.opensymphony.xwork2.util;
import ognl.*;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.opensymphony.xwork2.XWorkException;
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.util.*;
/**
* A stack that is able to call methods on objects in the stack.
*
* @author $Author: mrdon $
* @author Rainer Hermanns
* @version $Revision: 1194 $
*/
public class CompoundRootAccessor implements PropertyAccessor, MethodAccessor, ClassResolver {
private final static Log log = LogFactory.getLog(CompoundRootAccessor.class);
private static Map invalidMethods = new HashMap();
public void setProperty(Map context, Object target, Object name, Object value) throws OgnlException {
CompoundRoot root = (CompoundRoot) target;
OgnlContext ognlContext = (OgnlContext) context;
for (Iterator iterator = root.iterator(); iterator.hasNext();) {
Object o = iterator.next();
if (o == null) {
continue;
}
try {
if (OgnlRuntime.hasSetProperty(ognlContext, o, name)) {
OgnlRuntime.setProperty(ognlContext, o, name, value);
return;
} else if (o instanceof Map) {
Map map = (Map) o;
map.put(name, value);
return;
}
// } catch (OgnlException e) {
// if (e.getReason() != null) {
// final String msg = "Caught an Ognl exception while setting property " + name;
// log.error(msg, e);
// throw new RuntimeException(msg, e.getReason());
// }
} catch (IntrospectionException e) {
// this is OK if this happens, we'll just keep trying the next
}
}
Boolean reportError = (Boolean) context.get(ValueStack.REPORT_ERRORS_ON_NO_PROP);
final String msg = "No object in the CompoundRoot has a publicly accessible property named '" + name + "' (no setter could be found).";
if ((reportError != null) && (reportError.booleanValue())) {
throw new XWorkException(msg);
} else {
log.debug(msg);
}
}
public Object getProperty(Map context, Object target, Object name) throws OgnlException {
CompoundRoot root = (CompoundRoot) target;
OgnlContext ognlContext = (OgnlContext) context;
if (name instanceof Integer) {
Integer index = (Integer) name;
return root.cutStack(index.intValue());
} else if (name instanceof String) {
if ("top".equals(name)) {
if (root.size() > 0) {
return root.get(0);
} else {
return null;
}
}
for (Iterator iterator = root.iterator(); iterator.hasNext();) {
Object o = iterator.next();
if (o == null) {
continue;
}
try {
if ((OgnlRuntime.hasGetProperty(ognlContext, o, name)) || ((o instanceof Map) && ((Map) o).containsKey(name)))
{
return OgnlRuntime.getProperty(ognlContext, o, name);
}
} catch (OgnlException e) {
if (e.getReason() != null) {
final String msg = "Caught an Ognl exception while getting property " + name;
throw new XWorkException(msg, e);
}
} catch (IntrospectionException e) {
// this is OK if this happens, we'll just keep trying the next
}
}
return null;
} else {
return null;
}
}
public Object callMethod(Map context, Object target, String name, Object[] objects) throws MethodFailedException {
CompoundRoot root = (CompoundRoot) target;
if ("describe".equals(name)) {
Object v;
if (objects != null && objects.length == 1) {
v = objects[0];
} else {
v = root.get(0);
}
if (v instanceof Collection || v instanceof Map || v.getClass().isArray()) {
return v.toString();
}
try {
Map descriptors = OgnlRuntime.getPropertyDescriptors(v.getClass());
int maxSize = 0;
for (Iterator iterator = descriptors.keySet().iterator(); iterator.hasNext();) {
String pdName = (String) iterator.next();
if (pdName.length() > maxSize) {
maxSize = pdName.length();
}
}
SortedSet set = new TreeSet();
StringBuffer sb = new StringBuffer();
for (Iterator iterator = descriptors.values().iterator(); iterator.hasNext();) {
PropertyDescriptor pd = (PropertyDescriptor) iterator.next();
sb.append(pd.getName()).append(": ");
int padding = maxSize - pd.getName().length();
for (int i = 0; i < padding; i++) {
sb.append(" ");
}
sb.append(pd.getPropertyType().getName());
set.add(sb.toString());
sb = new StringBuffer();
}
sb = new StringBuffer();
for (Iterator iterator = set.iterator(); iterator.hasNext();) {
String s = (String) iterator.next();
sb.append(s).append("\n");
}
return sb.toString();
} catch (IntrospectionException e) {
e.printStackTrace();
} catch (OgnlException e) {
e.printStackTrace();
}
return null;
}
for (Iterator iterator = root.iterator(); iterator.hasNext();) {
Object o = iterator.next();
if (o == null) {
continue;
}
Class clazz = o.getClass();
Class[] argTypes = getArgTypes(objects);
CompoundRootAccessor.MethodCall mc = null;
if (argTypes != null) {
mc = new CompoundRootAccessor.MethodCall(clazz, name, argTypes);
}
if ((argTypes == null) || !invalidMethods.containsKey(mc)) {
try {
Object value = OgnlRuntime.callMethod((OgnlContext) context, o, name, name, objects);
if (value != null) {
return value;
}
} catch (OgnlException e) {
// try the next one
Throwable reason = e.getReason();
if ((mc != null) && (reason != null) && (reason.getClass() == NoSuchMethodException.class)) {
invalidMethods.put(mc, Boolean.TRUE);
} else if (reason != null) {
throw new MethodFailedException(o, name, e.getReason());
}
}
}
}
return null;
}
public Object callStaticMethod(Map transientVars, Class aClass, String s, Object[] objects) throws MethodFailedException {
return null;
}
public Class classForName(String className, Map context) throws ClassNotFoundException {
Object root = Ognl.getRoot(context);
try {
if (root instanceof CompoundRoot) {
if (className.startsWith("vs")) {
CompoundRoot compoundRoot = (CompoundRoot) root;
if (className.equals("vs")) {
return compoundRoot.peek().getClass();
}
int index = Integer.parseInt(className.substring(2));
return compoundRoot.get(index - 1).getClass();
}
}
} catch (Exception e) {
// just try the old fashioned way
}
return Thread.currentThread().getContextClassLoader().loadClass(className);
}
private Class[] getArgTypes(Object[] args) {
if (args == null) {
return new Class[0];
}
Class[] classes = new Class[args.length];
for (int i = 0; i < args.length; i++) {
Object arg = args[i];
classes[i] = (arg != null) ? arg.getClass() : Object.class;
}
return classes;
}
static class MethodCall {
Class clazz;
String name;
Class[] args;
int hash;
public MethodCall(Class clazz, String name, Class[] args) {
this.clazz = clazz;
this.name = name;
this.args = args;
this.hash = clazz.hashCode() + name.hashCode();
for (int i = 0; i < args.length; i++) {
Class arg = args[i];
hash += arg.hashCode();
}
}
public boolean equals(Object obj) {
MethodCall mc = (CompoundRootAccessor.MethodCall) obj;
return (mc.clazz.equals(clazz) && mc.name.equals(name) && Arrays.equals(mc.args, args));
}
public int hashCode() {
return hash;
}
}
}