diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/common/IntegrationEntity.java b/navalplanner-business/src/main/java/org/navalplanner/business/common/IntegrationEntity.java
index ba7046365..8c070e774 100644
--- a/navalplanner-business/src/main/java/org/navalplanner/business/common/IntegrationEntity.java
+++ b/navalplanner-business/src/main/java/org/navalplanner/business/common/IntegrationEntity.java
@@ -20,6 +20,8 @@
package org.navalplanner.business.common;
+import java.util.HashSet;
+import java.util.Set;
import java.util.UUID;
import org.apache.commons.lang.StringUtils;
@@ -123,6 +125,35 @@ public abstract class IntegrationEntity extends BaseEntity {
}
+ /**
+ * It returns the first repeated code in the entities received as a
+ * parameter. If none is repeated, it returns null.
+ * Concrete entities may use this method to implement validation rules
+ * for detecting repeated codes in dependent entities.
+ */
+ protected String getFirstRepeatedCode(
+ Set extends IntegrationEntity> entities) {
+
+ Set codes = new HashSet();
+
+ for (IntegrationEntity e : entities) {
+
+ String code = e.getCode();
+
+ if (!StringUtils.isBlank(code)) {
+ if (codes.contains(code.toLowerCase())) {
+ return code;
+ } else {
+ codes.add(code.toLowerCase());
+ }
+ }
+
+ }
+
+ return null;
+
+ }
+
/**
* It returns the DAO of this entity.
*/
diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/common/daos/IIntegrationEntityDAO.java b/navalplanner-business/src/main/java/org/navalplanner/business/common/daos/IIntegrationEntityDAO.java
index 3a0db691f..862470b38 100644
--- a/navalplanner-business/src/main/java/org/navalplanner/business/common/daos/IIntegrationEntityDAO.java
+++ b/navalplanner-business/src/main/java/org/navalplanner/business/common/daos/IIntegrationEntityDAO.java
@@ -20,6 +20,8 @@
package org.navalplanner.business.common.daos;
+import java.util.List;
+
import org.navalplanner.business.common.IntegrationEntity;
import org.navalplanner.business.common.exceptions.InstanceNotFoundException;
@@ -60,4 +62,9 @@ public interface IIntegrationEntityDAO
public E findExistingEntityByCode(String code);
+ /**
+ * It returns all entities ordered by ascending code.
+ */
+ public List findAll();
+
}
diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/common/daos/IntegrationEntityDAO.java b/navalplanner-business/src/main/java/org/navalplanner/business/common/daos/IntegrationEntityDAO.java
index 2c65dca70..8317def3c 100644
--- a/navalplanner-business/src/main/java/org/navalplanner/business/common/daos/IntegrationEntityDAO.java
+++ b/navalplanner-business/src/main/java/org/navalplanner/business/common/daos/IntegrationEntityDAO.java
@@ -20,7 +20,10 @@
package org.navalplanner.business.common.daos;
+import java.util.List;
+
import org.apache.commons.lang.StringUtils;
+import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.navalplanner.business.common.IntegrationEntity;
import org.navalplanner.business.common.exceptions.InstanceNotFoundException;
@@ -95,4 +98,11 @@ public class IntegrationEntityDAO
}
+ @SuppressWarnings("unchecked")
+ @Override
+ public List findAll() {
+ return getSession().createCriteria(getEntityClass()).
+ addOrder(Order.asc("code")).list();
+ }
+
}
diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/resources/daos/CriterionTypeDAO.java b/navalplanner-business/src/main/java/org/navalplanner/business/resources/daos/CriterionTypeDAO.java
index a1786aef9..3743bbc9a 100644
--- a/navalplanner-business/src/main/java/org/navalplanner/business/resources/daos/CriterionTypeDAO.java
+++ b/navalplanner-business/src/main/java/org/navalplanner/business/resources/daos/CriterionTypeDAO.java
@@ -45,22 +45,6 @@ import org.springframework.transaction.annotation.Transactional;
public class CriterionTypeDAO extends IntegrationEntityDAO
implements ICriterionTypeDAO {
- @Override
- @Transactional(readOnly = true, propagation = Propagation.REQUIRES_NEW)
- public CriterionType findByCodeAnotherTransactionInitialized(
- String code) throws InstanceNotFoundException {
-
- CriterionType criterionType = findByCode(code);
-
- for (Criterion c : criterionType.getCriterions()) {
- c.getChildren().size();
- c.getType().getName();
- }
-
- return criterionType;
-
- }
-
@Override
public List findByName(CriterionType criterionType) {
Criteria c = getSession().createCriteria(CriterionType.class);
diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/resources/daos/ICriterionTypeDAO.java b/navalplanner-business/src/main/java/org/navalplanner/business/resources/daos/ICriterionTypeDAO.java
index beb1cdf9d..e39f93767 100644
--- a/navalplanner-business/src/main/java/org/navalplanner/business/resources/daos/ICriterionTypeDAO.java
+++ b/navalplanner-business/src/main/java/org/navalplanner/business/resources/daos/ICriterionTypeDAO.java
@@ -36,9 +36,6 @@ import org.navalplanner.business.resources.entities.ResourceEnum;
public interface ICriterionTypeDAO
extends IIntegrationEntityDAO {
- CriterionType findByCodeAnotherTransactionInitialized(String code)
- throws InstanceNotFoundException;
-
CriterionType findUniqueByName(String name)
throws InstanceNotFoundException;
diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/resources/entities/CriterionType.java b/navalplanner-business/src/main/java/org/navalplanner/business/resources/entities/CriterionType.java
index 81129edb8..5cd7e2346 100644
--- a/navalplanner-business/src/main/java/org/navalplanner/business/resources/entities/CriterionType.java
+++ b/navalplanner-business/src/main/java/org/navalplanner/business/resources/entities/CriterionType.java
@@ -346,6 +346,12 @@ public class CriterionType extends IntegrationEntity implements
}
+ @AssertTrue(message="criterion codes must be unique inside a criterion " +
+ "type")
+ public boolean checkConstraintNonRepeatedCriterionCodes() {
+ return getFirstRepeatedCode(criterions) == null;
+ }
+
@AssertTrue(message="criterion names must be unique inside a criterion " +
"type")
public boolean checkConstraintNonRepeatedCriterionNames() {
diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/ws/common/api/DuplicateCodeBeingImportedException.java b/navalplanner-webapp/src/main/java/org/navalplanner/ws/common/api/DuplicateCodeBeingImportedException.java
deleted file mode 100644
index 16b9cd72c..000000000
--- a/navalplanner-webapp/src/main/java/org/navalplanner/ws/common/api/DuplicateCodeBeingImportedException.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * This file is part of NavalPlan
- *
- * Copyright (C) 2009 Fundación para o Fomento da Calidade Industrial e
- * Desenvolvemento Tecnolóxico de Galicia
- *
- * 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.navalplanner.ws.common.api;
-
-/**
- * An exception for notifying that an instance is already being imported in
- * a bulk import because it has a code used by another instance of the same
- * type.
- *
- * @author Fernando Bellas Permuy
- */
-@SuppressWarnings("serial")
-public class DuplicateCodeBeingImportedException
- extends DuplicateInstanceBeingImportedException {
-
- private String code;
-
- public DuplicateCodeBeingImportedException(String instanceType,
- String code) {
-
- super(instanceType);
- this.code = code;
- }
-
- public String getCode() {
- return code;
- }
-
-}
diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/ws/common/api/DuplicateInstanceBeingImportedException.java b/navalplanner-webapp/src/main/java/org/navalplanner/ws/common/api/DuplicateInstanceBeingImportedException.java
deleted file mode 100644
index 26727d8cd..000000000
--- a/navalplanner-webapp/src/main/java/org/navalplanner/ws/common/api/DuplicateInstanceBeingImportedException.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * This file is part of NavalPlan
- *
- * Copyright (C) 2009 Fundación para o Fomento da Calidade Industrial e
- * Desenvolvemento Tecnolóxico de Galicia
- *
- * 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.navalplanner.ws.common.api;
-
-/**
- * An exception for notifying that an instance is already being imported in
- * a bulk import.
- *
- * @author Fernando Bellas Permuy
- */
-@SuppressWarnings("serial")
-public class DuplicateInstanceBeingImportedException extends Exception {
-
- private String entityType;
-
- public DuplicateInstanceBeingImportedException(String entityType) {
- this.entityType = entityType;
- }
-
- public String getEntityType() {
- return entityType;
- }
-
-}
diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/ws/common/api/DuplicateNaturalKeyBeingImportedException.java b/navalplanner-webapp/src/main/java/org/navalplanner/ws/common/api/DuplicateNaturalKeyBeingImportedException.java
deleted file mode 100644
index 9e1a4bbe4..000000000
--- a/navalplanner-webapp/src/main/java/org/navalplanner/ws/common/api/DuplicateNaturalKeyBeingImportedException.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * This file is part of NavalPlan
- *
- * Copyright (C) 2009 Fundación para o Fomento da Calidade Industrial e
- * Desenvolvemento Tecnolóxico de Galicia
- *
- * 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.navalplanner.ws.common.api;
-
-/**
- * An exception for notifying that an instance is already being imported in
- * a bulk import because it has a natural key used by another instance of the
- * same type.
- *
- * @author Fernando Bellas Permuy
- */
-@SuppressWarnings("serial")
-public class DuplicateNaturalKeyBeingImportedException
- extends DuplicateInstanceBeingImportedException {
-
- private String[] naturalKeyValues;
-
- public DuplicateNaturalKeyBeingImportedException(String instanceType,
- String[] naturalKeyValues) {
-
- super(instanceType);
- this.naturalKeyValues = naturalKeyValues;
-
- }
-
- public String[] getNaturalKeyValues() {
- return naturalKeyValues;
- }
-
-}
diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/ws/common/api/InstanceConstraintViolationsDTO.java b/navalplanner-webapp/src/main/java/org/navalplanner/ws/common/api/InstanceConstraintViolationsDTO.java
index 42a105b82..92bdb771f 100644
--- a/navalplanner-webapp/src/main/java/org/navalplanner/ws/common/api/InstanceConstraintViolationsDTO.java
+++ b/navalplanner-webapp/src/main/java/org/navalplanner/ws/common/api/InstanceConstraintViolationsDTO.java
@@ -27,6 +27,7 @@ import java.util.List;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
/**
* DTO for modeling the list of constraint violations on a given instance.
@@ -56,9 +57,13 @@ public class InstanceConstraintViolationsDTO {
@XmlAttribute(name=ENTITY_TYPE_ATTRIBUTE_NAME)
public String entityType;
+ @XmlElementWrapper(name="constraint-violations")
@XmlElement(name="constraint-violation")
public List constraintViolations;
+ @XmlElement(name="internal-error")
+ public InternalErrorDTO internalError;
+
public InstanceConstraintViolationsDTO() {}
@Deprecated
@@ -70,17 +75,33 @@ public class InstanceConstraintViolationsDTO {
}
- public InstanceConstraintViolationsDTO(
- InstanceConstraintViolationsDTOId instanceId,
- List constraintViolations) {
+ private InstanceConstraintViolationsDTO(
+ InstanceConstraintViolationsDTOId instanceId) {
this.numItem = instanceId.getNumItem();
this.code = instanceId.getCode();
this.entityType = instanceId.getEntityType();
+
+ }
+
+ public InstanceConstraintViolationsDTO(
+ InstanceConstraintViolationsDTOId instanceId,
+ List constraintViolations) {
+
+ this(instanceId);
this.constraintViolations = constraintViolations;
}
+ public InstanceConstraintViolationsDTO(
+ InstanceConstraintViolationsDTOId instanceId,
+ InternalErrorDTO internalError) {
+
+ this(instanceId);
+ this.internalError = internalError;
+
+ }
+
@Deprecated
public static InstanceConstraintViolationsDTO create(String instanceId,
String message) {
diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/ws/common/api/IntegrationEntityDTO.java b/navalplanner-webapp/src/main/java/org/navalplanner/ws/common/api/IntegrationEntityDTO.java
index 266fdca25..44b632f20 100644
--- a/navalplanner-webapp/src/main/java/org/navalplanner/ws/common/api/IntegrationEntityDTO.java
+++ b/navalplanner-webapp/src/main/java/org/navalplanner/ws/common/api/IntegrationEntityDTO.java
@@ -20,28 +20,13 @@
package org.navalplanner.ws.common.api;
-import java.util.Set;
import java.util.UUID;
import javax.xml.bind.annotation.XmlAttribute;
-import org.apache.commons.lang.StringUtils;
-
/**
* DTO for IntegrationEntity. All DTOs corresponding to entities
* to be used in application integration must extend from this DTO.
- *
- *
- * All entities must redefine getEntityType(). Additionally,
- * entities that can be bulk imported may need to redefine the following
- * methods (ordered by probability of being redefined):
- *
- * getNaturalKeyValues().
- * checkDuplicateCode().
- * getUniversalCodePrefix().
- * getUniversalNaturalKeyPrefix().
- * checkDuplicateNaturalKey().
- *
*
* @author Fernando Bellas Permuy
*/
@@ -64,93 +49,6 @@ public abstract class IntegrationEntityDTO {
*/
public abstract String getEntityType();
- /**
- * It returns the prefix specified in getUniversalCode(). The
- * default implementation returns the same value as
- * getEntityType(). Entities that can be bulk imported, and
- * that have derived entities, must redefine this method to return the
- * same String for all child entities if they share the code space.
- */
- protected String getUniversalCodePrefix() {
- return getEntityType();
- }
-
- /**
- * It returns the prefix specified in getUniversalNaturalKey().
- * The default implementation returns the same value as
- * getEntityType(). Entities that can be bulk imported, and
- * that have derived entities, must redefine this method to return the
- * same String for all child entities if they share the natural key space.
- */
- protected String getUniversalNaturalKeyPrefix() {
- return getEntityType();
- }
-
- /**
- * It returns the values (as String) of the fields that represent the
- * natural key. If the entity has no natural key fields, it must return
- * null or an empty array. The default implementation
- * returns null. Entities, with natural key, that can be bulk
- * imported must redefine this method.
- */
- protected String[] getNaturalKeyValues() {
- return null;
- }
-
- /**
- * It checks if this entity or one its contained entities has a code
- * (the entity code is obtained by calling on
- * getUniversalCode()) contained in the set of keys passed as
- * a parameter. If the code is not contained, it is added to the set of
- * keys. No other class should manipulate this set. Comparison is case
- * insensitive and leading and trailing whitespace is discarded. If the
- * code is whitespace, empty ("") or null, the check is
- * considered OK (and the code is not added to the set of existing keys).
- *
- *
- * The default implementation only provides this semantics for the
- * container (this) entity. Entities, with contained entities, that can be
- * bulk imported must redefine this method to apply it recursively to their
- * contained entities.
- */
- public void checkDuplicateCode(Set existingKeys)
- throws DuplicateCodeBeingImportedException {
-
- if (containsKeyAndAdd(existingKeys, getUniversalCode())) {
- throw new DuplicateCodeBeingImportedException(getEntityType(),
- code);
- }
-
- }
-
- /**
- * It checks if this entity or one its contained entities has a natural key
- * (the entity natural key is obtained by calling on
- * getUniversalNaturalKey()) contained in the set of keys
- * passed as a parameter. If the natural key is not contained, it is added
- * to the set of keys. No other class should manipulate this set.
- * Comparison is case insensitive and leading and trailing whitespace is
- * discarded. If some value of the natural key is whitespace, empty ("") or
- * null, the check is considered OK (and the natural key is
- * not added to the set of existing keys).
- *
- *
- * The default implementation only provides this semantics for the
- * container entity. Entities that can be bulk imported could be interested
- * in redefining this method. However, the default implementation is
- * probably good enough for them, since probably only the container
- * entities will have natural keys.
- */
- public void checkDuplicateNaturalKey(Set existingKeys)
- throws DuplicateNaturalKeyBeingImportedException {
-
- if (containsKeyAndAdd(existingKeys, getUniversalNaturalKey())) {
- throw new DuplicateNaturalKeyBeingImportedException(getEntityType(),
- getNaturalKeyValues());
- }
-
- }
-
/**
* This method is useful to implement constructors (in subclasses) that
* automatically generate a unique code. Such constructors are useful for
@@ -161,76 +59,4 @@ public abstract class IntegrationEntityDTO {
return UUID.randomUUID().toString();
}
- /**
- * It returns a String with the format
- * getUniversalCodePrefix().code.<>, or
- * null if code is whitespace, empty ("") or
- * null.
- */
- private String getUniversalCode() {
-
- if (!StringUtils.isBlank(code)) {
- return getUniversalCodePrefix() + ".code." + StringUtils.trim(code);
- } else {
- return null;
- }
-
- }
-
- /**
- * It returns a String with the format
- * getUniversalNaturalKeyPrefix().naturalkey.<>,
- * or null if some natural key value is whitespace, empty ("")
- * or null.
- */
- protected final String getUniversalNaturalKey() {
-
- String[] naturalKeyValues = getNaturalKeyValues();
-
- if (naturalKeyValues == null || naturalKeyValues.length == 0) {
- return null;
- }
-
- String universalNaturalKey = getUniversalNaturalKeyPrefix() +
- ".natural-key.";
-
- for (String k : naturalKeyValues) {
-
- if (StringUtils.isBlank(k)) {
- return null;
- }
-
- universalNaturalKey += StringUtils.trim(k);
-
- }
-
- return universalNaturalKey;
-
- }
-
- /**
- * It checks if a key is contained in a set of existing keys. If not
- * contained, the key is added to the set of existing keys. Comparison is
- * case insensitive and leading and trailing whitespace is discarded. If
- * the key is whitespace, empty ("") or null, it
- * returns false (and the key is not added to the set of
- * existing keys).
- */
- protected boolean containsKeyAndAdd(Set existingKeys, String newKey) {
-
- if (StringUtils.isBlank(newKey)) {
- return false;
- }
-
- String key = StringUtils.trim(newKey).toLowerCase();
-
- if (!existingKeys.contains(key)) {
- existingKeys.add(key);
- return false;
- }
-
- return true;
-
- }
-
}
diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/ws/common/impl/ConstraintViolationConverter.java b/navalplanner-webapp/src/main/java/org/navalplanner/ws/common/impl/ConstraintViolationConverter.java
index db4498def..853d91bd8 100644
--- a/navalplanner-webapp/src/main/java/org/navalplanner/ws/common/impl/ConstraintViolationConverter.java
+++ b/navalplanner-webapp/src/main/java/org/navalplanner/ws/common/impl/ConstraintViolationConverter.java
@@ -28,6 +28,7 @@ import org.navalplanner.business.common.exceptions.ValidationException;
import org.navalplanner.ws.common.api.ConstraintViolationDTO;
import org.navalplanner.ws.common.api.InstanceConstraintViolationsDTO;
import org.navalplanner.ws.common.api.InstanceConstraintViolationsDTOId;
+import org.navalplanner.ws.common.api.InternalErrorDTO;
/**
* Converter for constraint violations.
@@ -114,4 +115,17 @@ public class ConstraintViolationConverter {
}
+ public final static InstanceConstraintViolationsDTO toDTO(
+ InstanceConstraintViolationsDTOId instanceId,
+ RuntimeException runtimeException) {
+
+ InternalErrorDTO internalErrorDTO = new InternalErrorDTO(
+ runtimeException.getMessage(),
+ Util.getStackTrace(runtimeException));
+
+ return new InstanceConstraintViolationsDTO(instanceId,
+ internalErrorDTO);
+
+ }
+
}
diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/ws/common/impl/GenericRESTService.java b/navalplanner-webapp/src/main/java/org/navalplanner/ws/common/impl/GenericRESTService.java
new file mode 100644
index 000000000..d65d0e1be
--- /dev/null
+++ b/navalplanner-webapp/src/main/java/org/navalplanner/ws/common/impl/GenericRESTService.java
@@ -0,0 +1,183 @@
+/*
+ * This file is part of ###PROJECT_NAME###
+ *
+ * Copyright (C) 2009 Fundación para o Fomento da Calidade Industrial e
+ * Desenvolvemento Tecnolóxico de Galicia
+ *
+ * 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.navalplanner.ws.common.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.navalplanner.business.common.IAdHocTransactionService;
+import org.navalplanner.business.common.IOnTransaction;
+import org.navalplanner.business.common.IntegrationEntity;
+import org.navalplanner.business.common.daos.IIntegrationEntityDAO;
+import org.navalplanner.business.common.exceptions.InstanceNotFoundException;
+import org.navalplanner.business.common.exceptions.ValidationException;
+import org.navalplanner.ws.common.api.InstanceConstraintViolationsDTO;
+import org.navalplanner.ws.common.api.InstanceConstraintViolationsListDTO;
+import org.navalplanner.ws.common.api.IntegrationEntityDTO;
+import org.springframework.beans.factory.annotation.Autowired;
+
+/**
+ * This class provides generic support for implementing REST services
+ * as subclasses of this. .
+ *
+ * @author Fernando Bellas Permuy
+ */
+public abstract class GenericRESTService {
+
+ @Autowired
+ private IAdHocTransactionService transactionService;
+
+ /**
+ * It retrieves all entities.
+ */
+ protected List findAll() {
+ return toDTO(getIntegrationEntityDAO().findAll());
+ }
+
+ /**
+ * It saves (inserts or updates) a list of entities. Each entity is
+ * saved in a separate transaction.
+ */
+ protected InstanceConstraintViolationsListDTO save(List entityDTOs) {
+
+ List instanceConstraintViolationsList =
+ new ArrayList();
+ Long numItem = new Long(1);
+
+ for (DTO entityDTO : entityDTOs) {
+
+ InstanceConstraintViolationsDTO instanceConstraintViolationsDTO =
+ null;
+
+ try {
+ insertOrUpdate(entityDTO);
+ } catch (ValidationException e) {
+ instanceConstraintViolationsDTO =
+ ConstraintViolationConverter.toDTO(
+ Util.generateInstanceConstraintViolationsDTOId(
+ numItem, entityDTO), e);
+ } catch (RuntimeException e) {
+ instanceConstraintViolationsDTO =
+ ConstraintViolationConverter.toDTO(
+ Util.generateInstanceConstraintViolationsDTOId(
+ numItem, entityDTO), e);
+ }
+
+ if (instanceConstraintViolationsDTO != null) {
+ instanceConstraintViolationsList.add(
+ instanceConstraintViolationsDTO);
+ }
+
+ numItem++;
+
+ }
+
+ return new InstanceConstraintViolationsListDTO(
+ instanceConstraintViolationsList);
+
+ }
+
+ /**
+ * It saves (inserts or updates) an entity DTO by using a new transaction.
+ *
+ * @throws ValidationException if validations are not passed
+ */
+ protected void insertOrUpdate(final DTO entityDTO)
+ throws ValidationException {
+
+ IOnTransaction save = new IOnTransaction() {
+
+ @Override
+ public Void execute() {
+
+ E entity = null;
+ IIntegrationEntityDAO entityDAO =
+ getIntegrationEntityDAO();
+
+ /* Insert or update? */
+ try {
+ entity = entityDAO.findByCode(entityDTO.code);
+ updateEntity(entity, entityDTO);
+ } catch (InstanceNotFoundException e) {
+ entity = toEntity(entityDTO);
+ }
+
+ /*
+ * Save the entity (insert or update). If validations are
+ * not passed (they are automatically executed by
+ * GenericDAO::save), the transaction is rolled back since
+ * ValidationException is a runtime exception, automatically
+ * discarding any change made to the entity.
+ *
+ */
+ entityDAO.save(entity);
+
+ return null;
+
+ }
+
+ };
+
+ transactionService.runOnAnotherTransaction(save);
+
+ }
+
+ /**
+ * It creates an entity from a DTO.
+ */
+ protected abstract E toEntity(DTO entityDTO);
+
+ /**
+ * It creates a DTO from an entity.
+ */
+ protected abstract DTO toDTO(E entity);
+
+ /**
+ * It must return the DAO for the entity "E".
+ */
+ protected abstract IIntegrationEntityDAO
+ getIntegrationEntityDAO();
+
+ /**
+ * It must update the entity from the DTO.
+ *
+ * @throws ValidationException if updating is not possible
+ */
+ protected abstract void updateEntity(E entity, DTO entityDTO)
+ throws ValidationException;
+
+ /**
+ * It returns a list of DTOs from a list of entities.
+ */
+ protected List toDTO(List entities) {
+
+ List dtos = new ArrayList();
+
+ for (E entity : entities) {
+ dtos.add(toDTO(entity));
+ }
+
+ return dtos;
+
+ }
+
+}
diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/ws/resources/criterion/api/CriterionDTO.java b/navalplanner-webapp/src/main/java/org/navalplanner/ws/resources/criterion/api/CriterionDTO.java
index 4a42e7d4c..f8b636dc0 100644
--- a/navalplanner-webapp/src/main/java/org/navalplanner/ws/resources/criterion/api/CriterionDTO.java
+++ b/navalplanner-webapp/src/main/java/org/navalplanner/ws/resources/criterion/api/CriterionDTO.java
@@ -22,13 +22,11 @@ package org.navalplanner.ws.resources.criterion.api;
import java.util.ArrayList;
import java.util.List;
-import java.util.Set;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
-import org.navalplanner.ws.common.api.DuplicateCodeBeingImportedException;
import org.navalplanner.ws.common.api.IntegrationEntityDTO;
/**
@@ -79,16 +77,4 @@ public class CriterionDTO extends IntegrationEntityDTO {
return ENTITY_TYPE;
}
- @Override
- public void checkDuplicateCode(Set existingKeys)
- throws DuplicateCodeBeingImportedException {
-
- super.checkDuplicateCode(existingKeys);
-
- for (CriterionDTO c : children) {
- c.checkDuplicateCode(existingKeys);
- }
-
- }
-
}
diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/ws/resources/criterion/api/CriterionTypeDTO.java b/navalplanner-webapp/src/main/java/org/navalplanner/ws/resources/criterion/api/CriterionTypeDTO.java
index 47d443b68..e5e8d8359 100644
--- a/navalplanner-webapp/src/main/java/org/navalplanner/ws/resources/criterion/api/CriterionTypeDTO.java
+++ b/navalplanner-webapp/src/main/java/org/navalplanner/ws/resources/criterion/api/CriterionTypeDTO.java
@@ -22,13 +22,11 @@ package org.navalplanner.ws.resources.criterion.api;
import java.util.ArrayList;
import java.util.List;
-import java.util.Set;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
-import org.navalplanner.ws.common.api.DuplicateCodeBeingImportedException;
import org.navalplanner.ws.common.api.IntegrationEntityDTO;
import org.navalplanner.ws.common.api.ResourceEnumDTO;
@@ -103,21 +101,4 @@ public class CriterionTypeDTO extends IntegrationEntityDTO {
return ENTITY_TYPE;
}
- @Override
- public String[] getNaturalKeyValues() {
- return new String[] {name};
- }
-
- @Override
- public void checkDuplicateCode(Set existingKeys)
- throws DuplicateCodeBeingImportedException {
-
- super.checkDuplicateCode(existingKeys);
-
- for (CriterionDTO c : criterions) {
- c.checkDuplicateCode(existingKeys);
- }
-
- }
-
}
diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/ws/resources/criterion/impl/CriterionConverter.java b/navalplanner-webapp/src/main/java/org/navalplanner/ws/resources/criterion/impl/CriterionConverter.java
index cbae4338f..443e7dab2 100644
--- a/navalplanner-webapp/src/main/java/org/navalplanner/ws/resources/criterion/impl/CriterionConverter.java
+++ b/navalplanner-webapp/src/main/java/org/navalplanner/ws/resources/criterion/impl/CriterionConverter.java
@@ -36,7 +36,6 @@ import org.navalplanner.business.resources.entities.CriterionType;
import org.navalplanner.ws.common.impl.ResourceEnumConverter;
import org.navalplanner.ws.resources.criterion.api.CriterionDTO;
import org.navalplanner.ws.resources.criterion.api.CriterionTypeDTO;
-import org.navalplanner.ws.resources.criterion.api.CriterionTypeListDTO;
/**
* Converter from/to criterion-related entities to/from DTOs.
@@ -47,20 +46,6 @@ public final class CriterionConverter {
private CriterionConverter() {}
- public final static CriterionTypeListDTO toDTO(
- Collection criterionTypes) {
-
- List criterionTypeDTOs =
- new ArrayList();
-
- for (CriterionType c : criterionTypes) {
- criterionTypeDTOs.add(toDTO(c));
- }
-
- return new CriterionTypeListDTO(criterionTypeDTOs);
-
- }
-
public final static CriterionTypeDTO toDTO(CriterionType criterionType) {
List criterionDTOs = new ArrayList();
diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/ws/resources/criterion/impl/CriterionServiceREST.java b/navalplanner-webapp/src/main/java/org/navalplanner/ws/resources/criterion/impl/CriterionServiceREST.java
index c74f196bd..a54b54263 100644
--- a/navalplanner-webapp/src/main/java/org/navalplanner/ws/resources/criterion/impl/CriterionServiceREST.java
+++ b/navalplanner-webapp/src/main/java/org/navalplanner/ws/resources/criterion/impl/CriterionServiceREST.java
@@ -20,30 +20,18 @@
package org.navalplanner.ws.resources.criterion.impl;
-import static org.navalplanner.web.I18nHelper._;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
-import org.navalplanner.business.common.exceptions.InstanceNotFoundException;
+import org.navalplanner.business.common.daos.IIntegrationEntityDAO;
import org.navalplanner.business.common.exceptions.ValidationException;
import org.navalplanner.business.resources.daos.ICriterionTypeDAO;
import org.navalplanner.business.resources.entities.CriterionType;
-import org.navalplanner.ws.common.api.DuplicateCodeBeingImportedException;
-import org.navalplanner.ws.common.api.DuplicateNaturalKeyBeingImportedException;
-import org.navalplanner.ws.common.api.InstanceConstraintViolationsDTO;
import org.navalplanner.ws.common.api.InstanceConstraintViolationsListDTO;
-import org.navalplanner.ws.common.impl.ConstraintViolationConverter;
-import org.navalplanner.ws.common.impl.Util;
+import org.navalplanner.ws.common.impl.GenericRESTService;
import org.navalplanner.ws.resources.criterion.api.CriterionTypeDTO;
import org.navalplanner.ws.resources.criterion.api.CriterionTypeListDTO;
import org.navalplanner.ws.resources.criterion.api.ICriterionService;
@@ -59,7 +47,9 @@ import org.springframework.transaction.annotation.Transactional;
@Path("/criteriontypes/")
@Produces("application/xml")
@Service("criterionServiceREST")
-public class CriterionServiceREST implements ICriterionService {
+public class CriterionServiceREST
+ extends GenericRESTService
+ implements ICriterionService {
@Autowired
private ICriterionTypeDAO criterionTypeDAO;
@@ -68,137 +58,39 @@ public class CriterionServiceREST implements ICriterionService {
@GET
@Transactional(readOnly = true)
public CriterionTypeListDTO getCriterionTypes() {
- return CriterionConverter.toDTO(criterionTypeDAO.getCriterionTypes());
+ return new CriterionTypeListDTO(findAll());
}
@Override
@POST
@Consumes("application/xml")
- @Transactional
public InstanceConstraintViolationsListDTO addCriterionTypes(
CriterionTypeListDTO criterionTypes) {
- List instanceConstraintViolationsList =
- new ArrayList();
- Long numItem = new Long(1);
- Set existingKeys = new HashSet();
-
- /* Process criterion types. */
- for (CriterionTypeDTO criterionTypeDTO :
- criterionTypes.criterionTypes) {
-
- InstanceConstraintViolationsDTO instanceConstraintViolationsDTO =
- null;
- CriterionType criterionType = null;
-
- try {
-
- /*
- * We must detect if there exists another instance being
- * imported with the same code or natural key, since
- * "IntegrationEntity::checkConstraintUniqueCode" and
- * the natural key unique constraint rule
- * (@AssertTrue/@AssertFalse method) in the concrete entity only
- * can check this condition with respect to the entities already
- * existing in database (such methods use DAO
- * "xxxAnotherTransaction" methods to avoid Hibernate to launch
- * INSERT statements for new objects when launching queries in
- * conversational use cases).
- */
- criterionTypeDTO.checkDuplicateCode(existingKeys);
- criterionTypeDTO.checkDuplicateNaturalKey(existingKeys);
-
- /*
- * Convert DTO to entity. Note that the entity, if exists in
- * the database, must be retrieved in another transaction.
- * Otherwise (if retrieved as part of the current
- * transaction), if the implementation of "updateEntity" makes
- * modifications to the entity passed as a parameter and
- * then throws an exception (because something make impossible
- * to continue updating), the entity would be considered as
- * dirty because it would be contained in the underlying ORM
- * session, and in consequence, the ORM would try to update it
- * when committing the transaction. Furthermore, the entity
- * must be initialized so that "updateEntity" can access
- * related entities.
- */
- try {
- criterionType =
- findByCodeAnotherTransactionInitialized(
- criterionTypeDTO.code);
- udpateEntity(criterionType, criterionTypeDTO);
- } catch (InstanceNotFoundException e) {
- criterionType = toEntity(criterionTypeDTO);
- }
-
- /*
- * Save the entity (insert or update).
- *
- * "validate" is executed before "save", since "save" first
- * adds the object to the underlying ORM session and then
- * validates. So, if "validate" method is not called explicitly
- * before "save", an invalid entity would be added to the
- * underlying ORM session, causing the invalid entity to be
- * added to the database when the ORM commits the transaction.
- * As a side effect, validations are executed twice.
- */
- criterionType.validate();
- criterionTypeDAO.save(criterionType);
-
- } catch (DuplicateCodeBeingImportedException e) {
- instanceConstraintViolationsDTO =
- InstanceConstraintViolationsDTO.create(
- Util.generateInstanceConstraintViolationsDTOId(numItem,
- criterionTypeDTO),
- _("code: {0} is used by another instance of type {1} " +
- "being imported", e.getCode(), e.getEntityType()));
- } catch (DuplicateNaturalKeyBeingImportedException e) {
- instanceConstraintViolationsDTO =
- InstanceConstraintViolationsDTO.create(
- Util.generateInstanceConstraintViolationsDTOId(numItem,
- criterionTypeDTO),
- _("values: {0} are used by another instance of type " +
- "{1} being imported",
- Arrays.toString(e.getNaturalKeyValues()),
- e.getEntityType()));
- } catch (ValidationException e) {
- instanceConstraintViolationsDTO =
- ConstraintViolationConverter.toDTO(
- Util.generateInstanceConstraintViolationsDTOId(
- numItem, criterionTypeDTO), e);
- }
-
-
- if (instanceConstraintViolationsDTO != null) {
- instanceConstraintViolationsList.add(
- instanceConstraintViolationsDTO);
- }
-
- numItem++;
-
- }
-
- return new InstanceConstraintViolationsListDTO(
- instanceConstraintViolationsList);
+ return save(criterionTypes.criterionTypes);
}
- private CriterionType findByCodeAnotherTransactionInitialized(
- String code) throws InstanceNotFoundException {
-
- return criterionTypeDAO.findByCodeAnotherTransactionInitialized(
- code);
-
+ @Override
+ protected CriterionType toEntity(CriterionTypeDTO entityDTO) {
+ return CriterionConverter.toEntity(entityDTO);
}
- private CriterionType toEntity(CriterionTypeDTO criterionTypeDTO) {
- return CriterionConverter.toEntity(criterionTypeDTO);
+ @Override
+ protected CriterionTypeDTO toDTO(CriterionType entity) {
+ return CriterionConverter.toDTO(entity);
}
- private void udpateEntity(CriterionType criterionType,
- CriterionTypeDTO criterionTypeDTO) throws ValidationException {
+ @Override
+ protected IIntegrationEntityDAO getIntegrationEntityDAO() {
+ return criterionTypeDAO;
+ }
- CriterionConverter.updateCriterionType(criterionType, criterionTypeDTO);
+ @Override
+ protected void updateEntity(CriterionType entity,
+ CriterionTypeDTO entityDTO) throws ValidationException {
+
+ CriterionConverter.updateCriterionType(entity, entityDTO);
}
diff --git a/navalplanner-webapp/src/test/java/org/navalplanner/web/test/ws/resources/criterion/api/CriterionServiceTest.java b/navalplanner-webapp/src/test/java/org/navalplanner/web/test/ws/resources/criterion/api/CriterionServiceTest.java
index a9020d606..4f6041350 100644
--- a/navalplanner-webapp/src/test/java/org/navalplanner/web/test/ws/resources/criterion/api/CriterionServiceTest.java
+++ b/navalplanner-webapp/src/test/java/org/navalplanner/web/test/ws/resources/criterion/api/CriterionServiceTest.java
@@ -28,7 +28,6 @@ import static org.navalplanner.business.BusinessGlobalNames.BUSINESS_SPRING_CONF
import static org.navalplanner.web.WebappGlobalNames.WEBAPP_SPRING_CONFIG_FILE;
import static org.navalplanner.web.test.WebappGlobalNames.WEBAPP_SPRING_CONFIG_TEST_FILE;
import static org.navalplanner.web.test.ws.common.Util.assertNoConstraintViolations;
-import static org.navalplanner.web.test.ws.common.Util.assertOneConstraintViolation;
import static org.navalplanner.web.test.ws.common.Util.getUniqueName;
import java.util.ArrayList;
@@ -71,9 +70,10 @@ public class CriterionServiceTest {
private ICriterionTypeDAO criterionTypeDAO;
@Test
+ @NotTransactional
public void testAddAndGetCriterionTypes() {
- /* Build criterion type "ct1" (4 constraint violations). */
+ /* Build criterion type "ct1" (5 constraint violations). */
CriterionDTO ct1c1 = new CriterionDTO(null, true, // Missing criterion
// name.
new ArrayList());
@@ -91,11 +91,15 @@ public class CriterionServiceTest {
new ArrayList());
CriterionDTO ct1c4 = new CriterionDTO(" C3 ", true,
new ArrayList()); // Repeated criterion name.
+ CriterionDTO ct1c5 = new CriterionDTO(ct1c3.code, // Repeated criterion
+ "c4", true, // code inside this criterion type.
+ new ArrayList());
List ct1Criterions = new ArrayList();
ct1Criterions.add(ct1c1);
ct1Criterions.add(ct1c2);
ct1Criterions.add(ct1c3);
ct1Criterions.add(ct1c4);
+ ct1Criterions.add(ct1c5);
String ct1Name = null;
CriterionTypeDTO ct1 = new CriterionTypeDTO(ct1Name, "desc",
false, true, true, ResourceEnumDTO.RESOURCE, // Missing criterion
@@ -141,9 +145,18 @@ public class CriterionServiceTest {
"desc", true, true, true,
ResourceEnumDTO.RESOURCE, new ArrayList());
+ /* Build criterion type "ct5" (1 constraint violation). */
+ CriterionDTO ct5c1 = new CriterionDTO(ct3c1.code, // Criterion code
+ "c1", true, // used by another criterion type.
+ new ArrayList());
+ List ct5Criterions = new ArrayList();
+ ct5Criterions.add(ct5c1);
+ CriterionTypeDTO ct5 = new CriterionTypeDTO(getUniqueName(), "desc",
+ true, true, true, ResourceEnumDTO.RESOURCE, ct5Criterions);
+
/* Criterion type list. */
CriterionTypeListDTO criterionTypes =
- createCriterionTypeListDTO(ct1, ct2, ct3, ct4);
+ createCriterionTypeListDTO(ct1, ct2, ct3, ct4, ct5);
List instanceConstraintViolationsList =
criterionService.addCriterionTypes(criterionTypes).
@@ -151,12 +164,12 @@ public class CriterionServiceTest {
assertTrue(
instanceConstraintViolationsList.toString(),
- instanceConstraintViolationsList.size() == 3);
+ instanceConstraintViolationsList.size() == 4);
assertTrue(
instanceConstraintViolationsList.get(0).
constraintViolations.toString(),
instanceConstraintViolationsList.get(0).
- constraintViolations.size() == 4);
+ constraintViolations.size() == 5);
assertTrue(
instanceConstraintViolationsList.get(1).
constraintViolations.toString(),
@@ -167,6 +180,11 @@ public class CriterionServiceTest {
constraintViolations.toString(),
instanceConstraintViolationsList.get(2).
constraintViolations.size() == 1);
+ assertTrue(
+ instanceConstraintViolationsList.get(3).
+ constraintViolations.toString(),
+ instanceConstraintViolationsList.get(3).
+ constraintViolations.size() == 1);
/* Find criterion types. */
List returnedCriterionTypes =
@@ -179,28 +197,7 @@ public class CriterionServiceTest {
}
@Test
- @NotTransactional
- public void testAddRepeatedCriterionTypeThatAlreadyExistsInDB()
- throws InstanceNotFoundException {
-
- CriterionTypeDTO criterionType = new CriterionTypeDTO(
- getUniqueName(), "desc", true, true, true,
- ResourceEnumDTO.RESOURCE, new ArrayList());
-
- assertNoConstraintViolations(criterionService.addCriterionTypes(
- createCriterionTypeListDTO(criterionType)));
-
- criterionType.code = getUniqueName(); // Another criterion with the
- // same data.
- assertOneConstraintViolation(criterionService.addCriterionTypes(
- createCriterionTypeListDTO(criterionType))); // Repeated criterion
- // type name.
-
- }
-
-
- @Test
- @NotTransactional
+ @Transactional
public void testUpdateCriterionType() throws InstanceNotFoundException {
/* Build criterion type with criteria: c1, c2->c2-1. */
@@ -245,8 +242,7 @@ public class CriterionServiceTest {
assertNoConstraintViolations(criterionService.addCriterionTypes(
createCriterionTypeListDTO(ctUpdated)));
- CriterionType ctEntity =
- criterionTypeDAO.findByCodeAnotherTransactionInitialized(ct.code);
+ CriterionType ctEntity = criterionTypeDAO.findByCode(ct.code);
assertTrue(ctEntity.getCriterions().size() == 4);
/* Test criterion hierarchy. */
diff --git a/scripts/rest-clients/criterion-types-sample.xml b/scripts/rest-clients/criterion-types-sample.xml
index 007dbdc16..79042977a 100644
--- a/scripts/rest-clients/criterion-types-sample.xml
+++ b/scripts/rest-clients/criterion-types-sample.xml
@@ -37,6 +37,12 @@
+
+
+
-
-
-
-
-
-
-
-
+
-
@@ -108,37 +101,26 @@
-
-
-
-
+
-
-
+
+
-
+
-
-
-
-
-
-
-
+
diff --git a/scripts/rest-clients/criterion-types-update-sample.xml b/scripts/rest-clients/criterion-types-update-sample.xml
index ae0fbb1ad..957543d4d 100644
--- a/scripts/rest-clients/criterion-types-update-sample.xml
+++ b/scripts/rest-clients/criterion-types-update-sample.xml
@@ -1,17 +1,23 @@
+
+
-
-
-
-
-
+
+
+