/* * Copyright (c) 2006-2011 Nuxeo SA (http://nuxeo.com/) and others. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * bstefanescu * * $Id$ */ package org.eclipse.ecr.runtime.service.proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import org.eclipse.ecr.runtime.model.Adaptable; import org.eclipse.ecr.runtime.service.AdaptableService; import org.eclipse.ecr.runtime.service.AdapterManager; /** * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a> * */ public class AdaptableServiceInvoker<T extends AdaptableService> implements ServiceProxy<T>, InvocationHandler, Adaptable { protected final T remote; //TODO this map should be managed by derived classes protected static final Map<Method, Method> methods = new ConcurrentHashMap<Method, Method>(); public AdaptableServiceInvoker(T remote) { this.remote = remote; } @Override public T getRemote() { return remote; } @Override public <A> A getAdapter(Class<A> adapter) { A adapterInst = AdapterManager.getInstance().getAdapter(this, adapter); if (adapterInst != null) { return adapterInst; } if (remote.hasAdapter(adapter)) { return getAdapterProxy(adapter); } return null; } @SuppressWarnings({"unchecked"}) protected <A> A getAdapterProxy(Class<A> adapter) { return (A) Proxy.newProxyInstance( getClass().getClassLoader(), new Class<?>[]{adapter}, new ServiceAdapterInvoker(this)); } protected static void handleException(Throwable t) throws Throwable { throw t; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Method m = methods.get(method); if (m == null) { try { m = getClass().getMethod(method.getName(), method.getParameterTypes()); } catch (NoSuchMethodException e) { m = method; } methods.put(method, m); } try { return m.invoke(m == method ? remote : this, args) ; } catch (InvocationTargetException e) { Throwable cause = e.getCause(); if (cause != null) { handleException(cause); } else { handleException(e); } throw e; } catch (Throwable t) { handleException(t); throw t; } } }