/****************************************************************************** * Copyright (c) 2006, 2010 VMware Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * and Apache License v2.0 which accompanies this distribution. * The Eclipse Public License is available at * http://www.eclipse.org/legal/epl-v10.html and the Apache License v2.0 * is available at http://www.opensource.org/licenses/apache2.0.php. * You may elect to redistribute this code under either of these licenses. * * Contributors: * VMware Inc. *****************************************************************************/ package org.eclipse.gemini.blueprint.context.support.internal.classloader; import java.lang.ref.WeakReference; import java.util.HashMap; import java.util.Map; import java.util.WeakHashMap; import org.eclipse.gemini.blueprint.util.BundleDelegatingClassLoader; import org.osgi.framework.Bundle; /** * Default implementation for {@link BundleClassLoaderFactory}. * * @author Costin Leau */ class CachingBundleClassLoaderFactory implements BundleClassLoaderFactory { private static final String DELIMITER = "|"; /** bundle -> map of class loaders (as a bundle can be refreshed) */ private final Map<Bundle, Map<Object, WeakReference<ClassLoader>>> cache = new WeakHashMap<Bundle, Map<Object, WeakReference<ClassLoader>>>(); public ClassLoader createClassLoader(Bundle bundle) { ClassLoader loader = null; // create a bundle identity object Object key = createKeyFor(bundle); Map<Object, WeakReference<ClassLoader>> loaders = null; // get associated class loaders (if any) synchronized (cache) { loaders = cache.get(bundle); if (loaders == null) { loaders = new HashMap<Object, WeakReference<ClassLoader>>(4); loader = createBundleClassLoader(bundle); loaders.put(key, new WeakReference<ClassLoader>(loader)); return loader; } } // check the associated loaders synchronized (loaders) { WeakReference<ClassLoader> reference = loaders.get(key); if (reference != null) loader = (ClassLoader) reference.get(); // loader not found (or already recycled) if (loader == null) { loader = createBundleClassLoader(bundle); loaders.put(key, new WeakReference<ClassLoader>(loader)); } return loader; } } /** * Creates a key for the given bundle. This is needed since the bundle can * be updated or refreshed and thus can have different class loaders during * its lifetime which are not reflected in its identity. Additionally, the * given key will behave the same across the OSGi implementations and * provide weak reference semantics. * * @param bundle OSGi bundle * @return key generated for the given bundle */ private Object createKeyFor(Bundle bundle) { StringBuilder buffer = new StringBuilder(); // add the bundle id first buffer.append(bundle.getBundleId()); // followed by its update time (in hex to reduce its length) buffer.append(DELIMITER); buffer.append(Long.toHexString(bundle.getLastModified())); // plus the bundle class name (just to be triple sure) buffer.append(DELIMITER); buffer.append(bundle.getClass().getName()); return buffer.toString(); } private ClassLoader createBundleClassLoader(Bundle bundle) { return BundleDelegatingClassLoader.createBundleClassLoaderFor(bundle); } }