/****************************************************************************** * 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.lang.reflect.Modifier; import java.util.LinkedHashSet; import java.util.Set; import org.aopalliance.aop.Advice; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.eclipse.gemini.blueprint.context.support.internal.classloader.ClassLoaderFactory; import org.eclipse.gemini.blueprint.service.importer.support.internal.aop.ServiceInvoker; import org.eclipse.gemini.blueprint.service.importer.support.internal.aop.ServiceStaticInterceptor; import org.eclipse.gemini.blueprint.service.util.internal.aop.ServiceTCCLInterceptor; import org.eclipse.gemini.blueprint.util.OsgiServiceReferenceUtils; import org.eclipse.gemini.blueprint.util.OsgiStringUtils; import org.eclipse.gemini.blueprint.util.internal.ClassUtils; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceReference; import org.springframework.util.ObjectUtils; /** * @author Costin Leau * */ class StaticServiceProxyCreator extends AbstractServiceProxyCreator { private static final Log log = LogFactory.getLog(StaticServiceProxyCreator.class); /** greedy proxying mechanism */ private final boolean greedyProxying; /** should greedy proxying consider just interfaces ? */ private final boolean interfacesOnlyProxying; /** use SpringDM or Blueprint exceptions ? */ private final boolean useBlueprintExceptions; /** * Constructs a new <code>StaticServiceProxyCreator</code> instance. * * @param classes * @param aopClassLoader * @param bundleContext * @param iccl * @param greedyProxying */ StaticServiceProxyCreator(Class<?>[] classes, ClassLoader aopClassLoader, ClassLoader bundleClassLoader, BundleContext bundleContext, ImportContextClassLoaderEnum iccl, boolean greedyProxying, boolean useBlueprintExceptions) { super(classes, aopClassLoader, bundleClassLoader, bundleContext, iccl); this.greedyProxying = greedyProxying; this.useBlueprintExceptions = useBlueprintExceptions; boolean onlyInterfaces = true; // see if cglib is used or not for (int i = 0; i < classes.length; i++) { if (!classes[i].isInterface()) onlyInterfaces = false; } interfacesOnlyProxying = onlyInterfaces; String msg = (interfacesOnlyProxying ? "NOT" : ""); if (log.isDebugEnabled()) log.debug("Greedy proxying will " + msg + " consider exposed classes"); } ServiceInvoker createDispatcherInterceptor(ServiceReference reference) { ServiceStaticInterceptor interceptor = new ServiceStaticInterceptor(bundleContext, reference); interceptor.setUseBlueprintExceptions(useBlueprintExceptions); return interceptor; } Advice createServiceProviderTCCLAdvice(ServiceReference reference) { Bundle bundle = reference.getBundle(); // if reference is dead already, it's impossible to provide the service // class loader if (bundle == null) return null; return new ServiceTCCLInterceptor(ClassLoaderFactory.getBundleClassLoaderFor(bundle)); } /** * Apply 'greedy' proxying by discovering the exposed classes. * * @param ref * @return */ Class<?>[] discoverProxyClasses(ServiceReference ref) { boolean trace = log.isTraceEnabled(); if (trace) log.trace("Generating greedy proxy for service " + OsgiStringUtils.nullSafeToString(ref)); String[] classNames = OsgiServiceReferenceUtils.getServiceObjectClasses(ref); if (trace) log.trace("Discovered raw classes " + ObjectUtils.nullSafeToString(classNames)); // try to get as many classes as possible Class<?>[] classes = ClassUtils.loadClassesIfPossible(classNames, classLoader); if (trace) log.trace("Visible classes are " + ObjectUtils.nullSafeToString(classes)); // exclude final classes classes = ClassUtils.excludeClassesWithModifier(classes, Modifier.FINAL); if (trace) log.trace("Filtering out final classes; left out with " + ObjectUtils.nullSafeToString(classes)); // remove classes if needed if (interfacesOnlyProxying) { Set<Class<?>> clazzes = new LinkedHashSet<Class<?>>(classes.length); for (int classIndex = 0; classIndex < classes.length; classIndex++) { Class<?> clazz = classes[classIndex]; if (clazz.isInterface()) clazzes.add(clazz); } if (trace) log.trace("Filtering out concrete classes; left out with " + clazzes); classes = (Class[]) clazzes.toArray(new Class[clazzes.size()]); } // remove class duplicates/parents classes = ClassUtils.removeParents(classes); if (trace) log.trace("Filtering out parent classes; left out with " + classes); return classes; } Class<?>[] getInterfaces(ServiceReference reference) { if (greedyProxying) { Class<?>[] clazzes = discoverProxyClasses(reference); if (log.isTraceEnabled()) log.trace("generating 'greedy' service proxy using classes " + ObjectUtils.nullSafeToString(clazzes) + " over " + ObjectUtils.nullSafeToString(this.classes)); return clazzes; } // no greedy proxy, return just the configured classes return classes; } }