/******************************************************************************
* Copyright (c) 2006, 2010 VMware Inc., Oracle 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.
* Oracle Inc.
*****************************************************************************/
package org.eclipse.gemini.blueprint.service.importer.support;
import java.security.AccessController;
import java.security.PrivilegedAction;
import org.eclipse.gemini.blueprint.context.support.internal.classloader.ChainedClassLoader;
import org.eclipse.gemini.blueprint.context.support.internal.classloader.ClassLoaderFactory;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.FactoryBeanNotInitializedException;
import org.springframework.beans.factory.SmartFactoryBean;
/**
* Package protected class that provides the common aop infrastructure functionality for OSGi service importers.
* Provides most of the constructs required for assembling the service proxies, leaving subclasses to decide on the
* service cardinality (one service or multiple) and proxy weaving.
*
*
* @author Costin Leau
* @author Adrian Colyer
* @author Hal Hildebrand
*
*/
abstract class AbstractServiceImporterProxyFactoryBean extends AbstractOsgiServiceImportFactoryBean implements
SmartFactoryBean<Object> {
private volatile boolean initialized = false;
protected Object proxy;
private boolean useBlueprintException = false;
private volatile boolean lazyProxy = false;
/** aop classloader */
private ChainedClassLoader aopClassLoader;
private boolean blueprintCompliant;
public void afterPropertiesSet() {
super.afterPropertiesSet();
if (blueprintCompliant) {
setUseBlueprintExceptions(true);
}
Class<?>[] intfs = getInterfaces();
for (int i = 0; i < intfs.length; i++) {
Class<?> intf = intfs[i];
if (blueprintCompliant && !intf.isInterface()) {
throw new IllegalArgumentException(
"Blueprint importers support only interfaces - for concrete classes, use the Spring DM namespace");
}
aopClassLoader.addClassLoader(intf);
}
initialized = true;
}
public void destroy() throws Exception {
Runnable callback = getProxyDestructionCallback();
try {
if (callback != null) {
callback.run();
}
} finally {
proxy = null;
}
}
/**
* Returns a managed object for accessing OSGi service(s).
*
* @return managed OSGi service(s)
*/
public Object getObject() {
if (!initialized)
throw new FactoryBeanNotInitializedException();
if (proxy == null) {
synchronized (this) {
if (proxy == null) {
proxy = createProxy(false);
}
}
}
if (lazyProxy) {
synchronized (this) {
if (lazyProxy) {
getProxyInitializer().run();
lazyProxy = false;
}
}
}
return proxy;
}
/**
* Returns the managed proxy type. Note that calling this method will cause the creation of the proxy but not its
* initialization.
*/
public Class<?> getObjectType() {
if (!initialized)
// not yet initialized, cannot determine type
return null;
if (proxy == null) {
synchronized (this) {
if (proxy == null) {
proxy = createProxy(true);
lazyProxy = true;
}
}
}
return proxy.getClass();
}
/**
* {@inheritDoc}
*
* The object managed by this factory is a singleton.
*
* @return true (i.e. the FactoryBean returns singletons)
*/
public boolean isSingleton() {
return true;
}
/**
* {@inheritDoc}
*
* The object created by this factory bean is eagerly initialized.
*
* @return true (this factory bean should be eagerly initialized)
*/
public boolean isEagerInit() {
return true;
}
/**
* {@inheritDoc} The object returned by this FactoryBean is a not a prototype.
*
* @return false (the managed object is not a prototype)
*/
public boolean isPrototype() {
return false;
}
/**
* Creates the proxy tracking the matching OSGi services. This method is guaranteed to be called only once, normally
* during initialization.
*
* @param lazy indicates whether the proxy is lazy (no code is executed in the proxy) or not
* @return OSGi service tracking proxy.
* @see #getProxyDestructionCallback()
*/
abstract Object createProxy(boolean lazy);
/**
* Returns a callback to the proxy which gets called when the proxy is called for the first time, if a lazy creation
* was used. For eager initialization, a null object should be returned.
*
* @return proxy initialization callback
*/
abstract Runnable getProxyInitializer();
/**
* Returns the destruction callback associated with the proxy created by this object. The callback is called once,
* during the destruction process of the {@link FactoryBean}.
*
* @return destruction callback for the service proxy.
* @see #createProxy()
*/
abstract Runnable getProxyDestructionCallback();
/**
* Returns the class loader used for AOP weaving
*
* @return the classloader used for weaving
*/
ClassLoader getAopClassLoader() {
return aopClassLoader;
}
/**
* {@inheritDoc}
*
* The class will automatically chain this classloader with the AOP infrastructure classes (even if these are not
* visible to the user) so that the proxy creation can be completed successfully.
*/
public void setBeanClassLoader(final ClassLoader classLoader) {
super.setBeanClassLoader(classLoader);
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Object run() {
aopClassLoader = ClassLoaderFactory.getAopClassLoaderFor(classLoader);
return null;
}
});
} else {
aopClassLoader = ClassLoaderFactory.getAopClassLoaderFor(classLoader);
}
}
/**
* Indicates whether Blueprint exceptions are preferred over Spring DM ones.
*
* @param useBlueprintExceptions
*/
public void setUseBlueprintExceptions(boolean useBlueprintExceptions) {
this.useBlueprintException = useBlueprintExceptions;
}
boolean isUseBlueprintExceptions() {
return useBlueprintException;
}
/**
* Indicates whether the importer should use (strict) blueprint spec compliance or not. Strict compliance means that
* only interfaces are supported and that Blueprint exceptions are thrown by default.
*
* @param compliant
*/
public void setBlueprintCompliant(boolean compliant) {
this.blueprintCompliant = compliant;
}
boolean isBlueprintCompliant() {
return blueprintCompliant;
}
}