diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/common/AdHocTransactionService.java b/navalplanner-business/src/main/java/org/navalplanner/business/common/AdHocTransactionService.java index ecdeb7d65..27e1859f2 100644 --- a/navalplanner-business/src/main/java/org/navalplanner/business/common/AdHocTransactionService.java +++ b/navalplanner-business/src/main/java/org/navalplanner/business/common/AdHocTransactionService.java @@ -20,6 +20,10 @@ package org.navalplanner.business.common; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; + import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; @@ -27,7 +31,80 @@ import org.springframework.transaction.annotation.Transactional; @Service public class AdHocTransactionService implements IAdHocTransactionService { - @Override + private static T proxy(IAdHocTransactionService transactionService, + boolean readOnly, + Class interfaceClass, + T interfaceObject) { + Class[] interfaces = { interfaceClass }; + return interfaceClass.cast(Proxy.newProxyInstance(interfaceClass + .getClassLoader(), interfaces, createHandler(interfaceObject, + transactionService, readOnly))); + } + + /** + * Returns a new object implementing the same interface but with its calls + * wrapped on read only transactions + * @param transactionService + * @param interfaceClass + * @param interfaceObject + * @return + */ + public static T readOnlyProxy(IAdHocTransactionService transactionService, + Class interfaceClass, T interfaceObject) { + return proxy(transactionService, true, interfaceClass, interfaceObject); + } + + /** + * Returns a new object implementing the same interface but with its calls + * wrapped on transactions + * @param transactionService + * @param interfaceClass + * @param interfaceObject + * @return + */ + public static T proxy(IAdHocTransactionService transactionService, + Class interfaceClass, T interfaceObject) { + return proxy(transactionService, false, interfaceClass, interfaceObject); + } + + private static InvocationHandler createHandler(final Object originalObject, + final IAdHocTransactionService transactionService, + final boolean readOnly) { + return new InvocationHandler() { + @Override + public Object invoke(final Object proxy, final Method method, + final Object[] args) throws Throwable { + IOnTransaction onTransaction = createOnTransaction(originalObject, method, args); + try { + if (readOnly) { + return transactionService + .runOnReadOnlyTransaction(onTransaction); + } else { + return transactionService.runOnTransaction(onTransaction); + } + } catch (RuntimeException e) { + throw e.getCause(); + } + } + }; + } + + private static IOnTransaction createOnTransaction( + final Object originalObject, final Method method, + final Object[] args) { + return new IOnTransaction() { + + @Override + public Object execute() { + try { + return method.invoke(originalObject, args); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + }; + } + @Transactional public T runOnTransaction(IOnTransaction onTransaction) { return onTransaction.execute(); diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/order/OrderPlanningModel.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/order/OrderPlanningModel.java index a580cfbde..e5528741a 100644 --- a/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/order/OrderPlanningModel.java +++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/order/OrderPlanningModel.java @@ -20,6 +20,7 @@ package org.navalplanner.web.planner.order; +import static org.navalplanner.business.common.AdHocTransactionService.readOnlyProxy; import static org.navalplanner.web.I18nHelper._; import java.math.BigDecimal; @@ -495,19 +496,20 @@ public abstract class OrderPlanningModel implements IOrderPlanningModel { ISaveCommand saveCommand, final Chart loadChart) { planner.getTimeTracker().addZoomListener(fillOnZoomChange(loadChart)); saveCommand.addListener(fillChartOnSave(loadChart)); - taskElementAdapter.addListener(new IOnMoveListener() { - @Override - public void moved(TaskElement taskElement) { - loadChart.fillChart(); - } - }); - configuration.addReloadChartListener(new IReloadChartListener() { - - @Override - public void reloadChart() { - loadChart.fillChart(); - } - }); + taskElementAdapter.addListener(readOnlyProxy(transactionService, + IOnMoveListener.class, new IOnMoveListener() { + @Override + public void moved(TaskElement taskElement) { + loadChart.fillChart(); + } + })); + configuration.addReloadChartListener(readOnlyProxy(transactionService, + IReloadChartListener.class, new IReloadChartListener() { + @Override + public void reloadChart() { + loadChart.fillChart(); + } + })); } private void addAdditional(List> additional,