org.beangle.model.persist.hibernate.internal.ClassUtils.java Source code

Java tutorial

Introduction

Here is the source code for org.beangle.model.persist.hibernate.internal.ClassUtils.java

Source

/* Copyright c 2005-2012.
 * Licensed under GNU  LESSER General Public License, Version 3.
 * http://www.gnu.org/licenses
 */
package org.beangle.model.persist.hibernate.internal;

import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.commons.lang.Validate;
import org.osgi.framework.Bundle;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.util.ObjectUtils;

public class ClassUtils {
    private static class ReadOnlySetFromMap<E> implements Set<E> {

        private final Set<E> keys;

        public ReadOnlySetFromMap(Map<E, ?> lookupMap) {
            keys = lookupMap.keySet();
        }

        public boolean add(Object o) {
            throw new UnsupportedOperationException();
        }

        public boolean addAll(Collection<? extends E> c) {
            throw new UnsupportedOperationException();
        }

        public void clear() {
            throw new UnsupportedOperationException();
        }

        public boolean contains(Object o) {
            return keys.contains(o);
        }

        public boolean containsAll(Collection<?> c) {
            return keys.containsAll(c);
        }

        public boolean isEmpty() {
            return keys.isEmpty();
        }

        public Iterator<E> iterator() {
            return keys.iterator();
        }

        public boolean remove(Object o) {
            throw new UnsupportedOperationException();
        }

        public boolean removeAll(Collection<?> c) {
            throw new UnsupportedOperationException();
        }

        public boolean retainAll(Collection<?> c) {
            throw new UnsupportedOperationException();
        }

        public int size() {
            return keys.size();
        }

        public Object[] toArray() {
            return keys.toArray();
        }

        public <T> T[] toArray(T[] array) {
            return keys.toArray(array);
        }

        public String toString() {
            return keys.toString();
        }

        public int hashCode() {
            return keys.hashCode();
        }

        public boolean equals(Object o) {
            return o == this || keys.equals(o);
        }
    }

    public enum ClassSet {
        /**
         * Include only the interfaces inherited from superclasses or
         * implemented by the current class
         */
        INTERFACES,
        /** Include only the class hierarchy (interfaces are excluded) */
        CLASS_HIERARCHY,
        /** Include all inherited classes (classes or interfaces) */
        ALL_CLASSES;
    }

    /**
     * List of special class loaders, outside OSGi, that might be used by the
     * user through boot delegation. read-only.
     */
    public static final List<ClassLoader> knownNonOsgiLoaders;

    /**
     * Set of special class loaders, outside OSGi, that might be used by the
     * user through boot delegation. read-only.
     */
    public static final Set<ClassLoader> knownNonOsgiLoadersSet;

    // add the known, non-OSGi class loaders
    // note that the order is important
    static {
        // start with the framework class loader
        // then get all its parents (normally the this should be fwk -> (*) ->
        // app -> ext -> boot)
        // where (*) represents some optional loaders for cases where the
        // framework is embedded

        final Map<ClassLoader, Boolean> lookupMap = new ConcurrentHashMap<ClassLoader, Boolean>(8);
        final List<ClassLoader> lookupList = Collections.synchronizedList(new ArrayList<ClassLoader>());

        final ClassLoader classLoader = getFwkClassLoader();

        if (System.getSecurityManager() != null) {
            AccessController.doPrivileged(new PrivilegedAction<Object>() {
                public Object run() {
                    addNonOsgiClassLoader(classLoader, lookupList, lookupMap);
                    // get the system class loader
                    ClassLoader sysLoader = ClassLoader.getSystemClassLoader();
                    addNonOsgiClassLoader(sysLoader, lookupList, lookupMap);
                    return null;
                }
            });
        } else {
            addNonOsgiClassLoader(classLoader, lookupList, lookupMap);
            // get the system class loader
            ClassLoader sysLoader = ClassLoader.getSystemClassLoader();
            addNonOsgiClassLoader(sysLoader, lookupList, lookupMap);
        }

        // wrap the fields as read-only collections
        knownNonOsgiLoaders = Collections.unmodifiableList(lookupList);
        knownNonOsgiLoadersSet = new ReadOnlySetFromMap<ClassLoader>(lookupMap);

    }

    public static ClassLoader getFwkClassLoader() {
        if (System.getSecurityManager() != null) {
            return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
                public ClassLoader run() {
                    return Bundle.class.getClassLoader();
                }
            });
        } else {
            return Bundle.class.getClassLoader();
        }
    }

    /**
     * Special static method used during the class initialization.
     * 
     * @param classLoader
     *            non OSGi class loader
     */
    private static void addNonOsgiClassLoader(ClassLoader classLoader, List<ClassLoader> list,
            Map<ClassLoader, Boolean> map) {
        while (classLoader != null) {
            synchronized (list) {
                if (!map.containsKey(classLoader)) {
                    list.add(classLoader);
                    map.put(classLoader, Boolean.TRUE);
                }
            }
            classLoader = classLoader.getParent();
        }
    }

    /**
     * Simple class loading abstraction working on both ClassLoader and Bundle
     * classes.
     * 
     * @author Costin Leau
     */
    @SuppressWarnings("unused")
    private static class ClassLoaderBridge {

        private final Bundle bundle;

        private final ClassLoader classLoader;

        public ClassLoaderBridge(Bundle bundle) {
            Validate.notNull(bundle);
            this.bundle = bundle;
            this.classLoader = null;
        }

        public ClassLoaderBridge(ClassLoader classLoader) {
            Validate.notNull(classLoader);
            this.classLoader = classLoader;
            this.bundle = null;
        }

        public Class<?> loadClass(String className) throws ClassNotFoundException {
            return (bundle == null ? classLoader.loadClass(className) : bundle.loadClass(className));
        }

        public boolean canSee(String className) {
            return (bundle == null ? org.springframework.util.ClassUtils.isPresent(className, classLoader)
                    : isPresent(className, bundle));
        }
    }

    /**
     * Checks the present of a class inside a bundle. This method returns true
     * if the given bundle can load the given class or false otherwise.
     * 
     * @param className
     * @param bundle
     * @return
     */
    public static boolean isPresent(String className, Bundle bundle) {
        Validate.notEmpty(className);
        Validate.notNull(bundle);
        try {
            bundle.loadClass(className);
            return true;
        } catch (Exception cnfe) {
            return false;
        }
    }

    /**
     * Returns the classloader for the given class. This method deals with JDK
     * classes which return by default, a null classloader.
     * 
     * @param clazz
     * @return
     */
    public static ClassLoader getClassLoader(Class<?> clazz) {
        Validate.notNull(clazz);
        ClassLoader loader = clazz.getClassLoader();
        return (loader == null ? ClassLoader.getSystemClassLoader() : loader);
    }

    /**
     * Returns an array of class string names for the given classes.
     * 
     * @param array
     * @return
     */
    public static String[] toStringArray(Class<?>[] array) {
        if (ObjectUtils.isEmpty(array))
            return new String[0];
        String[] strings = new String[array.length];
        for (int i = 0; i < array.length; i++) {
            strings[i] = array[i].getName();
        }
        return strings;
    }

    /**
     * Determines if multiple classes(not interfaces) are specified, without any
     * relation to each other. Interfaces will simply be ignored.
     * 
     * @param classes
     *            an array of classes
     * @return true if at least two classes unrelated to each other are found,
     *         false otherwise
     */
    public static boolean containsUnrelatedClasses(Class<?>[] classes) {
        if (ObjectUtils.isEmpty(classes))
            return false;

        Class<?> clazz = null;
        // check if is more then one class specified
        for (int i = 0; i < classes.length; i++) {
            if (!classes[i].isInterface()) {
                if (clazz == null)
                    clazz = classes[i];
                // check relationship
                else {
                    if (clazz.isAssignableFrom(classes[i]))
                        // clazz is a parent, switch with the child
                        clazz = classes[i];
                    else if (!classes[i].isAssignableFrom(clazz))
                        return true;

                }
            }
        }

        // everything is in order
        return false;
    }

    /**
     * Parses the given class array and eliminate parents of existing classes.
     * Useful when creating proxies to minimize the number of implemented
     * interfaces and redundant class information.
     * 
     * @see #containsUnrelatedClasses(Class[])
     * @see #configureFactoryForClass(ProxyFactory, Class[])
     * @param classes
     *            array of classes
     * @return a new array without superclasses
     */
    public static Class<?>[] removeParents(Class<?>[] classes) {
        if (ObjectUtils.isEmpty(classes))
            return new Class[0];

        List<Class<?>> clazz = new ArrayList<Class<?>>(classes.length);
        for (int i = 0; i < classes.length; i++) {
            clazz.add(classes[i]);
        }

        // remove null elements
        while (clazz.remove(null)) {
        }

        // only one class is allowed
        // there can be multiple interfaces
        // parents of classes inside the array are removed

        boolean dirty;
        do {
            dirty = false;
            for (int i = 0; i < clazz.size(); i++) {
                Class<?> currentClass = clazz.get(i);
                for (int j = 0; j < clazz.size(); j++) {
                    if (i != j) {
                        if (currentClass.isAssignableFrom(clazz.get(j))) {
                            clazz.remove(i);
                            i--;
                            dirty = true;
                            break;
                        }
                    }
                }
            }
        } while (dirty);

        return (Class[]) clazz.toArray(new Class[clazz.size()]);
    }

    /**
     * Based on the given class, properly instructs the ProxyFactory proxies.
     * For additional sanity checks on the passed classes, check the methods
     * below.
     * 
     * @see #containsUnrelatedClasses(Class[])
     * @see #removeParents(Class[])
     * @param factory
     * @param classes
     */
    public static void configureFactoryForClass(ProxyFactory factory, Class<?>[] classes) {
        if (ObjectUtils.isEmpty(classes))
            return;

        for (int i = 0; i < classes.length; i++) {
            Class<?> clazz = classes[i];

            if (clazz.isInterface()) {
                factory.addInterface(clazz);
            } else {
                factory.setTargetClass(clazz);
                factory.setProxyTargetClass(true);
            }
        }
    }

    /**
     * Loads classes with the given name, using the given classloader.
     * {@link ClassNotFoundException} exceptions are being ignored. The return
     * class array will not contain duplicates.
     * 
     * @param classNames
     *            array of classnames to load (in FQN format)
     * @param classLoader
     *            classloader used for loading the classes
     * @return an array of classes (can be smaller then the array of class
     *         names) w/o duplicates
     */
    public static Class<?>[] loadClassesIfPossible(String[] classNames, ClassLoader classLoader) {
        if (ObjectUtils.isEmpty(classNames))
            return new Class[0];

        Validate.notNull(classLoader, "classLoader is required");
        Set<Class<?>> classes = new LinkedHashSet<Class<?>>(classNames.length);

        for (int i = 0; i < classNames.length; i++) {
            try {
                classes.add(classLoader.loadClass(classNames[i]));
            } catch (ClassNotFoundException ex) {
                // ignore
            }
        }

        return (Class[]) classes.toArray(new Class[classes.size()]);
    }

    /**
     * Loads and returns the classes given as names, using the given class
     * loader. Throws IllegalArgument exception if the classes cannot be loaded.
     * 
     * @param classNames
     *            array of class names
     * @param classLoader
     *            class loader for loading the classes
     * @return the loaded classes
     */
    public static Class<?>[] loadClasses(String[] classNames, ClassLoader classLoader) {
        if (ObjectUtils.isEmpty(classNames))
            return new Class[0];

        Validate.notNull(classLoader, "classLoader is required");
        Set<Class<?>> classes = new LinkedHashSet<Class<?>>(classNames.length);

        for (int i = 0; i < classNames.length; i++) {
            classes.add(org.springframework.util.ClassUtils.resolveClassName(classNames[i], classLoader));
        }

        return (Class[]) classes.toArray(new Class[classes.size()]);
    }

    /**
     * Excludes classes from the given array, which match the given modifier.
     * 
     * @param classes
     *            array of classes (can be null)
     * @param modifier
     *            class modifier
     * @return array of classes (w/o duplicates) which does not have the given
     *         modifier
     */
    public static Class<?>[] excludeClassesWithModifier(Class<?>[] classes, int modifier) {
        if (ObjectUtils.isEmpty(classes))
            return new Class[0];

        Set<Class<?>> clazzes = new LinkedHashSet<Class<?>>(classes.length);

        for (int i = 0; i < classes.length; i++) {
            if ((modifier & classes[i].getModifiers()) == 0)
                clazzes.add(classes[i]);
        }
        return (Class[]) clazzes.toArray(new Class[clazzes.size()]);
    }

    /**
     * Returns the first matching class from the given array, that doens't
     * belong to common libraries such as the JDK or OSGi API. Useful for
     * filtering OSGi services by type to prevent class cast problems.
     * <p/>
     * No sanity checks are done on the given array class.
     * 
     * @param classes
     *            array of classes
     * @return a 'particular' (non JDK/OSGi) class if one is found. Else the
     *         first available entry is returned.
     */
    public static Class<?> getParticularClass(Class<?>[] classes) {
        boolean hasSecurity = (System.getSecurityManager() != null);
        for (int i = 0; i < classes.length; i++) {
            final Class<?> clazz = classes[i];
            ClassLoader loader = null;
            if (hasSecurity) {
                loader = AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
                    public ClassLoader run() {
                        return clazz.getClassLoader();
                    }
                });
            } else {
                loader = clazz.getClassLoader();
            }
            // quick boot/system check
            if (loader != null) {
                // consider known loaders
                if (!knownNonOsgiLoadersSet.contains(loader)) {
                    return clazz;
                }
            }
        }

        return (ObjectUtils.isEmpty(classes) ? null : classes[0]);
    }
}