From 0c98cad7aa5c824c0ba10cdf989093d0e9230200 Mon Sep 17 00:00:00 2001 From: Javier Moran Rua Date: Thu, 10 Nov 2011 11:40:37 +0100 Subject: [PATCH] [Bug #1238] Fix concurrent modification exception The fix consists of changing the persistence model of the Dependency entity. So far, it was deleted in the database when orphan dependencies appear in the Hibernate session being flushed. Now, the orphan dependencies are removed explicitely on saving the Planning state. An orphan dependency in the database is the one which has origin or destination NULL. FEA: ItEr75S04BugFixing --- .../business/planner/daos/DependencyDAO.java | 23 ++++++++++++-- .../business/planner/daos/IDependencyDAO.java | 6 ++-- .../business/planner/entities/Tasks.hbm.xml | 4 +-- .../web/planner/order/SaveCommandBuilder.java | 31 +++++++++++++------ 4 files changed, 49 insertions(+), 15 deletions(-) diff --git a/libreplan-business/src/main/java/org/libreplan/business/planner/daos/DependencyDAO.java b/libreplan-business/src/main/java/org/libreplan/business/planner/daos/DependencyDAO.java index 4ea0d8fb4..a9660c2cb 100644 --- a/libreplan-business/src/main/java/org/libreplan/business/planner/daos/DependencyDAO.java +++ b/libreplan-business/src/main/java/org/libreplan/business/planner/daos/DependencyDAO.java @@ -20,21 +20,40 @@ */ package org.libreplan.business.planner.daos; +import java.util.List; + +import org.hibernate.Criteria; +import org.hibernate.criterion.Restrictions; import org.libreplan.business.common.daos.GenericDAOHibernate; +import org.libreplan.business.common.exceptions.InstanceNotFoundException; import org.libreplan.business.planner.entities.Dependency; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Repository; +import org.springframework.transaction.annotation.Transactional; /** * DAO for entity @{link Dedenpency} + * * @author Javier Moran Rua * */ @Repository @Scope(BeanDefinition.SCOPE_SINGLETON) -public class DependencyDAO extends GenericDAOHibernate - implements IDependencyDAO { +public class DependencyDAO extends GenericDAOHibernate + implements IDependencyDAO { + + @Override + @Transactional + public void deleteUnattachedDependencies() throws InstanceNotFoundException { + Criteria c = getSession().createCriteria(Dependency.class); + c.add(Restrictions.or(Restrictions.isNull("origin"), + Restrictions.isNull("destination"))); + List results = c.list(); + for (Dependency each : results) { + remove(each.getId()); + } + } } diff --git a/libreplan-business/src/main/java/org/libreplan/business/planner/daos/IDependencyDAO.java b/libreplan-business/src/main/java/org/libreplan/business/planner/daos/IDependencyDAO.java index 027570306..3dc80d8f9 100644 --- a/libreplan-business/src/main/java/org/libreplan/business/planner/daos/IDependencyDAO.java +++ b/libreplan-business/src/main/java/org/libreplan/business/planner/daos/IDependencyDAO.java @@ -21,6 +21,7 @@ package org.libreplan.business.planner.daos; import org.libreplan.business.common.daos.IGenericDAO; +import org.libreplan.business.common.exceptions.InstanceNotFoundException; import org.libreplan.business.planner.entities.Dependency; /** @@ -28,8 +29,9 @@ import org.libreplan.business.planner.entities.Dependency; * entity * * @author Javier Moran Rua - * */ -public interface IDependencyDAO extends IGenericDAO { +public interface IDependencyDAO extends IGenericDAO { + + void deleteUnattachedDependencies() throws InstanceNotFoundException; } diff --git a/libreplan-business/src/main/resources/org/libreplan/business/planner/entities/Tasks.hbm.xml b/libreplan-business/src/main/resources/org/libreplan/business/planner/entities/Tasks.hbm.xml index a9e5c0685..34d83d7cd 100644 --- a/libreplan-business/src/main/resources/org/libreplan/business/planner/entities/Tasks.hbm.xml +++ b/libreplan-business/src/main/resources/org/libreplan/business/planner/entities/Tasks.hbm.xml @@ -36,13 +36,13 @@ - + - + diff --git a/libreplan-webapp/src/main/java/org/libreplan/web/planner/order/SaveCommandBuilder.java b/libreplan-webapp/src/main/java/org/libreplan/web/planner/order/SaveCommandBuilder.java index f4f8acc49..2b0bb4cfe 100644 --- a/libreplan-webapp/src/main/java/org/libreplan/web/planner/order/SaveCommandBuilder.java +++ b/libreplan-webapp/src/main/java/org/libreplan/web/planner/order/SaveCommandBuilder.java @@ -57,6 +57,7 @@ import org.libreplan.business.orders.entities.Order; import org.libreplan.business.orders.entities.OrderElement; import org.libreplan.business.orders.entities.OrderLineGroup; import org.libreplan.business.planner.daos.IConsolidationDAO; +import org.libreplan.business.planner.daos.IDependencyDAO; import org.libreplan.business.planner.daos.ISubcontractedTaskDataDAO; import org.libreplan.business.planner.daos.ITaskElementDAO; import org.libreplan.business.planner.daos.ITaskSourceDAO; @@ -125,7 +126,7 @@ public class SaveCommandBuilder { "/planner/index.zul;company_scheduling", ISaveCommand.class, result); } - + public static void dontPoseAsTransientAndChildrenObjects( Collection> resourceAllocations) { for (ResourceAllocation each : resourceAllocations) { @@ -134,8 +135,7 @@ public class SaveCommandBuilder { for (DayAssignment eachAssignment : each.getAssignments()) { eachAssignment.dontPoseAsTransientObjectAnymore(); } - for (DerivedAllocation eachDerived : each - .getDerivedAllocations()) { + for (DerivedAllocation eachDerived : each.getDerivedAllocations()) { eachDerived.dontPoseAsTransientObjectAnymore(); Collection containers = eachDerived .getContainers(); @@ -151,8 +151,7 @@ public class SaveCommandBuilder { } } - private static void dontPoseAsTransient( - LimitingResourceQueueElement element) { + private static void dontPoseAsTransient(LimitingResourceQueueElement element) { if (element != null) { for (LimitingResourceQueueDependency d : element .getDependenciesAsOrigin()) { @@ -199,6 +198,9 @@ public class SaveCommandBuilder { @Autowired private IOrderAuthorizationDAO orderAuthorizationDAO; + @Autowired + private IDependencyDAO dependencyDAO; + private class SaveCommand implements ISaveCommand { private PlanningState state; @@ -209,7 +211,7 @@ public class SaveCommandBuilder { private IAdapterToTaskFundamentalProperties adapter; - private List listeners = new ArrayList(); + private final List listeners = new ArrayList(); public SaveCommand(PlanningState planningState, PlannerConfiguration configuration) { @@ -270,7 +272,7 @@ public class SaveCommandBuilder { } doTheSaving(); return null; - } + } }); dontPoseAsTransientObjectAnymore(state.getOrder()); state.getScenarioInfo().afterCommit(); @@ -286,7 +288,8 @@ public class SaveCommandBuilder { try { String message = validationException.getMessage(); - for (InvalidValue invalidValue : validationException.getInvalidValues()) { + for (InvalidValue invalidValue : validationException + .getInvalidValues()) { message += "\n" + invalidValue.getPropertyName() + ": " + invalidValue.getMessage(); } @@ -329,6 +332,7 @@ public class SaveCommandBuilder { checkConstraintOrderUniqueCode(order); checkConstraintHoursGroupUniqueCode(order); state.synchronizeTrees(); + TaskGroup rootTask = state.getRootTask(); if (rootTask != null) { // This reattachment is needed to ensure that the root task in @@ -339,8 +343,10 @@ public class SaveCommandBuilder { taskElementDAO.reattach(rootTask); } orderDAO.save(order); + saveDerivedScenarios(order); deleteOrderElementWithoutParent(order); + deleteUnboundedDependencies(); updateTasksRelatedData(); removeTasksToRemove(); @@ -492,6 +498,14 @@ public class SaveCommandBuilder { } } + private void deleteUnboundedDependencies() { + try { + dependencyDAO.deleteUnattachedDependencies(); + } catch (InstanceNotFoundException e) { + throw new RuntimeException(e); + } + } + private void tryToRemove(OrderElement orderElement) { // checking no work reports for that orderElement if (orderElementDAO @@ -843,7 +857,6 @@ public class SaveCommandBuilder { } } - private void dontPoseAsTransientObjectAnymore(OrderElement orderElement) { orderElement.dontPoseAsTransientObjectAnymore(); dontPoseAsTransientObjectAnymore(orderElement.getOrderVersions());