Creates the entities EntitySequence, EntitySequenceDao and an enum that represents the entities which use code generation.

FEA :ItEr61S04NavalPlanEntities
This commit is contained in:
Susana Montes Pedreira 2010-10-13 19:30:26 +02:00 committed by Javier Moran Rua
parent 23880328f7
commit fe60ae5511
9 changed files with 696 additions and 0 deletions

View file

@ -27,6 +27,7 @@ import org.navalplanner.business.calendars.daos.ICalendarDataDAO;
import org.navalplanner.business.calendars.daos.ICalendarExceptionDAO;
import org.navalplanner.business.calendars.daos.ICalendarExceptionTypeDAO;
import org.navalplanner.business.common.daos.IConfigurationDAO;
import org.navalplanner.business.common.daos.IEntitySequenceDAO;
import org.navalplanner.business.costcategories.daos.ICostCategoryDAO;
import org.navalplanner.business.costcategories.daos.IHourCostDAO;
import org.navalplanner.business.costcategories.daos.IResourcesCostCategoryAssignmentDAO;
@ -186,6 +187,9 @@ public class Registry {
@Autowired
private ITaskElementDAO taskElementDAO;
@Autowired
private IEntitySequenceDAO entitySequenceDAO;
private Registry() {
}
@ -339,4 +343,7 @@ public class Registry {
return getInstance().taskElementDAO;
}
public static IEntitySequenceDAO getEntitySequenceDAO() {
return getInstance().entitySequenceDAO;
}
}

View file

@ -0,0 +1,132 @@
/*
* This file is part of NavalPlan
*
* Copyright (C) 2009-2010 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 java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang.Validate;
import org.hibernate.NonUniqueResultException;
import org.hibernate.criterion.Restrictions;
import org.navalplanner.business.common.IAdHocTransactionService;
import org.navalplanner.business.common.entities.EntityNameEnum;
import org.navalplanner.business.common.entities.EntitySequence;
import org.navalplanner.business.common.exceptions.InstanceNotFoundException;
import org.navalplanner.business.i18n.I18nHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Scope;
import org.springframework.orm.hibernate3.HibernateOptimisticLockingFailureException;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
/**
* DAO for {@link EntitySequence}.
* @author Susana Montes Pedreira <smontes@wirelessgalicia.com>
*/
@Repository
@Scope(BeanDefinition.SCOPE_SINGLETON)
public class EntitySequenceDAO extends
GenericDAOHibernate<EntitySequence, Long> implements IEntitySequenceDAO {
@Autowired
private IAdHocTransactionService transactionService;
@Override
public List<EntitySequence> getAll() {
return list(EntitySequence.class);
}
@Override
@SuppressWarnings("unchecked")
public List<EntitySequence> findEntitySquencesNotIn(
List<EntitySequence> entitySequences) {
List<Long> entitySequenceIds = new ArrayList<Long>();
for (EntitySequence entitySequence : entitySequences) {
if (!entitySequence.isNewObject()) {
entitySequenceIds.add(entitySequence.getId());
}
}
return getSession().createCriteria(EntitySequence.class).add(
Restrictions.not(Restrictions.in("id", entitySequenceIds)))
.list();
}
@Override
public void remove(final EntitySequence entitySequence)
throws InstanceNotFoundException, IllegalArgumentException {
if (entitySequence.getLastValue() > 0) {
throw new IllegalArgumentException(
I18nHelper
._("You can not remove this order sequence, it is already in use"));
}
remove(entitySequence.getId());
}
@Override
public EntitySequence getActiveEntitySequence(EntityNameEnum entityName)
throws InstanceNotFoundException, NonUniqueResultException {
return (EntitySequence) getSession().createCriteria(
EntitySequence.class).add(
Restrictions.eq("entityName", entityName)).add(
Restrictions.eq("active", true)).uniqueResult();
}
@Override
@Transactional(propagation = Propagation.REQUIRES_NEW)
public String getNextEntityCode(EntityNameEnum entityName) {
for (int i = 0; i < 5; i++) {
try {
EntitySequence entitySequence = getActiveEntitySequence(entityName);
entitySequence.incrementLastValue();
save(entitySequence);
return entitySequence.getCode();
} catch (HibernateOptimisticLockingFailureException e) {
// Do nothing (optimistic approach 5 attempts)
} catch (InstanceNotFoundException e) {
} catch (NonUniqueResultException e) {
}
}
return null;
}
@Override
public boolean existOtherActiveSequenceByEntityNameForNewObject(
EntitySequence entitySequence) {
Validate.notNull(entitySequence);
try {
EntitySequence t = getActiveEntitySequence(entitySequence
.getEntityName());
return (t != null && t != entitySequence);
} catch (InstanceNotFoundException e) {
return false;
} catch (NonUniqueResultException e) {
return true;
}
}
}

View file

@ -0,0 +1,57 @@
/*
* This file is part of NavalPlan
*
* Copyright (C) 2009-2010 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 java.util.List;
import org.hibernate.NonUniqueResultException;
import org.navalplanner.business.common.entities.EntityNameEnum;
import org.navalplanner.business.common.entities.EntitySequence;
import org.navalplanner.business.common.exceptions.InstanceNotFoundException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Repository;
/**
* DAO interface for {@link EntitySequenceDAO}.
* @author Susana Montes Pedreira <smontes@wirelessgalicia.com>
*/
@Repository
@Scope(BeanDefinition.SCOPE_SINGLETON)
public interface IEntitySequenceDAO extends IGenericDAO<EntitySequence, Long> {
List<EntitySequence> getAll();
List<EntitySequence> findEntitySquencesNotIn(
List<EntitySequence> entitySequences);
void remove(EntitySequence entitySequence)
throws InstanceNotFoundException, IllegalArgumentException;
EntitySequence getActiveEntitySequence(EntityNameEnum entityName)
throws InstanceNotFoundException, NonUniqueResultException;
String getNextEntityCode(EntityNameEnum entityName);
boolean existOtherActiveSequenceByEntityNameForNewObject(
EntitySequence entitySequence);
}

View file

@ -0,0 +1,43 @@
/*
* This file is part of NavalPlan
*
* Copyright (C) 2009-2010 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.entities;
import static org.navalplanner.business.i18n.I18nHelper._;
/**
* It represents the entities which use code generation
* @author Susana Montes Pedreira <smontes@wirelessgalicia.com>
*/
public enum EntityNameEnum {
ORDER(_("Order")), CRITERION(_("Criterion")), LABEL(_("Label")), MACHINE(
_("Machine")), WORKER(_("Worker")), UNIT_TYPE(_("Unit type")), CALENDAR(
_("Calendar"));
private String description;
private EntityNameEnum(String description) {
this.description = description;
}
public String getDescription() {
return this.description;
}
}

View file

@ -0,0 +1,198 @@
/*
* This file is part of NavalPlan
*
* Copyright (C) 2009-2010 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.entities;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import org.hibernate.NonUniqueResultException;
import org.hibernate.validator.AssertTrue;
import org.hibernate.validator.NotEmpty;
import org.hibernate.validator.NotNull;
import org.navalplanner.business.common.BaseEntity;
import org.navalplanner.business.common.IntegrationEntity;
import org.navalplanner.business.common.Registry;
import org.navalplanner.business.common.daos.IEntitySequenceDAO;
import org.navalplanner.business.common.exceptions.InstanceNotFoundException;
import org.navalplanner.business.i18n.I18nHelper;
/**
* Sequence for {@link IntegrationEntity} codes.
* @author Susana Montes Pedreira <smontes@wirelessgalicia.com>
*/
public class EntitySequence extends BaseEntity {
public static final Integer MIN_NUMBER_OF_DIGITS = 5;
public static final Integer MAX_NUMBER_OF_DIGITS = 9;
public static EntitySequence create(String prefix, EntityNameEnum entityName) {
return create(new EntitySequence(prefix, entityName));
}
/**
* Constructor for hibernate. Do not use!
*/
public EntitySequence() {
}
public EntitySequence(String prefix, EntityNameEnum entityName) {
this.prefix = prefix;
this.entityName = entityName;
}
private String prefix;
private EntityNameEnum entityName;
private Integer lastValue = 0;
private Integer numberOfDigits = MIN_NUMBER_OF_DIGITS;
private Boolean active = false;
public void setPrefix(String prefix) throws IllegalArgumentException {
if (isAlreadyInUse()) {
throw new IllegalArgumentException(
I18nHelper
._("You can not modifiy this order sequence, it is already in use"));
}
this.prefix = prefix;
}
@NotEmpty(message = "prefix not specified")
public String getPrefix() {
if (prefix != null) {
prefix = prefix.trim();
}
return prefix;
}
@NotNull(message = "last value not specified")
public Integer getLastValue() {
return lastValue;
}
@AssertTrue(message = "prefix must not contain white spaces")
public boolean checkConstraintPrefixWithoutWhiteSpaces() {
if ((prefix == null) || (prefix.isEmpty())) {
return false;
}
return !prefix.contains(" ");
}
public void setActive(Boolean active) {
this.active = active;
}
public Boolean isActive() {
return active;
}
public void setNumberOfDigits(Integer numberOfDigits)
throws IllegalArgumentException {
if (isAlreadyInUse()) {
throw new IllegalArgumentException(
I18nHelper
._("You can not modifiy this order sequence, it is already in use"));
}
if ((numberOfDigits != null)
&& (numberOfDigits >= MIN_NUMBER_OF_DIGITS)
&& (numberOfDigits <= MAX_NUMBER_OF_DIGITS)) {
this.numberOfDigits = numberOfDigits;
} else {
throw new IllegalArgumentException(I18nHelper._(
"number of digits must be between {0} and {1}",
MIN_NUMBER_OF_DIGITS, MAX_NUMBER_OF_DIGITS));
}
}
@NotNull(message = "number of digits not specified")
public Integer getNumberOfDigits() {
return numberOfDigits;
}
@AssertTrue(message = "number of digits is out of range")
public boolean checkConstraintNumberOfDigitsInRange() {
if ((numberOfDigits != null)
&& (numberOfDigits >= MIN_NUMBER_OF_DIGITS)
&& (numberOfDigits <= MAX_NUMBER_OF_DIGITS)) {
return true;
}
return false;
}
public static String formatValue(int numberOfDigits, int value) {
String format = "";
for (int i = 0; i < numberOfDigits; i++) {
format += "0";
}
NumberFormat numberFormat = new DecimalFormat(format);
return numberFormat.format(value);
}
public boolean isAlreadyInUse() {
return lastValue > 0;
}
public String getCode() {
return prefix + formatValue(numberOfDigits, lastValue);
}
public void incrementLastValue() {
lastValue++;
}
@NotNull(message = "entity name not specified")
public EntityNameEnum getEntityName() {
return entityName;
}
public void setEntityName(EntityNameEnum entityName) {
this.entityName = entityName;
}
@AssertTrue(message = "Only one sequence for each entity can be active at the same time.")
public boolean checkConstraintOnlyOneSequenceForEachEntityIsActive() {
if (!isActive()) {
return true;
}
IEntitySequenceDAO entitySequenceDAO = Registry.getEntitySequenceDAO();
if (isNewObject()) {
return !entitySequenceDAO
.existOtherActiveSequenceByEntityNameForNewObject(this);
} else {
try {
EntitySequence c = entitySequenceDAO
.getActiveEntitySequence(this.entityName);
return c.getId().equals(getId());
} catch (NonUniqueResultException e) {
return false;
} catch (InstanceNotFoundException e) {
return true;
}
}
}
}

View file

@ -75,6 +75,9 @@
<value>
org/navalplanner/business/common/entities/OrderSequence.hbm.xml
</value>
<value>
org/navalplanner/business/common/entities/EntitySequence.hbm.xml
</value>
<value>
org/navalplanner/business/externalcompanies/entities/ExternalCompanies.hbm.xml
</value>

View file

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping default-access="field"
package="org.navalplanner.business.common.entities">
<!-- EntitySequence -->
<class name="EntitySequence">
<id name="id" column="id" type="long" access="property">
<generator class="hilo">
<param name="max_lo">100</param>
</generator>
</id>
<version name="version" access="property" type="long" />
<property name="entityName">
<type name="org.hibernate.type.EnumType">
<param name="enumClass">org.navalplanner.business.common.entities.EntityNameEnum</param>
</type>
</property>
<property name="prefix" />
<property name="lastValue" />
<property name="numberOfDigits" />
<property name="active" />
</class>
</hibernate-mapping>

View file

@ -0,0 +1,226 @@
/*
* This file is part of NavalPlan
*
* Copyright (C) 2009-2010 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 static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.navalplanner.business.BusinessGlobalNames.BUSINESS_SPRING_CONFIG_FILE;
import static org.navalplanner.business.test.BusinessGlobalNames.BUSINESS_SPRING_CONFIG_TEST_FILE;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.navalplanner.business.common.daos.IEntitySequenceDAO;
import org.navalplanner.business.common.entities.EntityNameEnum;
import org.navalplanner.business.common.entities.EntitySequence;
import org.navalplanner.business.common.exceptions.InstanceNotFoundException;
import org.navalplanner.business.common.exceptions.ValidationException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.annotation.NotTransactional;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;
/**
* Tests for {@link EntitySequence}. <br />
* @author Susana Montes Pedreira <smontes@wirelessgalicia.com>
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { BUSINESS_SPRING_CONFIG_FILE,
BUSINESS_SPRING_CONFIG_TEST_FILE })
@Transactional
public class EntitySequenceTest {
@Autowired
IEntitySequenceDAO entitySequenceDAO;
@Autowired
private IAdHocTransactionService transactionService;
@Test
public void testCreateActiveEntitySequence() throws Exception {
try {
entitySequenceDAO.save(givenEntitySequence("prefix_test",
EntityNameEnum.CALENDAR, true));
entitySequenceDAO.flush();
} catch (ValidationException e) {
fail("It should not throw an exception");
}
assertTrue(entitySequenceDAO.getAll().size() == 1);
}
@Test
public void testCreateEntitySequenceWithEmptyPrefix() throws Exception {
try {
entitySequenceDAO.save(givenEntitySequence("",
EntityNameEnum.CALENDAR, true));
fail("It should throw an exception");
} catch (ValidationException e) {
// It should throw an exception
}
}
@Test
public void testCreateEntitySequenceWithPrefixWithWhiteSpace()
throws Exception {
try {
entitySequenceDAO.save(givenEntitySequence(
"prefix with white spaces", EntityNameEnum.CALENDAR, true));
fail("It should throw an exception");
} catch (ValidationException e) {
// It should throw an exception
}
}
@Test
public void testCreateEntitySequenceWithEmptyEntityName() throws Exception {
try {
entitySequenceDAO.save(givenEntitySequence("prefix", null, false));
fail("It should throw an exception");
} catch (ValidationException e) {
// It should throw an exception
}
}
@Test
public void testCreateEntitySequenceWithNumberOfDigitsNotSpecified()
throws Exception {
try {
EntitySequence entitySequence = givenEntitySequence("prefix",
EntityNameEnum.CRITERION, true);
entitySequence.setNumberOfDigits(null);
entitySequenceDAO.save(entitySequence);
fail("It should throw an exception");
} catch (IllegalArgumentException e) {
// It should throw an exception
}
}
@Test
public void testCreateEntitySequenceWithNumberOfDigitsOutRange()
throws Exception {
try {
EntitySequence entitySequence = givenEntitySequence("prefix",
EntityNameEnum.CRITERION, true);
entitySequence.setNumberOfDigits(15);
entitySequenceDAO.save(entitySequence);
fail("It should throw an exception");
} catch (IllegalArgumentException e) {
// It should throw an exception
}
}
@Test
@NotTransactional
public void testCreateTwoActiveEntitySequenceWithTheSameEntityName() {
EntitySequence entitySequenceA = givenEntitySequence("prefixA",
EntityNameEnum.CRITERION, true);
saveEntitySequenceInTransaction(entitySequenceA);
try {
EntitySequence entitySequenceB = givenEntitySequence("prefixB",
EntityNameEnum.CRITERION, true);
saveEntitySequenceInTransaction(entitySequenceB);
fail("Expected ValidationException");
} catch (ValidationException e) {
}
}
@Test
@NotTransactional
public void testCreateTwoEntitySequenceWithTheSameEntityName() {
EntitySequence entitySequenceA = givenEntitySequence("prefixA",
EntityNameEnum.LABEL, true);
saveEntitySequenceInTransaction(entitySequenceA);
try {
EntitySequence entitySequenceB = givenEntitySequence("prefixB",
EntityNameEnum.LABEL, false);
saveEntitySequenceInTransaction(entitySequenceB);
} catch (ValidationException e) {
fail("It shouldn't throw an exception");
}
}
@Test
@NotTransactional
public void testCreateAndRemoveTwoEntitySequenceWithTheSameEntityName() {
EntitySequence entitySequenceA = givenEntitySequence("prefixA",
EntityNameEnum.MACHINE, true);
saveEntitySequenceInTransaction(entitySequenceA);
try {
removeEntitySequenceInTransaction(entitySequenceA);
} catch (ValidationException e) {
fail("It shouldn't throw an exception");
}
try {
EntitySequence entitySequenceB = givenEntitySequence("prefixB",
EntityNameEnum.MACHINE, true);
saveEntitySequenceInTransaction(entitySequenceB);
} catch (ValidationException e) {
fail("It shouldn't throw an exception");
}
}
private void saveEntitySequenceInTransaction(
final EntitySequence entitySequence) {
IOnTransaction<Void> createEntitySequenceTransaction = new IOnTransaction<Void>() {
@Override
public Void execute() {
entitySequenceDAO.save(entitySequence);
return null;
}
};
transactionService.runOnTransaction(createEntitySequenceTransaction);
}
private void removeEntitySequenceInTransaction(
final EntitySequence entitySequence) {
IOnTransaction<Void> createEntitySequenceTransaction = new IOnTransaction<Void>() {
@Override
public Void execute() {
try {
entitySequenceDAO.remove(entitySequence);
} catch (InstanceNotFoundException e) {
} catch (IllegalArgumentException e) {
}
return null;
}
};
transactionService.runOnTransaction(createEntitySequenceTransaction);
}
private EntitySequence givenEntitySequence(String prefix,
EntityNameEnum entityName, boolean active) {
EntitySequence entitySequence = EntitySequence.create(prefix,
entityName);
entitySequence.setActive(active);
return entitySequence;
}
}

View file

@ -81,6 +81,9 @@
<value>
org/navalplanner/business/common/entities/OrderSequence.hbm.xml
</value>
<value>
org/navalplanner/business/common/entities/EntitySequence.hbm.xml
</value>
<value>
org/navalplanner/business/externalcompanies/entities/ExternalCompanies.hbm.xml
</value>