/******************************************************************************
* 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.service.importer.support;
import java.util.ArrayList;
import java.util.List;
import org.aopalliance.aop.Advice;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.gemini.blueprint.service.importer.support.internal.aop.ImportedOsgiServiceProxyAdvice;
import org.eclipse.gemini.blueprint.service.importer.support.internal.aop.InfrastructureOsgiProxyAdvice;
import org.eclipse.gemini.blueprint.service.importer.support.internal.aop.ProxyPlusCallback;
import org.eclipse.gemini.blueprint.service.importer.support.internal.aop.ServiceInvoker;
import org.eclipse.gemini.blueprint.service.importer.support.internal.aop.ServiceProxyCreator;
import org.eclipse.gemini.blueprint.service.util.internal.aop.ProxyUtils;
import org.eclipse.gemini.blueprint.service.util.internal.aop.ServiceTCCLInterceptor;
import org.eclipse.gemini.blueprint.util.OsgiStringUtils;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.springframework.util.Assert;
/**
* Internal (package visible) class used for handling common aspects in creating a proxy over OSGi services.
*
* Notably, this class creates common aspects such as publishing the bundleContext on a thread-local or handling of
* thread context classloader.
*
* @author Costin Leau
*/
abstract class AbstractServiceProxyCreator implements ServiceProxyCreator {
private static final Log log = LogFactory.getLog(AbstractServiceProxyCreator.class);
/** shared immutable interceptor for client TCCL selection (default) */
private final Advice clientTCCLAdvice;
/** shared immutable interceptor for publishing the client bundle context */
private final Advice invokerBundleContextAdvice;
/** importing bundle/client classLoader */
protected final ClassLoader classLoader;
/** proxy classes (for static generation) */
protected final Class<?>[] classes;
/** client bundle context */
protected final BundleContext bundleContext;
private final ImportContextClassLoaderEnum iccl;
AbstractServiceProxyCreator(Class<?>[] classes, ClassLoader aopClassLoader, ClassLoader bundleClassLoader,
BundleContext bundleContext, ImportContextClassLoaderEnum iccl) {
Assert.notNull(bundleContext);
Assert.notNull(aopClassLoader);
this.classes = classes;
this.bundleContext = bundleContext;
this.classLoader = aopClassLoader;
this.iccl = iccl;
clientTCCLAdvice =
(ImportContextClassLoaderEnum.CLIENT.equals(iccl) ? new ServiceTCCLInterceptor(bundleClassLoader)
: null);
invokerBundleContextAdvice = new LocalBundleContextAdvice(bundleContext);
}
public ProxyPlusCallback createServiceProxy(ServiceReference reference) {
List advices = new ArrayList(4);
// 1. the ServiceReference-like mixin
Advice mixin = new ImportedOsgiServiceProxyAdvice(reference);
advices.add(mixin);
// 2. publication of bundleContext (if there is any)
// TODO: make this configurable (so it can be disabled)
advices.add(invokerBundleContextAdvice);
// 3. TCCL handling (if there is any)
Advice tcclAdvice = determineTCCLAdvice(reference);
if (tcclAdvice != null)
advices.add(tcclAdvice);
// 4. add the infrastructure proxy
// but first create the dispatcher since we need
ServiceInvoker dispatcherInterceptor = createDispatcherInterceptor(reference);
Advice infrastructureMixin = new InfrastructureOsgiProxyAdvice(dispatcherInterceptor);
advices.add(infrastructureMixin);
advices.add(dispatcherInterceptor);
return new ProxyPlusCallback(ProxyUtils.createProxy(getInterfaces(reference), null, classLoader, bundleContext,
advices), dispatcherInterceptor);
}
private Advice determineTCCLAdvice(ServiceReference reference) {
try {
switch (iccl) {
case CLIENT:
return clientTCCLAdvice;
case SERVICE_PROVIDER:
return createServiceProviderTCCLAdvice(reference);
case UNMANAGED:
// do nothing
return null;
default:
return null;
}
} finally {
if (log.isTraceEnabled()) {
log.trace(iccl + " TCCL used for invoking " + OsgiStringUtils.nullSafeToString(reference));
}
}
}
Class<?>[] getInterfaces(ServiceReference reference) {
return classes;
}
/**
* Create service provider TCCL advice. Subclasses should extend this based on their configuration (i.e. is a static
* proxy or is it dynamic).
*
* @param reference service reference
* @return AOP advice
*/
abstract Advice createServiceProviderTCCLAdvice(ServiceReference reference);
/**
* Create a dispatcher interceptor that actually execute the call on the target service.
*
* @param reference service reference
* @return AOP advice
*/
abstract ServiceInvoker createDispatcherInterceptor(ServiceReference reference);
}