ItEr46S13CUImportacionRecursosProductivosItEr45S11: First version of the generic REST service and CriterionServiceREST reimplemented in terms of it.
GenericRESTService provides initial common functionality to all services. Some another generic infraestructure has been improved (IntegrationEntity, IIntegrationEntityDAO, InstanceConstraintViolationsDTO, and ConstraintViolationConverter) or simplified (IntegrationEntityDTO). GenericRESTService does not implement all desirable features yet (e.g. recoverable errors). Please, do not use it yet. CriterionServiceREST has been reimplemented in terms of it. Tests have also been improved.
This commit is contained in:
parent
6d5a365e0d
commit
16b87de8ed
20 changed files with 348 additions and 578 deletions
|
|
@ -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 <code>null</code>.
|
||||
* 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<String> codes = new HashSet<String>();
|
||||
|
||||
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.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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<E extends IntegrationEntity>
|
|||
|
||||
public E findExistingEntityByCode(String code);
|
||||
|
||||
/**
|
||||
* It returns all entities ordered by ascending code.
|
||||
*/
|
||||
public List<E> findAll();
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<E extends IntegrationEntity>
|
|||
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public List<E> findAll() {
|
||||
return getSession().createCriteria(getEntityClass()).
|
||||
addOrder(Order.asc("code")).list();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,22 +45,6 @@ import org.springframework.transaction.annotation.Transactional;
|
|||
public class CriterionTypeDAO extends IntegrationEntityDAO<CriterionType>
|
||||
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<CriterionType> findByName(CriterionType criterionType) {
|
||||
Criteria c = getSession().createCriteria(CriterionType.class);
|
||||
|
|
|
|||
|
|
@ -36,9 +36,6 @@ import org.navalplanner.business.resources.entities.ResourceEnum;
|
|||
public interface ICriterionTypeDAO
|
||||
extends IIntegrationEntityDAO<CriterionType> {
|
||||
|
||||
CriterionType findByCodeAnotherTransactionInitialized(String code)
|
||||
throws InstanceNotFoundException;
|
||||
|
||||
CriterionType findUniqueByName(String name)
|
||||
throws InstanceNotFoundException;
|
||||
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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 <fbellas@udc.es>
|
||||
*/
|
||||
@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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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 <fbellas@udc.es>
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class DuplicateInstanceBeingImportedException extends Exception {
|
||||
|
||||
private String entityType;
|
||||
|
||||
public DuplicateInstanceBeingImportedException(String entityType) {
|
||||
this.entityType = entityType;
|
||||
}
|
||||
|
||||
public String getEntityType() {
|
||||
return entityType;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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 <fbellas@udc.es>
|
||||
*/
|
||||
@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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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<ConstraintViolationDTO> constraintViolations;
|
||||
|
||||
@XmlElement(name="internal-error")
|
||||
public InternalErrorDTO internalError;
|
||||
|
||||
public InstanceConstraintViolationsDTO() {}
|
||||
|
||||
@Deprecated
|
||||
|
|
@ -70,17 +75,33 @@ public class InstanceConstraintViolationsDTO {
|
|||
|
||||
}
|
||||
|
||||
public InstanceConstraintViolationsDTO(
|
||||
InstanceConstraintViolationsDTOId instanceId,
|
||||
List<ConstraintViolationDTO> constraintViolations) {
|
||||
private InstanceConstraintViolationsDTO(
|
||||
InstanceConstraintViolationsDTOId instanceId) {
|
||||
|
||||
this.numItem = instanceId.getNumItem();
|
||||
this.code = instanceId.getCode();
|
||||
this.entityType = instanceId.getEntityType();
|
||||
|
||||
}
|
||||
|
||||
public InstanceConstraintViolationsDTO(
|
||||
InstanceConstraintViolationsDTOId instanceId,
|
||||
List<ConstraintViolationDTO> 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) {
|
||||
|
|
|
|||
|
|
@ -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 <code>IntegrationEntity</code>. All DTOs corresponding to entities
|
||||
* to be used in application integration must extend from this DTO.
|
||||
* <br/>
|
||||
* <br/>
|
||||
* All entities must redefine <code>getEntityType()</code>. Additionally,
|
||||
* entities that can be bulk imported may need to redefine the following
|
||||
* methods (ordered by probability of being redefined):
|
||||
* <ul>
|
||||
* <li><code>getNaturalKeyValues()</code>.</li>
|
||||
* <li><code>checkDuplicateCode()</code>.</li>
|
||||
* <li><code>getUniversalCodePrefix()</code>.</li>
|
||||
* <li><code>getUniversalNaturalKeyPrefix()</code>.</li>
|
||||
* <li><code>checkDuplicateNaturalKey()</code>.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Fernando Bellas Permuy <fbellas@udc.es>
|
||||
*/
|
||||
|
|
@ -64,93 +49,6 @@ public abstract class IntegrationEntityDTO {
|
|||
*/
|
||||
public abstract String getEntityType();
|
||||
|
||||
/**
|
||||
* It returns the prefix specified in <code>getUniversalCode()</code>. The
|
||||
* default implementation returns the same value as
|
||||
* <code>getEntityType()</code>. 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 <code>getUniversalNaturalKey()</code>.
|
||||
* The default implementation returns the same value as
|
||||
* <code>getEntityType()</code>. 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
|
||||
* <code>null</code> or an empty array. The default implementation
|
||||
* returns <code>null</code>. 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
|
||||
* <code>getUniversalCode()</code>) 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 <code>null</code>, the check is
|
||||
* considered OK (and the code is not added to the set of existing keys).
|
||||
* <br/>
|
||||
* <br/>
|
||||
* 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<String> 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
|
||||
* <code>getUniversalNaturalKey()</code>) 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
|
||||
* <code>null</code>, the check is considered OK (and the natural key is
|
||||
* not added to the set of existing keys).
|
||||
* <br/>
|
||||
* <br/>
|
||||
* 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<String> 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
|
||||
* <code>getUniversalCodePrefix().code.<<code-value>></code>, or
|
||||
* <code>null</code> if <code>code</code> is whitespace, empty ("") or
|
||||
* <code>null</code>.
|
||||
*/
|
||||
private String getUniversalCode() {
|
||||
|
||||
if (!StringUtils.isBlank(code)) {
|
||||
return getUniversalCodePrefix() + ".code." + StringUtils.trim(code);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* It returns a String with the format
|
||||
* <code>getUniversalNaturalKeyPrefix().naturalkey.<<getNaturalKeyValues()>></code>,
|
||||
* or <code>null</code> if some natural key value is whitespace, empty ("")
|
||||
* or <code>null</code>.
|
||||
*/
|
||||
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 <code>null</code>, it
|
||||
* returns <code>false</code> (and the key is not added to the set of
|
||||
* existing keys).
|
||||
*/
|
||||
protected boolean containsKeyAndAdd(Set<String> 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;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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. </code>.
|
||||
*
|
||||
* @author Fernando Bellas Permuy <fbellas@udc.es>
|
||||
*/
|
||||
public abstract class GenericRESTService<E extends IntegrationEntity,
|
||||
DTO extends IntegrationEntityDTO> {
|
||||
|
||||
@Autowired
|
||||
private IAdHocTransactionService transactionService;
|
||||
|
||||
/**
|
||||
* It retrieves all entities.
|
||||
*/
|
||||
protected List<DTO> 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<DTO> entityDTOs) {
|
||||
|
||||
List<InstanceConstraintViolationsDTO> instanceConstraintViolationsList =
|
||||
new ArrayList<InstanceConstraintViolationsDTO>();
|
||||
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<Void> save = new IOnTransaction<Void>() {
|
||||
|
||||
@Override
|
||||
public Void execute() {
|
||||
|
||||
E entity = null;
|
||||
IIntegrationEntityDAO<E> 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<E>
|
||||
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<DTO> toDTO(List<E> entities) {
|
||||
|
||||
List<DTO> dtos = new ArrayList<DTO>();
|
||||
|
||||
for (E entity : entities) {
|
||||
dtos.add(toDTO(entity));
|
||||
}
|
||||
|
||||
return dtos;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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<String> existingKeys)
|
||||
throws DuplicateCodeBeingImportedException {
|
||||
|
||||
super.checkDuplicateCode(existingKeys);
|
||||
|
||||
for (CriterionDTO c : children) {
|
||||
c.checkDuplicateCode(existingKeys);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<String> existingKeys)
|
||||
throws DuplicateCodeBeingImportedException {
|
||||
|
||||
super.checkDuplicateCode(existingKeys);
|
||||
|
||||
for (CriterionDTO c : criterions) {
|
||||
c.checkDuplicateCode(existingKeys);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<CriterionType> criterionTypes) {
|
||||
|
||||
List<CriterionTypeDTO> criterionTypeDTOs =
|
||||
new ArrayList<CriterionTypeDTO>();
|
||||
|
||||
for (CriterionType c : criterionTypes) {
|
||||
criterionTypeDTOs.add(toDTO(c));
|
||||
}
|
||||
|
||||
return new CriterionTypeListDTO(criterionTypeDTOs);
|
||||
|
||||
}
|
||||
|
||||
public final static CriterionTypeDTO toDTO(CriterionType criterionType) {
|
||||
|
||||
List<CriterionDTO> criterionDTOs = new ArrayList<CriterionDTO>();
|
||||
|
|
|
|||
|
|
@ -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<CriterionType, CriterionTypeDTO>
|
||||
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<InstanceConstraintViolationsDTO> instanceConstraintViolationsList =
|
||||
new ArrayList<InstanceConstraintViolationsDTO>();
|
||||
Long numItem = new Long(1);
|
||||
Set<String> existingKeys = new HashSet<String>();
|
||||
|
||||
/* 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<CriterionType> getIntegrationEntityDAO() {
|
||||
return criterionTypeDAO;
|
||||
}
|
||||
|
||||
CriterionConverter.updateCriterionType(criterionType, criterionTypeDTO);
|
||||
@Override
|
||||
protected void updateEntity(CriterionType entity,
|
||||
CriterionTypeDTO entityDTO) throws ValidationException {
|
||||
|
||||
CriterionConverter.updateCriterionType(entity, entityDTO);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<CriterionDTO>());
|
||||
|
|
@ -91,11 +91,15 @@ public class CriterionServiceTest {
|
|||
new ArrayList<CriterionDTO>());
|
||||
CriterionDTO ct1c4 = new CriterionDTO(" C3 ", true,
|
||||
new ArrayList<CriterionDTO>()); // Repeated criterion name.
|
||||
CriterionDTO ct1c5 = new CriterionDTO(ct1c3.code, // Repeated criterion
|
||||
"c4", true, // code inside this criterion type.
|
||||
new ArrayList<CriterionDTO>());
|
||||
List<CriterionDTO> ct1Criterions = new ArrayList<CriterionDTO>();
|
||||
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<CriterionDTO>());
|
||||
|
||||
/* Build criterion type "ct5" (1 constraint violation). */
|
||||
CriterionDTO ct5c1 = new CriterionDTO(ct3c1.code, // Criterion code
|
||||
"c1", true, // used by another criterion type.
|
||||
new ArrayList<CriterionDTO>());
|
||||
List<CriterionDTO> ct5Criterions = new ArrayList<CriterionDTO>();
|
||||
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<InstanceConstraintViolationsDTO> 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<CriterionTypeDTO> 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<CriterionDTO>());
|
||||
|
||||
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. */
|
||||
|
|
|
|||
|
|
@ -37,6 +37,12 @@
|
|||
</criterion-list>
|
||||
</criterion-type>
|
||||
|
||||
<!-- OK -->
|
||||
<criterion-type code="ct-3" name="ct-3" description="ct-3 desc"
|
||||
allow-hierarchy="false"
|
||||
allow-simultaneous-criterions-per-resource="false" enabled="false"
|
||||
resource="WORKER"/>
|
||||
|
||||
<!-- OK -->
|
||||
<criterion-type code="ct-4" name="ct-4" description="ct-4 desc"
|
||||
allow-hierarchy="true" allow-simultaneous-criterions-per-resource="true"
|
||||
|
|
@ -58,19 +64,6 @@
|
|||
</criterion-list>
|
||||
</criterion-type>
|
||||
|
||||
<!-- Repeated criterion type name (see above) -->
|
||||
<criterion-type code="ct-4b" name=" CT-4 " description="ct-4 desc"
|
||||
allow-hierarchy="false"
|
||||
allow-simultaneous-criterions-per-resource="false" enabled="false"
|
||||
resource="WORKER"/>
|
||||
|
||||
<!-- Repeated criterion type name (probably a criterion type with this name
|
||||
already exists in the database) -->
|
||||
<criterion-type code="ct-4c" name="training" description="ct-4 desc"
|
||||
allow-hierarchy="false"
|
||||
allow-simultaneous-criterions-per-resource="false" enabled="false"
|
||||
resource="WORKER"/>
|
||||
|
||||
<!-- A non-active criterion has an active subcriterion -->
|
||||
<criterion-type code="ct-5" name="ct-5" description="ct-5 desc"
|
||||
allow-hierarchy="true" allow-simultaneous-criterions-per-resource="true"
|
||||
|
|
@ -91,14 +84,14 @@
|
|||
</criterion-list>
|
||||
</criterion-type>
|
||||
|
||||
<!-- OK -->
|
||||
<criterion-type code="ct-6" name="ct-6" description="ct-6 desc"
|
||||
<!-- Repeated criterion type name (see above) -->
|
||||
<criterion-type code="ct-6" name=" CT-4 " description="ct-6 desc"
|
||||
allow-hierarchy="false"
|
||||
allow-simultaneous-criterions-per-resource="false" enabled="false"
|
||||
resource="WORKER"/>
|
||||
|
||||
<!-- Resource type does not allow enabled criteria -->
|
||||
<criterion-type code="ct-7" name="ct-7" description="ct-5 desc"
|
||||
<criterion-type code="ct-7" name="ct-7" description="ct-7 desc"
|
||||
allow-hierarchy="true" allow-simultaneous-criterions-per-resource="true"
|
||||
enabled="false" resource="RESOURCE">
|
||||
|
||||
|
|
@ -108,37 +101,26 @@
|
|||
</criterion-list>
|
||||
</criterion-type>
|
||||
|
||||
<!-- Repeated criterion type code ("ct-6") -->
|
||||
<criterion-type code="ct-6" name="ct-7" description="ct-7 desc"
|
||||
allow-hierarchy="false"
|
||||
allow-simultaneous-criterions-per-resource="false" enabled="false"
|
||||
resource="WORKER"/>
|
||||
|
||||
<!-- Repeated criterion code (ct-8-c1) -->
|
||||
<!-- Repeated criterion code ("ct-8-c1") inside this criterion type -->
|
||||
<criterion-type code="ct-8" name="ct-8" description="ct-8 desc"
|
||||
allow-hierarchy="true" allow-simultaneous-criterions-per-resource="true"
|
||||
enabled="true" resource="RESOURCE">
|
||||
|
||||
<criterion-list>
|
||||
<criterion code="ct-8-c1" name="c8" active="true"/>
|
||||
<criterion code="ct-8-c1" name="c8" active="true"/>
|
||||
<criterion code="ct-8-c1" name="c1" active="true"/>
|
||||
<criterion code="ct-8-c1" name="c2" active="true"/>
|
||||
</criterion-list>
|
||||
|
||||
</criterion-type>
|
||||
|
||||
<!-- Repeated criterion code (ct-4-c2-1) -->
|
||||
<!-- Repeated criterion code ("ct-4-c1") (used by a criterion of another
|
||||
criterion type) -->
|
||||
<criterion-type code="ct-9" name="ct-9" description="ct-9 desc"
|
||||
allow-hierarchy="true" allow-simultaneous-criterions-per-resource="true"
|
||||
enabled="true" resource="RESOURCE">
|
||||
|
||||
<criterion-list>
|
||||
<criterion code="ct-9-c1" name="c9" active="true"/>
|
||||
<criterion code="ct-9-c2" name="c9" active="true">
|
||||
<children>
|
||||
<criterion code="ct-9-c2-1" name="c9-1" active="true"/>
|
||||
<criterion code="ct-4-c2-1" name="c9-2" active="true"/>
|
||||
</children>
|
||||
</criterion>
|
||||
<criterion code="ct-4-c1" name="c1" active="true"/>
|
||||
</criterion-list>
|
||||
</criterion-type>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,17 +1,23 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
|
||||
<!-- These updates could be part of criterion-types-sample.xml but have been
|
||||
extracted to an independent file for clarity (this way, by using the Web
|
||||
user interface, one can see the effects of importing
|
||||
criterion-types-sample.xml first, and then
|
||||
criterion-types-update-sample.xml). -->
|
||||
|
||||
<criterion-type-list xmlns="http://rest.ws.navalplanner.org">
|
||||
|
||||
<!-- OK -->
|
||||
<criterion-type code="ct-6" name="ct-6-XXX" description="ct-6 desc XXX"/>
|
||||
|
||||
<!-- OK -->
|
||||
<criterion-type code="ct-4">
|
||||
<!-- OK (change criterion type's name and description, move criterion
|
||||
"ct-4-c2-1-1" of position in the criterion hierarchy and set active to
|
||||
true, and add a new criterion ("ct-4-c2-3"). -->
|
||||
<criterion-type code="ct-4" name="ct-4 UPDATED" description="ct-4 desc UPDATED">
|
||||
|
||||
<criterion-list>
|
||||
<criterion code="ct-4-c2">
|
||||
<children>
|
||||
<criterion code="ct-4-c2-1-1" active="true"/>
|
||||
<criterion code="ct-4-c2-3" name="c2-3" active="true"/>
|
||||
</children>
|
||||
</criterion>
|
||||
</criterion-list>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue