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