/******************************************************************************
* 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);
}
}