mirror of
https://github.com/apache/struts.git
synced 2026-08-05 14:47:09 +00:00
Merge pull request #393 from apache/WW-5054-debug-browser
[WW-5054] debug=browser
This commit is contained in:
@@ -54,7 +54,7 @@ public class OgnlUtil {
|
||||
private static final Logger LOG = LogManager.getLogger(OgnlUtil.class);
|
||||
|
||||
private final ConcurrentMap<String, Object> expressions = new ConcurrentHashMap<>();
|
||||
private final ConcurrentMap<Class, BeanInfo> beanInfoCache = new ConcurrentHashMap<>();
|
||||
private final ConcurrentMap<Class<?>, BeanInfo> beanInfoCache = new ConcurrentHashMap<>();
|
||||
private TypeConverter defaultConverter;
|
||||
|
||||
private boolean devMode;
|
||||
@@ -65,18 +65,23 @@ public class OgnlUtil {
|
||||
private Set<Pattern> excludedPackageNamePatterns;
|
||||
private Set<String> excludedPackageNames;
|
||||
|
||||
private Set<Class<?>> devModeExcludedClasses;
|
||||
private Set<Pattern> devModeExcludedPackageNamePatterns;
|
||||
private Set<String> devModeExcludedPackageNames;
|
||||
|
||||
private Container container;
|
||||
private boolean allowStaticFieldAccess = true;
|
||||
private boolean allowStaticMethodAccess;
|
||||
private boolean disallowProxyMemberAccess;
|
||||
|
||||
public OgnlUtil() {
|
||||
excludedClasses = new HashSet<>();
|
||||
excludedPackageNamePatterns = new HashSet<>();
|
||||
excludedPackageNames = new HashSet<>();
|
||||
excludedClasses = Collections.unmodifiableSet(excludedClasses);
|
||||
excludedPackageNamePatterns = Collections.unmodifiableSet(excludedPackageNamePatterns);
|
||||
excludedPackageNames = Collections.unmodifiableSet(excludedPackageNames);
|
||||
excludedClasses = Collections.unmodifiableSet(new HashSet<>());
|
||||
excludedPackageNamePatterns = Collections.unmodifiableSet(new HashSet<>());
|
||||
excludedPackageNames = Collections.unmodifiableSet(new HashSet<>());
|
||||
|
||||
devModeExcludedClasses = Collections.unmodifiableSet(new HashSet<>());
|
||||
devModeExcludedPackageNamePatterns = Collections.unmodifiableSet(new HashSet<>());
|
||||
devModeExcludedPackageNames = Collections.unmodifiableSet(new HashSet<>());
|
||||
}
|
||||
|
||||
@Inject
|
||||
@@ -111,6 +116,14 @@ public class OgnlUtil {
|
||||
this.excludedClasses = Collections.unmodifiableSet(excludedClasses);
|
||||
}
|
||||
|
||||
@Inject(value = StrutsConstants.STRUTS_DEV_MODE_EXCLUDED_CLASSES, required = false)
|
||||
protected void setDevModeExcludedClasses(String commaDelimitedClasses) {
|
||||
Set<Class<?>> excludedClasses = new HashSet<>();
|
||||
excludedClasses.addAll(this.devModeExcludedClasses);
|
||||
excludedClasses.addAll(parseExcludedClasses(commaDelimitedClasses));
|
||||
this.devModeExcludedClasses = Collections.unmodifiableSet(excludedClasses);
|
||||
}
|
||||
|
||||
private Set<Class<?>> parseExcludedClasses(String commaDelimitedClasses) {
|
||||
Set<String> classNames = TextParseUtil.commaDelimitedStringToSet(commaDelimitedClasses);
|
||||
Set<Class<?>> classes = new HashSet<>();
|
||||
@@ -134,6 +147,14 @@ public class OgnlUtil {
|
||||
this.excludedPackageNamePatterns = Collections.unmodifiableSet(excludedPackageNamePatterns);
|
||||
}
|
||||
|
||||
@Inject(value = StrutsConstants.STRUTS_DEV_MODE_EXCLUDED_PACKAGE_NAME_PATTERNS, required = false)
|
||||
protected void setDevModeExcludedPackageNamePatterns(String commaDelimitedPackagePatterns) {
|
||||
Set<Pattern> excludedPackageNamePatterns = new HashSet<>();
|
||||
excludedPackageNamePatterns.addAll(this.devModeExcludedPackageNamePatterns);
|
||||
excludedPackageNamePatterns.addAll(parseExcludedPackageNamePatterns(commaDelimitedPackagePatterns));
|
||||
this.devModeExcludedPackageNamePatterns = Collections.unmodifiableSet(excludedPackageNamePatterns);
|
||||
}
|
||||
|
||||
private Set<Pattern> parseExcludedPackageNamePatterns(String commaDelimitedPackagePatterns) {
|
||||
Set<String> packagePatterns = TextParseUtil.commaDelimitedStringToSet(commaDelimitedPackagePatterns);
|
||||
Set<Pattern> packageNamePatterns = new HashSet<>();
|
||||
@@ -153,6 +174,14 @@ public class OgnlUtil {
|
||||
this.excludedPackageNames = Collections.unmodifiableSet(excludedPackageNames);
|
||||
}
|
||||
|
||||
@Inject(value = StrutsConstants.STRUTS_DEV_MODE_EXCLUDED_PACKAGE_NAMES, required = false)
|
||||
protected void setDevModeExcludedPackageNames(String commaDelimitedPackageNames) {
|
||||
Set<String> excludedPackageNames = new HashSet<>();
|
||||
excludedPackageNames.addAll(this.devModeExcludedPackageNames);
|
||||
excludedPackageNames.addAll(parseExcludedPackageNames(commaDelimitedPackageNames));
|
||||
this.devModeExcludedPackageNames = Collections.unmodifiableSet(excludedPackageNames);
|
||||
}
|
||||
|
||||
private Set<String> parseExcludedPackageNames(String commaDelimitedPackageNames) {
|
||||
return TextParseUtil.commaDelimitedStringToSet(commaDelimitedPackageNames);
|
||||
}
|
||||
@@ -339,7 +368,7 @@ public class OgnlUtil {
|
||||
* problems setting the properties
|
||||
*/
|
||||
public void setProperties(Map<String, ?> properties, Object o, boolean throwPropertyExceptions) {
|
||||
Map context = createDefaultContext(o, null);
|
||||
Map<String, Object> context = createDefaultContext(o);
|
||||
setProperties(properties, o, context, throwPropertyExceptions);
|
||||
}
|
||||
|
||||
@@ -428,17 +457,15 @@ public class OgnlUtil {
|
||||
* @throws OgnlException in case of ognl errors
|
||||
*/
|
||||
public void setValue(final String name, final Map<String, Object> context, final Object root, final Object value) throws OgnlException {
|
||||
compileAndExecute(name, context, new OgnlTask<Void>() {
|
||||
public Void execute(Object tree) throws OgnlException {
|
||||
if (isEvalExpression(tree, context)) {
|
||||
throw new OgnlException("Eval expression/chained expressions cannot be used as parameter name");
|
||||
}
|
||||
if (isArithmeticExpression(tree, context)) {
|
||||
throw new OgnlException("Arithmetic expressions cannot be used as parameter name");
|
||||
}
|
||||
Ognl.setValue(tree, context, root, value);
|
||||
return null;
|
||||
compileAndExecute(name, context, (OgnlTask<Void>) tree -> {
|
||||
if (isEvalExpression(tree, context)) {
|
||||
throw new OgnlException("Eval expression/chained expressions cannot be used as parameter name");
|
||||
}
|
||||
if (isArithmeticExpression(tree, context)) {
|
||||
throw new OgnlException("Arithmetic expressions cannot be used as parameter name");
|
||||
}
|
||||
Ognl.setValue(tree, context, root, value);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -447,7 +474,7 @@ public class OgnlUtil {
|
||||
SimpleNode node = (SimpleNode) tree;
|
||||
OgnlContext ognlContext = null;
|
||||
|
||||
if (context!=null && context instanceof OgnlContext) {
|
||||
if (context instanceof OgnlContext) {
|
||||
ognlContext = (OgnlContext) context;
|
||||
}
|
||||
return node.isEvalChain(ognlContext) || node.isSequence(ognlContext);
|
||||
@@ -460,7 +487,7 @@ public class OgnlUtil {
|
||||
SimpleNode node = (SimpleNode) tree;
|
||||
OgnlContext ognlContext = null;
|
||||
|
||||
if (context!=null && context instanceof OgnlContext) {
|
||||
if (context instanceof OgnlContext) {
|
||||
ognlContext = (OgnlContext) context;
|
||||
}
|
||||
return node.isOperation(ognlContext);
|
||||
@@ -473,7 +500,7 @@ public class OgnlUtil {
|
||||
SimpleNode node = (SimpleNode) tree;
|
||||
OgnlContext ognlContext = null;
|
||||
|
||||
if (context!=null && context instanceof OgnlContext) {
|
||||
if (context instanceof OgnlContext) {
|
||||
ognlContext = (OgnlContext) context;
|
||||
}
|
||||
return node.isSimpleMethod(ognlContext) && !node.isChain(ognlContext);
|
||||
@@ -482,27 +509,15 @@ public class OgnlUtil {
|
||||
}
|
||||
|
||||
public Object getValue(final String name, final Map<String, Object> context, final Object root) throws OgnlException {
|
||||
return compileAndExecute(name, context, new OgnlTask<Object>() {
|
||||
public Object execute(Object tree) throws OgnlException {
|
||||
return Ognl.getValue(tree, context, root);
|
||||
}
|
||||
});
|
||||
return compileAndExecute(name, context, tree -> Ognl.getValue(tree, context, root));
|
||||
}
|
||||
|
||||
public Object callMethod(final String name, final Map<String, Object> context, final Object root) throws OgnlException {
|
||||
return compileAndExecuteMethod(name, context, new OgnlTask<Object>() {
|
||||
public Object execute(Object tree) throws OgnlException {
|
||||
return Ognl.getValue(tree, context, root);
|
||||
}
|
||||
});
|
||||
return compileAndExecuteMethod(name, context, tree -> Ognl.getValue(tree, context, root));
|
||||
}
|
||||
|
||||
public Object getValue(final String name, final Map<String, Object> context, final Object root, final Class resultType) throws OgnlException {
|
||||
return compileAndExecute(name, context, new OgnlTask<Object>() {
|
||||
public Object execute(Object tree) throws OgnlException {
|
||||
return Ognl.getValue(tree, context, root, resultType);
|
||||
}
|
||||
});
|
||||
public Object getValue(final String name, final Map<String, Object> context, final Object root, final Class<?> resultType) throws OgnlException {
|
||||
return compileAndExecute(name, context, tree -> Ognl.getValue(tree, context, root, resultType));
|
||||
}
|
||||
|
||||
|
||||
@@ -553,11 +568,7 @@ public class OgnlUtil {
|
||||
}
|
||||
|
||||
public Object compile(String expression, Map<String, Object> context) throws OgnlException {
|
||||
return compileAndExecute(expression,context,new OgnlTask<Object>() {
|
||||
public Object execute(Object tree) throws OgnlException {
|
||||
return tree;
|
||||
}
|
||||
});
|
||||
return compileAndExecute(expression, context, tree -> tree);
|
||||
}
|
||||
|
||||
private void checkEnableEvalExpression(Object tree, Map<String, Object> context) throws OgnlException {
|
||||
@@ -608,8 +619,8 @@ public class OgnlUtil {
|
||||
return;
|
||||
}
|
||||
|
||||
final Map contextFrom = createDefaultContext(from, null);
|
||||
final Map contextTo = createDefaultContext(to, null);
|
||||
final Map<String, Object> contextFrom = createDefaultContext(from);
|
||||
final Map<String, Object> contextTo = createDefaultContext(to);
|
||||
|
||||
PropertyDescriptor[] fromPds;
|
||||
PropertyDescriptor[] toPds;
|
||||
@@ -646,12 +657,10 @@ public class OgnlUtil {
|
||||
PropertyDescriptor toPd = toPdHash.get(fromPd.getName());
|
||||
if ((toPd != null) && (toPd.getWriteMethod() != null)) {
|
||||
try {
|
||||
compileAndExecute(fromPd.getName(), context, new OgnlTask<Object>() {
|
||||
public Void execute(Object expr) throws OgnlException {
|
||||
Object value = Ognl.getValue(expr, contextFrom, from);
|
||||
Ognl.setValue(expr, contextTo, to, value);
|
||||
return null;
|
||||
}
|
||||
compileAndExecute(fromPd.getName(), context, expr -> {
|
||||
Object value = Ognl.getValue(expr, contextFrom, from);
|
||||
Ognl.setValue(expr, contextTo, to, value);
|
||||
return null;
|
||||
});
|
||||
|
||||
} catch (OgnlException e) {
|
||||
@@ -700,7 +709,7 @@ public class OgnlUtil {
|
||||
* @return property descriptors.
|
||||
* @throws IntrospectionException is thrown if an exception occurs during introspection.
|
||||
*/
|
||||
public PropertyDescriptor[] getPropertyDescriptors(Class clazz) throws IntrospectionException {
|
||||
public PropertyDescriptor[] getPropertyDescriptors(Class<?> clazz) throws IntrospectionException {
|
||||
BeanInfo beanInfo = getBeanInfo(clazz);
|
||||
return beanInfo.getPropertyDescriptors();
|
||||
}
|
||||
@@ -719,17 +728,13 @@ public class OgnlUtil {
|
||||
*/
|
||||
public Map<String, Object> getBeanMap(final Object source) throws IntrospectionException, OgnlException {
|
||||
Map<String, Object> beanMap = new HashMap<>();
|
||||
final Map sourceMap = createDefaultContext(source, null);
|
||||
final Map<String, Object> sourceMap = createDefaultContext(source);
|
||||
PropertyDescriptor[] propertyDescriptors = getPropertyDescriptors(source);
|
||||
for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
|
||||
final String propertyName = propertyDescriptor.getDisplayName();
|
||||
Method readMethod = propertyDescriptor.getReadMethod();
|
||||
if (readMethod != null) {
|
||||
final Object value = compileAndExecute(propertyName, null, new OgnlTask<Object>() {
|
||||
public Object execute(Object expr) throws OgnlException {
|
||||
return Ognl.getValue(expr, sourceMap, source);
|
||||
}
|
||||
});
|
||||
final Object value = compileAndExecute(propertyName, null, expr -> Ognl.getValue(expr, sourceMap, source));
|
||||
beanMap.put(propertyName, value);
|
||||
} else {
|
||||
beanMap.put(propertyName, "There is no read method for " + propertyName);
|
||||
@@ -757,7 +762,7 @@ public class OgnlUtil {
|
||||
* @return java bean info.
|
||||
* @throws IntrospectionException is thrown if an exception occurs during introspection.
|
||||
*/
|
||||
public BeanInfo getBeanInfo(Class clazz) throws IntrospectionException {
|
||||
public BeanInfo getBeanInfo(Class<?> clazz) throws IntrospectionException {
|
||||
synchronized (beanInfoCache) {
|
||||
BeanInfo beanInfo = beanInfoCache.get(clazz);
|
||||
if (beanInfo == null) {
|
||||
@@ -787,22 +792,30 @@ public class OgnlUtil {
|
||||
}
|
||||
}
|
||||
|
||||
protected Map createDefaultContext(Object root) {
|
||||
protected Map<String, Object> createDefaultContext(Object root) {
|
||||
return createDefaultContext(root, null);
|
||||
}
|
||||
|
||||
protected Map createDefaultContext(Object root, ClassResolver classResolver) {
|
||||
protected Map<String, Object> createDefaultContext(Object root, ClassResolver classResolver) {
|
||||
ClassResolver resolver = classResolver;
|
||||
if (resolver == null) {
|
||||
resolver = container.getInstance(CompoundRootAccessor.class);
|
||||
}
|
||||
|
||||
SecurityMemberAccess memberAccess = new SecurityMemberAccess(allowStaticMethodAccess, allowStaticFieldAccess);
|
||||
memberAccess.setExcludedClasses(excludedClasses);
|
||||
memberAccess.setExcludedPackageNamePatterns(excludedPackageNamePatterns);
|
||||
memberAccess.setExcludedPackageNames(excludedPackageNames);
|
||||
memberAccess.setDisallowProxyMemberAccess(disallowProxyMemberAccess);
|
||||
|
||||
if (devMode) {
|
||||
LOG.warn("Working in devMode, using devMode excluded classes and packages!");
|
||||
memberAccess.setExcludedClasses(devModeExcludedClasses);
|
||||
memberAccess.setExcludedPackageNamePatterns(devModeExcludedPackageNamePatterns);
|
||||
memberAccess.setExcludedPackageNames(devModeExcludedPackageNames);
|
||||
} else {
|
||||
memberAccess.setExcludedClasses(excludedClasses);
|
||||
memberAccess.setExcludedPackageNamePatterns(excludedPackageNamePatterns);
|
||||
memberAccess.setExcludedPackageNames(excludedPackageNames);
|
||||
}
|
||||
|
||||
return Ognl.createDefaultContext(root, memberAccess, resolver, defaultConverter);
|
||||
}
|
||||
|
||||
|
||||
@@ -319,6 +319,11 @@ public final class StrutsConstants {
|
||||
public static final String STRUTS_EXCLUDED_PACKAGE_NAME_PATTERNS = "struts.excludedPackageNamePatterns";
|
||||
public static final String STRUTS_EXCLUDED_PACKAGE_NAMES = "struts.excludedPackageNames";
|
||||
|
||||
/** Comma delimited set of excluded classes and package names which cannot be accessed via expressions in devMode */
|
||||
public static final String STRUTS_DEV_MODE_EXCLUDED_CLASSES = "struts.devMode.excludedClasses";
|
||||
public static final String STRUTS_DEV_MODE_EXCLUDED_PACKAGE_NAME_PATTERNS = "struts.devMode.excludedPackageNamePatterns";
|
||||
public static final String STRUTS_DEV_MODE_EXCLUDED_PACKAGE_NAMES = "struts.devMode.excludedPackageNames";
|
||||
|
||||
/** Dedicated services to check if passed string is excluded/accepted */
|
||||
public static final String STRUTS_EXCLUDED_PATTERNS_CHECKER = "struts.excludedPatterns.checker";
|
||||
public static final String STRUTS_ACCEPTED_PATTERNS_CHECKER = "struts.acceptedPatterns.checker";
|
||||
|
||||
@@ -129,6 +129,9 @@ public class ConstantConfig {
|
||||
private Set<Class<?>> excludedClasses;
|
||||
private List<Pattern> excludedPackageNamePatterns;
|
||||
private Set<String> excludedPackageNames;
|
||||
private Set<Class<?>> devModeExcludedClasses;
|
||||
private List<Pattern> devModeExcludedPackageNamePatterns;
|
||||
private Set<String> devModeExcludedPackageNames;
|
||||
private BeanConfig excludedPatternsChecker;
|
||||
private BeanConfig acceptedPatternsChecker;
|
||||
private Set<Pattern> overrideExcludedPatterns;
|
||||
@@ -149,7 +152,7 @@ public class ConstantConfig {
|
||||
private String classesToString(Set<Class<?>> classes) {
|
||||
List<String> list = null;
|
||||
if (classes != null && !classes.isEmpty()) {
|
||||
list = new ArrayList<String>();
|
||||
list = new ArrayList<>();
|
||||
for (Class<?> c : classes) {
|
||||
list.add(c.getName());
|
||||
}
|
||||
@@ -257,6 +260,9 @@ public class ConstantConfig {
|
||||
map.put(StrutsConstants.STRUTS_EXCLUDED_CLASSES, classesToString(excludedClasses));
|
||||
map.put(StrutsConstants.STRUTS_EXCLUDED_PACKAGE_NAME_PATTERNS, StringUtils.join(excludedPackageNamePatterns, ','));
|
||||
map.put(StrutsConstants.STRUTS_EXCLUDED_PACKAGE_NAMES, StringUtils.join(excludedPackageNames, ','));
|
||||
map.put(StrutsConstants.STRUTS_DEV_MODE_EXCLUDED_CLASSES, classesToString(devModeExcludedClasses));
|
||||
map.put(StrutsConstants.STRUTS_DEV_MODE_EXCLUDED_PACKAGE_NAME_PATTERNS, StringUtils.join(devModeExcludedPackageNamePatterns, ','));
|
||||
map.put(StrutsConstants.STRUTS_DEV_MODE_EXCLUDED_PACKAGE_NAMES, StringUtils.join(devModeExcludedPackageNames, ','));
|
||||
map.put(StrutsConstants.STRUTS_EXCLUDED_PATTERNS_CHECKER, beanConfToString(excludedPatternsChecker));
|
||||
map.put(StrutsConstants.STRUTS_ACCEPTED_PATTERNS_CHECKER, beanConfToString(acceptedPatternsChecker));
|
||||
map.put(StrutsConstants.STRUTS_OVERRIDE_EXCLUDED_PATTERNS, StringUtils.join(overrideExcludedPatterns, ','));
|
||||
@@ -1209,6 +1215,30 @@ public class ConstantConfig {
|
||||
this.excludedPackageNames = excludedPackageNames;
|
||||
}
|
||||
|
||||
public Set<Class<?>> getDevModeExcludedClasses() {
|
||||
return devModeExcludedClasses;
|
||||
}
|
||||
|
||||
public void setDevModeExcludedClasses(Set<Class<?>> devModeExcludedClasses) {
|
||||
this.devModeExcludedClasses = devModeExcludedClasses;
|
||||
}
|
||||
|
||||
public List<Pattern> getDevModeExcludedPackageNamePatterns() {
|
||||
return devModeExcludedPackageNamePatterns;
|
||||
}
|
||||
|
||||
public void setDevModeExcludedPackageNamePatterns(List<Pattern> devModeExcludedPackageNamePatterns) {
|
||||
this.devModeExcludedPackageNamePatterns = devModeExcludedPackageNamePatterns;
|
||||
}
|
||||
|
||||
public Set<String> getDevModeExcludedPackageNames() {
|
||||
return devModeExcludedPackageNames;
|
||||
}
|
||||
|
||||
public void setDevModeExcludedPackageNames(Set<String> devModeExcludedPackageNames) {
|
||||
this.devModeExcludedPackageNames = devModeExcludedPackageNames;
|
||||
}
|
||||
|
||||
public BeanConfig getExcludedPatternsChecker() {
|
||||
return excludedPatternsChecker;
|
||||
}
|
||||
|
||||
+58
-52
@@ -43,7 +43,12 @@ import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* <!-- START SNIPPET: description -->
|
||||
@@ -65,8 +70,8 @@ import java.util.*;
|
||||
* the 'xml' mode is inserted at the top of the page.</li>
|
||||
* <li> <code>command</code> - Tests an OGNL expression and returns the
|
||||
* string result. Only used by the OGNL console.</li>
|
||||
* <li><code>browser</code> Shows field values of an object specified in the
|
||||
* <code>object</code> parameter (#context by default). When the <code>object</code>
|
||||
* <li><code>browser</code> Shows field values of an object specified in the
|
||||
* <code>object</code> parameter (action by default). When the <code>object</code>
|
||||
* parameters is set, the '#' character needs to be escaped to '%23'. Like
|
||||
* debug=browser&object=%23parameters</li>
|
||||
* </ul>
|
||||
@@ -93,9 +98,9 @@ public class DebuggingInterceptor extends AbstractInterceptor {
|
||||
private final static Logger LOG = LogManager.getLogger(DebuggingInterceptor.class);
|
||||
|
||||
private String[] ignorePrefixes = new String[]{"org.apache.struts.",
|
||||
"com.opensymphony.xwork2.", "xwork."};
|
||||
"com.opensymphony.xwork2.", "xwork."};
|
||||
private String[] _ignoreKeys = new String[]{"application", "session",
|
||||
"parameters", "request"};
|
||||
"parameters", "request"};
|
||||
private HashSet<String> ignoreKeys = new HashSet<>(Arrays.asList(_ignoreKeys));
|
||||
|
||||
private final static String XML_MODE = "xml";
|
||||
@@ -111,10 +116,10 @@ public class DebuggingInterceptor extends AbstractInterceptor {
|
||||
private final static String DECORATE_PARAM = "decorate";
|
||||
|
||||
private boolean enableXmlWithConsole = false;
|
||||
|
||||
|
||||
private boolean devMode;
|
||||
private FreemarkerManager freemarkerManager;
|
||||
|
||||
|
||||
private boolean consoleEnabled = false;
|
||||
private ReflectionProvider reflectionProvider;
|
||||
|
||||
@@ -122,12 +127,12 @@ public class DebuggingInterceptor extends AbstractInterceptor {
|
||||
public void setDevMode(String mode) {
|
||||
this.devMode = "true".equals(mode);
|
||||
}
|
||||
|
||||
|
||||
@Inject
|
||||
public void setFreemarkerManager(FreemarkerManager mgr) {
|
||||
this.freemarkerManager = mgr;
|
||||
}
|
||||
|
||||
|
||||
@Inject
|
||||
public void setReflectionProvider(ReflectionProvider reflectionProvider) {
|
||||
this.reflectionProvider = reflectionProvider;
|
||||
@@ -149,40 +154,40 @@ public class DebuggingInterceptor extends AbstractInterceptor {
|
||||
ctx.getParameters().remove(DEBUG_PARAM);
|
||||
if (XML_MODE.equals(type)) {
|
||||
inv.addPreResultListener(
|
||||
new PreResultListener() {
|
||||
public void beforeResult(ActionInvocation inv, String result) {
|
||||
printContext();
|
||||
}
|
||||
});
|
||||
new PreResultListener() {
|
||||
public void beforeResult(ActionInvocation inv, String result) {
|
||||
printContext();
|
||||
}
|
||||
});
|
||||
} else if (CONSOLE_MODE.equals(type)) {
|
||||
consoleEnabled = true;
|
||||
inv.addPreResultListener(
|
||||
new PreResultListener() {
|
||||
public void beforeResult(ActionInvocation inv, String actionResult) {
|
||||
String xml = "";
|
||||
if (enableXmlWithConsole) {
|
||||
StringWriter writer = new StringWriter();
|
||||
printContext(new PrettyPrintWriter(writer));
|
||||
xml = writer.toString();
|
||||
xml = xml.replaceAll("&", "&");
|
||||
xml = xml.replaceAll(">", ">");
|
||||
xml = xml.replaceAll("<", "<");
|
||||
}
|
||||
ActionContext.getContext().put("debugXML", xml);
|
||||
|
||||
FreemarkerResult result = new FreemarkerResult();
|
||||
result.setFreemarkerManager(freemarkerManager);
|
||||
result.setContentType("text/html");
|
||||
result.setLocation("/org/apache/struts2/interceptor/debugging/console.ftl");
|
||||
result.setParse(false);
|
||||
try {
|
||||
result.execute(inv);
|
||||
} catch (Exception ex) {
|
||||
LOG.error("Unable to create debugging console", ex);
|
||||
}
|
||||
|
||||
new PreResultListener() {
|
||||
public void beforeResult(ActionInvocation inv, String actionResult) {
|
||||
String xml = "";
|
||||
if (enableXmlWithConsole) {
|
||||
StringWriter writer = new StringWriter();
|
||||
printContext(new PrettyPrintWriter(writer));
|
||||
xml = writer.toString();
|
||||
xml = xml.replaceAll("&", "&");
|
||||
xml = xml.replaceAll(">", ">");
|
||||
xml = xml.replaceAll("<", "<");
|
||||
}
|
||||
});
|
||||
ActionContext.getContext().put("debugXML", xml);
|
||||
|
||||
FreemarkerResult result = new FreemarkerResult();
|
||||
result.setFreemarkerManager(freemarkerManager);
|
||||
result.setContentType("text/html");
|
||||
result.setLocation("/org/apache/struts2/interceptor/debugging/console.ftl");
|
||||
result.setParse(false);
|
||||
try {
|
||||
result.execute(inv);
|
||||
} catch (Exception ex) {
|
||||
LOG.error("Unable to create debugging console", ex);
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
} else if (COMMAND_MODE.equals(type)) {
|
||||
ValueStack stack = (ValueStack) ctx.getSession().get(SESSION_KEY);
|
||||
if (stack == null) {
|
||||
@@ -197,7 +202,7 @@ public class DebuggingInterceptor extends AbstractInterceptor {
|
||||
res.setContentType("text/plain");
|
||||
|
||||
try (PrintWriter writer =
|
||||
ServletActionContext.getResponse().getWriter()) {
|
||||
ServletActionContext.getResponse().getWriter()) {
|
||||
writer.print(stack.findValue(cmd));
|
||||
} catch (IOException ex) {
|
||||
ex.printStackTrace();
|
||||
@@ -209,25 +214,26 @@ public class DebuggingInterceptor extends AbstractInterceptor {
|
||||
new PreResultListener() {
|
||||
public void beforeResult(ActionInvocation inv, String actionResult) {
|
||||
String rootObjectExpression = getParameter(OBJECT_PARAM);
|
||||
if (rootObjectExpression == null)
|
||||
rootObjectExpression = "#context";
|
||||
if (rootObjectExpression == null) {
|
||||
rootObjectExpression = "action";
|
||||
}
|
||||
String decorate = getParameter(DECORATE_PARAM);
|
||||
ValueStack stack = (ValueStack) ctx.get(ActionContext.VALUE_STACK);
|
||||
Object rootObject = stack.findValue(rootObjectExpression);
|
||||
|
||||
|
||||
try (StringWriter writer = new StringWriter()) {
|
||||
ObjectToHTMLWriter htmlWriter = new ObjectToHTMLWriter(writer);
|
||||
htmlWriter.write(reflectionProvider, rootObject, rootObjectExpression);
|
||||
String html = writer.toString();
|
||||
writer.close();
|
||||
|
||||
|
||||
stack.set("debugHtml", html);
|
||||
|
||||
|
||||
//on the first request, response can be decorated
|
||||
//but we need plain text on the other ones
|
||||
if ("false".equals(decorate))
|
||||
ServletActionContext.getRequest().setAttribute("decorator", "none");
|
||||
|
||||
|
||||
FreemarkerResult result = new FreemarkerResult();
|
||||
result.setFreemarkerManager(freemarkerManager);
|
||||
result.setContentType("text/html");
|
||||
@@ -240,7 +246,7 @@ public class DebuggingInterceptor extends AbstractInterceptor {
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
if (cont) {
|
||||
try {
|
||||
if (actionOnly) {
|
||||
@@ -280,7 +286,7 @@ public class DebuggingInterceptor extends AbstractInterceptor {
|
||||
|
||||
try {
|
||||
PrettyPrintWriter writer = new PrettyPrintWriter(
|
||||
ServletActionContext.getResponse().getWriter());
|
||||
ServletActionContext.getResponse().getWriter());
|
||||
printContext(writer);
|
||||
writer.close();
|
||||
} catch (IOException ex) {
|
||||
@@ -421,10 +427,10 @@ public class DebuggingInterceptor extends AbstractInterceptor {
|
||||
private List<Object> filterValueStack(Map requestMap) {
|
||||
List<Object> filter = new ArrayList<>();
|
||||
Object valueStack = requestMap.get("struts.valueStack");
|
||||
if(valueStack != null) {
|
||||
filter.add(valueStack);
|
||||
}
|
||||
return filter;
|
||||
if (valueStack != null) {
|
||||
filter.add(valueStack);
|
||||
}
|
||||
return filter;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+24
-12
@@ -20,6 +20,8 @@ package org.apache.struts2.interceptor.debugging;
|
||||
|
||||
import com.opensymphony.xwork2.util.reflection.ReflectionException;
|
||||
import com.opensymphony.xwork2.util.reflection.ReflectionProvider;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.beans.IntrospectionException;
|
||||
import java.io.Writer;
|
||||
@@ -33,6 +35,9 @@ import java.util.Set;
|
||||
*
|
||||
*/
|
||||
class ObjectToHTMLWriter {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(ObjectToHTMLWriter.class);
|
||||
|
||||
private PrettyPrintWriter prettyWriter;
|
||||
|
||||
ObjectToHTMLWriter(Writer writer) {
|
||||
@@ -40,36 +45,43 @@ class ObjectToHTMLWriter {
|
||||
this.prettyWriter.setEscape(false);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void write(ReflectionProvider reflectionProvider, Object root, String expr) throws IntrospectionException,
|
||||
ReflectionException {
|
||||
prettyWriter.startNode("table");
|
||||
prettyWriter.addAttribute("class", "debugTable");
|
||||
|
||||
if (root instanceof Map) {
|
||||
for (Object next : ((Map) root).entrySet()) {
|
||||
Map.Entry property = (Map.Entry) next;
|
||||
if (root == null) {
|
||||
LOG.info("Root is null");
|
||||
writeProperty("root", null, expr);
|
||||
} else if (root instanceof Map) {
|
||||
LOG.info("Root is a Map");
|
||||
for (Object next : ((Map<?, ?>) root).entrySet()) {
|
||||
Map.Entry<?, ?> property = (Map.Entry<?, ?>) next;
|
||||
String key = property.getKey().toString();
|
||||
Object value = property.getValue();
|
||||
writeProperty(key, value, expr);
|
||||
}
|
||||
} else if (root instanceof List) {
|
||||
List list = (List) root;
|
||||
LOG.info("Root is a List");
|
||||
List<?> list = (List<?>) root;
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
Object element = list.get(i);
|
||||
writeProperty(String.valueOf(i), element, expr);
|
||||
}
|
||||
} else if (root instanceof Set) {
|
||||
Set set = (Set) root;
|
||||
LOG.info("Root is a Set");
|
||||
Set<?> set = (Set<?>) root;
|
||||
for (Object next : set) {
|
||||
writeProperty("", next, expr);
|
||||
}
|
||||
} else if (root.getClass().isArray()) {
|
||||
LOG.info("Root is an Array");
|
||||
Object[] objects = (Object[]) root;
|
||||
for (int i = 0; i < objects.length; i++) {
|
||||
writeProperty(String.valueOf(i), objects[i], expr);
|
||||
}
|
||||
} else {
|
||||
LOG.info("Root is {}", root.getClass());
|
||||
//print properties
|
||||
Map<String, Object> properties = reflectionProvider.getBeanMap(root);
|
||||
for (Map.Entry<String, Object> property : properties.entrySet()) {
|
||||
@@ -99,9 +111,9 @@ class ObjectToHTMLWriter {
|
||||
//value cell
|
||||
prettyWriter.startNode("td");
|
||||
if (value != null) {
|
||||
LOG.info("Writing property [{}] as [{}]", name, value);
|
||||
//if is is an empty collection or array, don't write a link
|
||||
if (isEmptyCollection(value) || isEmptyMap(value) || (value.getClass()
|
||||
.isArray() && ((Object[]) value).length == 0)) {
|
||||
if (isEmptyCollection(value) || isEmptyMap(value) || (value.getClass().isArray() && ((Object[]) value).length == 0)) {
|
||||
prettyWriter.addAttribute("class", "emptyCollection");
|
||||
prettyWriter.setValue("empty");
|
||||
} else {
|
||||
@@ -118,7 +130,7 @@ class ObjectToHTMLWriter {
|
||||
prettyWriter.startNode("td");
|
||||
if (value != null) {
|
||||
prettyWriter.addAttribute("class", "typeColumn");
|
||||
Class clazz = value.getClass();
|
||||
Class<?> clazz = value.getClass();
|
||||
prettyWriter.setValue(clazz.getName());
|
||||
} else {
|
||||
prettyWriter.addAttribute("class", "nullValue");
|
||||
@@ -135,7 +147,7 @@ class ObjectToHTMLWriter {
|
||||
*/
|
||||
private boolean isEmptyMap(Object value) {
|
||||
try {
|
||||
return value instanceof Map && ((Map) value).isEmpty();
|
||||
return value instanceof Map && ((Map<?, ?>) value).isEmpty();
|
||||
} catch (Exception e) {
|
||||
return true;
|
||||
}
|
||||
@@ -146,14 +158,14 @@ class ObjectToHTMLWriter {
|
||||
*/
|
||||
private boolean isEmptyCollection(Object value) {
|
||||
try {
|
||||
return value instanceof Collection && ((Collection) value).isEmpty();
|
||||
return value instanceof Collection && ((Collection<?>) value).isEmpty();
|
||||
} catch (Exception e) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private void writeValue(String name, Object value, String expr) {
|
||||
Class clazz = value.getClass();
|
||||
Class<?> clazz = value.getClass();
|
||||
if (clazz.isPrimitive() || Number.class.isAssignableFrom(clazz) ||
|
||||
clazz.equals(String.class) || Boolean.class.equals(clazz)) {
|
||||
prettyWriter.setValue(String.valueOf(value));
|
||||
|
||||
@@ -86,6 +86,6 @@
|
||||
</script>
|
||||
|
||||
<body>
|
||||
${debugHtml}
|
||||
${debugHtml?no_esc}
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -48,9 +48,21 @@
|
||||
sun.misc.Unsafe,
|
||||
com.opensymphony.xwork2.ActionContext" />
|
||||
|
||||
<constant name="struts.devMode.excludedClasses"
|
||||
value="
|
||||
java.lang.Object,
|
||||
java.lang.Runtime,
|
||||
java.lang.System,
|
||||
java.lang.Class,
|
||||
java.lang.ClassLoader,
|
||||
java.lang.Shutdown,
|
||||
java.lang.ProcessBuilder,
|
||||
sun.misc.Unsafe" />
|
||||
|
||||
<!-- this must be valid regex, each '.' in package name must be escaped! -->
|
||||
<!-- it's more flexible but slower than simple string comparison -->
|
||||
<!-- constant name="struts.excludedPackageNamePatterns" value="^java\.lang\..*,^ognl.*,^(?!javax\.servlet\..+)(javax\..+)" / -->
|
||||
<!-- constant name="struts.devMode.excludedPackageNamePatterns" value="^java\.lang\..*,^ognl.*,^(?!javax\.servlet\..+)(javax\..+)" / -->
|
||||
|
||||
<!-- this is simpler version of the above used with string comparison -->
|
||||
<constant name="struts.excludedPackageNames"
|
||||
@@ -75,6 +87,28 @@
|
||||
com.opensymphony.xwork2.security.,
|
||||
com.opensymphony.xwork2.util." />
|
||||
|
||||
<constant name="struts.devMode.excludedPackageNames"
|
||||
value="
|
||||
ognl.,
|
||||
java.io.,
|
||||
java.net.,
|
||||
java.nio.,
|
||||
javax.,
|
||||
freemarker.core.,
|
||||
freemarker.template.,
|
||||
freemarker.ext.jsp.,
|
||||
freemarker.ext.rhino.,
|
||||
sun.misc.,
|
||||
sun.reflect.,
|
||||
javassist.,
|
||||
org.apache.velocity.,
|
||||
org.objectweb.asm.,
|
||||
org.springframework.context.,
|
||||
com.opensymphony.xwork2.inject.,
|
||||
com.opensymphony.xwork2.ognl.,
|
||||
com.opensymphony.xwork2.security.,
|
||||
com.opensymphony.xwork2.util." />
|
||||
|
||||
<bean class="com.opensymphony.xwork2.ObjectFactory" name="struts"/>
|
||||
<bean type="com.opensymphony.xwork2.factory.ResultFactory" name="struts" class="org.apache.struts2.factory.StrutsResultFactory" />
|
||||
<bean type="com.opensymphony.xwork2.factory.ActionFactory" name="struts" class="com.opensymphony.xwork2.factory.DefaultActionFactory" />
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -252,4 +252,9 @@ public class Foo {
|
||||
public void setAnimalMap(Map<MyNumber, Animal> animalMap) {
|
||||
this.animalMap = animalMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Foo";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,13 @@
|
||||
*/
|
||||
package org.apache.struts2.config.entities;
|
||||
|
||||
import com.opensymphony.xwork2.TestBean;
|
||||
import com.opensymphony.xwork2.inject.Container;
|
||||
import org.apache.struts2.StrutsConstants;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
@@ -25,20 +32,14 @@ import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.struts2.StrutsConstants;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.opensymphony.xwork2.TestBean;
|
||||
import com.opensymphony.xwork2.inject.Container;
|
||||
|
||||
public class ConstantConfigTest {
|
||||
|
||||
@Test
|
||||
public void testBeanConfToString() throws Exception {
|
||||
public void testBeanConfToString() {
|
||||
ConstantConfig constantConfig = new ConstantConfig();
|
||||
|
||||
String actual = constantConfig.beanConfToString(null);
|
||||
Assert.assertEquals(null, actual);
|
||||
Assert.assertNull(actual);
|
||||
|
||||
actual = constantConfig.beanConfToString(new BeanConfig(TestBean.class));
|
||||
Assert.assertEquals(Container.DEFAULT_NAME, actual);
|
||||
@@ -49,7 +50,7 @@ public class ConstantConfigTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAllAsStringsMap() throws Exception {
|
||||
public void testGetAllAsStringsMap() {
|
||||
ConstantConfig constantConfig = new ConstantConfig();
|
||||
|
||||
boolean expectedDevMode = true;
|
||||
@@ -65,22 +66,32 @@ public class ConstantConfigTest {
|
||||
|
||||
Assert.assertEquals(String.valueOf(expectedDevMode), map.get(StrutsConstants.STRUTS_DEVMODE));
|
||||
Assert.assertEquals(expectedActionExtensions, map.get(StrutsConstants.STRUTS_ACTION_EXTENSION));
|
||||
Assert.assertEquals(null, map.get(StrutsConstants.STRUTS_I18N_RELOAD));
|
||||
Assert.assertNull(map.get(StrutsConstants.STRUTS_I18N_RELOAD));
|
||||
Assert.assertEquals(expectedLanguage, map.get(StrutsConstants.STRUTS_LOCALE));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmptyClassesToString() throws Exception {
|
||||
public void testEmptyClassesToString() {
|
||||
ConstantConfig constantConfig = new ConstantConfig();
|
||||
|
||||
constantConfig.setExcludedClasses(new HashSet<Class<?>>());
|
||||
constantConfig.setExcludedClasses(null);
|
||||
constantConfig.setExcludedPackageNamePatterns(null);
|
||||
constantConfig.setExcludedPackageNames(null);
|
||||
constantConfig.setDevModeExcludedClasses(null);
|
||||
constantConfig.setDevModeExcludedPackageNamePatterns(null);
|
||||
constantConfig.setDevModeExcludedPackageNames(null);
|
||||
|
||||
Map<String, String> map = constantConfig.getAllAsStringsMap();
|
||||
Assert.assertEquals(null, map.get(StrutsConstants.STRUTS_EXCLUDED_CLASSES));
|
||||
Assert.assertNull(map.get(StrutsConstants.STRUTS_EXCLUDED_CLASSES));
|
||||
Assert.assertNull(map.get(StrutsConstants.STRUTS_EXCLUDED_PACKAGE_NAME_PATTERNS));
|
||||
Assert.assertNull(map.get(StrutsConstants.STRUTS_EXCLUDED_PACKAGE_NAMES));
|
||||
Assert.assertNull(map.get(StrutsConstants.STRUTS_DEV_MODE_EXCLUDED_CLASSES));
|
||||
Assert.assertNull(map.get(StrutsConstants.STRUTS_DEV_MODE_EXCLUDED_PACKAGE_NAME_PATTERNS));
|
||||
Assert.assertNull(map.get(StrutsConstants.STRUTS_DEV_MODE_EXCLUDED_PACKAGE_NAMES));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClassesToString() throws Exception {
|
||||
public void testClassesToString() {
|
||||
ConstantConfig constantConfig = new ConstantConfig();
|
||||
|
||||
Set<Class<?>> excludedClasses = new LinkedHashSet<>();
|
||||
@@ -89,9 +100,13 @@ public class ConstantConfigTest {
|
||||
excludedClasses.add(System.class);
|
||||
|
||||
constantConfig.setExcludedClasses(excludedClasses);
|
||||
constantConfig.setDevModeExcludedClasses(excludedClasses);
|
||||
|
||||
Map<String, String> map = constantConfig.getAllAsStringsMap();
|
||||
Assert.assertEquals("java.lang.Object,java.lang.Runtime,java.lang.System",
|
||||
map.get(StrutsConstants.STRUTS_EXCLUDED_CLASSES));
|
||||
map.get(StrutsConstants.STRUTS_EXCLUDED_CLASSES));
|
||||
Assert.assertEquals("java.lang.Object,java.lang.Runtime,java.lang.System",
|
||||
map.get(StrutsConstants.STRUTS_DEV_MODE_EXCLUDED_CLASSES));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
<td>
|
||||
<ul>
|
||||
<#list actionNames as name>
|
||||
<@s.url var="showConfig" action="showConfig" includeParams="none">
|
||||
<@s.url var="showConfig" action="showConfig" includeParams="none" escapeAmp="false">
|
||||
<@s.param name="namespace">${namespace}</@s.param>
|
||||
<@s.param name="actionName">${name}</@s.param>
|
||||
</@s.url>
|
||||
|
||||
@@ -39,11 +39,11 @@
|
||||
</table>
|
||||
|
||||
<!-- URLTag is faulty -->
|
||||
<@s.url var="url" action="showConfig" includeParams="none">
|
||||
<@s.url var="url" action="showConfig" includeParams="none" escapeAmp="false">
|
||||
<@s.param name="namespace">${namespace}</@s.param>
|
||||
<@s.param name="actionName">${actionName}</@s.param>
|
||||
</@s.url>
|
||||
<#assign url = url + "&detailView=">
|
||||
<#assign url = url + "&detailView=">
|
||||
<!-- Set all to false -->
|
||||
<#assign detailsSelected = false>
|
||||
<#assign exceptionsSelected = false>
|
||||
|
||||
Reference in New Issue
Block a user