/** * Copyright (C) 2014 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.sesame.proxy; import java.lang.reflect.Method; import com.opengamma.sesame.config.EngineUtils; import com.opengamma.util.result.FailureResult; import com.opengamma.util.result.Result; /** * Proxy implementation that wraps each function node and catches * any exceptions thrown on method invocations. These are then * wrapped in FailureResult objects. * <p> * Using this class means that exceptions are trapped as close as possible * to where they occur - without it stack traces can become long * as the stack is extended due to other proxies. Additionally catching * the exceptions means that other function code is potentially able to * perform useful work. */ public class ExceptionWrappingProxy extends ProxyNodeDecorator { /** * Singleton instance of the proxy. */ public static final ExceptionWrappingProxy INSTANCE = new ExceptionWrappingProxy(); /** * Private constructor. */ private ExceptionWrappingProxy() { } /** * Indicates whether a node should be wrapped in a proxy. * <p> * We want all nodes where at least one method returns {@link Result} wrapped * in a proxy as potentially any of them could throw an exception. * * @param interfaceType the type of the interface being decorated, not null * @param implementationType the implementation type being decorated, not null * @return true if one or more of the methods on the interface returns {@link Result} */ @Override protected boolean decorate(Class<?> interfaceType, Class<?> implementationType) { for (Method method : interfaceType.getMethods()) { if (methodHasResultReturnType(method)) { return true; } } return false; } /** * Called when a method on the proxy is invoked. If the method called * normally returns {@link Result} but throws an exception, the exception * is wrapped in a Failure result. If the method does not return Result or * the invocation does not throw an exception then the result is returned * unaltered. * * * @param proxy the proxy whose method was invoked, not null * @param delegate the object being proxied, not null * @param method the method that was invoked, not null * @param args the method arguments, null if the method takes * no arguments * @return the return value of the call * @throws Throwable if something goes wrong with the underlying call and * it cannot be safely wrapped in a {@link FailureResult} */ @Override protected Object invoke(Object proxy, Object delegate, Method method, Object[] args) throws Throwable { try { return method.invoke(delegate, args); } catch (Exception ex) { Exception cause = EngineUtils.getCause(ex); if (methodHasResultReturnType(method)) { return Result.failure(cause); } else { throw cause; } } } private boolean methodHasResultReturnType(Method method) { return Result.class.isAssignableFrom(method.getReturnType()); } }