org.jboss.el.cache.BeanPropertiesCache Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jboss-javaee-all-8.0
Show all versions of jboss-javaee-all-8.0
Combine jar files which includes all Java EE 8 Spec APIs
The newest version!
package org.jboss.el.cache;
import javax.el.ELException;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author Stuart Douglas
*/
public class BeanPropertiesCache {
static private class BPSoftReference extends SoftReference {
final Class> key;
BPSoftReference(Class> key, BeanProperties beanProperties,
ReferenceQueue refQ) {
super(beanProperties, refQ);
this.key = key;
}
}
public static class SoftConcurrentHashMap extends
ConcurrentHashMap, BeanProperties> {
private static final int CACHE_INIT_SIZE = 1024;
private ConcurrentHashMap, BPSoftReference> map =
new ConcurrentHashMap, BPSoftReference>(CACHE_INIT_SIZE);
private ReferenceQueue refQ =
new ReferenceQueue();
// Remove map entries that have been placed on the queue by GC.
private void cleanup() {
BPSoftReference BPRef = null;
while ((BPRef = (BPSoftReference)refQ.poll()) != null) {
map.remove(BPRef.key);
}
}
protected void clear(ClassLoader classLoader) {
Iterator, BPSoftReference>> it = map.entrySet().iterator();
while (it.hasNext()) {
Map.Entry, BPSoftReference> entry = it.next();
if(entry.getKey().getClassLoader() == classLoader) {
it.remove();
}
}
}
@Override
public BeanProperties put(Class> key, BeanProperties value) {
cleanup();
BPSoftReference prev =
map.put(key, new BPSoftReference(key, value, refQ));
return prev == null? null: prev.get();
}
@Override
public BeanProperties putIfAbsent(Class> key, BeanProperties value) {
cleanup();
BPSoftReference prev =
map.putIfAbsent(key, new BPSoftReference(key, value, refQ));
return prev == null? null: prev.get();
}
@Override
public BeanProperties get(Object key) {
cleanup();
BPSoftReference BPRef = map.get(key);
if (BPRef == null) {
return null;
}
if (BPRef.get() == null) {
// value has been garbage collected, remove entry in map
map.remove(key);
return null;
}
return BPRef.get();
}
}
/*
* Defines a property for a bean.
*/
public final static class BeanProperty {
private Method readMethod;
private Method writeMethod;
private PropertyDescriptor descriptor;
public BeanProperty(Class> baseClass,
PropertyDescriptor descriptor) {
this.descriptor = descriptor;
readMethod = getMethod(baseClass, descriptor.getReadMethod());
writeMethod = getMethod(baseClass, descriptor.getWriteMethod());
}
public Class getPropertyType() {
return descriptor.getPropertyType();
}
public boolean isReadOnly() {
return getWriteMethod() == null;
}
public Method getReadMethod() {
return readMethod;
}
public Method getWriteMethod() {
return writeMethod;
}
}
/*
* Defines the properties for a bean.
*/
public final static class BeanProperties {
private final Map propertyMap =
new HashMap();
public BeanProperties(Class> baseClass) {
PropertyDescriptor[] descriptors;
try {
BeanInfo info = Introspector.getBeanInfo(baseClass);
descriptors = info.getPropertyDescriptors();
} catch (IntrospectionException ie) {
throw new ELException(ie);
}
for (PropertyDescriptor pd: descriptors) {
propertyMap.put(pd.getName(),
new BeanProperty(baseClass, pd));
}
}
public BeanProperty getBeanProperty(String property) {
return propertyMap.get(property);
}
}
/**
* sfot references are horrible
*/
private static final SoftConcurrentHashMap properties =
new SoftConcurrentHashMap();
/*
* Get a public method form a public class or interface of a given method.
* Note that if a PropertyDescriptor is obtained for a non-public class that
* implements a public interface, the read/write methods will be for the
* class, and therefore inaccessible. To correct this, a version of the
* same method must be found in a superclass or interface.
**/
public static Method getMethod(Class> cl, Method method) {
if (method == null) {
return null;
}
if (Modifier.isPublic(cl.getModifiers())) {
return method;
}
Class> [] interfaces = cl.getInterfaces ();
for (int i = 0; i < interfaces.length; i++) {
Class> c = interfaces[i];
Method m = null;
try {
m = c.getMethod(method.getName(), method.getParameterTypes());
c = m.getDeclaringClass();
if ((m = getMethod(c, m)) != null)
return m;
} catch (NoSuchMethodException ex) {
}
}
Class> c = cl.getSuperclass();
if (c != null) {
Method m = null;
try {
m = c.getMethod(method.getName(), method.getParameterTypes());
c = m.getDeclaringClass();
if ((m = getMethod(c, m)) != null)
return m;
} catch (NoSuchMethodException ex) {
}
}
return null;
}
public static SoftConcurrentHashMap getProperties() {
return properties;
}
static void clear(ClassLoader classLoader) {
properties.clear(classLoader);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy