package org.csstudio.ui.util.dnd; import java.io.IOException; import java.io.InputStream; import java.io.ObjectInputStream; import java.io.ObjectStreamClass; import java.lang.reflect.Array; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import org.csstudio.ui.util.Activator; import org.csstudio.ui.util.ReflectUtil; import org.osgi.framework.Bundle; /** * De-serializes java classes looking for the classloaders in the appropriate osgi bundle. * Using the normal ObjectInputStream would resolve classes only according * to this plugin classloader. This resolves the classes by looking for the * class in any plugin whose name is a package parent of the given class. * * @author Gabriele Carcassi */ public class ObjectInputStreamWithOsgiClassResolution extends ObjectInputStream { /** * {@inheritDoc} */ public ObjectInputStreamWithOsgiClassResolution(InputStream in) throws IOException { super(in); } // classes already resolved private static Map<String, Class<?>> resolvedClasses = new ConcurrentHashMap<String, Class<?>>(); private static Class<?> findClass(String className, String bundleName) { try { // Find the matching bundle and try to load the class for (Bundle bundle : Activator.getDefault().getContext().getBundles()) { if (bundle.getSymbolicName().equals(bundleName)) { return bundle.loadClass(className); } } } catch(ClassNotFoundException ex) { // class not found } return null; } private static Class<?> findClass(String className) { // Let's first find a class normally try { return Class.forName(className); } catch (ClassNotFoundException ex) { // Not found continue } // Look inside bundle that have the same name as one of the packages // of the class String currentBundleName = className; while (currentBundleName.lastIndexOf(".") != -1) { currentBundleName = currentBundleName.substring(0, currentBundleName.lastIndexOf('.')); Class<?> clazz = findClass(className, currentBundleName); if (clazz != null) return clazz; } // Can't find it return null; } private static Class<?> getClass(String className) { // Look if it's already resolved Class<?> clazz = resolvedClasses.get(className); if (clazz == null) { // If it's an array, resolve the class String classNameToResolve = className; if (ReflectUtil.isArray(className)) { classNameToResolve = ReflectUtil.getComponentType(className); } // Resolve it clazz = findClass(classNameToResolve); // If found, cache it if (clazz == null) return null; resolvedClasses.put(classNameToResolve, clazz); if (ReflectUtil.isArray(className)) { clazz = Array.newInstance(clazz, 0).getClass(); resolvedClasses.put(className, clazz); } } return clazz; } @Override protected Class<?> resolveClass(final ObjectStreamClass desc) throws IOException, ClassNotFoundException { String name = desc.getName(); Class<?> clazz = getClass(name); if (clazz == null) { throw new ClassNotFoundException(name); } return clazz; } }