| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| package org.apache.aries.proxy.impl; |
| |
| import static java.lang.String.format; |
| |
| import java.lang.reflect.Constructor; |
| import java.lang.reflect.InvocationHandler; |
| import java.lang.reflect.InvocationTargetException; |
| import java.util.Collection; |
| import java.util.concurrent.Callable; |
| |
| import org.apache.aries.proxy.InvocationListener; |
| import org.apache.aries.proxy.ProxyManager; |
| import org.apache.aries.proxy.UnableToProxyException; |
| import org.apache.aries.proxy.weaving.WovenProxy; |
| import org.osgi.framework.Bundle; |
| import org.osgi.framework.wiring.BundleWiring; |
| |
| public abstract class AbstractProxyManager implements ProxyManager |
| { |
| public final Object createDelegatingProxy(Bundle clientBundle, Collection<Class<?>> classes, |
| Callable<Object> dispatcher, Object template) |
| throws UnableToProxyException |
| { |
| return createDelegatingInterceptingProxy(clientBundle, classes, dispatcher, template, null); |
| } |
| |
| public Object createInterceptingProxy(Bundle clientBundle, |
| Collection<Class<?>> classes, Object delegate, InvocationListener listener) |
| throws UnableToProxyException { |
| |
| if (delegate instanceof WovenProxy) { |
| WovenProxy proxy = ((WovenProxy) delegate). |
| org_apache_aries_proxy_weaving_WovenProxy_createNewProxyInstance( |
| new SingleInstanceDispatcher(delegate), listener); |
| return proxy; |
| } else { |
| return createDelegatingInterceptingProxy(clientBundle, classes, |
| new SingleInstanceDispatcher(delegate), delegate, listener); |
| } |
| } |
| |
| public final Object createDelegatingInterceptingProxy(Bundle clientBundle, Collection<Class<?>> classes, |
| Callable<Object> dispatcher, Object template, InvocationListener listener) |
| throws UnableToProxyException |
| { |
| if(dispatcher == null) |
| throw new NullPointerException("You must specify a dipatcher"); |
| |
| if (template instanceof WovenProxy) { |
| WovenProxy proxy = ((WovenProxy) template). |
| org_apache_aries_proxy_weaving_WovenProxy_createNewProxyInstance( |
| dispatcher, listener); |
| return proxy; |
| } |
| |
| Object proxyObject = duplicateProxy(classes, dispatcher, template, listener); |
| |
| if (proxyObject == null) { |
| proxyObject = createNewProxy(clientBundle, classes, dispatcher, listener); |
| } |
| |
| return proxyObject; |
| } |
| |
| public final Callable<Object> unwrap(Object proxy) |
| { |
| Callable<Object> target = null; |
| |
| if(proxy instanceof WovenProxy) { |
| //Woven proxies are a bit different, they can be proxies without |
| //having a dispatcher, so we fake one up if we need to |
| |
| WovenProxy wp = (WovenProxy) proxy; |
| if(wp.org_apache_aries_proxy_weaving_WovenProxy_isProxyInstance()) { |
| target = wp.org_apache_aries_proxy_weaving_WovenProxy_unwrap(); |
| if(target == null) { |
| target = new SingleInstanceDispatcher(proxy); |
| } |
| } |
| } else { |
| InvocationHandler ih = getInvocationHandler(proxy); |
| |
| if (ih instanceof ProxyHandler) { |
| target = ((ProxyHandler)ih).getTarget(); |
| } |
| } |
| return target; |
| } |
| |
| public final boolean isProxy(Object proxy) |
| { |
| return (proxy != null && |
| ((proxy instanceof WovenProxy && ((WovenProxy)proxy).org_apache_aries_proxy_weaving_WovenProxy_isProxyInstance()) || |
| getInvocationHandler(proxy) instanceof ProxyHandler)); |
| } |
| |
| protected abstract Object createNewProxy(Bundle clientBundle, Collection<Class<?>> classes, |
| Callable<Object> dispatcher, InvocationListener listener) throws UnableToProxyException; |
| protected abstract InvocationHandler getInvocationHandler(Object proxy); |
| protected abstract boolean isProxyClass(Class<?> clazz); |
| |
| protected synchronized ClassLoader getClassLoader(final Bundle clientBundle, Collection<Class<?>> classes) |
| { |
| if (clientBundle != null && clientBundle.getState() == Bundle.UNINSTALLED) { |
| throw new IllegalStateException(format("The bundle %s at version %s with id %d has been uninstalled.", |
| clientBundle.getSymbolicName(), clientBundle.getVersion(), clientBundle.getBundleId())); |
| } |
| |
| ClassLoader cl = null; |
| |
| if (classes.size() == 1) cl = classes.iterator().next().getClassLoader(); |
| |
| if (cl == null) { |
| cl = getWiringClassloader(clientBundle); |
| } |
| |
| return cl; |
| } |
| |
| private ClassLoader getWiringClassloader(final Bundle bundle) { |
| BundleWiring wiring = bundle != null ? bundle.adapt(BundleWiring.class) : null; |
| return wiring != null ? wiring.getClassLoader() : null; |
| } |
| |
| private Object duplicateProxy(Collection<Class<?>> classes, Callable<Object> dispatcher, |
| Object template, InvocationListener listener) |
| { |
| Object proxyObject = null; |
| Class<?> classToProxy = null; |
| |
| if (template != null) { |
| if(isProxyClass(template.getClass())) |
| classToProxy = template.getClass(); |
| } else if (classes.size() == 1) { |
| |
| classToProxy = classes.iterator().next(); |
| |
| if(!!!isProxyClass(classToProxy)) |
| classToProxy = null; |
| } |
| |
| if (classToProxy != null) { |
| try { |
| /* |
| * the class is already a proxy, we should just invoke |
| * the constructor to get a new instance of the proxy |
| * with a new Collaborator using the specified delegate |
| */ |
| if(WovenProxy.class.isAssignableFrom(classToProxy)) { |
| Constructor<?> c = classToProxy.getDeclaredConstructor(Callable.class, |
| InvocationListener.class); |
| c.setAccessible(true); |
| proxyObject = c.newInstance(dispatcher, listener); |
| } else { |
| proxyObject = classToProxy.getConstructor(InvocationHandler.class). |
| newInstance(new ProxyHandler(this, dispatcher, listener)); |
| } |
| } catch (InvocationTargetException e) { |
| } catch (NoSuchMethodException e) { |
| } catch (InstantiationException e) { |
| } catch (IllegalArgumentException e) { |
| } catch (SecurityException e) { |
| } catch (IllegalAccessException e) { |
| } |
| } |
| |
| return proxyObject; |
| } |
| } |