/** * @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 { LOGGER.logTrace("Invoking method {0} on {1} in {2}.", method, model, workspace); if (null != args && 0 < args.length && LOGGER.isDebugEnabled()) { for (int i = 0; i < args.length; i++) LOGGER.logDebug("args[{0}]:{1}", i, args[i]); } final Object lock; switch (extractLock(method)) { case NONE: lock = new Object(); break; case EXCLUSIVE: // deliberate fall-through case LOCAL_READ: // deliberate fall-through default: lock = workspace; } synchronized (lock) { final Transaction transaction = workspace.getTransaction(); final TransactionContext transactionContext = newXAContext(method); beginXA(transaction, transactionContext); try { /* if the method is annotated as online, ensure that we are * online */ if (isOnline(method)) model.ensureOnline(); model.setInvocationContext( new ModelInvocationContext() { public Object[] getArguments() { return null == args ? NO_ARGS : args; } public Method getMethod() { return method; } }); final Object metricsContext = newMetricsContext(lock, method); ModelInvocationMetrics.begin(metricsContext); final Object result = method.invoke(model, args); ModelInvocationMetrics.end(metricsContext); model.notifyListeners(); return LOGGER.logVariable("result", result); } catch (final InvocationTargetException itx) { rollbackXA(transaction, transactionContext); throw itx.getTargetException(); } catch (final Throwable t) { rollbackXA(transaction, transactionContext); throw t; } finally { completeXA(transaction, transactionContext); } } }