/*******************************************************************************
* Copyright (c) 2008, 2014 Stuart McCulloch
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Stuart McCulloch - initial API and implementation
*******************************************************************************/
package org.eclipse.sisu.peaberry.osgi;
import static java.util.Collections.singletonMap;
import org.eclipse.sisu.peaberry.ServiceException;
import org.osgi.framework.BundleContext;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;
import com.google.inject.Key;
import com.google.inject.Provider;
import com.google.inject.Scope;
/**
* Custom {@link Scope} that provides singletons per {@link BundleContext}.
*
* @author mcculls@gmail.com (Stuart McCulloch)
*/
final class BundleScopeImpl
implements Scope {
// attribute used to select bundle-scoped services
private static final String BUNDLE_ID = "bundle.id";
final Provider<BundleContext> contextProvider;
BundleScopeImpl(final Provider<BundleContext> contextProvider) {
this.contextProvider = contextProvider;
}
public <T> Provider<T> scope(final Key<T> key, final Provider<T> creator) {
final String clazzName = key.getTypeLiteral().getRawType().getName();
return new Provider<T>() {
private volatile T instance; // cache for repeated requests
@SuppressWarnings("unchecked")
public T get() {
if (null == instance) {
final BundleContext bundleContext = contextProvider.get();
synchronized (bundleContext) {
if (null == instance) {
final ServiceReference[] refs;
// filter services to those registered by this context
final long bundleId = bundleContext.getBundle().getBundleId();
final String filter = '(' + BUNDLE_ID + '=' + bundleId + ')';
try {
// see if the context has an instance for this binding class
refs = bundleContext.getServiceReferences(clazzName, filter);
} catch (final InvalidSyntaxException e) {
throw new ServiceException(e); // this should never happen!
}
if (null != refs && refs.length > 0) {
// retrieve the existing instance from the registry
instance = (T) bundleContext.getService(refs[0]);
} else {
instance = creator.get();
// register the brand-new instance with the registry
bundleContext.registerService(clazzName, instance,
new AttributeDictionary(singletonMap(BUNDLE_ID, bundleId)));
}
}
}
}
return instance;
}
@Override
public String toString() {
return String.format("%s[BundleScope [%s]]", creator, contextProvider.get().getBundle());
}
};
}
@Override
public String toString() {
return "BundleScope";
}
}