Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package com.opensymphony.xwork2.ognl;
import com.opensymphony.xwork2.XWorkConstants;
import com.opensymphony.xwork2.config.ConfigurationException;
import com.opensymphony.xwork2.conversion.impl.XWorkConverter;
import com.opensymphony.xwork2.inject.Container;
import com.opensymphony.xwork2.inject.Inject;
import com.opensymphony.xwork2.ognl.accessor.CompoundRootAccessor;
import com.opensymphony.xwork2.util.CompoundRoot;
import com.opensymphony.xwork2.util.TextParseUtil;
import com.opensymphony.xwork2.util.reflection.ReflectionException;
import ognl.*;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.struts2.StrutsConstants;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.regex.Pattern;
/**
* Utility class that provides common access to the Ognl APIs for
* setting and getting properties from objects (usually Actions).
*
* @author Jason Carreira
*/
public class OgnlUtil {
private static final Logger LOG = LogManager.getLogger(OgnlUtil.class);
private final ConcurrentMap expressions = new ConcurrentHashMap<>();
private final ConcurrentMap beanInfoCache = new ConcurrentHashMap<>();
private TypeConverter defaultConverter;
private boolean devMode;
private boolean enableExpressionCache = true;
private boolean enableEvalExpression;
private Set> excludedClasses;
private Set excludedPackageNamePatterns;
private Set excludedPackageNames;
private Container container;
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);
}
@Inject
protected void setXWorkConverter(XWorkConverter conv) {
this.defaultConverter = new OgnlTypeConverterWrapper(conv);
}
@Inject(XWorkConstants.DEV_MODE)
protected void setDevMode(String mode) {
this.devMode = BooleanUtils.toBoolean(mode);
}
@Inject(XWorkConstants.ENABLE_OGNL_EXPRESSION_CACHE)
protected void setEnableExpressionCache(String cache) {
enableExpressionCache = BooleanUtils.toBoolean(cache);
}
@Inject(value = XWorkConstants.ENABLE_OGNL_EVAL_EXPRESSION, required = false)
protected void setEnableEvalExpression(String evalExpression) {
this.enableEvalExpression = BooleanUtils.toBoolean(evalExpression);
if (this.enableEvalExpression) {
LOG.warn("Enabling OGNL expression evaluation may introduce security risks " +
"(see http://struts.apache.org/release/2.3.x/docs/s2-013.html for further details)");
}
}
@Inject(value = XWorkConstants.OGNL_EXCLUDED_CLASSES, required = false)
protected void setExcludedClasses(String commaDelimitedClasses) {
Set> excludedClasses = new HashSet<>();
excludedClasses.addAll(this.excludedClasses);
excludedClasses.addAll(parseExcludedClasses(commaDelimitedClasses));
this.excludedClasses = Collections.unmodifiableSet(excludedClasses);
}
private Set> parseExcludedClasses(String commaDelimitedClasses) {
Set classNames = TextParseUtil.commaDelimitedStringToSet(commaDelimitedClasses);
Set> classes = new HashSet<>();
for (String className : classNames) {
try {
classes.add(Class.forName(className));
} catch (ClassNotFoundException e) {
throw new ConfigurationException("Cannot load excluded class: " + className, e);
}
}
return classes;
}
@Inject(value = XWorkConstants.OGNL_EXCLUDED_PACKAGE_NAME_PATTERNS, required = false)
protected void setExcludedPackageNamePatterns(String commaDelimitedPackagePatterns) {
Set excludedPackageNamePatterns = new HashSet<>();
excludedPackageNamePatterns.addAll(this.excludedPackageNamePatterns);
excludedPackageNamePatterns.addAll(parseExcludedPackageNamePatterns(commaDelimitedPackagePatterns));
this.excludedPackageNamePatterns = Collections.unmodifiableSet(excludedPackageNamePatterns);
}
private Set parseExcludedPackageNamePatterns(String commaDelimitedPackagePatterns) {
Set packagePatterns = TextParseUtil.commaDelimitedStringToSet(commaDelimitedPackagePatterns);
Set packageNamePatterns = new HashSet<>();
for (String pattern : packagePatterns) {
packageNamePatterns.add(Pattern.compile(pattern));
}
return packageNamePatterns;
}
@Inject(value = XWorkConstants.OGNL_EXCLUDED_PACKAGE_NAMES, required = false)
protected void setExcludedPackageNames(String commaDelimitedPackageNames) {
Set excludedPackageNames = new HashSet<>();
excludedPackageNames.addAll(this.excludedPackageNames);
excludedPackageNames.addAll(parseExcludedPackageNames(commaDelimitedPackageNames));
this.excludedPackageNames = Collections.unmodifiableSet(excludedPackageNames);
}
private Set parseExcludedPackageNames(String commaDelimitedPackageNames) {
return TextParseUtil.commaDelimitedStringToSet(commaDelimitedPackageNames);
}
public Set> getExcludedClasses() {
return excludedClasses;
}
public Set getExcludedPackageNamePatterns() {
return excludedPackageNamePatterns;
}
public Set getExcludedPackageNames() {
return excludedPackageNames;
}
@Inject
protected void setContainer(Container container) {
this.container = container;
}
@Inject(value = XWorkConstants.ALLOW_STATIC_METHOD_ACCESS, required = false)
protected void setAllowStaticMethodAccess(String allowStaticMethodAccess) {
this.allowStaticMethodAccess = BooleanUtils.toBoolean(allowStaticMethodAccess);
}
@Inject(value = StrutsConstants.STRUTS_DISALLOW_PROXY_MEMBER_ACCESS, required = false)
protected void setDisallowProxyMemberAccess(String disallowProxyMemberAccess) {
this.disallowProxyMemberAccess = Boolean.parseBoolean(disallowProxyMemberAccess);
}
/**
* @param maxLength Injects the Struts OGNL maximum expression length.
*/
@Inject(value = StrutsConstants.STRUTS_OGNL_EXPRESSION_MAX_LENGTH, required = false)
protected void applyExpressionMaxLength(String maxLength) {
try {
if (maxLength == null || maxLength.isEmpty()) {
// user is going to disable this functionality
Ognl.applyExpressionMaxLength(null);
} else {
Ognl.applyExpressionMaxLength(Integer.parseInt(maxLength));
}
} catch (Exception ex) {
LOG.error("Unable to set OGNL Expression Max Length {}.", maxLength); // Help configuration debugging.
throw ex;
}
}
public boolean isDisallowProxyMemberAccess() {
return disallowProxyMemberAccess;
}
/**
* Convenience mechanism to clear the OGNL Runtime Cache via OgnlUtil. May be utilized
* by applications that generate many unique OGNL expressions over time.
*
* Note: This call affects the global OGNL cache, see ({@link ognl.OgnlRuntime#clearCache()} for details.
*
* Warning: Frequent calling if this method may negatively impact performance, but may be required
* to avoid memory exhaustion (resource leak) with too many OGNL expressions being cached.
*
* @since 2.5.21
*/
public static void clearRuntimeCache() {
OgnlRuntime.clearCache();
}
/**
* Provide a mechanism to clear the OGNL expression cache. May be utilized by applications
* that generate many unique OGNL expressions over time.
*
* Note: This call affects the current OgnlUtil instance. For Struts this is often a Singleton
* instance so it can be "effectively global".
*
* Warning: Frequent calling if this method may negatively impact performance, but may be required
* to avoid memory exhaustion (resource leak) with too many OGNL expressions being cached.
*
* @since 2.5.21
*/
public void clearExpressionCache() {
expressions.clear();
}
/**
* Check the size of the expression cache (current number of elements).
*
* @return current number of elements in the expression cache.
*
* @since 2.5.21
*/
public int expressionCacheSize() {
return expressions.size();
}
/**
* Provide a mechanism to clear the BeanInfo cache. May be utilized by applications
* that request BeanInfo and/or PropertyDescriptors for many unique classes or objects over time
* (especially dynamic objects).
*
* Note: This call affects the current OgnlUtil instance. For Struts this is often a Singleton
* instance so it can be "effectively global".
*
* Warning: Frequent calling if this method may negatively impact performance, but may be required
* to avoid memory exhaustion (resource leak) with too many BeanInfo elements being cached.
*
* @since 2.5.21
*/
public void clearBeanInfoCache() {
beanInfoCache.clear();
}
/**
* Check the size of the BeanInfo cache (current number of elements).
*
* @return current number of elements in the BeanInfo cache.
*
* @since 2.5.21
*/
public int beanInfoCacheSize() {
return beanInfoCache.size();
}
/**
* Sets the object's properties using the default type converter, defaulting to not throw
* exceptions for problems setting the properties.
*
* @param props the properties being set
* @param o the object
* @param context the action context
*/
public void setProperties(Map props, Object o, Map context) {
setProperties(props, o, context, false);
}
/**
* Sets the object's properties using the default type converter.
*
* @param props the properties being set
* @param o the object
* @param context the action context
* @param throwPropertyExceptions boolean which tells whether it should throw exceptions for
* problems setting the properties
*/
public void setProperties(Map props, Object o, Map context, boolean throwPropertyExceptions) throws ReflectionException{
if (props == null) {
return;
}
Ognl.setTypeConverter(context, getTypeConverterFromContext(context));
Object oldRoot = Ognl.getRoot(context);
Ognl.setRoot(context, o);
for (Map.Entry entry : props.entrySet()) {
String expression = entry.getKey();
internalSetProperty(expression, entry.getValue(), o, context, throwPropertyExceptions);
}
Ognl.setRoot(context, oldRoot);
}
/**
* Sets the properties on the object using the default context, defaulting to not throwing
* exceptions for problems setting the properties.
*
* @param properties map of properties
* @param o object
*/
public void setProperties(Map properties, Object o) {
setProperties(properties, o, false);
}
/**
* Sets the properties on the object using the default context.
*
* @param properties the property map to set on the object
* @param o the object to set the properties into
* @param throwPropertyExceptions boolean which tells whether it should throw exceptions for
* problems setting the properties
*/
public void setProperties(Map properties, Object o, boolean throwPropertyExceptions) {
Map context = createDefaultContext(o, null);
setProperties(properties, o, context, throwPropertyExceptions);
}
/**
* Sets the named property to the supplied value on the Object, defaults to not throwing
* property exceptions.
*
* @param name the name of the property to be set
* @param value the value to set into the named property
* @param o the object upon which to set the property
* @param context the context which may include the TypeConverter
*/
public void setProperty(String name, Object value, Object o, Map context) {
setProperty(name, value, o, context, false);
}
/**
* Sets the named property to the supplied value on the Object.
*
* @param name the name of the property to be set
* @param value the value to set into the named property
* @param o the object upon which to set the property
* @param context the context which may include the TypeConverter
* @param throwPropertyExceptions boolean which tells whether it should throw exceptions for
* problems setting the property
*/
public void setProperty(String name, Object value, Object o, Map context, boolean throwPropertyExceptions) {
Ognl.setTypeConverter(context, getTypeConverterFromContext(context));
Object oldRoot = Ognl.getRoot(context);
Ognl.setRoot(context, o);
internalSetProperty(name, value, o, context, throwPropertyExceptions);
Ognl.setRoot(context, oldRoot);
}
/**
* Looks for the real target with the specified property given a root Object which may be a
* CompoundRoot.
*
* @param property the property
* @param context context map
* @param root compound root
*
* @return the real target or null if no object can be found with the specified property
* @throws OgnlException in case of ognl errors
*/
public Object getRealTarget(String property, Map context, Object root) throws OgnlException {
//special keyword, they must be cutting the stack
if ("top".equals(property)) {
return root;
}
if (root instanceof CompoundRoot) {
// find real target
CompoundRoot cr = (CompoundRoot) root;
try {
for (Object target : cr) {
if (OgnlRuntime.hasSetProperty((OgnlContext) context, target, property)
|| OgnlRuntime.hasGetProperty((OgnlContext) context, target, property)
|| OgnlRuntime.getIndexedPropertyType((OgnlContext) context, target.getClass(), property) != OgnlRuntime.INDEXED_PROPERTY_NONE
) {
return target;
}
}
} catch (IntrospectionException ex) {
throw new ReflectionException("Cannot figure out real target class", ex);
}
return null;
}
return root;
}
/**
* Wrapper around Ognl.setValue() to handle type conversion for collection elements.
* Ideally, this should be handled by OGNL directly.
*
* @param name the name
* @param context context map
* @param root root
* @param value value
*
* @throws OgnlException in case of ognl errors
*/
public void setValue(final String name, final Map context, final Object root, final Object value) throws OgnlException {
compileAndExecute(name, context, new OgnlTask() {
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;
}
});
}
private boolean isEvalExpression(Object tree, Map context) throws OgnlException {
if (tree instanceof SimpleNode) {
SimpleNode node = (SimpleNode) tree;
OgnlContext ognlContext = null;
if (context!=null && context instanceof OgnlContext) {
ognlContext = (OgnlContext) context;
}
return node.isEvalChain(ognlContext) || node.isSequence(ognlContext);
}
return false;
}
private boolean isArithmeticExpression(Object tree, Map context) throws OgnlException {
if (tree instanceof SimpleNode) {
SimpleNode node = (SimpleNode) tree;
OgnlContext ognlContext = null;
if (context!=null && context instanceof OgnlContext) {
ognlContext = (OgnlContext) context;
}
return node.isOperation(ognlContext);
}
return false;
}
private boolean isSimpleMethod(Object tree, Map context) throws OgnlException {
if (tree instanceof SimpleNode) {
SimpleNode node = (SimpleNode) tree;
OgnlContext ognlContext = null;
if (context!=null && context instanceof OgnlContext) {
ognlContext = (OgnlContext) context;
}
return node.isSimpleMethod(ognlContext) && !node.isChain(ognlContext);
}
return false;
}
public Object getValue(final String name, final Map context, final Object root) throws OgnlException {
return compileAndExecute(name, context, new OgnlTask