blob: f156d89452bbae811a63724d19438d59932f08dc [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.ejb.openejb.extender;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.WeakHashMap;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicReference;
import org.apache.aries.proxy.InvocationListener;
import org.apache.aries.proxy.ProxyManager;
import org.apache.aries.proxy.UnableToProxyException;
import org.apache.aries.util.tracker.SingleServiceTracker;
import org.apache.aries.util.tracker.SingleServiceTracker.SingleServiceListener;
import org.apache.openejb.OpenEJBException;
import org.apache.openejb.util.proxy.InvocationHandler;
import org.apache.openejb.util.proxy.ProxyFactory;
import org.osgi.framework.BundleContext;
public class AriesProxyService implements ProxyFactory, SingleServiceListener {
private static class NoProxySupportException extends RuntimeException {
public NoProxySupportException() {
super("No Proxy support is available");
}
}
private static final class InvocationHandlerProxy implements Callable<Object>, InvocationListener {
private final InvocationHandler handler;
private final Map<Thread, Class<?>> invocations = new ConcurrentHashMap<Thread, Class<?>>();
private final ConcurrentMap<Class<?>, Object> proxys = new ConcurrentHashMap<Class<?>, Object>();
public InvocationHandlerProxy(InvocationHandler handler) {
this.handler = handler;
}
public InvocationHandler getHandler() {
return handler;
}
public void postInvoke(Object arg0, Object arg1, Method arg2, Object arg3)
throws Throwable {
// No op
}
public void postInvokeExceptionalReturn(Object arg0, Object arg1,
Method arg2, Throwable arg3) throws Throwable {
//No op
}
public Object preInvoke(Object arg0, Method arg1, Object[] arg2)
throws Throwable {
invocations.put(Thread.currentThread(), arg1.getDeclaringClass());
return null;
}
public Object call() throws Exception {
Class<?> c = invocations.remove(Thread.currentThread());
if(c == null)
throw new IllegalStateException("Unable to establish any context");
else if (c.equals(Object.class)) {
//This is a toString or similar, just use an interface we know
//we can see and that doesn't have any methods on it :)
c = Serializable.class;
}
Object proxy = proxys.get(c);
if(proxy == null) {
Object tmp = Proxy.newProxyInstance(c.getClassLoader(), new Class[] {c}, handler);
proxy = proxys.putIfAbsent(c, tmp);
if(proxy == null)
proxy = tmp;
}
return proxy;
}
}
private static class InnerProxyDelegator implements Callable<Object> {
private final Object delegate;
public InnerProxyDelegator(Object delegate) {
this.delegate = delegate;
}
public Object call() {
return delegate;
}
}
private final Map<Class<?>, Object> proxies = Collections.synchronizedMap(
new WeakHashMap<Class<?>, Object>());
private final SingleServiceTracker<ProxyManager> proxyTracker;
private AriesProxyService(BundleContext ctx) {
proxyTracker = new SingleServiceTracker<ProxyManager>(ctx, ProxyManager.class, this);
proxyTracker.open();
}
private final AtomicReference<ProxyManager> manager =
new AtomicReference<ProxyManager>();
private static final AtomicReference<AriesProxyService> INSTANCE =
new AtomicReference<AriesProxyService>();
private final ProxyManager getManager() {
ProxyManager pManager = manager.get();
if(pManager == null) {
throw new NoProxySupportException();
}
return pManager;
}
public static AriesProxyService get() {
return INSTANCE.get();
}
public static void init(BundleContext ctx) {
AriesProxyService oTM = new AriesProxyService(ctx);
if(!!!INSTANCE.compareAndSet(null, oTM))
oTM.destroy();
}
public void destroy() {
INSTANCE.set(null);
proxyTracker.close();
}
public void serviceFound() {
update();
}
public void serviceLost() {
update();
}
public void serviceReplaced() {
update();
}
private void update() {
manager.set(proxyTracker.getService());
}
public InvocationHandler getInvocationHandler(Object arg0)
throws IllegalArgumentException {
Callable<Object> unwrapped = getManager().unwrap(arg0);
if(unwrapped instanceof InnerProxyDelegator) {
unwrapped = getManager().unwrap(((InnerProxyDelegator)unwrapped).call());
}
if(unwrapped instanceof InvocationHandlerProxy) {
return ((InvocationHandlerProxy) unwrapped).getHandler();
}
return null;
}
public Class getProxyClass(Class iface) throws IllegalArgumentException {
if(iface == null || !!!iface.isInterface())
throw new IllegalArgumentException("Not an interface " + iface);
return newProxyInstance(iface, null).getClass();
}
public Class getProxyClass(Class[] ifaces) throws IllegalArgumentException {
if(ifaces == null || ifaces.length == 0)
throw new IllegalArgumentException("No interfaces.");
for(Class iface : ifaces) {
if (!!!iface.isInterface())
throw new IllegalArgumentException("Not an interface " + iface + " in " + Arrays.toString(ifaces));
}
return newProxyInstance(ifaces, null).getClass();
}
public void init(Properties arg0) throws OpenEJBException {
//No op
}
public boolean isProxyClass(Class arg0) {
return proxies.containsKey(arg0);
}
public Object newProxyInstance(Class iface, InvocationHandler arg1)
throws IllegalArgumentException {
return newProxyInstance(new Class[] {iface}, arg1);
}
public Object newProxyInstance(Class[] ifaces, InvocationHandler arg1)
throws IllegalArgumentException {
InvocationHandlerProxy ihProxy = new InvocationHandlerProxy(arg1);
List<Class<?>> classes = new ArrayList<Class<?>>();
for(Class<?> iface : ifaces)
classes.add(iface);
try {
Object inner = getManager().createDelegatingProxy(null, classes, ihProxy, null);
Object proxy = getManager().createDelegatingInterceptingProxy(null, classes,
new InnerProxyDelegator(inner), null, ihProxy);
proxies.put(proxy.getClass(), null);
return proxy;
} catch (UnableToProxyException e) {
throw new IllegalArgumentException(e);
}
}
}