org.apache.river.reggie.proxy.ClassMapper Maven / Gradle / Ivy
/*
* 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 org.apache.river.reggie.proxy;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.Comparator;
import java.util.WeakHashMap;
import java.lang.ref.SoftReference;
import java.rmi.MarshalException;
/**
* Maps Class to ServiceType/Base, Class to EntryClass/Base, and Class to
* Field[], with caching for efficiency.
*
* @author Sun Microsystems, Inc.
*
*/
class ClassMapper {
/** Weak Map from Class to SoftReference(ServiceTypeBase) */
private static final WeakHashMap serviceMap = new WeakHashMap(23);
/** Weak Map from Class to SoftReference(EntryClassBase) */
private static final WeakHashMap entryMap = new WeakHashMap(17);
/** Weak Map from Class to SoftReference(sorted Field[]) */
private static final WeakHashMap fieldMap = new WeakHashMap(17);
/** Comparator for sorting fields */
private static final FieldComparator comparator = new FieldComparator();
private static final ServiceType[] empty = {};
private static final Class[] noArg = new Class[0];
private ClassMapper() {}
/** Returns a ServiceTypeBase descriptor for a class. */
public static ServiceTypeBase toServiceTypeBase(Class cls)
throws MarshalException
{
synchronized (serviceMap) {
return toServiceTypeBase(cls, true);
}
}
/**
* Returns a ServiceTypeBase descriptor for a class. If needCodebase
* is false, the returned descriptor's codebase may be null.
*/
private static ServiceTypeBase toServiceTypeBase(Class cls,
boolean needCodebase)
throws MarshalException
{
if (cls == null)
return null;
SoftReference cref = (SoftReference)serviceMap.get(cls);
ServiceTypeBase stype = null;
if (cref != null)
stype = (ServiceTypeBase)cref.get();
if (stype == null) {
stype = new ServiceTypeBase(
new ServiceType(cls,
toServiceType(cls.getSuperclass()),
toServiceType(cls.getInterfaces())),
null);
serviceMap.put(cls, new SoftReference(stype));
}
if (needCodebase && stype.codebase == null)
stype.setCodebase(cls);
return stype;
}
/** Returns a ServiceType descriptor for a class. */
private static ServiceType toServiceType(Class cls)
throws MarshalException
{
if (cls != null)
return toServiceTypeBase(cls, false).type;
return null;
}
/** Converts an array of Class to an array of ServiceType. */
public static ServiceType[] toServiceType(Class[] classes)
throws MarshalException
{
if (classes == null)
return null;
if (classes.length == 0)
return empty;
ServiceType[] stypes = new ServiceType[classes.length];
synchronized (serviceMap) {
for (int i = classes.length; --i >= 0; ) {
stypes[i] = toServiceType(classes[i]);
}
}
return stypes;
}
/** Returns a EntryClassBase descriptor for a class. */
public static EntryClassBase toEntryClassBase(Class cls)
throws MarshalException
{
synchronized (entryMap) {
return toEntryClassBase(cls, true);
}
}
/**
* Returns a EntryClassBase descriptor for a class. If base is false,
* the returned descriptor's codebase may be null, and the class need
* not be public and need not have a no-arg constructor.
*/
private static EntryClassBase toEntryClassBase(Class cls, boolean base)
throws MarshalException
{
if (cls == null)
return null;
SoftReference cref = (SoftReference)entryMap.get(cls);
EntryClassBase eclass = null;
if (cref != null)
eclass = (EntryClassBase)cref.get();
if (eclass == null) {
if (base) {
if (!Modifier.isPublic(cls.getModifiers()))
throw new IllegalArgumentException("entry class " +
cls.getName() +
" is not public");
try {
cls.getConstructor(noArg);
} catch (NoSuchMethodException e) {
throw new IllegalArgumentException("entry class " +
cls.getName() +
" does not have a public no-arg constructor");
}
}
eclass = new EntryClassBase(
new EntryClass(cls,
toEntryClass(cls.getSuperclass())),
null);
entryMap.put(cls, new SoftReference(eclass));
}
if (base && eclass.codebase == null)
eclass.setCodebase(cls);
return eclass;
}
/** Returns an EntryClass descriptor for a class. */
private static EntryClass toEntryClass(Class cls) throws MarshalException {
if (cls != null)
return toEntryClassBase(cls, false).eclass;
return null;
}
/** Field of an Entry class, with marshalling information */
static class EntryField {
/** Field for the field */
public final Field field;
/**
* True if instances of the field need to be converted
* to MarshalledWrapper. False if the type of the field
* is String, Integer, Boolean, Character, Long, Float,
* Double, Byte, or Short.
*/
public final boolean marshal;
/**
* Basic constructor.
*/
public EntryField(Field field) {
this.field = field;
Class c = field.getType();
marshal = !(c == String.class ||
c == Integer.class ||
c == Boolean.class ||
c == Character.class ||
c == Long.class ||
c == Float.class ||
c == Double.class ||
c == Byte.class ||
c == Short.class);
}
}
/**
* Returns public fields, in super to subclass order, sorted
* alphabetically within a given class.
*/
public static EntryField[] getFields(Class cls) {
synchronized (fieldMap) {
SoftReference cref = (SoftReference)fieldMap.get(cls);
EntryField[] efields = null;
if (cref != null)
efields = (EntryField[])cref.get();
if (efields == null) {
Field[] fields = cls.getFields();
Arrays.sort(fields, comparator);
int len = 0;
for (int i = 0; i < fields.length; i++) {
if ((fields[i].getModifiers() &
(Modifier.STATIC|Modifier.FINAL|Modifier.TRANSIENT))
== 0)
{
if (fields[i].getType().isPrimitive())
throw new IllegalArgumentException("entry class " +
cls.getName() +
" has a primitive field");
fields[len++] = fields[i];
}
}
efields = new EntryField[len];
while (--len >= 0) {
efields[len] = new EntryField(fields[len]);
}
fieldMap.put(cls, new SoftReference(efields));
}
return efields;
}
}
/** Comparator for sorting fields. */
private static class FieldComparator implements Comparator {
public FieldComparator() {}
/** Super before subclass, alphabetical within a given class */
public int compare(Object o1, Object o2) {
Field f1 = (Field)o1;
Field f2 = (Field)o2;
if (f1 == f2)
return 0;
if (f1.getDeclaringClass() == f2.getDeclaringClass())
return f1.getName().compareTo(f2.getName());
if (f1.getDeclaringClass().isAssignableFrom(
f2.getDeclaringClass()))
return -1;
return 1;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy