diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/planner/entities/DerivedAllocation.java b/navalplanner-business/src/main/java/org/navalplanner/business/planner/entities/DerivedAllocation.java
new file mode 100644
index 000000000..79c42fe6e
--- /dev/null
+++ b/navalplanner-business/src/main/java/org/navalplanner/business/planner/entities/DerivedAllocation.java
@@ -0,0 +1,143 @@
+/*
+ * This file is part of ###PROJECT_NAME###
+ *
+ * Copyright (C) 2009 Fundación para o Fomento da Calidade Industrial e
+ * Desenvolvemento Tecnolóxico de Galicia
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+package org.navalplanner.business.planner.entities;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+
+import org.apache.commons.lang.Validate;
+import org.hibernate.validator.NotNull;
+import org.joda.time.LocalDate;
+import org.navalplanner.business.common.BaseEntity;
+import org.navalplanner.business.resources.entities.Machine;
+import org.navalplanner.business.resources.entities.MachineWorkersConfigurationUnit;
+
+/**
+ * @author Óscar González Fernández
+ *
+ */
+public class DerivedAllocation extends BaseEntity {
+
+ private static boolean isIfGenericContainsMachine(
+ ResourceAllocation> derivedFrom,
+ MachineWorkersConfigurationUnit configurationUnit) {
+ if (derivedFrom instanceof GenericResourceAllocation) {
+ GenericResourceAllocation generic = (GenericResourceAllocation) derivedFrom;
+ return generic.getAssociatedResources().contains(
+ configurationUnit.getMachine());
+ }
+ return true;
+ }
+
+ private static boolean isIfSpecificSameMachine(
+ ResourceAllocation> derivedFrom,
+ MachineWorkersConfigurationUnit configurationUnit) {
+ if (derivedFrom instanceof SpecificResourceAllocation) {
+ SpecificResourceAllocation specific = (SpecificResourceAllocation) derivedFrom;
+ return specific.getResource()
+ .equals(configurationUnit.getMachine());
+ }
+ return true;
+ }
+
+ @NotNull
+ private ResourceAllocation> derivedFrom;
+
+ @NotNull
+ private MachineWorkersConfigurationUnit configurationUnit;
+
+ private HashSet assignments;
+
+ public static DerivedAllocation create(ResourceAllocation> derivedFrom,
+ MachineWorkersConfigurationUnit configurationUnit) {
+ return create(new DerivedAllocation(derivedFrom, configurationUnit));
+ }
+
+ /**
+ * Constructor for hibernate. DO NOT USE!
+ */
+ public DerivedAllocation() {
+
+ }
+
+ public DerivedAllocation(ResourceAllocation> derivedFrom,
+ MachineWorkersConfigurationUnit configurationUnit) {
+ Validate.notNull(derivedFrom);
+ Validate.notNull(configurationUnit);
+ Validate
+ .isTrue(isIfSpecificSameMachine(derivedFrom, configurationUnit));
+ Validate.isTrue(isIfGenericContainsMachine(derivedFrom,
+ configurationUnit));
+ this.derivedFrom = derivedFrom;
+ this.configurationUnit = configurationUnit;
+ }
+
+ public MachineWorkersConfigurationUnit getConfigurationUnit() {
+ return configurationUnit;
+ }
+
+ public ResourceAllocation> getDerivedFrom() {
+ return derivedFrom;
+ }
+
+ public void resetAssignmentsTo(List dayAssignments) {
+ checkAreValid(dayAssignments);
+ this.assignments = new HashSet(dayAssignments);
+ }
+
+ private void checkAreValid(List dayAssignments) {
+ for (DerivedDayAssignment each : dayAssignments) {
+ checkIsValid(each);
+ }
+ }
+
+ private void checkIsValid(DerivedDayAssignment dayAssingment) {
+ Machine machine = configurationUnit.getMachine();
+ if (!dayAssingment.getResource().equals(machine)) {
+ throw new IllegalArgumentException(dayAssingment
+ + " has the resource: " + dayAssingment.getResource()
+ + " but this derived allocation has the resource: "
+ + machine);
+ }
+ if (!dayAssingment.getAllocation().equals(this)) {
+ throw new IllegalArgumentException(dayAssingment
+ + " is related to " + dayAssingment.getAllocation()
+ + " instead of this: " + this);
+ }
+ }
+
+ public void resetAssignmentsTo(LocalDate startInclusive,
+ LocalDate endExclusive, List newAssignments) {
+ List toBeRemoved = DayAssignment.getAtInterval(
+ getAssignments(), startInclusive, endExclusive);
+ assignments.removeAll(toBeRemoved);
+ checkAreValid(newAssignments);
+ assignments.addAll(DayAssignment.getAtInterval(newAssignments,
+ startInclusive, endExclusive));
+ }
+
+ public List getAssignments() {
+ return DayAssignment.orderedByDay(new ArrayList(
+ assignments));
+ }
+
+
+}
diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/planner/entities/DerivedDayAssignment.java b/navalplanner-business/src/main/java/org/navalplanner/business/planner/entities/DerivedDayAssignment.java
new file mode 100644
index 000000000..249ecb983
--- /dev/null
+++ b/navalplanner-business/src/main/java/org/navalplanner/business/planner/entities/DerivedDayAssignment.java
@@ -0,0 +1,61 @@
+/*
+ * This file is part of ###PROJECT_NAME###
+ *
+ * Copyright (C) 2009 Fundación para o Fomento da Calidade Industrial e
+ * Desenvolvemento Tecnolóxico de Galicia
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+package org.navalplanner.business.planner.entities;
+
+import org.apache.commons.lang.Validate;
+import org.hibernate.validator.NotNull;
+import org.joda.time.LocalDate;
+import org.navalplanner.business.resources.entities.Machine;
+import org.navalplanner.business.resources.entities.Resource;
+
+
+/**
+ * @author Óscar González Fernández
+ *
+ */
+public class DerivedDayAssignment extends DayAssignment {
+
+ public static DerivedDayAssignment create(LocalDate day, int hours,
+ Resource resource, DerivedAllocation derivedAllocation) {
+ return create(new DerivedDayAssignment(day, hours, resource,
+ derivedAllocation));
+ }
+
+ @NotNull
+ private DerivedAllocation allocation;
+
+ private DerivedDayAssignment(LocalDate day, int hours, Resource resource,
+ DerivedAllocation derivedAllocation) {
+ super(day, hours, resource);
+ Validate.notNull(derivedAllocation);
+ Validate.isTrue(resource instanceof Machine);
+ this.allocation = derivedAllocation;
+ }
+
+ @Override
+ protected void detachFromAllocation() {
+ this.allocation = null;
+ }
+
+ public DerivedAllocation getAllocation() {
+ return allocation;
+ }
+
+}
diff --git a/navalplanner-business/src/test/java/org/navalplanner/business/test/planner/entities/DerivedAllocationTest.java b/navalplanner-business/src/test/java/org/navalplanner/business/test/planner/entities/DerivedAllocationTest.java
new file mode 100644
index 000000000..a2b004f38
--- /dev/null
+++ b/navalplanner-business/src/test/java/org/navalplanner/business/test/planner/entities/DerivedAllocationTest.java
@@ -0,0 +1,221 @@
+/*x
+ * This file is part of ###PROJECT_NAME###
+ *
+ * Copyright (C) 2009 Fundación para o Fomento da Calidade Industrial e
+ * Desenvolvemento Tecnolóxico de Galicia
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+package org.navalplanner.business.test.planner.entities;
+
+import static org.easymock.EasyMock.expect;
+import static org.easymock.classextension.EasyMock.createNiceMock;
+import static org.easymock.classextension.EasyMock.replay;
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.joda.time.LocalDate;
+import org.junit.Test;
+import org.navalplanner.business.planner.entities.DerivedAllocation;
+import org.navalplanner.business.planner.entities.DerivedDayAssignment;
+import org.navalplanner.business.planner.entities.GenericResourceAllocation;
+import org.navalplanner.business.planner.entities.ResourceAllocation;
+import org.navalplanner.business.planner.entities.SpecificResourceAllocation;
+import org.navalplanner.business.resources.entities.Machine;
+import org.navalplanner.business.resources.entities.MachineWorkersConfigurationUnit;
+import org.navalplanner.business.resources.entities.Resource;
+import org.navalplanner.business.resources.entities.Worker;
+
+/**
+ * @author Óscar González Fernández
+ */
+public class DerivedAllocationTest {
+
+ private Machine machine = Machine.create();
+
+ private MachineWorkersConfigurationUnit configurationUnit;
+
+ private ResourceAllocation> derivedFrom;
+
+ private DerivedAllocation derivedAllocation;
+
+ private List dayAssignments;
+
+ private void givenConfigurationUnit(Machine machine) {
+ configurationUnit = createNiceMock(MachineWorkersConfigurationUnit.class);
+ expect(configurationUnit.getMachine()).andReturn(machine).anyTimes();
+ replay(configurationUnit);
+ }
+
+ private void givenConfigurationUnit() {
+ givenConfigurationUnit(machine);
+ }
+
+ private void givenADerivedAllocation() {
+ givenDerivedFrom();
+ givenConfigurationUnit();
+ derivedAllocation = DerivedAllocation.create(derivedFrom,
+ configurationUnit);
+ }
+
+ private void givenDayAssignments(LocalDate start, Resource resource, int... hours) {
+ givenDayAssignments(derivedAllocation, start, resource, hours);
+ }
+
+ private void givenDayAssignments(DerivedAllocation derivedAllocation,
+ LocalDate start, Resource resource, int... hours) {
+ dayAssignments = new ArrayList();
+ for (int i = 0; i < hours.length; i++) {
+ LocalDate current = start.plusDays(i);
+ DerivedDayAssignment d = DerivedDayAssignment.create(current,
+ hours[i], resource, derivedAllocation);
+ dayAssignments.add(d);
+ }
+ }
+
+ private Machine createMachine() {
+ Machine result = createNiceMock(Machine.class);
+ replay(result);
+ return result;
+ }
+
+ private void givenSpecificDerivedFrom(Resource resource) {
+ derivedFrom = createNiceMock(SpecificResourceAllocation.class);
+ SpecificResourceAllocation specific = (SpecificResourceAllocation) derivedFrom;
+ expect(specific.getResource()).andReturn(resource).anyTimes();
+ replay(derivedFrom);
+ }
+
+ private void givenGenericDerivedFrom(Resource... resources) {
+ derivedFrom = createNiceMock(GenericResourceAllocation.class);
+ GenericResourceAllocation generic = (GenericResourceAllocation) derivedFrom;
+ expect(generic.getAssociatedResources()).andReturn(
+ Arrays.asList(resources));
+ replay(derivedFrom);
+ }
+
+ private void givenDerivedFrom() {
+ givenSpecificDerivedFrom(machine);
+ }
+
+ @Test
+ public void aDerivedAllocationHasAMachineWorkerConfigurationUnitAndAResourceAllocation() {
+ givenConfigurationUnit();
+ givenDerivedFrom();
+ DerivedAllocation result = DerivedAllocation.create(derivedFrom,
+ configurationUnit);
+ assertNotNull(result);
+ assertThat(result.getConfigurationUnit(), equalTo(configurationUnit));
+ assertEquals(result.getDerivedFrom(), derivedFrom);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void theConfigurationUnitMachineMustBeTheSameThanTheAllocationIfItIsSpecific() {
+ givenConfigurationUnit(createMachine());
+ givenSpecificDerivedFrom(createMachine());
+ DerivedAllocation.create(derivedFrom, configurationUnit);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void theMachineOfTheConfigurationUnitMustBeInTheResourcesOfTheGenericAlloation() {
+ givenConfigurationUnit();
+ givenGenericDerivedFrom(Worker.create(), Worker.create());
+ DerivedAllocation.create(derivedFrom, configurationUnit);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void theDerivedFromMustBeNotNull() {
+ givenConfigurationUnit();
+ DerivedAllocation.create(derivedFrom, configurationUnit);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void theConfigurationUnitMustBeNotNull() {
+ givenDerivedFrom();
+ DerivedAllocation.create(derivedFrom, configurationUnit);
+ }
+
+ @Test
+ public void aJustCreatedDerivedAllocationIsANewObject() {
+ givenDerivedFrom();
+ givenConfigurationUnit();
+ DerivedAllocation result = DerivedAllocation.create(derivedFrom,
+ configurationUnit);
+ assertTrue(result.isNewObject());
+ }
+
+ @Test
+ public void aDerivedAllocationCanBeResetToSomeDayAssignmentsAndIsOrderedByDay() {
+ givenADerivedAllocation();
+ givenDayAssignments(new LocalDate(2008, 12, 1), machine, 8, 8, 8, 8);
+ derivedAllocation.resetAssignmentsTo(dayAssignments);
+ assertThat(derivedAllocation.getAssignments(), equalTo(dayAssignments));
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void theDerivedDayAssignmentsMustBeForTheSameMachine() {
+ givenADerivedAllocation();
+ final Machine otherMachine = Machine.create();
+ givenDayAssignments(new LocalDate(2008, 12, 1), otherMachine, 8, 8,
+ 8);
+ derivedAllocation.resetAssignmentsTo(dayAssignments);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void theDerivedDayAssignmentsMustBeForTheSameDerivedAllocation() {
+ givenADerivedAllocation();
+ DerivedAllocation another = DerivedAllocation.create(derivedFrom,
+ configurationUnit);
+ givenDayAssignments(another, new LocalDate(2008, 12, 1), machine, 8, 8,
+ 8);
+ derivedAllocation.resetAssignmentsTo(dayAssignments);
+ }
+
+ @Test
+ public void theAssignmentsCanBeResetOnAnInterval() {
+ givenADerivedAllocation();
+ LocalDate start = new LocalDate(2008, 12, 1);
+ givenDayAssignments(start, machine, 8, 8, 8, 8);
+ derivedAllocation.resetAssignmentsTo(dayAssignments);
+ final LocalDate startInterval = start.plusDays(2);
+ final LocalDate finishInterval = start.plusDays(4);
+ DerivedDayAssignment newAssignment = DerivedDayAssignment.create(
+ startInterval, 3, machine, derivedAllocation);
+ derivedAllocation.resetAssignmentsTo(startInterval, finishInterval,
+ Arrays.asList(newAssignment));
+ assertThat(derivedAllocation.getAssignments(), equalTo(Arrays.asList(
+ dayAssignments.get(0), dayAssignments.get(1), newAssignment)));
+ }
+
+ @Test
+ public void whenResettingAssignmentsOnIntervalOnlyTheOnesAtTheIntervalAreAdded() {
+ givenADerivedAllocation();
+ LocalDate start = new LocalDate(2008, 12, 1);
+ givenDayAssignments(start, machine, 8, 8, 8, 8);
+ derivedAllocation.resetAssignmentsTo(dayAssignments);
+ DerivedDayAssignment newAssignment = DerivedDayAssignment.create(start
+ .minusDays(1), 3, machine, derivedAllocation);
+ derivedAllocation.resetAssignmentsTo(start, start.plusDays(4), Arrays
+ .asList(newAssignment));
+ assertTrue(derivedAllocation.getAssignments().isEmpty());
+ }
+
+}