blob: c84c976882176a0600be5a1096a1e5058db47982 [file] [log] [blame]
/*
* 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;
}
}