From 7b54a5063ef8db14def7fb8964bef3c610946e8d Mon Sep 17 00:00:00 2001 From: Oscar Gonzalez Fernandez Date: Thu, 1 May 2014 16:36:02 +0200 Subject: [PATCH] Upgrade Spring to 3.2.8 and Hibernate to 4.2.8 Now Libreplan can be run on Java8. This implied some changes: * Latest versions of hibernate use the Bean Validation API. This implied renaming the imports and use ConstraintViolationException instead of InvalidValue. Besides some constraints had to be renamed, otherwise they wouldn't be recognized by Hibernate validation. In the new version of Hibernate validator @AssertTrue can only be applied to properties. So all methods it was applied to must follow the is.* format. Automatic execution of Bean Validation API is disabled, otherwise an infinite loop would happen. This is because there are some validation constraints that do launch queries to the database. This causes a flush of the objects in the session and automatic validation is called again. * A new library for persisting JodaTime is necessary since joda-time-hibernate is incompatible with hibernate 4. This library can automatically register its types for Date conversion so they're removed from configuration. * Now, in some places, an InvalidDataAccessApiUsageException is thrown instead of a DataIntegrityViolationException. This is because no constraint is violated, the API is being used incorrectly because a transient instance is being provided where a persisted one was expected. * In hibernate 4 listeners cannot be configured via properties. HibernateDatabaseModificationsListener registers itself in its @PostConstruct method. * ehcache classes used are now different. --- ganttzk/pom.xml | 10 +- .../timetracker/zoom/TimeTrackerState.java | 20 +- libreplan-business/pom.xml | 34 +- .../advance/entities/AdvanceAssignment.java | 2 +- .../entities/AdvanceAssignmentTemplate.java | 2 +- .../advance/entities/AdvanceMeasurement.java | 10 +- .../advance/entities/AdvanceType.java | 14 +- .../entities/DirectAdvanceAssignment.java | 12 +- .../entities/IndirectAdvanceAssignment.java | 2 +- .../calendars/daos/BaseCalendarDAO.java | 8 +- .../calendars/entities/BaseCalendar.java | 12 +- .../entities/CalendarAvailability.java | 2 +- .../calendars/entities/CalendarException.java | 2 +- .../entities/CalendarExceptionType.java | 10 +- .../calendars/entities/ResourceCalendar.java | 6 +- .../libreplan/business/common/BaseEntity.java | 19 +- .../business/common/IntegrationEntity.java | 6 +- .../common/LibrePlanClassValidator.java | 799 ------------------ .../common/daos/EntitySequenceDAO.java | 2 +- .../common/entities/Configuration.java | 18 +- .../entities/ConfigurationRolesLDAP.java | 2 +- .../business/common/entities/Connector.java | 8 +- .../common/entities/ConnectorProperty.java | 2 +- .../common/entities/EntitySequence.java | 14 +- .../entities/JobSchedulerConfiguration.java | 6 +- .../exceptions/ValidationException.java | 202 ++++- .../daos/TypeOfWorkHoursDAO.java | 8 +- .../costcategories/entities/CostCategory.java | 42 +- .../costcategories/entities/HourCost.java | 6 +- .../ResourcesCostCategoryAssignment.java | 6 +- .../entities/TypeOfWorkHours.java | 12 +- .../expensesheet/entities/ExpenseSheet.java | 14 +- .../entities/ExpenseSheetLine.java | 4 +- .../entities/CustomerCommunication.java | 4 +- .../entities/DeadlineCommunication.java | 4 +- .../entities/ExternalCompany.java | 10 +- ...ibernateDatabaseModificationsListener.java | 44 +- .../business/labels/entities/Label.java | 4 +- .../business/labels/entities/LabelType.java | 12 +- .../business/materials/entities/Material.java | 4 +- .../entities/MaterialAssignment.java | 2 +- .../materials/entities/MaterialCategory.java | 16 +- .../materials/entities/MaterialInfo.java | 2 +- .../business/materials/entities/UnitType.java | 6 +- .../business/orders/entities/HoursGroup.java | 7 +- .../business/orders/entities/Order.java | 19 +- .../orders/entities/OrderElement.java | 22 +- .../business/orders/entities/OrderLine.java | 10 +- .../orders/entities/OrderLineGroup.java | 12 +- .../orders/entities/OrderSyncInfo.java | 6 +- .../entities/SchedulingDataForVersion.java | 4 +- .../business/orders/entities/TaskSource.java | 4 +- .../planner/entities/DayAssignment.java | 2 +- .../planner/entities/DerivedAllocation.java | 2 +- .../entities/DerivedDayAssignment.java | 2 +- .../entities/GenericDayAssignment.java | 2 +- .../GenericDayAssignmentsContainer.java | 4 +- .../entities/GenericResourceAllocation.java | 2 +- .../planner/entities/ResourceAllocation.java | 2 +- .../entities/SpecificDayAssignment.java | 2 +- .../SpecificDayAssignmentsContainer.java | 4 +- .../entities/SpecificResourceAllocation.java | 4 +- .../business/planner/entities/Stretch.java | 2 +- .../planner/entities/StretchesFunction.java | 11 +- .../entities/SubcontractedTaskData.java | 8 +- .../entities/SubcontractorCommunication.java | 2 +- .../SubcontractorCommunicationValue.java | 4 +- .../business/planner/entities/Task.java | 7 +- .../planner/entities/TaskElement.java | 2 +- .../business/planner/entities/TaskGroup.java | 7 +- .../planner/entities/TaskMilestone.java | 5 +- .../consolidations/ConsolidatedValue.java | 2 +- .../LimitingResourceQueueElement.java | 2 +- .../qualityforms/daos/QualityFormDAO.java | 2 +- .../qualityforms/entities/QualityForm.java | 22 +- .../entities/QualityFormItem.java | 8 +- .../entities/TaskQualityForm.java | 10 +- .../entities/TaskQualityFormItem.java | 13 +- .../entities/CriterionRequirement.java | 2 +- .../IndirectCriterionRequirement.java | 2 +- .../resources/daos/ResourcesSearcher.java | 2 +- .../resources/entities/Criterion.java | 10 +- .../entities/CriterionSatisfaction.java | 6 +- .../resources/entities/CriterionType.java | 21 +- .../business/resources/entities/Machine.java | 4 +- .../MachineWorkersConfigurationUnit.java | 10 +- .../business/resources/entities/Resource.java | 32 +- .../resources/entities/VirtualWorker.java | 7 +- .../business/resources/entities/Worker.java | 16 +- .../scenarios/entities/OrderVersion.java | 2 +- .../business/scenarios/entities/Scenario.java | 6 +- .../entities/OrderElementTemplate.java | 12 +- .../entities/OrderLineGroupTemplate.java | 2 +- .../templates/entities/OrderLineTemplate.java | 4 +- .../templates/entities/OrderTemplate.java | 2 +- .../business/users/daos/ProfileDAO.java | 2 +- .../users/entities/OrderAuthorization.java | 2 +- .../business/users/entities/Profile.java | 6 +- .../business/users/entities/User.java | 8 +- .../business/workingday/IntraDayDate.java | 2 +- .../hibernate/EffortDurationType.java | 15 +- .../hibernate/ResourcesPerDayType.java | 19 +- .../business/workreports/entities/Task.java | 2 +- .../workreports/entities/WorkReport.java | 28 +- .../WorkReportLabelTypeAssigment.java | 2 +- .../workreports/entities/WorkReportLine.java | 24 +- .../workreports/entities/WorkReportType.java | 20 +- .../valueobjects/DescriptionField.java | 6 +- .../valueobjects/DescriptionValue.java | 4 +- .../libreplan-business-hibernate.cfg.xml | 16 +- .../libreplan-business-spring-config.xml | 19 +- .../business/advance/entities/Advance.hbm.xml | 4 +- .../calendars/entities/Calendars.hbm.xml | 18 +- .../common/entities/Configuration.hbm.xml | 2 +- .../common/entities/Connector.hbm.xml | 2 +- .../common/entities/EntitySequence.hbm.xml | 2 +- .../JobSchedulerConfiguration.hbm.xml | 2 +- .../entities/CostCategories.hbm.xml | 14 +- .../entities/ExpenseSheets.hbm.xml | 11 +- .../entities/ExternalCompanies.hbm.xml | 2 +- .../business/labels/entities/Labels.hbm.xml | 2 +- .../materials/entities/Materials.hbm.xml | 2 +- .../business/orders/entities/Orders.hbm.xml | 2 +- .../entities/AdvanceConsolidations.hbm.xml | 8 +- .../entities/ResourceAllocations.hbm.xml | 26 +- .../SubcontractorCommunication.hbm.xml | 2 +- .../business/planner/entities/Tasks.hbm.xml | 24 +- .../entities/QualityForms.hbm.xml | 2 +- .../entities/Requirements.hbm.xml | 10 +- .../resources/entities/Resources.hbm.xml | 10 +- .../scenarios/entities/Scenarios.hbm.xml | 4 +- .../templates/entities/Templates.hbm.xml | 2 +- .../business/users/entities/Users.hbm.xml | 2 +- .../workreports/entities/WorkReports.hbm.xml | 13 +- .../orders/entities/OrderElementTest.java | 35 +- .../entities/StretchesFunctionTest.java | 26 +- .../test/resources/daos/CriterionDAOTest.java | 3 +- .../daos/CriterionSatisfactionDAOTest.java | 4 +- .../src/test/resources/TestEntities.hbm.xml | 2 +- .../libreplan-business-hibernate-test.cfg.xml | 14 +- .../libreplan-business-spring-config-test.xml | 2 +- libreplan-webapp/pom.xml | 16 + .../web/calendars/BaseCalendarModel.java | 10 +- .../web/common/ConfigurationModel.java | 4 +- .../web/common/IMessagesForUser.java | 2 +- .../libreplan/web/common/MessagesForUser.java | 6 +- .../CostCategoryCRUDController.java | 2 +- .../ExpenseSheetCRUDController.java | 5 +- .../libreplan/web/labels/LabelTypeModel.java | 31 +- .../web/materials/MaterialsController.java | 14 +- .../web/materials/MaterialsModel.java | 8 +- ...kQualityFormsToOrderElementController.java | 12 +- ...edTaskQualityFormsToOrderElementModel.java | 15 +- .../ManageOrderElementAdvancesModel.java | 7 +- .../streches/StretchesFunctionModel.java | 6 +- .../web/planner/order/SaveCommandBuilder.java | 15 +- .../web/qualityforms/QualityFormModel.java | 9 +- .../criterion/CriterionTreeController.java | 4 +- .../criterion/CriterionTreeModel.java | 20 +- .../web/resources/machine/MachineModel.java | 4 - .../worker/CriterionSatisfactionDTO.java | 2 +- .../worker/CriterionsController.java | 6 +- .../worker/CriterionsMachineController.java | 6 +- .../web/scenarios/ScenarioModel.java | 11 +- .../web/templates/OrderTemplatesModel.java | 2 +- .../templates/TemplatesTreeController.java | 9 +- .../libreplan/web/tree/TreeController.java | 24 +- .../web/util/ValidationExceptionPrinter.java | 5 +- .../workreports/WorkReportCRUDController.java | 21 +- .../web/workreports/WorkReportTypeModel.java | 9 +- .../impl/ConstraintViolationConverter.java | 84 +- ...timisticLockingFailureExceptionMapper.java | 2 +- .../impl/ReportAdvancesServiceREST.java | 10 +- ...ibreplan-webapp-spring-security-config.xml | 2 +- .../libreplan-webapp-hibernate-test.cfg.xml | 11 +- .../libreplan-webapp-spring-config-test.xml | 2 +- pom.xml | 109 ++- 177 files changed, 1033 insertions(+), 1680 deletions(-) delete mode 100644 libreplan-business/src/main/java/org/libreplan/business/common/LibrePlanClassValidator.java diff --git a/ganttzk/pom.xml b/ganttzk/pom.xml index e7503dd20..cbdb8e63b 100644 --- a/ganttzk/pom.xml +++ b/ganttzk/pom.xml @@ -113,11 +113,11 @@ commons-lang commons-lang - - - commons-collections - commons-collections - + + commons-collections + commons-collections + + org.zkoss.zk diff --git a/ganttzk/src/main/java/org/zkoss/ganttz/timetracker/zoom/TimeTrackerState.java b/ganttzk/src/main/java/org/zkoss/ganttz/timetracker/zoom/TimeTrackerState.java index 36f3106c1..7a5fb8765 100644 --- a/ganttzk/src/main/java/org/zkoss/ganttz/timetracker/zoom/TimeTrackerState.java +++ b/ganttzk/src/main/java/org/zkoss/ganttz/timetracker/zoom/TimeTrackerState.java @@ -21,9 +21,12 @@ package org.zkoss.ganttz.timetracker.zoom; +import static java.util.Arrays.asList; + import java.util.ArrayList; import java.util.Calendar; import java.util.Collection; +import java.util.Collections; import java.util.Date; import java.util.Iterator; import java.util.List; @@ -266,20 +269,15 @@ public abstract class TimeTrackerState { protected abstract Period getMinimumPeriod(); - private Interval calculateIntervalWithMinimum(Interval interval) { - Period minimumPeriod = getMinimumPeriod(); - BaseSingleFieldPeriod intervalAsPeriod = minimumPeriod - .asPeriod(interval); - if (intervalAsPeriod.compareTo(minimumPeriod.toPeriod()) >= 0) { - return interval; - } - LocalDate newEnd = new LocalDate(interval.getStart()) - .plus(minimumPeriod.toPeriod()); - return new Interval(interval.getStart(), newEnd); + private Interval ensureMinimumInterval(Interval interval) { + LocalDate newEnd = interval.getStart().plus( + getMinimumPeriod().toPeriod()); + return new Interval(interval.getStart(), Collections.max(asList(newEnd, + interval.getFinish()))); } public Interval getRealIntervalFor(Interval testInterval) { - return calculateForAtLeastMinimum(calculateIntervalWithMinimum(testInterval)); + return calculateForAtLeastMinimum(ensureMinimumInterval(testInterval)); } private Interval calculateForAtLeastMinimum(Interval atLeastMinimum) { diff --git a/libreplan-business/pom.xml b/libreplan-business/pom.xml index 29e6196d6..1080622c9 100644 --- a/libreplan-business/pom.xml +++ b/libreplan-business/pom.xml @@ -30,24 +30,29 @@ org.hibernate hibernate-annotations + + org.hibernate + hibernate-ehcache + org.hibernate hibernate-validator - joda-time - joda-time-hibernate + org.jadira.usertype + usertype.core ${jdbcDriver.groupId} ${jdbcDriver.artifactId} + test - org.apache.geronimo.specs - geronimo-jta_1.0.1B_spec + org.jboss.spec.javax.transaction + jboss-transaction-api_1.1_spec @@ -55,18 +60,11 @@ org.springframework spring-context-support - - org.aspectj - aspectjrt - + org.aspectj aspectjweaver - - javassist - javassist - @@ -102,19 +100,11 @@ jdk15 - - commons-lang - commons-lang - commons-math commons-math - - commons-logging - commons-logging - org.slf4j slf4j-log4j12 @@ -129,10 +119,6 @@ org.dbunit dbunit - - net.sf.ehcache - ehcache - org.liquibase liquibase-core diff --git a/libreplan-business/src/main/java/org/libreplan/business/advance/entities/AdvanceAssignment.java b/libreplan-business/src/main/java/org/libreplan/business/advance/entities/AdvanceAssignment.java index a4d3e21be..5e26122d4 100644 --- a/libreplan-business/src/main/java/org/libreplan/business/advance/entities/AdvanceAssignment.java +++ b/libreplan-business/src/main/java/org/libreplan/business/advance/entities/AdvanceAssignment.java @@ -21,7 +21,7 @@ package org.libreplan.business.advance.entities; -import org.hibernate.validator.NotNull; +import javax.validation.constraints.NotNull; import org.libreplan.business.common.BaseEntity; import org.libreplan.business.orders.entities.OrderElement; import org.libreplan.business.orders.entities.OrderLineGroup; diff --git a/libreplan-business/src/main/java/org/libreplan/business/advance/entities/AdvanceAssignmentTemplate.java b/libreplan-business/src/main/java/org/libreplan/business/advance/entities/AdvanceAssignmentTemplate.java index 41423ac46..983c7c971 100644 --- a/libreplan-business/src/main/java/org/libreplan/business/advance/entities/AdvanceAssignmentTemplate.java +++ b/libreplan-business/src/main/java/org/libreplan/business/advance/entities/AdvanceAssignmentTemplate.java @@ -23,7 +23,7 @@ package org.libreplan.business.advance.entities; import java.math.BigDecimal; import org.apache.commons.lang.Validate; -import org.hibernate.validator.NotNull; +import javax.validation.constraints.NotNull; import org.libreplan.business.common.BaseEntity; import org.libreplan.business.orders.entities.OrderElement; import org.libreplan.business.templates.entities.OrderElementTemplate; diff --git a/libreplan-business/src/main/java/org/libreplan/business/advance/entities/AdvanceMeasurement.java b/libreplan-business/src/main/java/org/libreplan/business/advance/entities/AdvanceMeasurement.java index ae25d27e3..00afe9d8f 100644 --- a/libreplan-business/src/main/java/org/libreplan/business/advance/entities/AdvanceMeasurement.java +++ b/libreplan-business/src/main/java/org/libreplan/business/advance/entities/AdvanceMeasurement.java @@ -26,9 +26,9 @@ import java.util.Date; import java.util.HashSet; import java.util.Set; -import org.hibernate.validator.AssertTrue; -import org.hibernate.validator.NotNull; -import org.hibernate.validator.Valid; +import javax.validation.constraints.AssertTrue; +import javax.validation.constraints.NotNull; +import javax.validation.Valid; import org.joda.time.LocalDate; import org.libreplan.business.common.BaseEntity; import org.libreplan.business.orders.entities.OrderElement; @@ -153,7 +153,7 @@ public class AdvanceMeasurement extends BaseEntity { } @AssertTrue(message = "The current value must be less than the max value.") - public boolean checkConstraintValueIsLessThanMaxValue() { + public boolean isValueIsLessThanMaxValueConstraint() { if ((this.value == null) || (this.advanceAssignment == null)){ return true; } @@ -167,7 +167,7 @@ public class AdvanceMeasurement extends BaseEntity { } @AssertTrue(message = "The current value must be less than the max value.") - public boolean checkConstraintValidPrecision() { + public boolean isValidPrecisionConstraint() { if ((this.value == null) || (this.advanceAssignment == null) || (this.advanceAssignment.getAdvanceType() == null)) { return true; diff --git a/libreplan-business/src/main/java/org/libreplan/business/advance/entities/AdvanceType.java b/libreplan-business/src/main/java/org/libreplan/business/advance/entities/AdvanceType.java index bbbb320c9..54cb5cb31 100644 --- a/libreplan-business/src/main/java/org/libreplan/business/advance/entities/AdvanceType.java +++ b/libreplan-business/src/main/java/org/libreplan/business/advance/entities/AdvanceType.java @@ -27,9 +27,9 @@ import java.math.BigDecimal; import org.apache.commons.lang.BooleanUtils; import org.apache.commons.lang.StringUtils; -import org.hibernate.validator.AssertTrue; -import org.hibernate.validator.NotEmpty; -import org.hibernate.validator.NotNull; +import javax.validation.constraints.AssertTrue; +import org.hibernate.validator.constraints.NotEmpty; +import javax.validation.constraints.NotNull; import org.libreplan.business.advance.daos.IAdvanceTypeDAO; import org.libreplan.business.common.BaseEntity; import org.libreplan.business.common.IHumanIdentifiable; @@ -219,7 +219,7 @@ public class AdvanceType extends BaseEntity implements IHumanIdentifiable{ } @AssertTrue(message = "progress type marked as quality form but is updatable") - public boolean checkConstraintIfIsQualityFormIsNotUpdatable() { + public boolean isIfIsQualityFormIsNotUpdatableConstraint() { if (isQualityForm()) { if (isUpdatable()) { return false; @@ -229,7 +229,7 @@ public class AdvanceType extends BaseEntity implements IHumanIdentifiable{ } @AssertTrue(message = "default maximum value of percentage progress type must be 100") - public boolean checkConstraintDefaultMaxValueMustBe100ForPercentage() { + public boolean isDefaultMaxValueMustBe100ForPercentageConstraint() { if (percentage) { if (defaultMaxValue.compareTo(new BigDecimal(100)) != 0) { return false; @@ -244,7 +244,7 @@ public class AdvanceType extends BaseEntity implements IHumanIdentifiable{ } @AssertTrue(message = "progress type name is already in use") - public boolean checkConstraintUniqueName() { + public boolean isUniqueNameConstraint() { if (StringUtils.isBlank(unitName)) { return true; } @@ -266,7 +266,7 @@ public class AdvanceType extends BaseEntity implements IHumanIdentifiable{ } @AssertTrue(message = "default maximum value must be greater than precision value") - public boolean checkDefaultMaxValueGreaterThanPrecision() { + public boolean isDefaultMaxValueGreaterThanPrecisionConstraint() { if (defaultMaxValue.compareTo(unitPrecision) == -1) { return false; } diff --git a/libreplan-business/src/main/java/org/libreplan/business/advance/entities/DirectAdvanceAssignment.java b/libreplan-business/src/main/java/org/libreplan/business/advance/entities/DirectAdvanceAssignment.java index b44c06c30..41eb4cd44 100644 --- a/libreplan-business/src/main/java/org/libreplan/business/advance/entities/DirectAdvanceAssignment.java +++ b/libreplan-business/src/main/java/org/libreplan/business/advance/entities/DirectAdvanceAssignment.java @@ -30,9 +30,9 @@ import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; -import org.hibernate.validator.AssertTrue; -import org.hibernate.validator.NotNull; -import org.hibernate.validator.Valid; +import javax.validation.constraints.AssertTrue; +import javax.validation.constraints.NotNull; +import javax.validation.Valid; import org.joda.time.LocalDate; import org.libreplan.business.orders.entities.OrderElement; import org.libreplan.business.planner.entities.consolidations.NonCalculatedConsolidation; @@ -193,7 +193,7 @@ public class DirectAdvanceAssignment extends AdvanceAssignment { } @AssertTrue(message = "Progress measurements must have a value lower than their following progress measurements.") - public boolean checkConstraintValidAdvanceMeasurements() { + public boolean isValidAdvanceMeasurementsConstraint() { if (advanceMeasurements.isEmpty()) { return true; } @@ -224,7 +224,7 @@ public class DirectAdvanceAssignment extends AdvanceAssignment { } @AssertTrue(message = "maxixum value of percentage progress type must be 100") - public boolean checkConstraintMaxValueMustBe100ForPercentage() { + public boolean isMaxValueMustBe100ForPercentageConstraint() { AdvanceType advanceType = getAdvanceType(); if ((advanceType != null) && (advanceType.getPercentage())) { if (maxValue.compareTo(new BigDecimal(100)) != 0) { @@ -235,7 +235,7 @@ public class DirectAdvanceAssignment extends AdvanceAssignment { } @AssertTrue(message = "maximum value must be greater than zero") - public boolean checkConstraintMaxValueMustBeGreaterThanZero() { + public boolean isMaxValueMustBeGreaterThanZeroConstraint() { return maxValue.compareTo(BigDecimal.ZERO) > 0; } diff --git a/libreplan-business/src/main/java/org/libreplan/business/advance/entities/IndirectAdvanceAssignment.java b/libreplan-business/src/main/java/org/libreplan/business/advance/entities/IndirectAdvanceAssignment.java index d064a297b..ddaec5b5d 100644 --- a/libreplan-business/src/main/java/org/libreplan/business/advance/entities/IndirectAdvanceAssignment.java +++ b/libreplan-business/src/main/java/org/libreplan/business/advance/entities/IndirectAdvanceAssignment.java @@ -24,7 +24,7 @@ package org.libreplan.business.advance.entities; import java.util.HashSet; import java.util.Set; -import org.hibernate.validator.Valid; +import javax.validation.Valid; import org.libreplan.business.orders.entities.OrderLineGroup; import org.libreplan.business.planner.entities.consolidations.CalculatedConsolidation; diff --git a/libreplan-business/src/main/java/org/libreplan/business/calendars/daos/BaseCalendarDAO.java b/libreplan-business/src/main/java/org/libreplan/business/calendars/daos/BaseCalendarDAO.java index 33bb44b7c..93f0458b1 100644 --- a/libreplan-business/src/main/java/org/libreplan/business/calendars/daos/BaseCalendarDAO.java +++ b/libreplan-business/src/main/java/org/libreplan/business/calendars/daos/BaseCalendarDAO.java @@ -154,7 +154,7 @@ public class BaseCalendarDAO extends IntegrationEntityDAO .add(Restrictions.eq("calendarData.parent", calendar)).list(); if (!calendars.isEmpty()) { throw ValidationException - .invalidValue( + .invalidValueException( "Cannot delete calendar. It is being used at this moment by some resources.", calendar); } @@ -165,7 +165,7 @@ public class BaseCalendarDAO extends IntegrationEntityDAO .add(Restrictions.eq("calendar", calendar)).list(); if (!orders.isEmpty()) { throw ValidationException - .invalidValue( + .invalidValueException( "Cannot delete calendar. It is being used at this moment by some orders.", calendar); } @@ -176,7 +176,7 @@ public class BaseCalendarDAO extends IntegrationEntityDAO .add(Restrictions.eq("calendar", calendar)).list(); if (!tasks.isEmpty()) { throw ValidationException - .invalidValue( + .invalidValueException( "Cannot delete calendar. It is being used at this moment by some tasks.", calendar); } @@ -187,7 +187,7 @@ public class BaseCalendarDAO extends IntegrationEntityDAO .add(Restrictions.eq("calendar", calendar)).list(); if (!templates.isEmpty()) { throw ValidationException - .invalidValue( + .invalidValueException( "Cannot delete calendar. It is being used at this moment by some templates.", calendar); } diff --git a/libreplan-business/src/main/java/org/libreplan/business/calendars/entities/BaseCalendar.java b/libreplan-business/src/main/java/org/libreplan/business/calendars/entities/BaseCalendar.java index 444c531a6..97e39cb96 100644 --- a/libreplan-business/src/main/java/org/libreplan/business/calendars/entities/BaseCalendar.java +++ b/libreplan-business/src/main/java/org/libreplan/business/calendars/entities/BaseCalendar.java @@ -30,10 +30,10 @@ import java.util.Set; import org.apache.commons.lang.ObjectUtils; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.Validate; -import org.hibernate.validator.AssertTrue; -import org.hibernate.validator.NotEmpty; -import org.hibernate.validator.NotNull; -import org.hibernate.validator.Valid; +import javax.validation.constraints.AssertTrue; +import org.hibernate.validator.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import javax.validation.Valid; import org.joda.time.LocalDate; import org.libreplan.business.calendars.daos.IBaseCalendarDAO; import org.libreplan.business.calendars.entities.AvailabilityTimeLine.IVetoer; @@ -1104,7 +1104,7 @@ public class BaseCalendar extends IntegrationEntity implements ICalendar, @SuppressWarnings("unused") @AssertTrue(message = "dates must be sorted and cannot overlap") - public boolean checkConstraintDateCouldNotOverlap() { + public boolean isDateCouldNotOverlapConstraint() { if (calendarDataVersions == null || calendarDataVersions.isEmpty()) { return true; @@ -1216,7 +1216,7 @@ public class BaseCalendar extends IntegrationEntity implements ICalendar, } @AssertTrue(message = "calendars with zero hours are not allowed") - public boolean checkConstraintZeroHours() { + public boolean isZeroHoursConstraint() { if ((calendarDataVersions != null) && (!calendarDataVersions.isEmpty())) { for (CalendarData each : calendarDataVersions) { if (!each.isEmpty()) { diff --git a/libreplan-business/src/main/java/org/libreplan/business/calendars/entities/CalendarAvailability.java b/libreplan-business/src/main/java/org/libreplan/business/calendars/entities/CalendarAvailability.java index a9cf1c403..77fc814a1 100644 --- a/libreplan-business/src/main/java/org/libreplan/business/calendars/entities/CalendarAvailability.java +++ b/libreplan-business/src/main/java/org/libreplan/business/calendars/entities/CalendarAvailability.java @@ -24,7 +24,7 @@ package org.libreplan.business.calendars.entities; import java.util.Comparator; import java.util.Date; -import org.hibernate.validator.NotNull; +import javax.validation.constraints.NotNull; import org.joda.time.Interval; import org.joda.time.LocalDate; import org.libreplan.business.calendars.daos.ICalendarAvailabilityDAO; diff --git a/libreplan-business/src/main/java/org/libreplan/business/calendars/entities/CalendarException.java b/libreplan-business/src/main/java/org/libreplan/business/calendars/entities/CalendarException.java index e6e0e6067..a0d06f09f 100644 --- a/libreplan-business/src/main/java/org/libreplan/business/calendars/entities/CalendarException.java +++ b/libreplan-business/src/main/java/org/libreplan/business/calendars/entities/CalendarException.java @@ -22,7 +22,7 @@ package org.libreplan.business.calendars.entities; import org.apache.commons.lang.Validate; -import org.hibernate.validator.NotNull; +import javax.validation.constraints.NotNull; import org.joda.time.LocalDate; import org.libreplan.business.calendars.daos.ICalendarExceptionDAO; import org.libreplan.business.common.IntegrationEntity; diff --git a/libreplan-business/src/main/java/org/libreplan/business/calendars/entities/CalendarExceptionType.java b/libreplan-business/src/main/java/org/libreplan/business/calendars/entities/CalendarExceptionType.java index f7e81bd40..4f4534984 100644 --- a/libreplan-business/src/main/java/org/libreplan/business/calendars/entities/CalendarExceptionType.java +++ b/libreplan-business/src/main/java/org/libreplan/business/calendars/entities/CalendarExceptionType.java @@ -29,9 +29,9 @@ import org.apache.commons.lang.BooleanUtils; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.Validate; import org.hibernate.NonUniqueResultException; -import org.hibernate.validator.AssertTrue; -import org.hibernate.validator.NotEmpty; -import org.hibernate.validator.NotNull; +import javax.validation.constraints.AssertTrue; +import org.hibernate.validator.constraints.NotEmpty; +import javax.validation.constraints.NotNull; import org.libreplan.business.calendars.daos.ICalendarExceptionTypeDAO; import org.libreplan.business.common.IHumanIdentifiable; import org.libreplan.business.common.IntegrationEntity; @@ -39,7 +39,7 @@ import org.libreplan.business.common.Registry; import org.libreplan.business.common.exceptions.InstanceNotFoundException; import org.libreplan.business.workingday.EffortDuration; import org.libreplan.business.workingday.EffortDuration.Granularity; -import org.springframework.orm.hibernate3.HibernateOptimisticLockingFailureException; +import org.springframework.orm.hibernate4.HibernateOptimisticLockingFailureException; /** * Type of an exception day. @@ -180,7 +180,7 @@ public class CalendarExceptionType extends IntegrationEntity implements } @AssertTrue(message = "name is already used") - public boolean checkConstraintUniqueName() { + public boolean isUniqueNameConstraint() { if (StringUtils.isBlank(name)) { return true; } diff --git a/libreplan-business/src/main/java/org/libreplan/business/calendars/entities/ResourceCalendar.java b/libreplan-business/src/main/java/org/libreplan/business/calendars/entities/ResourceCalendar.java index 57b3ad2ae..1090b5011 100644 --- a/libreplan-business/src/main/java/org/libreplan/business/calendars/entities/ResourceCalendar.java +++ b/libreplan-business/src/main/java/org/libreplan/business/calendars/entities/ResourceCalendar.java @@ -21,8 +21,8 @@ package org.libreplan.business.calendars.entities; -import org.hibernate.validator.AssertTrue; -import org.hibernate.validator.NotNull; +import javax.validation.constraints.AssertTrue; +import javax.validation.constraints.NotNull; import org.joda.time.LocalDate; import org.libreplan.business.resources.entities.Resource; @@ -71,7 +71,7 @@ public class ResourceCalendar extends BaseCalendar { } @AssertTrue(message = "Capacity must be a positive integer number") - public boolean checkCapacityPositiveIntegerNumber() { + public boolean isCapacityPositiveIntegerNumberConstraint() { return (capacity >= 1); } diff --git a/libreplan-business/src/main/java/org/libreplan/business/common/BaseEntity.java b/libreplan-business/src/main/java/org/libreplan/business/common/BaseEntity.java index cf2b3650a..1f011b597 100644 --- a/libreplan-business/src/main/java/org/libreplan/business/common/BaseEntity.java +++ b/libreplan-business/src/main/java/org/libreplan/business/common/BaseEntity.java @@ -27,9 +27,13 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; +import javax.validation.ConstraintViolation; +import javax.validation.Validation; +import javax.validation.Validator; +import javax.validation.ValidatorFactory; + import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.hibernate.validator.InvalidValue; import org.libreplan.business.INewObject; import org.libreplan.business.common.exceptions.ValidationException; import org.libreplan.business.util.deepcopy.AfterCopy; @@ -67,6 +71,11 @@ public abstract class BaseEntity implements INewObject { private static final Log LOG = LogFactory.getLog(BaseEntity.class); + private static final ValidatorFactory validatorFactory = Validation + .buildDefaultValidatorFactory(); + + private static final Validator validator = validatorFactory.getValidator(); + @OnCopy(Strategy.IGNORE) private Long id; @@ -125,10 +134,10 @@ public abstract class BaseEntity implements INewObject { @SuppressWarnings("unchecked") public void validate() throws ValidationException { - LibrePlanClassValidator classValidator = new LibrePlanClassValidator(this.getClass()); - InvalidValue[] invalidValues = classValidator.getInvalidValues(this); - if (invalidValues.length > 0) { - throw new ValidationException(invalidValues); + Set> violations = validator + .validate(this); + if (!violations.isEmpty()) { + throw new ValidationException(violations); } } diff --git a/libreplan-business/src/main/java/org/libreplan/business/common/IntegrationEntity.java b/libreplan-business/src/main/java/org/libreplan/business/common/IntegrationEntity.java index 915762aff..6a573170d 100644 --- a/libreplan-business/src/main/java/org/libreplan/business/common/IntegrationEntity.java +++ b/libreplan-business/src/main/java/org/libreplan/business/common/IntegrationEntity.java @@ -26,8 +26,8 @@ import java.util.Set; import java.util.UUID; import org.apache.commons.lang.StringUtils; -import org.hibernate.validator.AssertTrue; -import org.hibernate.validator.NotEmpty; +import javax.validation.constraints.AssertTrue; +import org.hibernate.validator.constraints.NotEmpty; import org.libreplan.business.common.daos.IIntegrationEntityDAO; import org.libreplan.business.common.exceptions.InstanceNotFoundException; @@ -107,7 +107,7 @@ public abstract class IntegrationEntity extends BaseEntity { * calls on the abstract method getIntegrationEntityDAO(). */ @AssertTrue(message="code is already used") - public boolean checkConstraintUniqueCode() { + public boolean isUniqueCodeConstraint() { /* Check if it makes sense to check the constraint .*/ if (!iCodeSpecified()) { diff --git a/libreplan-business/src/main/java/org/libreplan/business/common/LibrePlanClassValidator.java b/libreplan-business/src/main/java/org/libreplan/business/common/LibrePlanClassValidator.java deleted file mode 100644 index e8fc3c959..000000000 --- a/libreplan-business/src/main/java/org/libreplan/business/common/LibrePlanClassValidator.java +++ /dev/null @@ -1,799 +0,0 @@ -/* - * This file is part of LibrePlan - * - * Copyright (C) 2010-2011 Igalia, S.L. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package org.libreplan.business.common; - -import java.beans.Introspector; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.io.Serializable; -import java.lang.annotation.Annotation; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.text.MessageFormat; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.MissingResourceException; -import java.util.ResourceBundle; -import java.util.Set; -import java.util.StringTokenizer; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.hibernate.AssertionFailure; -import org.hibernate.Hibernate; -import org.hibernate.MappingException; -import org.hibernate.annotations.common.reflection.Filter; -import org.hibernate.annotations.common.reflection.ReflectionManager; -import org.hibernate.annotations.common.reflection.XClass; -import org.hibernate.annotations.common.reflection.XMember; -import org.hibernate.annotations.common.reflection.XMethod; -import org.hibernate.annotations.common.reflection.XProperty; -import org.hibernate.annotations.common.reflection.java.JavaReflectionManager; -import org.hibernate.mapping.Component; -import org.hibernate.mapping.PersistentClass; -import org.hibernate.mapping.Property; -import org.hibernate.util.IdentitySet; -import org.hibernate.validator.InvalidStateException; -import org.hibernate.validator.InvalidValue; -import org.hibernate.validator.MessageInterpolator; -import org.hibernate.validator.PersistentClassConstraint; -import org.hibernate.validator.PropertyConstraint; -import org.hibernate.validator.Valid; -import org.hibernate.validator.Validator; -import org.hibernate.validator.ValidatorClass; -import org.hibernate.validator.Version; -import org.hibernate.validator.interpolator.DefaultMessageInterpolatorAggregator; - - -/** - * This class is copy-cat of HibernateValidator.ClassValidator - * - * Adds extra functionality to cache extra ClassValidators created for validating children elements (see getClassValidator) - * - * The function createChildValidator creates ClassValidators for getters and members marked for Validation, but it doesn't create - * ClassValidators for members that return Collections or ArrayList of entities. These ClassValidators are created later in getClasValidator - * but are not cached. - * - * Original code: http://anonsvn.jboss.org/repos/hibernate/validator/trunk/hibernate-validator-legacy/src/main/java/org/hibernate/validator/ClassValidator.java - * - * @author Diego Pino - */ -public class LibrePlanClassValidator implements Serializable { - - private static final long serialVersionUID = 1L; - - private static Log log = LogFactory.getLog( LibrePlanClassValidator.class ); - private static final InvalidValue[] EMPTY_INVALID_VALUE_ARRAY = new InvalidValue[]{}; - private static final String DEFAULT_VALIDATOR_MESSAGE = "org.hibernate.validator.resources.DefaultValidatorMessages"; - private static final String VALIDATOR_MESSAGE = "ValidatorMessages"; - private static final Set INDEXABLE_CLASS = new HashSet(); - - static { - INDEXABLE_CLASS.add( Integer.class ); - INDEXABLE_CLASS.add( Long.class ); - INDEXABLE_CLASS.add( String.class ); - } - - static { - Version.touch(); //touch version - } - - private final Class beanClass; - private transient ResourceBundle messageBundle; - private transient ResourceBundle defaultMessageBundle; - private transient boolean isUserProvidedResourceBundle; - private transient ReflectionManager reflectionManager; - - private final transient Map childClassValidators; - private final transient Map extraClassValidators; - private transient List beanValidators; - private transient List memberValidators; - private transient List memberGetters; - private transient List childGetters; - private transient DefaultMessageInterpolatorAggregator defaultInterpolator; - private transient MessageInterpolator userInterpolator; - private static final Filter GET_ALL_FILTER = new Filter() { - public boolean returnStatic() { - return true; - } - - public boolean returnTransient() { - return true; - } - }; - - /** - * create the validator engine for this bean type - */ - public LibrePlanClassValidator(Class beanClass) { - this( beanClass, (ResourceBundle) null ); - } - - /** - * create the validator engine for a particular bean class, using a resource bundle - * for message rendering on violation - */ - public LibrePlanClassValidator(Class beanClass, ResourceBundle resourceBundle) { - this( beanClass, resourceBundle, null, new HashMap(), null ); - } - - /** - * create the validator engine for a particular bean class, using a custom message interpolator - * for message rendering on violation - */ - public LibrePlanClassValidator(Class beanClass, MessageInterpolator interpolator) { - this( beanClass, null, interpolator, new HashMap(), null ); - } - - /** - * Not a public API - */ - public LibrePlanClassValidator( - Class beanClass, ResourceBundle resourceBundle, MessageInterpolator interpolator, - Map childClassValidators, ReflectionManager reflectionManager - ) { - this.reflectionManager = reflectionManager != null ? reflectionManager : new JavaReflectionManager(); - XClass beanXClass = this.reflectionManager.toXClass( beanClass ); - this.beanClass = beanClass; - this.messageBundle = resourceBundle == null ? - getDefaultResourceBundle() : - resourceBundle; - this.defaultMessageBundle = ResourceBundle.getBundle( DEFAULT_VALIDATOR_MESSAGE ); - this.userInterpolator = interpolator; - this.childClassValidators = childClassValidators != null ? - childClassValidators : - new HashMap(); - this.extraClassValidators = new HashMap(); - initValidator( beanXClass, this.childClassValidators ); - } - - @SuppressWarnings("unchecked") - protected LibrePlanClassValidator( - XClass beanXClass, ResourceBundle resourceBundle, MessageInterpolator userInterpolator, - Map childClassValidators, ReflectionManager reflectionManager - ) { - this.reflectionManager = reflectionManager; - this.beanClass = reflectionManager.toClass( beanXClass ); - this.messageBundle = resourceBundle == null ? - getDefaultResourceBundle() : - resourceBundle; - this.defaultMessageBundle = ResourceBundle.getBundle( DEFAULT_VALIDATOR_MESSAGE ); - this.userInterpolator = userInterpolator; - this.childClassValidators = childClassValidators; - this.extraClassValidators = new HashMap(); - initValidator( beanXClass, childClassValidators ); - } - - private ResourceBundle getDefaultResourceBundle() { - ResourceBundle rb; - try { - //use context class loader as a first citizen - ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); - if ( contextClassLoader == null ) { - throw new MissingResourceException( "No context classloader", null, VALIDATOR_MESSAGE ); - } - rb = ResourceBundle.getBundle( - VALIDATOR_MESSAGE, - Locale.getDefault(), - contextClassLoader - ); - } - catch (MissingResourceException e) { - log.trace( "ResourceBundle " + VALIDATOR_MESSAGE + " not found in thread context classloader" ); - //then use the Validator Framework classloader - try { - rb = ResourceBundle.getBundle( - VALIDATOR_MESSAGE, - Locale.getDefault(), - this.getClass().getClassLoader() - ); - } - catch (MissingResourceException ee) { - log.debug( - "ResourceBundle ValidatorMessages not found in Validator classloader. Delegate to " + DEFAULT_VALIDATOR_MESSAGE - ); - //the user did not override the default ValidatorMessages - rb = null; - } - } - isUserProvidedResourceBundle = true; - return rb; - } - - private void initValidator( - XClass xClass, Map childClassValidators - ) { - beanValidators = new ArrayList(); - memberValidators = new ArrayList(); - memberGetters = new ArrayList(); - childGetters = new ArrayList(); - defaultInterpolator = new DefaultMessageInterpolatorAggregator(); - defaultInterpolator.initialize( messageBundle, defaultMessageBundle ); - - //build the class hierarchy to look for members in - childClassValidators.put( xClass, this ); - Collection classes = new HashSet(); - addSuperClassesAndInterfaces( xClass, classes ); - for ( XClass currentClass : classes ) { - Annotation[] classAnnotations = currentClass.getAnnotations(); - for ( int i = 0; i < classAnnotations.length ; i++ ) { - Annotation classAnnotation = classAnnotations[i]; - Validator beanValidator = createValidator( classAnnotation ); - if ( beanValidator != null ) beanValidators.add( beanValidator ); - handleAggregateAnnotations(classAnnotation, null); - } - } - - //Check on all selected classes - for ( XClass currClass : classes ) { - List methods = currClass.getDeclaredMethods(); - for ( XMethod method : methods ) { - createMemberValidator( method ); - createChildValidator( method ); - } - - List fields = currClass.getDeclaredProperties( - "field", GET_ALL_FILTER - ); - for ( XProperty field : fields ) { - createMemberValidator( field ); - createChildValidator( field ); - } - } - } - - private void addSuperClassesAndInterfaces(XClass clazz, Collection classes) { - for ( XClass currClass = clazz; currClass != null ; currClass = currClass.getSuperclass() ) { - if ( ! classes.add( currClass ) ) return; - XClass[] interfaces = currClass.getInterfaces(); - for ( XClass interf : interfaces ) { - addSuperClassesAndInterfaces( interf, classes ); - } - } - } - - private boolean handleAggregateAnnotations(Annotation annotation, XMember member) { - Object[] values; - try { - Method valueMethod = annotation.getClass().getMethod( "value" ); - if ( valueMethod.getReturnType().isArray() ) { - values = (Object[]) valueMethod.invoke( annotation ); - } - else { - return false; - } - } - catch (NoSuchMethodException e) { - return false; - } - catch (Exception e) { - throw new IllegalStateException( e ); - } - - boolean validatorPresent = false; - for ( Object value : values ) { - if ( value instanceof Annotation ) { - annotation = (Annotation) value; - Validator validator = createValidator( annotation ); - if ( validator != null ) { - if ( member != null ) { - //member - memberValidators.add( validator ); - setAccessible( member ); - memberGetters.add( member ); - } - else { - //bean - beanValidators.add( validator ); - } - validatorPresent = true; - } - } - } - return validatorPresent; - } - - @SuppressWarnings("unchecked") - private void createChildValidator( XMember member) { - if ( member.isAnnotationPresent( Valid.class ) ) { - setAccessible( member ); - childGetters.add( member ); - XClass clazz; - if ( member.isCollection() || member.isArray() ) { - clazz = member.getElementClass(); - } - else { - clazz = member.getType(); - } - if ( !childClassValidators.containsKey( clazz ) ) { - //ClassValidator added by side effect (added to childClassValidators during CV construction) - new LibrePlanClassValidator( clazz, messageBundle, userInterpolator, childClassValidators, reflectionManager ); - } - } - } - - private void createMemberValidator(XMember member) { - boolean validatorPresent = false; - Annotation[] memberAnnotations = member.getAnnotations(); - for ( Annotation methodAnnotation : memberAnnotations ) { - Validator propertyValidator = createValidator( methodAnnotation ); - if ( propertyValidator != null ) { - memberValidators.add( propertyValidator ); - setAccessible( member ); - memberGetters.add( member ); - validatorPresent = true; - } - boolean agrValidPresent = handleAggregateAnnotations( methodAnnotation, member ); - validatorPresent = validatorPresent || agrValidPresent; - } - if ( validatorPresent && !member.isTypeResolved() ) { - log.warn( "Original type of property " + member + " is unbound and has been approximated." ); - } - } - - private static void setAccessible(XMember member) { - if ( !Modifier.isPublic( member.getModifiers() ) ) { - member.setAccessible( true ); - } - } - - @SuppressWarnings("unchecked") - private Validator createValidator(Annotation annotation) { - try { - ValidatorClass validatorClass = annotation.annotationType().getAnnotation( ValidatorClass.class ); - if ( validatorClass == null ) { - return null; - } - Validator beanValidator = validatorClass.value().newInstance(); - beanValidator.initialize( annotation ); - defaultInterpolator.addInterpolator( annotation, beanValidator ); - return beanValidator; - } - catch (Exception e) { - throw new IllegalArgumentException( "could not instantiate LibrePlanClassValidator", e ); - } - } - - public boolean hasValidationRules() { - return beanValidators.size() != 0 || memberValidators.size() != 0; - } - - /** - * apply constraints on a bean instance and return all the failures. - * if bean is null, an empty array is returned - */ - public InvalidValue[] getInvalidValues(T bean) { - return this.getInvalidValues( bean, new IdentitySet() ); - } - - /** - * apply constraints on a bean instance and return all the failures. - * if bean is null, an empty array is returned - */ - @SuppressWarnings("unchecked") - protected InvalidValue[] getInvalidValues(T bean, Set circularityState) { - if ( bean == null || circularityState.contains( bean ) ) { - return EMPTY_INVALID_VALUE_ARRAY; //Avoid circularity - } - else { - circularityState.add( bean ); - } - - if ( !beanClass.isInstance( bean ) ) { - throw new IllegalArgumentException( "not an instance of: " + bean.getClass() ); - } - - List results = new ArrayList(); - - for ( int i = 0; i < beanValidators.size() ; i++ ) { - Validator validator = beanValidators.get( i ); - if ( !validator.isValid( bean ) ) { - results.add( new InvalidValue( interpolate(validator), beanClass, null, bean, bean ) ); - } - } - - for ( int i = 0; i < memberValidators.size() ; i++ ) { - XMember getter = memberGetters.get( i ); - if ( Hibernate.isPropertyInitialized( bean, getPropertyName( getter ) ) ) { - Object value = getMemberValue( bean, getter ); - Validator validator = memberValidators.get( i ); - if ( !validator.isValid( value ) ) { - String propertyName = getPropertyName( getter ); - results.add( new InvalidValue( interpolate(validator), beanClass, propertyName, value, bean ) ); - } - } - } - - for ( int i = 0; i < childGetters.size() ; i++ ) { - XMember getter = childGetters.get( i ); - if ( Hibernate.isPropertyInitialized( bean, getPropertyName( getter ) ) ) { - Object value = getMemberValue( bean, getter ); - if ( value != null && Hibernate.isInitialized( value ) ) { - String propertyName = getPropertyName( getter ); - if ( getter.isCollection() ) { - int index = 0; - boolean isIterable = value instanceof Iterable; - Map map = ! isIterable ? (Map) value : null; - Iterable elements = isIterable ? - (Iterable) value : - map.keySet(); - for ( Object element : elements ) { - Object actualElement = isIterable ? element : map.get( element ); - if ( actualElement == null ) { - index++; - continue; - } - InvalidValue[] invalidValues = getClassValidator( actualElement ) - .getInvalidValues( actualElement, circularityState ); - - String indexedPropName = MessageFormat.format( - "{0}[{1}]", - propertyName, - INDEXABLE_CLASS.contains( element.getClass() ) ? - ( "'" + element + "'" ) : - index - ); - index++; - - for ( InvalidValue invalidValue : invalidValues ) { - invalidValue.addParentBean( bean, indexedPropName ); - results.add( invalidValue ); - } - } - } - if ( getter.isArray() ) { - int index = 0; - for ( Object element : (Object[]) value ) { - if ( element == null ) { - index++; - continue; - } - InvalidValue[] invalidValues = getClassValidator( element ) - .getInvalidValues( element, circularityState ); - - String indexedPropName = MessageFormat.format( - "{0}[{1}]", - propertyName, - index - ); - index++; - - for ( InvalidValue invalidValue : invalidValues ) { - invalidValue.addParentBean( bean, indexedPropName ); - results.add( invalidValue ); - } - } - } - else { - InvalidValue[] invalidValues = getClassValidator( value ) - .getInvalidValues( value, circularityState ); - for ( InvalidValue invalidValue : invalidValues ) { - invalidValue.addParentBean( bean, propertyName ); - results.add( invalidValue ); - } - } - } - } - } - - return results.toArray( new InvalidValue[results.size()] ); - } - - private String interpolate(Validator validator) { - String message = defaultInterpolator.getAnnotationMessage( validator ); - if (userInterpolator != null) { - return userInterpolator.interpolate( message, validator, defaultInterpolator ); - } - else { - return defaultInterpolator.interpolate( message, validator, null); - } - } - - @SuppressWarnings("unchecked") - private LibrePlanClassValidator getClassValidator(Object value) { - Class clazz = value.getClass(); - XClass xclass = reflectionManager.toXClass( clazz ); - LibrePlanClassValidator validator = (LibrePlanClassValidator) childClassValidators.get( xclass ); - if ( validator == null ) { //handles polymorphism - validator = extraClassValidators.get( xclass ); - if (validator == null) { - validator = new LibrePlanClassValidator( clazz ); - extraClassValidators.put( xclass, validator ); - } - } - return validator; - } - - /** - * Apply constraints of a particular property on a bean instance and return all the failures. - * Note this is not recursive. - */ - //TODO should it be recursive? - public InvalidValue[] getInvalidValues(T bean, String propertyName) { - List results = new ArrayList(); - - for ( int i = 0; i < memberValidators.size() ; i++ ) { - XMember getter = memberGetters.get( i ); - if ( getPropertyName( getter ).equals( propertyName ) ) { - Object value = getMemberValue( bean, getter ); - Validator validator = memberValidators.get( i ); - if ( !validator.isValid( value ) ) { - results.add( new InvalidValue( interpolate(validator), beanClass, propertyName, value, bean ) ); - } - } - } - - return results.toArray( new InvalidValue[results.size()] ); - } - - /** - * Apply constraints of a particular property value of a bean type and return all the failures. - * The InvalidValue objects returns return null for InvalidValue#getBean() and InvalidValue#getRootBean() - * Note this is not recursive. - */ - //TODO should it be recursive? - public InvalidValue[] getPotentialInvalidValues(String propertyName, Object value) { - List results = new ArrayList(); - - for ( int i = 0; i < memberValidators.size() ; i++ ) { - XMember getter = memberGetters.get( i ); - if ( getPropertyName( getter ).equals( propertyName ) ) { - Validator validator = memberValidators.get( i ); - if ( !validator.isValid( value ) ) { - results.add( new InvalidValue( interpolate(validator), beanClass, propertyName, value, null ) ); - } - } - } - - return results.toArray( new InvalidValue[results.size()] ); - } - - private Object getMemberValue(T bean, XMember getter) { - Object value; - try { - value = getter.invoke( bean ); - } - catch (Exception e) { - throw new IllegalStateException( "Could not get property value", e ); - } - return value; - } - - public String getPropertyName(XMember member) { - //Do no try to cache the result in a map, it's actually much slower (2.x time) - String propertyName; - if ( XProperty.class.isAssignableFrom( member.getClass() ) ) { - propertyName = member.getName(); - } - else if ( XMethod.class.isAssignableFrom( member.getClass() ) ) { - propertyName = member.getName(); - if ( propertyName.startsWith( "is" ) ) { - propertyName = Introspector.decapitalize( propertyName.substring( 2 ) ); - } - else if ( propertyName.startsWith( "get" ) ) { - propertyName = Introspector.decapitalize( propertyName.substring( 3 ) ); - } - //do nothing for non getter method, in case someone want to validate a PO Method - } - else { - throw new AssertionFailure( "Unexpected member: " + member.getClass().getName() ); - } - return propertyName; - } - - /** @deprecated */ - private String replace(String message, Annotation parameters) { - StringTokenizer tokens = new StringTokenizer( message, "#{}", true ); - StringBuilder buf = new StringBuilder( 30 ); - boolean escaped = false; - boolean el = false; - while ( tokens.hasMoreTokens() ) { - String token = tokens.nextToken(); - if ( !escaped && "#".equals( token ) ) { - el = true; - } - if ( !el && "{".equals( token ) ) { - escaped = true; - } - else if ( escaped && "}".equals( token ) ) { - escaped = false; - } - else if ( !escaped ) { - if ( "{".equals( token ) ) el = false; - buf.append( token ); - } - else { - Method member; - try { - member = parameters.getClass().getMethod( token, (Class[]) null ); - } - catch (NoSuchMethodException nsfme) { - member = null; - } - if ( member != null ) { - try { - buf.append( member.invoke( parameters ) ); - } - catch (Exception e) { - throw new IllegalArgumentException( "could not render message", e ); - } - } - else { - String string = null; - try { - string = messageBundle != null ? messageBundle.getString( token ) : null; - } - catch( MissingResourceException e ) { - //give a second chance with the default resource bundle - } - if (string == null) { - try { - string = defaultMessageBundle.getString( token ); - } - catch( MissingResourceException e) { - throw new MissingResourceException( - "Can't find resource in validator bundles, key " + token, - defaultMessageBundle.getClass().getName(), - token - ); - } - } - if ( string != null ) buf.append( replace( string, parameters ) ); - } - } - } - return buf.toString(); - } - - /** - * apply the registred constraints rules on the hibernate metadata (to be applied on DB schema...) - * - * @param persistentClass hibernate metadata - */ - public void apply(PersistentClass persistentClass) { - - for ( Validator validator : beanValidators ) { - if ( validator instanceof PersistentClassConstraint ) { - ( (PersistentClassConstraint) validator ).apply( persistentClass ); - } - } - - Iterator validators = memberValidators.iterator(); - Iterator getters = memberGetters.iterator(); - while ( validators.hasNext() ) { - Validator validator = validators.next(); - String propertyName = getPropertyName( getters.next() ); - if ( validator instanceof PropertyConstraint ) { - try { - Property property = findPropertyByName(persistentClass, propertyName); - if (property != null) { - ( (PropertyConstraint) validator ).apply( property ); - } - } - catch (MappingException pnfe) { - //do nothing - } - } - } - - } - - public void assertValid(T bean) { - InvalidValue[] values = getInvalidValues( bean ); - if ( values.length > 0 ) { - throw new InvalidStateException( values ); - } - } - - private void writeObject(ObjectOutputStream oos) throws IOException { - ResourceBundle rb = messageBundle; - MessageInterpolator interpolator = this.userInterpolator; - if ( rb != null && ! ( rb instanceof Serializable ) ) { - messageBundle = null; - if ( ! isUserProvidedResourceBundle ) { - log.warn( - "Serializing a LibrePlanClassValidator with a non serializable ResourceBundle: ResourceBundle ignored" - ); - } - } - if (interpolator != null && ! (interpolator instanceof Serializable) ) { - userInterpolator = null; - log.warn( "Serializing a non serializable MessageInterpolator" ); - } - oos.defaultWriteObject(); - oos.writeObject( messageBundle ); - oos.writeObject( userInterpolator ); - messageBundle = rb; - userInterpolator = interpolator; - } - - private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { - ois.defaultReadObject(); - ResourceBundle rb = (ResourceBundle) ois.readObject(); - if ( rb == null ) rb = getDefaultResourceBundle(); - this.messageBundle = rb; - this.userInterpolator = (MessageInterpolator) ois.readObject(); - this.defaultMessageBundle = ResourceBundle.getBundle( DEFAULT_VALIDATOR_MESSAGE ); - reflectionManager = new JavaReflectionManager(); - initValidator( reflectionManager.toXClass( beanClass ), new HashMap() ); - } - - /** - * Retrieve the property by path in a recursive way, including IndetifierProperty in the loop - * If propertyName is null or empty, the IdentifierProperty is returned - */ - public static Property findPropertyByName(PersistentClass associatedClass, String propertyName) { - Property property = null; - Property idProperty = associatedClass.getIdentifierProperty(); - String idName = idProperty != null ? idProperty.getName() : null; - try { - if ( propertyName == null - || propertyName.length() == 0 - || propertyName.equals( idName ) ) { - //default to id - property = idProperty; - } - else { - if ( propertyName.indexOf( idName + "." ) == 0 ) { - property = idProperty; - propertyName = propertyName.substring( idName.length() + 1 ); - } - StringTokenizer st = new StringTokenizer( propertyName, ".", false ); - while ( st.hasMoreElements() ) { - String element = (String) st.nextElement(); - if ( property == null ) { - property = associatedClass.getProperty( element ); - } - else { - if ( ! property.isComposite() ) return null; - property = ( (Component) property.getValue() ).getProperty( element ); - } - } - } - } - catch (MappingException e) { - try { - //if we do not find it try to check the identifier mapper - if ( associatedClass.getIdentifierMapper() == null ) return null; - StringTokenizer st = new StringTokenizer( propertyName, ".", false ); - while ( st.hasMoreElements() ) { - String element = (String) st.nextElement(); - if ( property == null ) { - property = associatedClass.getIdentifierMapper().getProperty( element ); - } - else { - if ( ! property.isComposite() ) return null; - property = ( (Component) property.getValue() ).getProperty( element ); - } - } - } - catch (MappingException ee) { - return null; - } - } - return property; - } -} diff --git a/libreplan-business/src/main/java/org/libreplan/business/common/daos/EntitySequenceDAO.java b/libreplan-business/src/main/java/org/libreplan/business/common/daos/EntitySequenceDAO.java index cb4ecdf92..bb9581063 100644 --- a/libreplan-business/src/main/java/org/libreplan/business/common/daos/EntitySequenceDAO.java +++ b/libreplan-business/src/main/java/org/libreplan/business/common/daos/EntitySequenceDAO.java @@ -35,7 +35,7 @@ import org.libreplan.business.i18n.I18nHelper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.context.annotation.Scope; -import org.springframework.orm.hibernate3.HibernateOptimisticLockingFailureException; +import org.springframework.orm.hibernate4.HibernateOptimisticLockingFailureException; import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; diff --git a/libreplan-business/src/main/java/org/libreplan/business/common/entities/Configuration.java b/libreplan-business/src/main/java/org/libreplan/business/common/entities/Configuration.java index c8a6c69fb..c56edd8ff 100644 --- a/libreplan-business/src/main/java/org/libreplan/business/common/entities/Configuration.java +++ b/libreplan-business/src/main/java/org/libreplan/business/common/entities/Configuration.java @@ -22,10 +22,10 @@ package org.libreplan.business.common.entities; import org.apache.commons.lang.StringUtils; -import org.hibernate.validator.AssertTrue; -import org.hibernate.validator.Min; -import org.hibernate.validator.NotEmpty; -import org.hibernate.validator.NotNull; +import javax.validation.constraints.AssertTrue; +import javax.validation.constraints.Min; +import org.hibernate.validator.constraints.NotEmpty; +import javax.validation.constraints.NotNull; import org.libreplan.business.calendars.entities.BaseCalendar; import org.libreplan.business.common.BaseEntity; import org.libreplan.business.costcategories.entities.TypeOfWorkHours; @@ -155,7 +155,7 @@ public class Configuration extends BaseEntity { } @AssertTrue(message = "company code cannot contain whitespaces") - public boolean checkConstraintCompanyCodeWithoutWhiteSpaces() { + public boolean isCompanyCodeWithoutWhiteSpacesConstraint() { if ((companyCode == null) || (companyCode.isEmpty())) { return false; } @@ -163,7 +163,7 @@ public class Configuration extends BaseEntity { } @AssertTrue(message = "host not specified") - public boolean checkConstraintLdapHostWithoutWhiteSpaces() { + public boolean isLdapHostWithoutWhiteSpacesConstraint() { if (getLdapConfiguration().getLdapAuthEnabled()) { if (StringUtils.isBlank(getLdapConfiguration().getLdapHost())) { return false; @@ -173,7 +173,7 @@ public class Configuration extends BaseEntity { } @AssertTrue(message = "port not specified") - public boolean checkConstraintLdapPortWithoutWhiteSpaces() { + public boolean isLdapPortWithoutWhiteSpacesConstraint() { if (getLdapConfiguration().getLdapAuthEnabled()) { if (StringUtils.isBlank(getLdapConfiguration().getLdapPort())) { return false; @@ -183,7 +183,7 @@ public class Configuration extends BaseEntity { } @AssertTrue(message = "base not specified") - public boolean checkConstraintLdapBaseWithoutWhiteSpaces() { + public boolean isLdapBaseWithoutWhiteSpacesConstraint() { if (getLdapConfiguration().getLdapAuthEnabled()) { if (StringUtils.isBlank(getLdapConfiguration().getLdapBase())) { return false; @@ -193,7 +193,7 @@ public class Configuration extends BaseEntity { } @AssertTrue(message = "userId not specified") - public boolean checkConstraintLdapUserIdWithoutWhiteSpaces() { + public boolean isLdapUserIdWithoutWhiteSpacesConstraint() { if (getLdapConfiguration().getLdapAuthEnabled()) { if (StringUtils.isBlank(getLdapConfiguration().getLdapUserId())) { return false; diff --git a/libreplan-business/src/main/java/org/libreplan/business/common/entities/ConfigurationRolesLDAP.java b/libreplan-business/src/main/java/org/libreplan/business/common/entities/ConfigurationRolesLDAP.java index a1c4c4b94..d364d3a6b 100644 --- a/libreplan-business/src/main/java/org/libreplan/business/common/entities/ConfigurationRolesLDAP.java +++ b/libreplan-business/src/main/java/org/libreplan/business/common/entities/ConfigurationRolesLDAP.java @@ -19,7 +19,7 @@ package org.libreplan.business.common.entities; -import org.hibernate.validator.NotEmpty; +import org.hibernate.validator.constraints.NotEmpty; /** * A class which is used to store the configuration of the matching between the diff --git a/libreplan-business/src/main/java/org/libreplan/business/common/entities/Connector.java b/libreplan-business/src/main/java/org/libreplan/business/common/entities/Connector.java index e57458358..3c7969200 100644 --- a/libreplan-business/src/main/java/org/libreplan/business/common/entities/Connector.java +++ b/libreplan-business/src/main/java/org/libreplan/business/common/entities/Connector.java @@ -28,9 +28,9 @@ import java.util.List; import java.util.Map; import org.apache.commons.lang.StringUtils; -import org.hibernate.validator.AssertTrue; -import org.hibernate.validator.NotEmpty; -import org.hibernate.validator.Valid; +import javax.validation.constraints.AssertTrue; +import org.hibernate.validator.constraints.NotEmpty; +import javax.validation.Valid; import org.libreplan.business.common.BaseEntity; import org.libreplan.business.common.Registry; import org.libreplan.business.common.daos.IConnectorDAO; @@ -98,7 +98,7 @@ public class Connector extends BaseEntity { } @AssertTrue(message = "connector name is already being used") - public boolean checkConstraintUniqueConnectorName() { + public boolean isUniqueConnectorNameConstraint() { if (StringUtils.isBlank(name)) { return true; } diff --git a/libreplan-business/src/main/java/org/libreplan/business/common/entities/ConnectorProperty.java b/libreplan-business/src/main/java/org/libreplan/business/common/entities/ConnectorProperty.java index 7cb6b79d7..ca75c6e71 100644 --- a/libreplan-business/src/main/java/org/libreplan/business/common/entities/ConnectorProperty.java +++ b/libreplan-business/src/main/java/org/libreplan/business/common/entities/ConnectorProperty.java @@ -19,7 +19,7 @@ package org.libreplan.business.common.entities; -import org.hibernate.validator.NotEmpty; +import org.hibernate.validator.constraints.NotEmpty; /** * This class is intended to work as a Hibernate component. It's formed by two diff --git a/libreplan-business/src/main/java/org/libreplan/business/common/entities/EntitySequence.java b/libreplan-business/src/main/java/org/libreplan/business/common/entities/EntitySequence.java index e589c0556..fc68d484f 100644 --- a/libreplan-business/src/main/java/org/libreplan/business/common/entities/EntitySequence.java +++ b/libreplan-business/src/main/java/org/libreplan/business/common/entities/EntitySequence.java @@ -25,9 +25,9 @@ import java.text.DecimalFormat; import java.text.NumberFormat; import org.hibernate.NonUniqueResultException; -import org.hibernate.validator.AssertTrue; -import org.hibernate.validator.NotEmpty; -import org.hibernate.validator.NotNull; +import javax.validation.constraints.AssertTrue; +import org.hibernate.validator.constraints.NotEmpty; +import javax.validation.constraints.NotNull; import org.libreplan.business.common.BaseEntity; import org.libreplan.business.common.IntegrationEntity; import org.libreplan.business.common.Registry; @@ -104,7 +104,7 @@ public class EntitySequence extends BaseEntity { } @AssertTrue(message = "Prefix cannot contain whitespaces") - public boolean checkConstraintPrefixWithoutWhiteSpaces() { + public boolean isPrefixWithoutWhiteSpacesConstraint() { if ((prefix == null) || (prefix.isEmpty())) { return false; } @@ -143,7 +143,7 @@ public class EntitySequence extends BaseEntity { } @AssertTrue(message = "number of digits out of range") - public boolean checkConstraintNumberOfDigitsInRange() { + public boolean isNumberOfDigitsInRangeConstraint() { if ((numberOfDigits != null) && (numberOfDigits >= MIN_NUMBER_OF_DIGITS) && (numberOfDigits <= MAX_NUMBER_OF_DIGITS)) { @@ -153,7 +153,7 @@ public class EntitySequence extends BaseEntity { } @AssertTrue(message = "format sequence code invalid. It must not contain '_'") - public boolean checkConstraintWithoutLowBar() { + public boolean isWithoutLowBarConstraint() { if ((prefix == null) || (prefix.isEmpty())) { return false; } @@ -199,7 +199,7 @@ public class EntitySequence extends BaseEntity { } @AssertTrue(message = "Only one sequence per entity can be active at the same time.") - public boolean checkConstraintOnlyOneSequenceForEachEntityIsActive() { + public boolean isOnlyOneSequenceForEachEntityIsActiveConstraint() { if (!isActive()) { return true; } diff --git a/libreplan-business/src/main/java/org/libreplan/business/common/entities/JobSchedulerConfiguration.java b/libreplan-business/src/main/java/org/libreplan/business/common/entities/JobSchedulerConfiguration.java index d9f970d8a..8ff62c4f6 100644 --- a/libreplan-business/src/main/java/org/libreplan/business/common/entities/JobSchedulerConfiguration.java +++ b/libreplan-business/src/main/java/org/libreplan/business/common/entities/JobSchedulerConfiguration.java @@ -20,8 +20,8 @@ package org.libreplan.business.common.entities; import org.apache.commons.lang.StringUtils; -import org.hibernate.validator.AssertTrue; -import org.hibernate.validator.NotNull; +import javax.validation.constraints.AssertTrue; +import javax.validation.constraints.NotNull; import org.libreplan.business.common.BaseEntity; import org.libreplan.business.common.IHumanIdentifiable; import org.libreplan.business.common.Registry; @@ -121,7 +121,7 @@ public class JobSchedulerConfiguration extends BaseEntity implements } @AssertTrue(message = "job group and name are already being used") - public boolean checkConstraintUniqueJobGroupAndName() { + public boolean isUniqueJobGroupAndNameConstraint() { if (StringUtils.isBlank(jobGroup) && StringUtils.isBlank(jobName)) { return true; } diff --git a/libreplan-business/src/main/java/org/libreplan/business/common/exceptions/ValidationException.java b/libreplan-business/src/main/java/org/libreplan/business/common/exceptions/ValidationException.java index 63cd956a6..e33d82b27 100644 --- a/libreplan-business/src/main/java/org/libreplan/business/common/exceptions/ValidationException.java +++ b/libreplan-business/src/main/java/org/libreplan/business/common/exceptions/ValidationException.java @@ -21,8 +21,16 @@ package org.libreplan.business.common.exceptions; +import static java.util.Collections.singleton; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +import javax.validation.ConstraintViolation; + import org.apache.commons.lang.Validate; -import org.hibernate.validator.InvalidValue; import org.libreplan.business.common.BaseEntity; /** @@ -32,23 +40,114 @@ import org.libreplan.business.common.BaseEntity; */ public class ValidationException extends RuntimeException { + public static abstract class InvalidValue { + + public abstract String getMessage(); + + public abstract String getPropertyPath(); + + public abstract Object getInvalidValue(); + + public abstract Object getRootBean(); + + } + + private static class BasedOnConstraintViolation extends InvalidValue { + + private ConstraintViolation violation; + + public BasedOnConstraintViolation(ConstraintViolation violation) { + Validate.notNull(violation); + this.violation = violation; + } + + @Override + public String getMessage() { + return violation.getMessage(); + } + + @Override + public String getPropertyPath() { + if (violation.getPropertyPath() == null) { + return null; + } + return violation.getPropertyPath().toString(); + } + + + @Override + public Object getRootBean() { + return violation.getRootBean(); + } + + @Override + public Object getInvalidValue() { + return violation.getInvalidValue(); + } + } + + private static class InstantiatedInvalidValue extends InvalidValue { + + private final String message; + private final String propertyPath; + private final Object invalidValue; + private final Object rootBean; + + private InstantiatedInvalidValue(String message, String propertyPath, + Object invalidValue, Object rootBean) { + super(); + this.message = message; + this.propertyPath = propertyPath; + this.invalidValue = invalidValue; + this.rootBean = rootBean; + } + + @Override + public String getMessage() { + return message; + } + + @Override + public String getPropertyPath() { + return propertyPath; + } + + @Override + public Object getInvalidValue() { + return invalidValue; + } + + @Override + public Object getRootBean() { + return rootBean; + } + } + private static String getValidationErrorSummary( - InvalidValue... invalidValues) { + Collection violations) { StringBuilder builder = new StringBuilder(); - for (InvalidValue each : invalidValues) { + for (InvalidValue each : violations) { builder.append(summaryFor(each)); builder.append("; "); } - if (invalidValues.length > 0) { + if (builder.length() > 0) { builder.delete(builder.length() - 2, builder.length()); } return builder.toString(); } - private static String summaryFor(InvalidValue invalidValue) { - return "at " + asString(invalidValue.getBean()) + " " - + invalidValue.getPropertyPath() + ": " - + invalidValue.getMessage(); + private static String summaryFor(InvalidValue invalid) { + Object bean = invalid.getRootBean(); + Object propertyPath = invalid.getPropertyPath(); + + StringBuilder builder = new StringBuilder(); + if (bean != null) { + builder = builder.append("at ").append(asString(bean)); + if (propertyPath != null) { + builder = builder.append(" ").append(propertyPath).append(": "); + } + } + return builder.append(invalid.getMessage()).toString(); } private static String asString(Object bean) { @@ -64,61 +163,90 @@ public class ValidationException extends RuntimeException { return bean.toString(); } - public static ValidationException invalidValue(String message, Object value) { - InvalidValue invalidValue = new InvalidValue(message, null, "", value, - null); - return new ValidationException(invalidValue); + public static ValidationException invalidValueException(String message, + Object bean) { + return new ValidationException(invalidValue(message, bean)); } - private InvalidValue[] invalidValues; + private static InvalidValue invalidValue(String message, Object bean) { + return invalidValue(message, null, null, bean); + } - public InvalidValue[] getInvalidValues() { - return invalidValues.clone(); + public static InvalidValue invalidValue(String message, + String propertyPath, Object invalidValue, Object rootBean) { + return new InstantiatedInvalidValue(message, propertyPath, + invalidValue, rootBean); + } + + private final Set invalidValues; + + public Set getInvalidValues() { + return invalidValues; } public InvalidValue getInvalidValue() { - return (invalidValues.length > 0) ? invalidValues.clone()[0] : null; + return invalidValues.isEmpty() ? null : invalidValues.iterator().next(); + } + + public ValidationException(ConstraintViolation violation) { + super(getValidationErrorSummary(convert(violation))); + this.invalidValues = convert(violation); } public ValidationException(InvalidValue invalidValue) { - super(getValidationErrorSummary(invalidValue)); - storeInvalidValues(toArray(invalidValue)); + super(getValidationErrorSummary(singleton(invalidValue))); + this.invalidValues = singleton(invalidValue); } - private InvalidValue[] toArray(InvalidValue invalidValue) { - InvalidValue[] result = new InvalidValue[1]; - result[0] = invalidValue; - return result; - } - - public ValidationException(InvalidValue[] invalidValues) { + public ValidationException(Collection invalidValues) { super(getValidationErrorSummary(invalidValues)); - storeInvalidValues(invalidValues); + this.invalidValues = new HashSet(invalidValues); } - private void storeInvalidValues(InvalidValue[] invalidValues) { - Validate.noNullElements(invalidValues); - this.invalidValues = invalidValues.clone(); + public ValidationException(String message, InvalidValue invalidValue) { + super(message); + this.invalidValues = singleton(invalidValue); } - public ValidationException(InvalidValue[] invalidValues, String message, + private static Set convert( + ConstraintViolation violation) { + return Collections.singleton(new BasedOnConstraintViolation(violation)); + } + + private static Set convert( + Collection> violations) { + Set result = new HashSet(); + for (ConstraintViolation each : violations) { + result.add(new BasedOnConstraintViolation(each)); + } + return Collections.unmodifiableSet(result); + } + + public ValidationException(Set> violations) { + super(getValidationErrorSummary(convert(violations))); + this.invalidValues = convert(violations); + } + + + public ValidationException( + Set> violations, String message, Throwable cause) { super(message, cause); - storeInvalidValues(invalidValues); + this.invalidValues = convert(violations); } - public ValidationException(InvalidValue[] invalidValues, String message) { + public ValidationException(Set> violations, String message) { super(message); - storeInvalidValues(invalidValues); + this.invalidValues = convert(violations); } - public ValidationException(InvalidValue[] invalidValues, Throwable cause) { - super(cause); - storeInvalidValues(invalidValues); + public ValidationException( + Set> violations, Throwable cause) { + this(violations, getValidationErrorSummary(convert(violations)), cause); } public ValidationException(String message) { - this(new InvalidValue[] {}, message); + this(Collections.> emptySet(), message); } } diff --git a/libreplan-business/src/main/java/org/libreplan/business/costcategories/daos/TypeOfWorkHoursDAO.java b/libreplan-business/src/main/java/org/libreplan/business/costcategories/daos/TypeOfWorkHoursDAO.java index b98e9f1b5..212609066 100644 --- a/libreplan-business/src/main/java/org/libreplan/business/costcategories/daos/TypeOfWorkHoursDAO.java +++ b/libreplan-business/src/main/java/org/libreplan/business/costcategories/daos/TypeOfWorkHoursDAO.java @@ -165,7 +165,7 @@ public class TypeOfWorkHoursDAO extends IntegrationEntityDAO .add(Restrictions.eq("typeOfWorkHours", type)).list(); if (!workReportLines.isEmpty()) { throw ValidationException - .invalidValue( + .invalidValueException( "Cannot delete type of work hours. It is being used at this moment in some timesheet line.", type); } @@ -176,7 +176,7 @@ public class TypeOfWorkHoursDAO extends IntegrationEntityDAO .add(Restrictions.eq("type", type)).list(); if (!hoursCost.isEmpty()) { throw ValidationException - .invalidValue( + .invalidValueException( "Cannot delete type of work hours. It is being used at this moment in some cost category.", type); } @@ -187,7 +187,7 @@ public class TypeOfWorkHoursDAO extends IntegrationEntityDAO if (configuration.getPersonalTimesheetsTypeOfWorkHours().getId() .equals(type.getId())) { throw ValidationException - .invalidValue( + .invalidValueException( "Cannot delete the type of work hours. It is configured as type of work hours for personal timesheets.", type); } @@ -208,7 +208,7 @@ public class TypeOfWorkHoursDAO extends IntegrationEntityDAO PredefinedConnectorProperties.JIRA_HOURS_TYPE); if (name.equals(type.getName())) { throw ValidationException - .invalidValue( + .invalidValueException( "Cannot delete the type of work hours. It is configured as type of work hours for JIRA connector.", type); } diff --git a/libreplan-business/src/main/java/org/libreplan/business/costcategories/entities/CostCategory.java b/libreplan-business/src/main/java/org/libreplan/business/costcategories/entities/CostCategory.java index ddc976623..1a3553178 100644 --- a/libreplan-business/src/main/java/org/libreplan/business/costcategories/entities/CostCategory.java +++ b/libreplan-business/src/main/java/org/libreplan/business/costcategories/entities/CostCategory.java @@ -29,12 +29,13 @@ import java.util.HashSet; import java.util.List; import java.util.Set; +import javax.validation.Valid; +import javax.validation.constraints.AssertFalse; +import javax.validation.constraints.AssertTrue; +import javax.validation.constraints.NotNull; + import org.apache.commons.lang.StringUtils; -import org.hibernate.validator.AssertFalse; -import org.hibernate.validator.AssertTrue; -import org.hibernate.validator.NotEmpty; -import org.hibernate.validator.NotNull; -import org.hibernate.validator.Valid; +import org.hibernate.validator.constraints.NotEmpty; import org.joda.time.LocalDate; import org.libreplan.business.common.IHumanIdentifiable; import org.libreplan.business.common.IntegrationEntity; @@ -106,7 +107,7 @@ public class CostCategory extends IntegrationEntity implements IHumanIdentifiabl || listHourCosts.get(i).getType() == null) { // this is not exactly an overlapping but a // problem with missing compulsory fields - throw ValidationException.invalidValue( + throw ValidationException.invalidValueException( "Hours cost type cannot be empty", listElement); } @@ -115,12 +116,12 @@ public class CostCategory extends IntegrationEntity implements IHumanIdentifiabl if (initDate == null || listElement.getInitDate() == null) { // this is not exactly an overlapping but a // problem with missing compulsory fields - throw ValidationException.invalidValue( + throw ValidationException.invalidValueException( "Init date cannot be empty", listElement); } if (endDate == null && listElement.getEndDate() == null) { - throw ValidationException.invalidValue( + throw ValidationException.invalidValueException( "End date cannot be empty", listElement); } else if ((endDate == null && listElement.getEndDate() @@ -128,7 +129,7 @@ public class CostCategory extends IntegrationEntity implements IHumanIdentifiabl || (listElement.getEndDate() == null && listElement .getInitDate().compareTo(endDate) <= 0)) { throw ValidationException - .invalidValue( + .invalidValueException( _("Two Hour Cost of the same type overlap in time"), listElement); } else if ((endDate != null && listElement.getEndDate() != null) @@ -137,7 +138,7 @@ public class CostCategory extends IntegrationEntity implements IHumanIdentifiabl .getInitDate().compareTo(initDate) >= 0 && listElement .getInitDate().compareTo(endDate) <= 0))) { throw ValidationException - .invalidValue( + .invalidValueException( _("Two Hour Cost of the same type overlap in time"), listElement); } @@ -156,12 +157,18 @@ public class CostCategory extends IntegrationEntity implements IHumanIdentifiabl ResourcesCostCategoryAssignment costCategory = costCategoryAssignments .get(j); if (endDate == null && costCategory.getEndDate() == null) { - throw ValidationException.invalidValue(_("Some cost category assignments overlap in time"), costCategory); + throw ValidationException + .invalidValueException( + _("Some cost category assignments overlap in time"), + costCategory); } else if ((endDate == null && costCategory.getEndDate() .compareTo(initDate) >= 0) || (costCategory.getEndDate() == null && costCategory .getInitDate().compareTo(endDate) <= 0)) { - throw ValidationException.invalidValue(_("Some cost category assignments overlap in time"), costCategory); + throw ValidationException + .invalidValueException( + _("Some cost category assignments overlap in time"), + costCategory); } else if ((endDate != null && costCategory.getEndDate() != null) && ((costCategory.getEndDate().compareTo(initDate) >= 0 && // (1) // listElement.getEndDate() @@ -181,7 +188,10 @@ public class CostCategory extends IntegrationEntity implements IHumanIdentifiabl costCategory.getEndDate().compareTo(endDate) >= 0))) { // contains // [initDate, // endDate] - throw ValidationException.invalidValue(_("Some cost category assignments overlap in time"), costCategory); + throw ValidationException + .invalidValueException( + _("Some cost category assignments overlap in time"), + costCategory); } } } @@ -269,7 +279,7 @@ public class CostCategory extends IntegrationEntity implements IHumanIdentifiabl } @AssertFalse(message="Two Hour Cost of the same type overlap in time") - public boolean checkHourCostsOverlap() { + public boolean isHourCostsOverlapConstraint() { try { validateHourCostsOverlap(getHourCosts()); return false; @@ -284,7 +294,7 @@ public class CostCategory extends IntegrationEntity implements IHumanIdentifiabl } @AssertTrue(message = "The hour cost codes must be unique.") - public boolean checkConstraintNonRepeatedHourCostCodes() { + public boolean isNonRepeatedHourCostCodesConstraint() { return getFirstRepeatedCode(this.hourCosts) == null; } @@ -337,7 +347,7 @@ public class CostCategory extends IntegrationEntity implements IHumanIdentifiabl } @AssertTrue(message = "the cost category name has to be unique and it is already in use") - public boolean checkConstraintUniqueName() { + public boolean isUniqueNameConstraint() { if (StringUtils.isBlank(name)) { return true; } diff --git a/libreplan-business/src/main/java/org/libreplan/business/costcategories/entities/HourCost.java b/libreplan-business/src/main/java/org/libreplan/business/costcategories/entities/HourCost.java index 988a709a1..92e085f8a 100644 --- a/libreplan-business/src/main/java/org/libreplan/business/costcategories/entities/HourCost.java +++ b/libreplan-business/src/main/java/org/libreplan/business/costcategories/entities/HourCost.java @@ -23,8 +23,8 @@ package org.libreplan.business.costcategories.entities; import java.math.BigDecimal; -import org.hibernate.validator.AssertTrue; -import org.hibernate.validator.NotNull; +import javax.validation.constraints.AssertTrue; +import javax.validation.constraints.NotNull; import org.joda.time.LocalDate; import org.libreplan.business.common.IntegrationEntity; import org.libreplan.business.common.Registry; @@ -151,7 +151,7 @@ public class HourCost extends IntegrationEntity { } @AssertTrue(message="The end date cannot be before the start date") - public boolean checkPositiveTimeInterval() { + public boolean isPositiveTimeIntervalConstraint() { if (initDate == null) { return true; } diff --git a/libreplan-business/src/main/java/org/libreplan/business/costcategories/entities/ResourcesCostCategoryAssignment.java b/libreplan-business/src/main/java/org/libreplan/business/costcategories/entities/ResourcesCostCategoryAssignment.java index c2c614a8a..8af79cc20 100644 --- a/libreplan-business/src/main/java/org/libreplan/business/costcategories/entities/ResourcesCostCategoryAssignment.java +++ b/libreplan-business/src/main/java/org/libreplan/business/costcategories/entities/ResourcesCostCategoryAssignment.java @@ -22,8 +22,8 @@ package org.libreplan.business.costcategories.entities; import org.apache.commons.lang.StringUtils; -import org.hibernate.validator.AssertTrue; -import org.hibernate.validator.NotNull; +import javax.validation.constraints.AssertTrue; +import javax.validation.constraints.NotNull; import org.joda.time.LocalDate; import org.libreplan.business.common.IntegrationEntity; import org.libreplan.business.common.Registry; @@ -143,7 +143,7 @@ public class ResourcesCostCategoryAssignment extends IntegrationEntity { } @AssertTrue(message="cost assignment with end date before start date") - public boolean checkConstraintPositiveTimeInterval() { + public boolean isPositiveTimeInterval() { /* Check if it makes sense to check the constraint .*/ if (!isInitDateSpecified()) { diff --git a/libreplan-business/src/main/java/org/libreplan/business/costcategories/entities/TypeOfWorkHours.java b/libreplan-business/src/main/java/org/libreplan/business/costcategories/entities/TypeOfWorkHours.java index 0f09a66c1..559f11480 100644 --- a/libreplan-business/src/main/java/org/libreplan/business/costcategories/entities/TypeOfWorkHours.java +++ b/libreplan-business/src/main/java/org/libreplan/business/costcategories/entities/TypeOfWorkHours.java @@ -24,9 +24,9 @@ package org.libreplan.business.costcategories.entities; import java.math.BigDecimal; import org.apache.commons.lang.StringUtils; -import org.hibernate.validator.AssertTrue; -import org.hibernate.validator.NotEmpty; -import org.hibernate.validator.NotNull; +import javax.validation.constraints.AssertTrue; +import org.hibernate.validator.constraints.NotEmpty; +import javax.validation.constraints.NotNull; import org.libreplan.business.common.IHumanIdentifiable; import org.libreplan.business.common.IntegrationEntity; import org.libreplan.business.common.Registry; @@ -126,7 +126,7 @@ public class TypeOfWorkHours extends IntegrationEntity implements IHumanIdentifi } @AssertTrue(message = "the type of work hours name has to be unique. It is already used") - public boolean checkConstraintUniqueName() { + public boolean isUniqueNameConstraint() { if (StringUtils.isBlank(name)) { return true; @@ -147,7 +147,7 @@ public class TypeOfWorkHours extends IntegrationEntity implements IHumanIdentifi } @AssertTrue(message = "type of work hours for personal timesheets cannot be disabled") - public boolean checkPersonalTimesheetsTypeOfWorkHoursNotDisabled() { + public boolean isPersonalTimesheetsTypeOfWorkHoursNotDisabledConstraint() { if (!isNewObject() && !getEnabled()) { TypeOfWorkHours typeOfWorkHours = Registry.getConfigurationDAO() .getConfiguration().getPersonalTimesheetsTypeOfWorkHours(); @@ -169,7 +169,7 @@ public class TypeOfWorkHours extends IntegrationEntity implements IHumanIdentifi } @AssertTrue(message = "type of work hours for JIRA connector cannot be disabled") - public boolean checkJiraConnectorTypeOfWorkHoursNotDisabled() { + public boolean isJiraConnectorTypeOfWorkHoursNotDisabledConstraint() { if (!isNewObject() && !getEnabled()) { Connector connector = Registry.getConnectorDAO().findUniqueByName( PredefinedConnectors.JIRA.getName()); diff --git a/libreplan-business/src/main/java/org/libreplan/business/expensesheet/entities/ExpenseSheet.java b/libreplan-business/src/main/java/org/libreplan/business/expensesheet/entities/ExpenseSheet.java index c0ebde4b3..646708a50 100644 --- a/libreplan-business/src/main/java/org/libreplan/business/expensesheet/entities/ExpenseSheet.java +++ b/libreplan-business/src/main/java/org/libreplan/business/expensesheet/entities/ExpenseSheet.java @@ -25,11 +25,11 @@ import java.util.SortedSet; import java.util.TreeSet; import org.apache.commons.lang.StringUtils; -import org.hibernate.validator.AssertTrue; -import org.hibernate.validator.Min; -import org.hibernate.validator.NotEmpty; -import org.hibernate.validator.NotNull; -import org.hibernate.validator.Valid; +import javax.validation.constraints.AssertTrue; +import javax.validation.constraints.Min; +import org.hibernate.validator.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import javax.validation.Valid; import org.joda.time.LocalDate; import org.libreplan.business.common.IHumanIdentifiable; import org.libreplan.business.common.IntegrationEntity; @@ -138,7 +138,7 @@ public class ExpenseSheet extends IntegrationEntity implements IHumanIdentifiabl } @AssertTrue(message = "The expense sheet line codes must be unique.") - public boolean checkConstraintNonRepeatedExpenseSheetLinesCodes() { + public boolean isNonRepeatedExpenseSheetLinesCodesConstraint() { return getFirstRepeatedCode(this.expenseSheetLines) == null; } @@ -239,7 +239,7 @@ public class ExpenseSheet extends IntegrationEntity implements IHumanIdentifiabl } @AssertTrue(message = "a personal expense sheet must have the same resource in all the lines") - public boolean checkConstraintPersonalExpenseSheetMustHaveTheSameResourceInAllLines() { + public boolean isPersonalExpenseSheetMustHaveTheSameResourceInAllLinesConstraint() { if (!personal) { return true; } diff --git a/libreplan-business/src/main/java/org/libreplan/business/expensesheet/entities/ExpenseSheetLine.java b/libreplan-business/src/main/java/org/libreplan/business/expensesheet/entities/ExpenseSheetLine.java index f14e7a97a..fa9ceb454 100644 --- a/libreplan-business/src/main/java/org/libreplan/business/expensesheet/entities/ExpenseSheetLine.java +++ b/libreplan-business/src/main/java/org/libreplan/business/expensesheet/entities/ExpenseSheetLine.java @@ -21,8 +21,8 @@ package org.libreplan.business.expensesheet.entities; import java.math.BigDecimal; -import org.hibernate.validator.Min; -import org.hibernate.validator.NotNull; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; import org.joda.time.LocalDate; import org.libreplan.business.common.IntegrationEntity; import org.libreplan.business.common.Registry; diff --git a/libreplan-business/src/main/java/org/libreplan/business/externalcompanies/entities/CustomerCommunication.java b/libreplan-business/src/main/java/org/libreplan/business/externalcompanies/entities/CustomerCommunication.java index 6153bec71..947c39d9f 100644 --- a/libreplan-business/src/main/java/org/libreplan/business/externalcompanies/entities/CustomerCommunication.java +++ b/libreplan-business/src/main/java/org/libreplan/business/externalcompanies/entities/CustomerCommunication.java @@ -21,8 +21,8 @@ package org.libreplan.business.externalcompanies.entities; import java.util.Date; -import org.hibernate.validator.NotEmpty; -import org.hibernate.validator.NotNull; +import org.hibernate.validator.constraints.NotEmpty; +import javax.validation.constraints.NotNull; import org.libreplan.business.common.BaseEntity; import org.libreplan.business.orders.entities.Order; diff --git a/libreplan-business/src/main/java/org/libreplan/business/externalcompanies/entities/DeadlineCommunication.java b/libreplan-business/src/main/java/org/libreplan/business/externalcompanies/entities/DeadlineCommunication.java index 8b8b39a67..8a02434e9 100644 --- a/libreplan-business/src/main/java/org/libreplan/business/externalcompanies/entities/DeadlineCommunication.java +++ b/libreplan-business/src/main/java/org/libreplan/business/externalcompanies/entities/DeadlineCommunication.java @@ -20,8 +20,8 @@ package org.libreplan.business.externalcompanies.entities; import java.util.Date; -import org.hibernate.validator.NotEmpty; -import org.hibernate.validator.NotNull; +import org.hibernate.validator.constraints.NotEmpty; +import javax.validation.constraints.NotNull; import org.libreplan.business.common.BaseEntity; /** diff --git a/libreplan-business/src/main/java/org/libreplan/business/externalcompanies/entities/ExternalCompany.java b/libreplan-business/src/main/java/org/libreplan/business/externalcompanies/entities/ExternalCompany.java index dc02ed291..3b8f7fc3d 100644 --- a/libreplan-business/src/main/java/org/libreplan/business/externalcompanies/entities/ExternalCompany.java +++ b/libreplan-business/src/main/java/org/libreplan/business/externalcompanies/entities/ExternalCompany.java @@ -22,8 +22,8 @@ package org.libreplan.business.externalcompanies.entities; import org.apache.commons.lang.StringUtils; -import org.hibernate.validator.AssertTrue; -import org.hibernate.validator.NotEmpty; +import javax.validation.constraints.AssertTrue; +import org.hibernate.validator.constraints.NotEmpty; import org.libreplan.business.common.BaseEntity; import org.libreplan.business.common.IHumanIdentifiable; import org.libreplan.business.common.Registry; @@ -147,7 +147,7 @@ public class ExternalCompany extends BaseEntity implements IHumanIdentifiable, } @AssertTrue(message="company name must be unique. Company name already used") - public boolean checkConstraintUniqueName() { + public boolean isUniqueNameConstraint() { IExternalCompanyDAO dao = Registry.getExternalCompanyDAO(); if (isNewObject()) { @@ -164,7 +164,7 @@ public class ExternalCompany extends BaseEntity implements IHumanIdentifiable, } @AssertTrue(message="Company ID already used. It must be unique") - public boolean checkConstraintUniqueNif() { + public boolean isUniqueNifConstraint() { IExternalCompanyDAO dao = Registry.getExternalCompanyDAO(); if (isNewObject()) { @@ -181,7 +181,7 @@ public class ExternalCompany extends BaseEntity implements IHumanIdentifiable, } @AssertTrue(message = "interaction fields are empty and company is marked as interact with applications") - public boolean checkConstraintInteractionFieldsNotEmptyIfNeeded() { + public boolean isInteractionFieldsNotEmptyIfNeededConstraint() { if (!interactsWithApplications) { return true; } diff --git a/libreplan-business/src/main/java/org/libreplan/business/hibernate/notification/HibernateDatabaseModificationsListener.java b/libreplan-business/src/main/java/org/libreplan/business/hibernate/notification/HibernateDatabaseModificationsListener.java index cf28045e1..49e5e4b16 100644 --- a/libreplan-business/src/main/java/org/libreplan/business/hibernate/notification/HibernateDatabaseModificationsListener.java +++ b/libreplan-business/src/main/java/org/libreplan/business/hibernate/notification/HibernateDatabaseModificationsListener.java @@ -33,25 +33,33 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.LinkedBlockingQueue; +import javax.annotation.PostConstruct; import javax.transaction.Status; import javax.transaction.Synchronization; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.hibernate.SessionFactory; import org.hibernate.Transaction; -import org.hibernate.event.AbstractEvent; -import org.hibernate.event.PostDeleteEvent; -import org.hibernate.event.PostDeleteEventListener; -import org.hibernate.event.PostInsertEvent; -import org.hibernate.event.PostInsertEventListener; -import org.hibernate.event.PostUpdateEvent; -import org.hibernate.event.PostUpdateEventListener; +import org.hibernate.event.service.spi.EventListenerRegistry; +import org.hibernate.event.spi.AbstractEvent; +import org.hibernate.event.spi.EventType; +import org.hibernate.event.spi.PostDeleteEvent; +import org.hibernate.event.spi.PostDeleteEventListener; +import org.hibernate.event.spi.PostInsertEvent; +import org.hibernate.event.spi.PostInsertEventListener; +import org.hibernate.event.spi.PostUpdateEvent; +import org.hibernate.event.spi.PostUpdateEventListener; +import org.hibernate.internal.SessionFactoryImpl; import org.hibernate.proxy.HibernateProxy; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; /** * @author Óscar González Fernández * */ +@Component public class HibernateDatabaseModificationsListener implements PostInsertEventListener, PostUpdateEventListener, PostDeleteEventListener, ISnapshotRefresherService { @@ -126,10 +134,27 @@ public class HibernateDatabaseModificationsListener implements } + @Autowired + private SessionFactory sessionFactory; + + private volatile boolean hibernateListenersRegistered = false; + public HibernateDatabaseModificationsListener() { interested = new ConcurrentHashMap, BlockingQueue>>(); } + @PostConstruct + private void registerHibernateListeners() { + SessionFactoryImpl impl = (SessionFactoryImpl) sessionFactory; + EventListenerRegistry registry = impl.getServiceRegistry().getService(EventListenerRegistry.class); + + registry.appendListeners(EventType.POST_INSERT, this); + registry.appendListeners(EventType.POST_UPDATE, this); + registry.appendListeners(EventType.POST_DELETE, this); + + hibernateListenersRegistered = true; + } + @Override public void onPostDelete(PostDeleteEvent event) { modificationOn(inferTransaction(event), @@ -202,6 +227,11 @@ public class HibernateDatabaseModificationsListener implements @Override public IAutoUpdatedSnapshot takeSnapshot(String name, Callable callable, ReloadOn reloadOn) { + if (!hibernateListenersRegistered) { + throw new IllegalStateException( + "The hibernate listeners has not been registered. There is some configuration problem."); + } + final NotBlockingAutoUpdatedSnapshot result; result = new NotBlockingAutoUpdatedSnapshot(name, callable); for (Class each : reloadOn.getClassesOnWhichToReload()) { diff --git a/libreplan-business/src/main/java/org/libreplan/business/labels/entities/Label.java b/libreplan-business/src/main/java/org/libreplan/business/labels/entities/Label.java index 9cb5886e1..3bdba5882 100644 --- a/libreplan-business/src/main/java/org/libreplan/business/labels/entities/Label.java +++ b/libreplan-business/src/main/java/org/libreplan/business/labels/entities/Label.java @@ -26,8 +26,8 @@ import java.util.HashSet; import java.util.Set; import org.apache.commons.lang.StringUtils; -import org.hibernate.validator.NotEmpty; -import org.hibernate.validator.NotNull; +import org.hibernate.validator.constraints.NotEmpty; +import javax.validation.constraints.NotNull; import org.libreplan.business.common.IntegrationEntity; import org.libreplan.business.common.Registry; import org.libreplan.business.labels.daos.ILabelDAO; diff --git a/libreplan-business/src/main/java/org/libreplan/business/labels/entities/LabelType.java b/libreplan-business/src/main/java/org/libreplan/business/labels/entities/LabelType.java index 1a4264265..644a1aba2 100644 --- a/libreplan-business/src/main/java/org/libreplan/business/labels/entities/LabelType.java +++ b/libreplan-business/src/main/java/org/libreplan/business/labels/entities/LabelType.java @@ -27,9 +27,9 @@ import java.util.Set; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.Validate; -import org.hibernate.validator.AssertTrue; -import org.hibernate.validator.NotEmpty; -import org.hibernate.validator.NotNull; +import javax.validation.constraints.AssertTrue; +import org.hibernate.validator.constraints.NotEmpty; +import javax.validation.constraints.NotNull; import org.libreplan.business.common.IHumanIdentifiable; import org.libreplan.business.common.IntegrationEntity; import org.libreplan.business.common.Registry; @@ -108,7 +108,7 @@ public class LabelType extends IntegrationEntity implements Comparable, } @AssertTrue(message = "label names must be unique inside a label type") - public boolean checkConstraintNonRepeatedLabelNames() { + public boolean isNonRepeatedLabelNamesConstraint() { Set labelNames = new HashSet(); for (Label label : labels) { @@ -125,7 +125,7 @@ public class LabelType extends IntegrationEntity implements Comparable, } @AssertTrue(message = "label type name is already in use") - public boolean checkConstraintUniqueLabelTypeName() { + public boolean isUniqueLabelTypeNameConstraint() { if (!firstLevelValidationsPassed()) { return true; } @@ -156,7 +156,7 @@ public class LabelType extends IntegrationEntity implements Comparable, } @AssertTrue(message = "label code is already being used") - public boolean checkConstraintNonRepeatedMaterialCodes() { + public boolean isNonRepeatedMaterialCodesConstraint() { return getFirstRepeatedCode(this.getLabels()) == null; } diff --git a/libreplan-business/src/main/java/org/libreplan/business/materials/entities/Material.java b/libreplan-business/src/main/java/org/libreplan/business/materials/entities/Material.java index 79ac84f40..cb4f4fb7f 100644 --- a/libreplan-business/src/main/java/org/libreplan/business/materials/entities/Material.java +++ b/libreplan-business/src/main/java/org/libreplan/business/materials/entities/Material.java @@ -24,8 +24,8 @@ package org.libreplan.business.materials.entities; import java.math.BigDecimal; import org.apache.commons.lang.StringUtils; -import org.hibernate.validator.NotEmpty; -import org.hibernate.validator.NotNull; +import org.hibernate.validator.constraints.NotEmpty; +import javax.validation.constraints.NotNull; import org.libreplan.business.common.IntegrationEntity; import org.libreplan.business.common.Registry; import org.libreplan.business.materials.bootstrap.UnitTypeBootstrap; diff --git a/libreplan-business/src/main/java/org/libreplan/business/materials/entities/MaterialAssignment.java b/libreplan-business/src/main/java/org/libreplan/business/materials/entities/MaterialAssignment.java index 82144d63a..d155f44a7 100644 --- a/libreplan-business/src/main/java/org/libreplan/business/materials/entities/MaterialAssignment.java +++ b/libreplan-business/src/main/java/org/libreplan/business/materials/entities/MaterialAssignment.java @@ -24,7 +24,7 @@ package org.libreplan.business.materials.entities; import java.math.BigDecimal; import java.util.Date; -import org.hibernate.validator.Valid; +import javax.validation.Valid; import org.libreplan.business.common.BaseEntity; import org.libreplan.business.orders.entities.OrderElement; diff --git a/libreplan-business/src/main/java/org/libreplan/business/materials/entities/MaterialCategory.java b/libreplan-business/src/main/java/org/libreplan/business/materials/entities/MaterialCategory.java index 9e9a8be06..292c216e9 100644 --- a/libreplan-business/src/main/java/org/libreplan/business/materials/entities/MaterialCategory.java +++ b/libreplan-business/src/main/java/org/libreplan/business/materials/entities/MaterialCategory.java @@ -29,10 +29,10 @@ import java.util.List; import java.util.Set; import org.apache.commons.lang.StringUtils; -import org.hibernate.validator.AssertTrue; -import org.hibernate.validator.NotEmpty; -import org.hibernate.validator.NotNull; -import org.hibernate.validator.Valid; +import javax.validation.constraints.AssertTrue; +import org.hibernate.validator.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import javax.validation.Valid; import org.libreplan.business.common.IntegrationEntity; import org.libreplan.business.common.Registry; import org.libreplan.business.common.entities.EntitySequence; @@ -151,7 +151,7 @@ public class MaterialCategory extends IntegrationEntity { } @AssertTrue(message="material category name has to be unique. It is already used") - public boolean checkConstraintUniqueName() { + public boolean isUniqueNameConstraint() { boolean result; if (isNewObject()) { result = !existsMaterialCategoryWithTheName(); @@ -220,7 +220,7 @@ public class MaterialCategory extends IntegrationEntity { @SuppressWarnings("unused") @AssertTrue(message = "Subcategory names must be unique.") - public boolean checkConstraintUniqueSubcategoryName() { + public boolean isUniqueSubcategoryNameConstraint() { Set subcategoriesNames = new HashSet(); for (MaterialCategory mc : this.getAllSubcategories()) { if (!StringUtils.isBlank(mc.getName())) { @@ -237,7 +237,7 @@ public class MaterialCategory extends IntegrationEntity { } @AssertTrue(message = "There are repeated material category codes") - public boolean checkConstraintNonRepeatedMaterialCategoryCodes() { + public boolean isNonRepeatedMaterialCategoryCodesConstraint() { Set allSubcategories = getAllSubcategories(); allSubcategories.add(this); return getFirstRepeatedCode(allSubcategories) == null; @@ -252,7 +252,7 @@ public class MaterialCategory extends IntegrationEntity { } @AssertTrue(message = "There are repeated material codes") - public boolean checkConstraintNonRepeatedMaterialCodes() { + public boolean isNonRepeatedMaterialCodesConstraint() { Set allMaterials = getAllMaterials(); return getFirstRepeatedCode(allMaterials) == null; } diff --git a/libreplan-business/src/main/java/org/libreplan/business/materials/entities/MaterialInfo.java b/libreplan-business/src/main/java/org/libreplan/business/materials/entities/MaterialInfo.java index 3fb8cedb1..f6c1cd7fc 100644 --- a/libreplan-business/src/main/java/org/libreplan/business/materials/entities/MaterialInfo.java +++ b/libreplan-business/src/main/java/org/libreplan/business/materials/entities/MaterialInfo.java @@ -22,7 +22,7 @@ package org.libreplan.business.materials.entities; import java.math.BigDecimal; -import org.hibernate.validator.NotNull; +import javax.validation.constraints.NotNull; /** * @author Óscar González Fernández diff --git a/libreplan-business/src/main/java/org/libreplan/business/materials/entities/UnitType.java b/libreplan-business/src/main/java/org/libreplan/business/materials/entities/UnitType.java index 7f8dcb7e2..668f54a5b 100644 --- a/libreplan-business/src/main/java/org/libreplan/business/materials/entities/UnitType.java +++ b/libreplan-business/src/main/java/org/libreplan/business/materials/entities/UnitType.java @@ -22,8 +22,8 @@ package org.libreplan.business.materials.entities; import org.apache.commons.lang.StringUtils; -import org.hibernate.validator.AssertTrue; -import org.hibernate.validator.NotEmpty; +import javax.validation.constraints.AssertTrue; +import org.hibernate.validator.constraints.NotEmpty; import org.libreplan.business.common.IHumanIdentifiable; import org.libreplan.business.common.IntegrationEntity; import org.libreplan.business.common.Registry; @@ -83,7 +83,7 @@ public class UnitType extends IntegrationEntity implements IHumanIdentifiable { } @AssertTrue(message = "the measure has to be unique") - public boolean checkConstraintUniqueName() { + public boolean isUniqueNameConstraint() { if (StringUtils.isBlank(measure)) { return true; } diff --git a/libreplan-business/src/main/java/org/libreplan/business/orders/entities/HoursGroup.java b/libreplan-business/src/main/java/org/libreplan/business/orders/entities/HoursGroup.java index 331479adb..5e311abf6 100644 --- a/libreplan-business/src/main/java/org/libreplan/business/orders/entities/HoursGroup.java +++ b/libreplan-business/src/main/java/org/libreplan/business/orders/entities/HoursGroup.java @@ -31,11 +31,12 @@ import java.util.Map; import java.util.Set; import java.util.UUID; +import javax.validation.Valid; +import javax.validation.constraints.NotNull; + import org.apache.commons.lang.Validate; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.hibernate.validator.NotNull; -import org.hibernate.validator.Valid; import org.libreplan.business.common.IntegrationEntity; import org.libreplan.business.common.Registry; import org.libreplan.business.common.daos.IIntegrationEntityDAO; @@ -399,7 +400,7 @@ public class HoursGroup extends IntegrationEntity implements Cloneable, } @Override - public boolean checkConstraintUniqueCode() { + public boolean isUniqueCodeConstraint() { // the automatic checking of this constraint is avoided because it uses // the wrong code property return true; diff --git a/libreplan-business/src/main/java/org/libreplan/business/orders/entities/Order.java b/libreplan-business/src/main/java/org/libreplan/business/orders/entities/Order.java index 0bc205fd1..1789d2fd8 100644 --- a/libreplan-business/src/main/java/org/libreplan/business/orders/entities/Order.java +++ b/libreplan-business/src/main/java/org/libreplan/business/orders/entities/Order.java @@ -33,11 +33,12 @@ import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; +import javax.validation.Valid; +import javax.validation.constraints.AssertTrue; +import javax.validation.constraints.NotNull; + import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.Validate; -import org.hibernate.validator.AssertTrue; -import org.hibernate.validator.NotNull; -import org.hibernate.validator.Valid; import org.libreplan.business.advance.bootstrap.PredefinedAdvancedTypes; import org.libreplan.business.advance.entities.AdvanceType; import org.libreplan.business.advance.entities.DirectAdvanceAssignment; @@ -351,27 +352,27 @@ public class Order extends OrderLineGroup implements Comparable { @SuppressWarnings("unused") @AssertTrue(message = "the project must have a start date") - private boolean ifSchedulingModeIsForwardOrderMustHaveStartDate() { + private boolean isIfSchedulingModeIsForwardOrderMustHaveStartDateConstraint() { return getSchedulingMode() != SchedulingMode.FORWARD || getInitDate() != null; } @SuppressWarnings("unused") @AssertTrue(message = "the project must have a deadline") - private boolean ifSchedulingModeIsBackwardsOrderMustHaveDeadline() { + private boolean isIfSchedulingModeIsBackwardsOrderMustHaveDeadlineConstraint() { return getSchedulingMode() != SchedulingMode.BACKWARDS || getDeadline() != null; } @SuppressWarnings("unused") @AssertTrue(message = "deadline must be after start date") - private boolean checkConstraintDeadlineMustBeAfterStart() { + private boolean isDeadlineMustBeAfterStartConstraint() { return getInitDate() == null || !this.isDeadlineBeforeStart(); } @SuppressWarnings("unused") @AssertTrue(message = "At least one hours group is needed for each task") - private boolean checkConstraintAtLeastOneHoursGroupForEachOrderElement() { + private boolean isAtLeastOneHoursGroupForEachOrderElementConstraint() { for (OrderElement orderElement : this.getOrderElements()) { if (!orderElement.checkAtLeastOneHoursGroup()) { return false; @@ -578,7 +579,7 @@ public class Order extends OrderLineGroup implements Comparable { } @AssertTrue(message = "project name is already being used") - public boolean checkConstraintProjectUniqueName() { + public boolean isProjectUniqueNameConstraint() { IOrderDAO orderDAO = Registry.getOrderDAO(); @@ -696,7 +697,7 @@ public class Order extends OrderLineGroup implements Comparable { } @AssertTrue(message = "task code is repeated inside the project") - public boolean checkConstraintUniqueCodeInsideOrder() { + public boolean isUniqueCodeInsideOrderConstraint() { List codes = new ArrayList(); codes.add(getCode()); diff --git a/libreplan-business/src/main/java/org/libreplan/business/orders/entities/OrderElement.java b/libreplan-business/src/main/java/org/libreplan/business/orders/entities/OrderElement.java index 4268632cf..3fbf8ac7b 100644 --- a/libreplan-business/src/main/java/org/libreplan/business/orders/entities/OrderElement.java +++ b/libreplan-business/src/main/java/org/libreplan/business/orders/entities/OrderElement.java @@ -34,12 +34,12 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Set; +import javax.validation.Valid; +import javax.validation.constraints.AssertTrue; + import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.Validate; -import org.hibernate.validator.AssertTrue; -import org.hibernate.validator.InvalidValue; -import org.hibernate.validator.NotEmpty; -import org.hibernate.validator.Valid; +import org.hibernate.validator.constraints.NotEmpty; import org.joda.time.LocalDate; import org.libreplan.business.advance.bootstrap.PredefinedAdvancedTypes; import org.libreplan.business.advance.entities.AdvanceAssignment; @@ -1160,22 +1160,22 @@ public abstract class OrderElement extends IntegrationEntity implements Validate.notNull(qualityForm); for (TaskQualityForm taskQualityForm : getTaskQualityForms()) { if (qualityForm.equals(taskQualityForm.getQualityForm())) { - throw new ValidationException(new InvalidValue( - _("Quality form already exists"), QualityForm.class, - "name", qualityForm.getName(), qualityForm)); + throw new ValidationException(ValidationException.invalidValue( + _("Quality form already exists"), "name", + qualityForm.getName(), qualityForm)); } } } @Override - public boolean checkConstraintUniqueCode() { + public boolean isUniqueCodeConstraint() { // the automatic checking of this constraint is avoided because it uses // the wrong code property return true; } @AssertTrue(message = "code is already used in another project") - public boolean checkConstraintCodeRepeatedInAnotherOrder() { + public boolean isCodeRepeatedInAnotherOrderConstraint() { if (StringUtils.isBlank(getCode())) { return true; } @@ -1185,7 +1185,7 @@ public abstract class OrderElement extends IntegrationEntity implements } @AssertTrue(message = "a label can not be assigned twice in the same branch") - public boolean checkConstraintLabelNotRepeatedInTheSameBranch() { + public boolean isLabelNotRepeatedInTheSameBranchConstraint() { return checkConstraintLabelNotRepeatedInTheSameBranch(new HashSet