Skip to content
Permalink
Browse files
JEXL-357: added permissions parser;
- added a (static) 'secure' permissions (used in tests);
- quiesce spotbugs on builder patterns;
  • Loading branch information
henrib committed Feb 3, 2022
1 parent 0e18632 commit 0b1cbdbe8aa7d98d71dbfe29279240adde8c136f
Show file tree
Hide file tree
Showing 13 changed files with 883 additions and 306 deletions.
@@ -51,4 +51,20 @@
<Match>
<Class name="org.apache.commons.jexl3.parser.SimpleNode"/>
</Match>
<Match>
<Class name="org.apache.commons.jexl3.JexlBuilder"/>
<Bug code="EI2,EI"></Bug>
</Match>
<Match>
<Package name="org.apache.commons.jexl3.internal"/>
<Bug code="EI2,EI"></Bug>
</Match>
<Match>
<Package name="org.apache.commons.jexl3.introspection.internal"/>
<Bug code="EI2,EI"></Bug>
</Match>
<Match>
<Package name="org.apache.commons.jexl3.parser"/>
<Bug code="EI2,EI"></Bug>
</Match>
</FindBugsFilter>
@@ -16,21 +16,21 @@
*/
package org.apache.commons.jexl3.internal.introspection;

import org.apache.commons.jexl3.introspection.JexlPermissions;
import org.apache.commons.logging.Log;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
* A cache of introspection information for a specific class instance.
@@ -77,16 +77,49 @@ public static Method cacheMiss() {
* </p>
* Uses ConcurrentMap since 3.0, marginally faster than 2.1 under contention.
*/
private final ConcurrentMap<MethodKey, Method> byKey = new ConcurrentHashMap<>();
private final Map<MethodKey, Method> byKey ;
/**
* Keep track of all methods with the same name; this is not modified after creation.
*/
private final Map<String, Method[]> byName = new HashMap<>();
private final Map<String, Method[]> byName;
/**
* Cache of fields.
*/
private final Map<String, Field> fieldCache;

/**
* Singleton for permissions non-allowed classes.
*/
private static final ClassMap EMPTY = new ClassMap();

/**
* @return the empty classmap instance
*/
static ClassMap empty() {
return EMPTY;
}

/**
* Empty map.
*/
private ClassMap() {
this.byKey = Collections.unmodifiableMap(new AbstractMap<MethodKey, Method>() {
@Override
public String toString() {
return "emptyClassMap{}";
}
@Override
public Set<Entry<MethodKey, Method>> entrySet() {
return null;
}
@Override public Method get(Object name) {
return CACHE_MISS;
}
});
this.byName = Collections.emptyMap();
this.fieldCache = Collections.emptyMap();
}

/**
* Standard constructor.
*
@@ -95,7 +128,9 @@ public static Method cacheMiss() {
* @param log the logger.
*/
@SuppressWarnings("LeakingThisInConstructor")
ClassMap(final Class<?> aClass, final Permissions permissions, final Log log) {
ClassMap(final Class<?> aClass, final JexlPermissions permissions, final Log log) {
this.byKey = new ConcurrentHashMap<>();
this.byName = new HashMap<>();
// eagerly cache methods
create(this, permissions, aClass, log);
// eagerly cache public fields
@@ -211,7 +246,7 @@ Method getMethod(final MethodKey methodKey) throws MethodKey.AmbiguousException
* @param clazz the class to cache
* @param log the Log
*/
private static void create(final ClassMap cache, final Permissions permissions, Class<?> clazz, final Log log) {
private static void create(final ClassMap cache, final JexlPermissions permissions, Class<?> clazz, final Log log) {
//
// Build a list of all elements in the class hierarchy. This one is bottom-first (i.e. we start
// with the actual declaring class and its interfaces and then move up (superclass etc.) until we
@@ -263,7 +298,7 @@ private static void create(final ClassMap cache, final Permissions permissions,
* @param log the Log
*/
private static void populateWithInterface(final ClassMap cache,
final Permissions permissions,
final JexlPermissions permissions,
final Class<?> iface,
final Log log) {
if (Modifier.isPublic(iface.getModifiers())) {
@@ -284,7 +319,7 @@ private static void populateWithInterface(final ClassMap cache,
* @param log the Log
*/
private static void populateWithClass(final ClassMap cache,
final Permissions permissions,
final JexlPermissions permissions,
final Class<?> clazz,
final Log log) {
try {
@@ -16,6 +16,7 @@
*/
package org.apache.commons.jexl3.internal.introspection;

import org.apache.commons.jexl3.introspection.JexlPermissions;
import org.apache.commons.logging.Log;

import java.lang.reflect.Constructor;
@@ -69,7 +70,7 @@ public CacheMiss() {
/**
* The permissions.
*/
private final Permissions permissions;
private final JexlPermissions permissions;
/**
* The read/write lock.
*/
@@ -93,7 +94,7 @@ public CacheMiss() {
* @param cloader the class loader
*/
public Introspector(final Log log, final ClassLoader cloader) {
this(log, cloader, null);
this(log, cloader, Permissions.DEFAULT);
}

/**
@@ -102,10 +103,10 @@ public Introspector(final Log log, final ClassLoader cloader) {
* @param cloader the class loader
* @param perms the permissions
*/
public Introspector(final Log log, final ClassLoader cloader, final Permissions perms) {
public Introspector(final Log log, final ClassLoader cloader, final JexlPermissions perms) {
this.logger = log;
this.loader = cloader;
this.permissions = perms != null? perms : Permissions.DEFAULT;
this.permissions = perms != null? perms : Permissions.SECURE;
}

/**
@@ -312,7 +313,9 @@ private ClassMap getMap(final Class<?> c) {
// try again
classMap = classMethodMaps.get(c);
if (classMap == null) {
classMap = new ClassMap(c, permissions, logger);
classMap = permissions.allow(c)
? new ClassMap(c, permissions, logger)
: ClassMap.empty();
classMethodMaps.put(c, classMap);
}
} finally {

0 comments on commit 0b1cbdb

Please sign in to comment.