/*******************************************************************************
* Copyright (c) 2007, 2014 compeople AG 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:
* compeople AG - initial API and implementation
*******************************************************************************/
package org.eclipse.riena.objecttransaction.context;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import org.eclipse.core.runtime.Assert;
/**
* A Proxy for the management of a Context on the contained Object. All public
* methods will be encapsulated by activating and passivating the corresponding
* context. If the encapsulated object is a Context holder, the context of this
* object is used, otherwise is the context stored in the proxy is used. -> the
* context of the object, if any there, has the higher priority
*
* (It does not make sense to extend the manufactured proxy with an extra
* interface. because it is not possible to access the corresponding methods)
*
*/
public final class ContextProxy implements InvocationHandler {
private final IContextHolder contextHolder;
private final Object service;
/**
* Create a Context Proxy
*/
private ContextProxy(final Object pService, final IContextHolder pContextProvider) {
service = pService;
contextHolder = pContextProvider;
}
/**
* @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object,
* java.lang.reflect.Method, java.lang.Object[])
*/
public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
try {
ContextHelper.activateContext(contextHolder.getContext());
// TODO not sure why accessible has to be true, fix some day
method.setAccessible(true);
return method.invoke(service, args);
} catch (final InvocationTargetException e) {
throw e.getTargetException();
} finally {
ContextHelper.passivateContext(contextHolder.getContext());
}
}
/**
* Creates a new Proxy on the passed object. The return type is created
* automatically depending on the passed interface type. The generics are
* checking the consistency of the passe object and interface automatically.
* The created proxy covers automatically the whole public interface of the
* passed object
*
* @param <T>
* the expected interface type equal also the type expected
* @param pObject
* the Object to create proxy on
* @param pContext
* the context to work on with this proxy
* @return the Proxy
*/
public static <T> T cover(final T pObject, final IContextHolder pContextProvider) {
Assert.isNotNull(pObject, "The object to proxy must not be null"); //$NON-NLS-1$
Assert.isNotNull(pContextProvider, "The context carrier must not be null"); //$NON-NLS-1$
return (T) Proxy.newProxyInstance(pObject.getClass().getClassLoader(), getInterfaces(pObject.getClass()),
new ContextProxy(pObject, pContextProvider));
}
/**
* Creates a new Proxy on the passed object. The return typ is created
* automatically depending on the passed interface type. The generics are
* checking the consistency of the passe object and interface automatically.
* The created proxy covers automatically the whole public interface of the
* passed object
*
* @param <T>
* the expected interface typ equals the type passe to
* @param pContext
* the context to work on with this proxy
* @return the Proxy
*/
public static <T extends IContextHolder> T cover(final T pContextProvider) {
Assert.isNotNull(pContextProvider, "The context carrier must not be null"); //$NON-NLS-1$
return (T) Proxy.newProxyInstance(pContextProvider.getClass().getClassLoader(),
getInterfaces(pContextProvider.getClass()), new ContextProxy(pContextProvider, pContextProvider));
}
/**
* Acertains all interfaces of the passed class
*
* @param pClass
* the class to find interfaces from
* @return an Array of interfaces
*/
private static Class<?>[] getInterfaces(final Class<?> pClass) {
Class<?>[] result = pClass.getInterfaces();
final Class<?> superclazz = pClass.getSuperclass();
if (superclazz != null) {
final Class<?>[] superinterfaces = getInterfaces(superclazz);
if (superinterfaces.length > 0) {
final Class<?>[] superresult = new Class[result.length + superinterfaces.length];
System.arraycopy(result, 0, superresult, 0, result.length);
System.arraycopy(superinterfaces, 0, superresult, result.length, superinterfaces.length);
result = superresult;
}
}
return result;
}
/**
* @return the service.
*/
public Object getService() {
return service;
}
}