ItEr44S17CUImportacionRecursosProductivosItEr43S08: First version of migration of criterion REST service to the new semantics of POST.

IMPORTANT: CriterionType and Criterion tables must be removed because they now need "code" column with non-null values. Any row in any other table refering to CriterionType and Criterion instances must also probably be removed. In consequence, it is probably better to remove all databases (navaldev, navaldevtest, navalprod and navalprodtest).

This first version does not implement updates yet (only insertions) and does not detect repeated codes in the entities being imported (repeated codes in database are detected). "code" attribute has now been added to entities, and "num-instance" + "code" + "entity-type" attribute has been added to InstanceConstraintViolationsDTO.

This effort has been implemented creating reusable classes (to facilitate migration of the rest of services) and with a non-invasive approach (to make possible migrate each service individually and minimize the number of changes to the current code [specially testing code]).

Some existing methods/attributes in existing reusable classes (e.g. Util, InstanceConstraintViolationsDTO) have been deprecated (to support migration of services incrementally) and new ones have been implemented.

New reusables clases have been implemented: IntegrationEntity (all entities used in application integration must extend from this one), IIntegrationEntityDAO, IntegrationEntityDAO, InstanceConstraintViolationsDTOId (identifier for an instance causing a list of constraint violations), and IntegrationEntityDTO (all entity DTOs must extend from this one). Please, have a look to the JavaDoc of such classes.
This commit is contained in:
Fernando Bellas Permuy 2010-01-23 16:28:31 +01:00 committed by Javier Moran Rua
parent 88717464b0
commit 1091ede3ca
22 changed files with 640 additions and 87 deletions

View file

@ -0,0 +1,152 @@
/*
* 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.business.common;
import java.util.UUID;
import org.apache.commons.lang.StringUtils;
import org.hibernate.validator.AssertTrue;
import org.hibernate.validator.NotEmpty;
import org.navalplanner.business.common.daos.IIntegrationEntityDAO;
import org.navalplanner.business.common.exceptions.InstanceNotFoundException;
/**
* Base class for all entities to be sent/received to/from other applications.
* These entities have a "code" attribute, which unlike "id" is unique among
* the applications to be integrated ("id" is only unique inside
* "navalplanner").
*
* @author Fernando Bellas Permuy <fbellas@udc.es>
*/
public abstract class IntegrationEntity extends BaseEntity {
private String code;
@NotEmpty(message="code not specified")
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
/**
* This creation method must be used when we want to create an instance
* specifying a specific code (e.g. provided by the end-user or an external
* application).
*/
protected static <T extends IntegrationEntity> T create(
T integrationEntity, String code) {
BaseEntity.create(integrationEntity);
integrationEntity.code = code;
return integrationEntity;
}
/**
* This creation method must be used when we want the creation method to
* automatically generate a code. This is a Template method which delegates
* code generation by calling on <code>generateCode()</code>.
*/
protected static <T extends IntegrationEntity> T create(
T integrationEntity) {
BaseEntity.create(integrationEntity);
integrationEntity.code = generateCode();
return integrationEntity;
}
/**
* This method is called by <code>create(IntegrationEntity)</code>. It
* returns an unique String UUID. The current implementation is good enough
* for entities created in test classes. However, concrete classes
* interested in automatically generating descriptive identifiers when
* calling <code>create(IntegrationEntity)</code>, will probably redefine
* this method.
*/
protected static String generateCode() {
return UUID.randomUUID().toString();
}
/**
* It checks if there exists another integration entity of the same type
* with the same code. This method is a Template method that calls on
* the private method <code>findIntegrationEntityDAO</code>, which in turn
* calls on the abstract method <code>getIntegrationEntityDAO()</code>.
*/
@AssertTrue(message="code is already being used")
public boolean checkConstraintUniqueCode() {
/* Check if it makes sense to check the constraint .*/
if (!iCodeSpecified()) {
return true;
}
/* Check the constraint. */
IIntegrationEntityDAO<? extends IntegrationEntity>
integrationEntityDAO = findIntegrationEntityDAO();
if (isNewObject()) {
return !integrationEntityDAO.existsByCodeAnotherTransaction(code);
} else {
try {
IntegrationEntity entity =
integrationEntityDAO.findByCodeAnotherTransaction(code);
return entity.getId().equals(getId());
} catch (InstanceNotFoundException e) {
return true;
}
}
}
/**
* It returns the DAO of this entity.
*/
protected abstract IIntegrationEntityDAO<? extends IntegrationEntity>
getIntegrationEntityDAO();
private IIntegrationEntityDAO<? extends IntegrationEntity>
findIntegrationEntityDAO() {
IIntegrationEntityDAO<? extends IntegrationEntity>
integrationEntityDAO = getIntegrationEntityDAO();
if (!integrationEntityDAO.getEntityClass().equals(this.getClass())) {
throw new RuntimeException(this.getClass().getName() + "::" +
"getIntegrationEntityDAO returns an incompatible " +
"DAO: " + integrationEntityDAO.getClass().getName());
} else {
return integrationEntityDAO;
}
}
private boolean iCodeSpecified() {
return !StringUtils.isBlank(code);
}
}

View file

@ -79,6 +79,10 @@ public class GenericDAOHibernate<E extends BaseEntity,
return sessionFactory.getCurrentSession(); return sessionFactory.getCurrentSession();
} }
public Class<E> getEntityClass() {
return entityClass;
}
/** /**
* It's necessary to save and validate later. * It's necessary to save and validate later.
* *

View file

@ -39,6 +39,8 @@ import org.springframework.dao.OptimisticLockingFailureException;
*/ */
public interface IGenericDAO <E, PK extends Serializable>{ public interface IGenericDAO <E, PK extends Serializable>{
public Class<E> getEntityClass();
/** /**
* It inserts the object passed as a parameter in the ORM session, planning * It inserts the object passed as a parameter in the ORM session, planning
* it for updating (even though it is not modified before or after the call * it for updating (even though it is not modified before or after the call

View file

@ -0,0 +1,47 @@
/*
* 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.business.common.daos;
import org.navalplanner.business.common.IntegrationEntity;
import org.navalplanner.business.common.exceptions.InstanceNotFoundException;
/**
* Common DAO interface for all entities used in application integration. All
* DAO interfaces of entities used in application integration must extend from
* this interface.
*
* @author Fernando Bellas Permuy <fbellas@udc.es>
*/
public interface IIntegrationEntityDAO<E extends IntegrationEntity>
extends IGenericDAO<E, Long> {
public boolean existsByCode(String code);
public boolean existsByCodeAnotherTransaction(String code);
public E findByCode(String code) throws InstanceNotFoundException;
public E findByCodeAnotherTransaction(String code)
throws InstanceNotFoundException;
public E findExistingEntityByCode(String code);
}

View file

@ -0,0 +1,92 @@
/*
* 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.business.common.daos;
import org.hibernate.criterion.Restrictions;
import org.navalplanner.business.common.IntegrationEntity;
import org.navalplanner.business.common.exceptions.InstanceNotFoundException;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
/**
* Default implementation of <code>IIntegrationEntityDAO</code>. DAOs of
* entities used in application integration may extend from this interface.
*
* @author Fernando Bellas Permuy <fbellas@udc.es>
*/
public class IntegrationEntityDAO<E extends IntegrationEntity>
extends GenericDAOHibernate<E, Long> implements IIntegrationEntityDAO<E> {
@Override
public boolean existsByCode(String code) {
try {
findByCode(code);
return true;
} catch (InstanceNotFoundException e) {
return false;
}
}
@Override
@Transactional(readOnly = true, propagation = Propagation.REQUIRES_NEW)
public boolean existsByCodeAnotherTransaction(String code) {
return existsByCode(code);
}
@SuppressWarnings("unchecked")
@Override
public E findByCode(String code) throws InstanceNotFoundException {
E entity = (E) getSession().createCriteria(getEntityClass()).add(
Restrictions.eq("code", code).ignoreCase()).uniqueResult();
if (entity == null) {
throw new InstanceNotFoundException(
code, getEntityClass().getName());
} else {
return entity;
}
}
@Override
@Transactional(readOnly = true, propagation = Propagation.REQUIRES_NEW)
public E findByCodeAnotherTransaction(String code)
throws InstanceNotFoundException {
return findByCode(code);
}
@Override
public E findExistingEntityByCode(String code) {
try {
return findByCode(code);
} catch (InstanceNotFoundException e) {
throw new RuntimeException(e);
}
}
}

View file

@ -27,7 +27,7 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.hibernate.Criteria; import org.hibernate.Criteria;
import org.hibernate.criterion.Restrictions; import org.hibernate.criterion.Restrictions;
import org.navalplanner.business.common.daos.GenericDAOHibernate; import org.navalplanner.business.common.daos.IntegrationEntityDAO;
import org.navalplanner.business.common.exceptions.InstanceNotFoundException; import org.navalplanner.business.common.exceptions.InstanceNotFoundException;
import org.navalplanner.business.resources.entities.Criterion; import org.navalplanner.business.resources.entities.Criterion;
import org.navalplanner.business.resources.entities.ICriterionType; import org.navalplanner.business.resources.entities.ICriterionType;
@ -46,8 +46,8 @@ import org.springframework.transaction.annotation.Transactional;
*/ */
@Repository @Repository
@Scope(BeanDefinition.SCOPE_SINGLETON) @Scope(BeanDefinition.SCOPE_SINGLETON)
public class CriterionDAO extends GenericDAOHibernate<Criterion, Long> public class CriterionDAO extends IntegrationEntityDAO<Criterion>
implements ICriterionDAO { implements ICriterionDAO {
private static final Log log = LogFactory.getLog(CriterionDAO.class); private static final Log log = LogFactory.getLog(CriterionDAO.class);

View file

@ -26,7 +26,7 @@ import java.util.List;
import org.apache.commons.lang.Validate; import org.apache.commons.lang.Validate;
import org.hibernate.Criteria; import org.hibernate.Criteria;
import org.hibernate.criterion.Restrictions; import org.hibernate.criterion.Restrictions;
import org.navalplanner.business.common.daos.GenericDAOHibernate; import org.navalplanner.business.common.daos.IntegrationEntityDAO;
import org.navalplanner.business.common.exceptions.InstanceNotFoundException; import org.navalplanner.business.common.exceptions.InstanceNotFoundException;
import org.navalplanner.business.resources.entities.CriterionType; import org.navalplanner.business.resources.entities.CriterionType;
import org.navalplanner.business.resources.entities.ResourceEnum; import org.navalplanner.business.resources.entities.ResourceEnum;
@ -41,8 +41,8 @@ import org.springframework.transaction.annotation.Transactional;
*/ */
@Component @Component
public class CriterionTypeDAO extends GenericDAOHibernate<CriterionType, Long> public class CriterionTypeDAO extends IntegrationEntityDAO<CriterionType>
implements ICriterionTypeDAO { implements ICriterionTypeDAO {
@Override @Override
public List<CriterionType> findByName(CriterionType criterionType) { public List<CriterionType> findByName(CriterionType criterionType) {

View file

@ -22,7 +22,7 @@ package org.navalplanner.business.resources.daos;
import java.util.List; import java.util.List;
import org.navalplanner.business.common.daos.IGenericDAO; import org.navalplanner.business.common.daos.IIntegrationEntityDAO;
import org.navalplanner.business.common.exceptions.InstanceNotFoundException; import org.navalplanner.business.common.exceptions.InstanceNotFoundException;
import org.navalplanner.business.resources.entities.Criterion; import org.navalplanner.business.resources.entities.Criterion;
import org.navalplanner.business.resources.entities.ICriterionType; import org.navalplanner.business.resources.entities.ICriterionType;
@ -33,8 +33,9 @@ import org.springframework.transaction.annotation.Transactional;
* *
* @author Óscar González Fernández <ogonzalez@igalia.com> * @author Óscar González Fernández <ogonzalez@igalia.com>
* @author Diego Pino García <dpino@igalia.com> * @author Diego Pino García <dpino@igalia.com>
* @author Fernando Bellas Permuy <fbellas@udc.es>
*/ */
public interface ICriterionDAO extends IGenericDAO<Criterion, Long> { public interface ICriterionDAO extends IIntegrationEntityDAO<Criterion> {
public void removeByNameAndType(Criterion criterion); public void removeByNameAndType(Criterion criterion);

View file

@ -23,7 +23,7 @@ package org.navalplanner.business.resources.daos;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import org.navalplanner.business.common.daos.IGenericDAO; import org.navalplanner.business.common.daos.IIntegrationEntityDAO;
import org.navalplanner.business.common.exceptions.InstanceNotFoundException; import org.navalplanner.business.common.exceptions.InstanceNotFoundException;
import org.navalplanner.business.resources.entities.CriterionType; import org.navalplanner.business.resources.entities.CriterionType;
import org.navalplanner.business.resources.entities.ResourceEnum; import org.navalplanner.business.resources.entities.ResourceEnum;
@ -33,7 +33,8 @@ import org.navalplanner.business.resources.entities.ResourceEnum;
* @author Diego Pino Garcia <dpino@igalia.com> * @author Diego Pino Garcia <dpino@igalia.com>
* @author Fernando Bellas Permuy <fbellas@udc.es> * @author Fernando Bellas Permuy <fbellas@udc.es>
*/ */
public interface ICriterionTypeDAO extends IGenericDAO<CriterionType, Long> { public interface ICriterionTypeDAO
extends IIntegrationEntityDAO<CriterionType> {
CriterionType findUniqueByName(String name) CriterionType findUniqueByName(String name)
throws InstanceNotFoundException; throws InstanceNotFoundException;

View file

@ -32,20 +32,22 @@ import org.hibernate.validator.AssertTrue;
import org.hibernate.validator.NotEmpty; import org.hibernate.validator.NotEmpty;
import org.hibernate.validator.NotNull; import org.hibernate.validator.NotNull;
import org.hibernate.validator.Valid; import org.hibernate.validator.Valid;
import org.navalplanner.business.common.BaseEntity; import org.navalplanner.business.common.IntegrationEntity;
import org.navalplanner.business.common.Registry;
import org.navalplanner.business.requirements.entities.CriterionRequirement; import org.navalplanner.business.requirements.entities.CriterionRequirement;
import org.navalplanner.business.resources.daos.ICriterionDAO;
/** /**
* A criterion stored in the database <br /> * A criterion stored in the database <br />
* @author Óscar González Fernández <ogonzalez@igalia.com> * @author Óscar González Fernández <ogonzalez@igalia.com>
* @author Fernando Bellas Permuy <fbellas@udc.es> * @author Fernando Bellas Permuy <fbellas@udc.es>
*/ */
public class Criterion extends BaseEntity implements ICriterion { public class Criterion extends IntegrationEntity implements ICriterion {
public static Criterion createUnvalidated(String name, CriterionType type, public static Criterion createUnvalidated(String code, String name,
Criterion parent, boolean active) { CriterionType type, Criterion parent, boolean active) {
Criterion criterion = create(new Criterion()); Criterion criterion = create(new Criterion(), code);
criterion.name = name; criterion.name = name;
criterion.type = type; criterion.type = type;
@ -57,26 +59,19 @@ public class Criterion extends BaseEntity implements ICriterion {
} }
public static Criterion create(CriterionType type) { public static Criterion create(CriterionType type) {
Criterion criterion = new Criterion(type); return create(new Criterion(type));
criterion.setNewObject(true);
return criterion;
} }
public static Criterion create(String name, CriterionType type) { public static Criterion create(String name, CriterionType type) {
Criterion criterion = new Criterion(name, type); return create(new Criterion(name, type));
criterion.setNewObject(true);
return criterion;
} }
@NotEmpty(message="criterion name not specified")
private String name; private String name;
@NotNull(message="criterion type not specified")
private CriterionType type; private CriterionType type;
private Criterion parent = null; private Criterion parent = null;
@Valid
private Set<Criterion> children = new HashSet<Criterion>(); private Set<Criterion> children = new HashSet<Criterion>();
private boolean active = true; private boolean active = true;
@ -127,6 +122,7 @@ public class Criterion extends BaseEntity implements ICriterion {
Interval.range(start, end)).result().isEmpty(); Interval.range(start, end)).result().isEmpty();
} }
@NotEmpty(message="criterion name not specified")
public String getName() { public String getName() {
return name; return name;
} }
@ -135,6 +131,7 @@ public class Criterion extends BaseEntity implements ICriterion {
this.name = name; this.name = name;
} }
@NotNull(message="criterion type not specified")
public CriterionType getType() { public CriterionType getType() {
return type; return type;
} }
@ -163,6 +160,7 @@ public class Criterion extends BaseEntity implements ICriterion {
this.parent = parent; this.parent = parent;
} }
@Valid
public Set<Criterion> getChildren() { public Set<Criterion> getChildren() {
return children; return children;
} }
@ -213,4 +211,9 @@ public class Criterion extends BaseEntity implements ICriterion {
criterionRequirement.setCriterion(this); criterionRequirement.setCriterion(this);
this.criterionRequirements.add(criterionRequirement); this.criterionRequirements.add(criterionRequirement);
} }
@Override
protected ICriterionDAO getIntegrationEntityDAO() {
return Registry.getCriterionDAO();
}
} }

View file

@ -28,7 +28,7 @@ import org.apache.commons.lang.builder.EqualsBuilder;
import org.hibernate.validator.AssertTrue; import org.hibernate.validator.AssertTrue;
import org.hibernate.validator.NotEmpty; import org.hibernate.validator.NotEmpty;
import org.hibernate.validator.Valid; import org.hibernate.validator.Valid;
import org.navalplanner.business.common.BaseEntity; import org.navalplanner.business.common.IntegrationEntity;
import org.navalplanner.business.common.Registry; import org.navalplanner.business.common.Registry;
import org.navalplanner.business.common.exceptions.InstanceNotFoundException; import org.navalplanner.business.common.exceptions.InstanceNotFoundException;
import org.navalplanner.business.resources.daos.ICriterionTypeDAO; import org.navalplanner.business.resources.daos.ICriterionTypeDAO;
@ -41,22 +41,20 @@ import org.springframework.stereotype.Component;
* @author Fernando Bellas Permuy <fbellas@udc.es> * @author Fernando Bellas Permuy <fbellas@udc.es>
*/ */
@Component @Component
public class CriterionType extends BaseEntity implements public class CriterionType extends IntegrationEntity implements
ICriterionType<Criterion> { ICriterionType<Criterion> {
public static CriterionType create() { public static CriterionType create() {
CriterionType criterionType = new CriterionType(); return create(new CriterionType());
criterionType.setNewObject(true);
return criterionType;
} }
public static CriterionType createUnvalidated(String name, public static CriterionType createUnvalidated(String code, String name,
String description, Boolean allowHierarchy, String description, Boolean allowHierarchy,
Boolean allowSimultaneousCriterionsPerResource, Boolean enabled, Boolean allowSimultaneousCriterionsPerResource, Boolean enabled,
ResourceEnum resource) { ResourceEnum resource) {
CriterionType criterionType = create(new CriterionType()); CriterionType criterionType = create(new CriterionType(), code);
criterionType.name = name; criterionType.name = name;
criterionType.description = description; criterionType.description = description;
@ -71,21 +69,18 @@ public class CriterionType extends BaseEntity implements
} }
public static CriterionType create(String name,String description) { public static CriterionType create(String name,String description) {
CriterionType criterionType = new CriterionType(name,description); return create(new CriterionType(name,description));
criterionType.setNewObject(true);
return criterionType;
} }
public static CriterionType create(String name,String description, public static CriterionType create(String name,String description,
boolean allowHierarchy,boolean allowSimultaneousCriterionsPerResource, boolean allowHierarchy,boolean allowSimultaneousCriterionsPerResource,
boolean enabled,ResourceEnum resource) { boolean enabled,ResourceEnum resource) {
CriterionType criterionType = new CriterionType(name,description, allowHierarchy,
allowSimultaneousCriterionsPerResource,enabled,resource); return create(new CriterionType(name,description, allowHierarchy,
criterionType.setNewObject(true); allowSimultaneousCriterionsPerResource,enabled,resource));
return criterionType;
} }
@NotEmpty(message="criterion type name not specified")
private String name; private String name;
private String description; private String description;
@ -98,7 +93,6 @@ public class CriterionType extends BaseEntity implements
private ResourceEnum resource = ResourceEnum.getDefault(); private ResourceEnum resource = ResourceEnum.getDefault();
@Valid
private Set<Criterion> criterions = new HashSet<Criterion>(); private Set<Criterion> criterions = new HashSet<Criterion>();
private int numCriterions; private int numCriterions;
@ -146,6 +140,7 @@ public class CriterionType extends BaseEntity implements
} }
@Override @Override
@NotEmpty(message="criterion type name not specified")
public String getName() { public String getName() {
return name; return name;
} }
@ -154,6 +149,7 @@ public class CriterionType extends BaseEntity implements
this.name = name; this.name = name;
} }
@Valid
public Set<Criterion> getCriterions() { public Set<Criterion> getCriterions() {
return criterions; return criterions;
} }
@ -378,4 +374,10 @@ public class CriterionType extends BaseEntity implements
return !StringUtils.isBlank(name); return !StringUtils.isBlank(name);
} }
@Override
protected ICriterionTypeDAO getIntegrationEntityDAO() {
return Registry.getCriterionTypeDAO();
}
} }

View file

@ -66,6 +66,7 @@
</generator> </generator>
</id> </id>
<version name="version" access="property" type="long" /> <version name="version" access="property" type="long" />
<property name="code" access="property" not-null="true" unique="true"/>
<property access="field" name="name"/> <property access="field" name="name"/>
<property access="field" name="active"/> <property access="field" name="active"/>
<many-to-one access="field" name="type" column="id_criterion_type" not-null="true" /> <many-to-one access="field" name="type" column="id_criterion_type" not-null="true" />
@ -110,6 +111,7 @@
<generator class="hilo"/> <generator class="hilo"/>
</id> </id>
<version name="version" access="property" type="long" /> <version name="version" access="property" type="long" />
<property name="code" access="property" not-null="true" unique="true"/>
<property name="name" unique="true"/> <property name="name" unique="true"/>
<property name="description"/> <property name="description"/>
<property name="allowSimultaneousCriterionsPerResource"/> <property name="allowSimultaneousCriterionsPerResource"/>

View file

@ -35,16 +35,33 @@ import javax.xml.bind.annotation.XmlElement;
*/ */
public class InstanceConstraintViolationsDTO { public class InstanceConstraintViolationsDTO {
public final static String NUM_ITEM_ATTRIBUTE_NAME = "num-item";
public final static String CODE_ATTRIBUTE_NAME =
IntegrationEntityDTO.CODE_ATTRIBUTE_NAME;
public final static String ENTITY_TYPE_ATTRIBUTE_NAME = "entity-type";
@Deprecated
public final static String INSTANCE_ID_ATTRIBUTE_NAME = "instance-id"; public final static String INSTANCE_ID_ATTRIBUTE_NAME = "instance-id";
@Deprecated
@XmlAttribute(name=INSTANCE_ID_ATTRIBUTE_NAME) @XmlAttribute(name=INSTANCE_ID_ATTRIBUTE_NAME)
public String instanceId; public String instanceId;
@XmlAttribute(name=NUM_ITEM_ATTRIBUTE_NAME)
public Long numItem;
@XmlAttribute(name=CODE_ATTRIBUTE_NAME)
public String code;
@XmlAttribute(name=ENTITY_TYPE_ATTRIBUTE_NAME)
public String entityType;
@XmlElement(name="constraint-violation") @XmlElement(name="constraint-violation")
public List<ConstraintViolationDTO> constraintViolations; public List<ConstraintViolationDTO> constraintViolations;
public InstanceConstraintViolationsDTO() {} public InstanceConstraintViolationsDTO() {}
@Deprecated
public InstanceConstraintViolationsDTO(String instanceId, public InstanceConstraintViolationsDTO(String instanceId,
List<ConstraintViolationDTO> constraintViolations) { List<ConstraintViolationDTO> constraintViolations) {
@ -53,6 +70,18 @@ public class InstanceConstraintViolationsDTO {
} }
public InstanceConstraintViolationsDTO(
InstanceConstraintViolationsDTOId instanceId,
List<ConstraintViolationDTO> constraintViolations) {
this.numItem = instanceId.getNumItem();
this.code = instanceId.getCode();
this.entityType = instanceId.getEntityType();
this.constraintViolations = constraintViolations;
}
@Deprecated
public static InstanceConstraintViolationsDTO create(String instanceId, public static InstanceConstraintViolationsDTO create(String instanceId,
String message) { String message) {
@ -66,6 +95,19 @@ public class InstanceConstraintViolationsDTO {
} }
public static InstanceConstraintViolationsDTO create(
InstanceConstraintViolationsDTOId instanceId, String message) {
List<ConstraintViolationDTO> constraintViolations =
new ArrayList<ConstraintViolationDTO>();
constraintViolations.add(new ConstraintViolationDTO(null, message));
return new InstanceConstraintViolationsDTO(instanceId,
constraintViolations);
}
@Override @Override
public String toString() { public String toString() {
@ -75,6 +117,12 @@ public class InstanceConstraintViolationsDTO {
printWriter.println("** " + INSTANCE_ID_ATTRIBUTE_NAME + " = " + printWriter.println("** " + INSTANCE_ID_ATTRIBUTE_NAME + " = " +
instanceId + " **"); instanceId + " **");
printWriter.println("** " +
NUM_ITEM_ATTRIBUTE_NAME + " = " + numItem + " - " +
CODE_ATTRIBUTE_NAME + " = " + code + " - " +
ENTITY_TYPE_ATTRIBUTE_NAME + " = " + entityType +
" **");
for (ConstraintViolationDTO i : constraintViolations) { for (ConstraintViolationDTO i : constraintViolations) {
printWriter.println(i); printWriter.println(i);
} }

View file

@ -0,0 +1,55 @@
/*
* 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.api;
/**
* Identifier for an instance causing a list of constraint violations.
*
* @author Fernando Bellas Permuy <fbellas@udc.es>
*/
public class InstanceConstraintViolationsDTOId {
private Long numItem;
private String code;
private String entityType;
public InstanceConstraintViolationsDTOId(Long numItem, String code,
String entityType) {
this.numItem = numItem;
this.code = code;
this.entityType = entityType;
}
public Long getNumItem() {
return numItem;
}
public String getCode() {
return code;
}
public String getEntityType() {
return entityType;
}
}

View file

@ -0,0 +1,62 @@
/*
* 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.api;
import java.util.UUID;
import javax.xml.bind.annotation.XmlAttribute;
/**
* DTO for <code>IntegrationEntity</code>. All DTOs corresponding to entities
* to be used in application integration must extend from this DTO.
*
* @author Fernando Bellas Permuy <fbellas@udc.es>
*/
public abstract class IntegrationEntityDTO {
public final static String CODE_ATTRIBUTE_NAME = "code";
@XmlAttribute(name=CODE_ATTRIBUTE_NAME)
public String code;
public IntegrationEntityDTO() {}
public IntegrationEntityDTO(String code) {
this.code = code;
}
/**
* It returns the String to use in
* <code>InstanceConstraintViolationsDTOId.entityType</code>.
*/
public abstract String getEntityType();
/**
* This method is useful to implement constructors (in subclasses) that
* automatically generate a unique code. Such constructors are useful for
* the implementation of test cases that add new instances (such instances
* will have a unique code).
*/
protected static String generateCode() {
return UUID.randomUUID().toString();
}
}

View file

@ -26,6 +26,7 @@ import java.util.List;
import org.hibernate.validator.InvalidValue; import org.hibernate.validator.InvalidValue;
import org.navalplanner.ws.common.api.ConstraintViolationDTO; import org.navalplanner.ws.common.api.ConstraintViolationDTO;
import org.navalplanner.ws.common.api.InstanceConstraintViolationsDTO; import org.navalplanner.ws.common.api.InstanceConstraintViolationsDTO;
import org.navalplanner.ws.common.api.InstanceConstraintViolationsDTOId;
/** /**
* Converter for constraint violations. * Converter for constraint violations.
@ -58,6 +59,7 @@ public class ConstraintViolationConverter {
} }
@Deprecated
public final static InstanceConstraintViolationsDTO toDTO(String instanceId, public final static InstanceConstraintViolationsDTO toDTO(String instanceId,
InvalidValue[] invalidValues) { InvalidValue[] invalidValues) {
@ -73,4 +75,20 @@ public class ConstraintViolationConverter {
} }
public final static InstanceConstraintViolationsDTO toDTO(
InstanceConstraintViolationsDTOId instanceId,
InvalidValue[] invalidValues) {
List<ConstraintViolationDTO> constraintViolationDTOs =
new ArrayList<ConstraintViolationDTO>();
for (InvalidValue i : invalidValues) {
constraintViolationDTOs.add(toDTO(i));
}
return new InstanceConstraintViolationsDTO(instanceId,
constraintViolationDTOs);
}
} }

View file

@ -25,14 +25,28 @@ import java.io.StringWriter;
import org.apache.cxf.common.util.Base64Utility; import org.apache.cxf.common.util.Base64Utility;
import org.apache.cxf.jaxrs.client.WebClient; import org.apache.cxf.jaxrs.client.WebClient;
import org.navalplanner.ws.common.api.InstanceConstraintViolationsDTOId;
import org.navalplanner.ws.common.api.IntegrationEntityDTO;
/** /**
* Utilities class related with web service. * Utilities class related with web service.
* *
* @author Manuel Rego Casasnovas <mrego@igalia.com> * @author Manuel Rego Casasnovas <mrego@igalia.com>
* @author Fernando Bellas Permuy <fbellas@udc.es>
*/ */
public class Util { public class Util {
public static InstanceConstraintViolationsDTOId
generateInstanceConstraintViolationsDTOId(Long numItem,
IntegrationEntityDTO integrationEntityDTO) {
return new InstanceConstraintViolationsDTOId(numItem,
integrationEntityDTO.code,
integrationEntityDTO.getEntityType());
}
@Deprecated
public static String generateInstanceId(int instanceNumber, public static String generateInstanceId(int instanceNumber,
String instanceIdentifier) { String instanceIdentifier) {
String instanceId = instanceNumber + ""; String instanceId = instanceNumber + "";

View file

@ -27,12 +27,16 @@ import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper; import javax.xml.bind.annotation.XmlElementWrapper;
import org.navalplanner.ws.common.api.IntegrationEntityDTO;
/** /**
* DTO for <code>Criterion</code> entity. * DTO for <code>Criterion</code> entity.
* *
* @author Fernando Bellas Permuy <fbellas@udc.es> * @author Fernando Bellas Permuy <fbellas@udc.es>
*/ */
public class CriterionDTO { public class CriterionDTO extends IntegrationEntityDTO {
public final static String ENTITY_TYPE = "criterion";
@XmlAttribute @XmlAttribute
public String name; public String name;
@ -46,13 +50,31 @@ public class CriterionDTO {
public CriterionDTO() {} public CriterionDTO() {}
public CriterionDTO(String name, boolean active, public CriterionDTO(String code, String name, boolean active,
List<CriterionDTO> children) { List<CriterionDTO> children) {
super(code);
this.name = name; this.name = name;
this.active = active; this.active = active;
this.children = children; this.children = children;
} }
/**
* This constructor automatically generates a unique code. It is intended
* to facilitate the implementation of test cases that add new instances
* (such instances will have a unique code).
*/
public CriterionDTO(String name, boolean active,
List<CriterionDTO> children) {
this(generateCode(), name, active, children);
}
@Override
public String getEntityType() {
return ENTITY_TYPE;
}
} }

View file

@ -27,6 +27,7 @@ import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper; import javax.xml.bind.annotation.XmlElementWrapper;
import org.navalplanner.ws.common.api.IntegrationEntityDTO;
import org.navalplanner.ws.common.api.ResourceEnumDTO; import org.navalplanner.ws.common.api.ResourceEnumDTO;
/** /**
@ -34,7 +35,9 @@ import org.navalplanner.ws.common.api.ResourceEnumDTO;
* *
* @author Fernando Bellas Permuy <fbellas@udc.es> * @author Fernando Bellas Permuy <fbellas@udc.es>
*/ */
public class CriterionTypeDTO { public class CriterionTypeDTO extends IntegrationEntityDTO {
public final static String ENTITY_TYPE = "criterion-type";
@XmlAttribute @XmlAttribute
public String name; public String name;
@ -60,11 +63,12 @@ public class CriterionTypeDTO {
public CriterionTypeDTO() {} public CriterionTypeDTO() {}
public CriterionTypeDTO(String name, String description, public CriterionTypeDTO(String code, String name, String description,
boolean allowHierarchy, boolean allowSimultaneousCriterionsPerResource, boolean allowHierarchy, boolean allowSimultaneousCriterionsPerResource,
boolean enabled, ResourceEnumDTO resource, boolean enabled, ResourceEnumDTO resource,
List<CriterionDTO> criterions) { List<CriterionDTO> criterions) {
super(code);
this.name = name; this.name = name;
this.description = description; this.description = description;
this.allowHierarchy = allowHierarchy; this.allowHierarchy = allowHierarchy;
@ -76,4 +80,25 @@ public class CriterionTypeDTO {
} }
/**
* This constructor automatically generates a unique code. It is intended
* to facilitate the implementation of test cases that add new instances
* (such instances will have a unique code).
*/
public CriterionTypeDTO(String name, String description,
boolean allowHierarchy, boolean allowSimultaneousCriterionsPerResource,
boolean enabled, ResourceEnumDTO resource,
List<CriterionDTO> criterions) {
this(generateCode(), name, description, allowHierarchy,
allowSimultaneousCriterionsPerResource, enabled, resource,
criterions);
}
@Override
public String getEntityType() {
return ENTITY_TYPE;
}
} }

View file

@ -70,6 +70,7 @@ public final class CriterionConverter {
} }
return new CriterionTypeDTO( return new CriterionTypeDTO(
criterionType.getCode(),
criterionType.getName(), criterionType.getName(),
criterionType.getDescription(), criterionType.getDescription(),
criterionType.allowHierarchy(), criterionType.allowHierarchy(),
@ -93,8 +94,8 @@ public final class CriterionConverter {
childrenDTOs = null; childrenDTOs = null;
} }
return new CriterionDTO(criterion.getName(), criterion.isActive(), return new CriterionDTO(criterion.getCode(), criterion.getName(),
childrenDTOs); criterion.isActive(), childrenDTOs);
} }
@ -102,6 +103,7 @@ public final class CriterionConverter {
CriterionTypeDTO criterionTypeDTO) { CriterionTypeDTO criterionTypeDTO) {
CriterionType criterionType = CriterionType.createUnvalidated( CriterionType criterionType = CriterionType.createUnvalidated(
StringUtils.trim(criterionTypeDTO.code),
StringUtils.trim(criterionTypeDTO.name), StringUtils.trim(criterionTypeDTO.name),
StringUtils.trim(criterionTypeDTO.description), StringUtils.trim(criterionTypeDTO.description),
criterionTypeDTO.allowHierarchy, criterionTypeDTO.allowHierarchy,
@ -139,6 +141,7 @@ public final class CriterionConverter {
Criterion criterionParent) { Criterion criterionParent) {
Criterion criterion = Criterion.createUnvalidated( Criterion criterion = Criterion.createUnvalidated(
StringUtils.trim(childDTO.code),
StringUtils.trim(childDTO.name), StringUtils.trim(childDTO.name),
criterionType, criterionParent, childDTO.active); criterionType, criterionParent, childDTO.active);

View file

@ -76,7 +76,7 @@ public class CriterionServiceREST implements ICriterionService {
List<InstanceConstraintViolationsDTO> instanceConstraintViolationsList = List<InstanceConstraintViolationsDTO> instanceConstraintViolationsList =
new ArrayList<InstanceConstraintViolationsDTO>(); new ArrayList<InstanceConstraintViolationsDTO>();
int instanceNumber = 1; Long numItem = new Long(1);
Set<String> criterionTypeNames = new HashSet<String>(); Set<String> criterionTypeNames = new HashSet<String>();
/* Process criterion types. */ /* Process criterion types. */
@ -98,8 +98,8 @@ public class CriterionServiceREST implements ICriterionService {
instanceConstraintViolationsDTO = instanceConstraintViolationsDTO =
InstanceConstraintViolationsDTO.create( InstanceConstraintViolationsDTO.create(
Util.generateInstanceId(instanceNumber, Util.generateInstanceConstraintViolationsDTOId(numItem,
criterionTypeDTO.name), criterionTypeDTO),
_("criterion type name is used by another criterion " + _("criterion type name is used by another criterion " +
"type being imported")); "type being imported"));
@ -138,8 +138,8 @@ public class CriterionServiceREST implements ICriterionService {
} catch (ValidationException e) { } catch (ValidationException e) {
instanceConstraintViolationsDTO = instanceConstraintViolationsDTO =
ConstraintViolationConverter.toDTO( ConstraintViolationConverter.toDTO(
Util.generateInstanceId(instanceNumber, Util.generateInstanceConstraintViolationsDTOId(
criterionTypeDTO.name), numItem, criterionTypeDTO),
e.getInvalidValues()); e.getInvalidValues());
} }
@ -151,7 +151,7 @@ public class CriterionServiceREST implements ICriterionService {
instanceConstraintViolationsDTO); instanceConstraintViolationsDTO);
} }
instanceNumber++; numItem++;
} }

View file

@ -3,87 +3,87 @@
<criterion-type-list xmlns="http://rest.ws.navalplanner.org"> <criterion-type-list xmlns="http://rest.ws.navalplanner.org">
<!-- Several errors: see comments --> <!-- Several errors: see comments -->
<criterion-type name="ct-1" description="ct-1 desc" <criterion-type code="ct-1" name="ct-1" description="ct-1 desc"
allow-hierarchy="false" allow-hierarchy="false"
allow-simultaneous-criterions-per-resource="true" enabled="true" allow-simultaneous-criterions-per-resource="true" enabled="true"
resource="RESOURCE"> resource="RESOURCE">
<criterion-list> <criterion-list>
<!-- Missing criterion name --> <!-- Missing criterion name -->
<criterion active="true"/> <criterion code="ct-1-c1" active="true"/>
<criterion name="c2" active="true"> <criterion code="ct-1-c2" name="c2" active="true">
<!-- Criterion hierarchy is not allowed --> <!-- Criterion hierarchy is not allowed -->
<children> <children>
<criterion name="c2-1" active="true"> <criterion code="ct-1-c2-1" name="c2-1" active="true">
<children> <children>
<criterion name="c2-1-1" active="false"/> <criterion code="ct-1-c2-1-1" name="c2-1-1" active="false"/>
<criterion name="c2-1-2" active="true"/> <criterion code="ct-1-c2-1-2" name="c2-1-2" active="true"/>
</children> </children>
</criterion> </criterion>
<!-- Repeated criterion name --> <!-- Repeated criterion name -->
<criterion name=" C2-1 " active="true"/> <criterion code="ct-1-c2-2" name=" C2-1 " active="true"/>
</children> </children>
</criterion> </criterion>
</criterion-list> </criterion-list>
</criterion-type> </criterion-type>
<!-- Missing criterion type name --> <!-- Missing criterion type name -->
<criterion-type description="ct-2 desc" allow-hierarchy="true" <criterion-type code="ct-2" description="ct-2 desc" allow-hierarchy="true"
allow-simultaneous-criterions-per-resource="true" enabled="true" allow-simultaneous-criterions-per-resource="true" enabled="true"
resource="RESOURCE"> resource="RESOURCE">
<criterion-list> <criterion-list>
<criterion name="c1" active="true"/> <criterion code="ct-2-c1" name="c1" active="true"/>
<criterion name="c2" active="true"/> <criterion code="ct-2-c2" name="c2" active="true"/>
</criterion-list> </criterion-list>
</criterion-type> </criterion-type>
<!-- OK --> <!-- OK -->
<criterion-type name="ct-4" description="ct-4 desc" allow-hierarchy="true" <criterion-type code="ct-4" name="ct-4" description="ct-4 desc"
allow-simultaneous-criterions-per-resource="true" enabled="true" allow-hierarchy="true" allow-simultaneous-criterions-per-resource="true"
resource="RESOURCE"> enabled="true" resource="RESOURCE">
<criterion-list> <criterion-list>
<criterion name="c1" active="true"/> <criterion code="ct-4-c1" name="c1" active="true"/>
<criterion name="c2" active="true"> <criterion code="ct-4-c2" name="c2" active="true">
<children> <children>
<criterion name="c2-1" active="true"> <criterion code="ct-4-c2-1" name="c2-1" active="true">
<children> <children>
<criterion name="c2-1-1" active="false"/> <criterion code="ct-4-c2-1-1" name="c2-1-1" active="false"/>
<criterion name="c2-1-2" active="true"/> <criterion code="ct-4-c2-1-2" name="c2-1-2" active="true"/>
</children> </children>
</criterion> </criterion>
<criterion name="c2-2" active="true"/> <criterion code="ct-4-c2-2" name="c2-2" active="true"/>
</children> </children>
</criterion> </criterion>
</criterion-list> </criterion-list>
</criterion-type> </criterion-type>
<!-- Repeated criterion type name (see above) --> <!-- Repeated criterion type name (see above) -->
<criterion-type name=" CT-4 " description="ct-4 desc" <criterion-type code="ct-4b" name=" CT-4 " description="ct-4 desc"
allow-hierarchy="false" allow-hierarchy="false"
allow-simultaneous-criterions-per-resource="false" enabled="false" allow-simultaneous-criterions-per-resource="false" enabled="false"
resource="WORKER"/> resource="WORKER"/>
<!-- Repeated criterion type name (probably a criterion type with this name <!-- Repeated criterion type name (probably a criterion type with this name
already exists in the database) --> already exists in the database) -->
<criterion-type name="training" description="ct-4 desc" <criterion-type code="ct-4c" name="training" description="ct-4 desc"
allow-hierarchy="false" allow-hierarchy="false"
allow-simultaneous-criterions-per-resource="false" enabled="false" allow-simultaneous-criterions-per-resource="false" enabled="false"
resource="WORKER"/> resource="WORKER"/>
<!-- A non-active criterion has an active subcriterion --> <!-- A non-active criterion has an active subcriterion -->
<criterion-type name="ct-5" description="ct-5 desc" allow-hierarchy="true" <criterion-type code="ct-5" name="ct-5" description="ct-5 desc"
allow-simultaneous-criterions-per-resource="true" enabled="true" allow-hierarchy="true" allow-simultaneous-criterions-per-resource="true"
resource="RESOURCE"> enabled="true" resource="RESOURCE">
<criterion-list> <criterion-list>
<criterion name="c1" active="true"/> <criterion code="ct-5-c1" name="c1" active="true"/>
<criterion name="c2" active="false"> <criterion code="ct-5-c2" name="c2" active="false">
<children> <children>
<criterion name="c2-1" active="false"/> <criterion code="ct-5-c2-1" name="c2-1" active="false"/>
<criterion name="c2-2" active="false"> <criterion code="ct-5-c2-2" name="c2-2" active="false">
<children> <children>
<criterion name="c2-2-1" active="true"/> <criterion code="ct-5-c2-2-1" name="c2-2-1" active="true"/>
</children> </children>
</criterion> </criterion>
</children> </children>
@ -92,19 +92,19 @@
</criterion-type> </criterion-type>
<!-- OK --> <!-- OK -->
<criterion-type name="ct-6" description="ct-6 desc" <criterion-type code="ct-6" name="ct-6" description="ct-6 desc"
allow-hierarchy="false" allow-hierarchy="false"
allow-simultaneous-criterions-per-resource="false" enabled="false" allow-simultaneous-criterions-per-resource="false" enabled="false"
resource="WORKER"/> resource="WORKER"/>
<!-- Resource type does not allow enabled criteria --> <!-- Resource type does not allow enabled criteria -->
<criterion-type name="ct-7" description="ct-5 desc" allow-hierarchy="true" <criterion-type code="ct-7" name="ct-7" description="ct-5 desc"
allow-simultaneous-criterions-per-resource="true" enabled="false" allow-hierarchy="true" allow-simultaneous-criterions-per-resource="true"
resource="RESOURCE"> enabled="false" resource="RESOURCE">
<criterion-list> <criterion-list>
<criterion name="c1" active="true"/> <criterion code="ct-7-c1" name="c1" active="true"/>
<criterion name="c2" active="false"/> <criterion code="ct-7-c2" name="c2" active="false"/>
</criterion-list> </criterion-list>
</criterion-type> </criterion-type>