From cce0fdc50b68c85313019f3606a16cc402d58053 Mon Sep 17 00:00:00 2001 From: msmock Date: Fri, 22 May 2015 21:04:37 +0200 Subject: [PATCH] implemented core planning functionality where activity with all child elements is created programmatically and the time and values of the changes is set by the programmmer. Note, that the persistence and xml serialization is not implemented yet. --- .../java/li/strolch/model/ModelGenerator.java | 1 + .../src/main/java/li/strolch/model/State.java | 3 +- .../src/main/java/li/strolch/model/Tags.java | 3 + .../li/strolch/model/activity/Action.java | 123 +++++++--- .../strolch/model/activity/ActionState.java | 28 --- .../li/strolch/model/activity/Activity.java | 184 ++++++++++---- .../model/activity/IActivityElement.java | 17 +- .../strolch/model/timevalue/IValueChange.java | 5 + .../model/timevalue/impl/ValueChange.java | 6 + .../li/strolch/model/activity/ActionTest.java | 52 ++++ .../strolch/model/activity/ActivityTest.java | 106 ++++++++ li.strolch.service/pom.xml | 184 +++++++------- .../command/plan/PlanActionCommand.java | 53 ++-- .../command/plan/PlanActivityCommand.java | 188 ++++++++++++++ .../strolch/command/plan/PlanActionTest.java | 72 +++--- .../command/plan/PlanActivityTest.java | 231 ++++++++++++++++++ 16 files changed, 999 insertions(+), 257 deletions(-) delete mode 100644 li.strolch.model/src/main/java/li/strolch/model/activity/ActionState.java create mode 100644 li.strolch.model/src/test/java/li/strolch/model/activity/ActionTest.java create mode 100644 li.strolch.model/src/test/java/li/strolch/model/activity/ActivityTest.java create mode 100644 li.strolch.service/src/main/java/li/strolch/command/plan/PlanActivityCommand.java create mode 100644 li.strolch.service/src/test/java/li/strolch/command/plan/PlanActivityTest.java diff --git a/li.strolch.model/src/main/java/li/strolch/model/ModelGenerator.java b/li.strolch.model/src/main/java/li/strolch/model/ModelGenerator.java index a4fd9dab8..a0ee7780b 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/ModelGenerator.java +++ b/li.strolch.model/src/main/java/li/strolch/model/ModelGenerator.java @@ -109,6 +109,7 @@ public class ModelGenerator { public static final long STATE_TIME_10 = 10L; public static final long STATE_TIME_20 = 20L; public static final long STATE_TIME_30 = 30L; + public static final long STATE_TIME_40 = 40L; public static final Double STATE_FLOAT_TIME_0 = 0.0D; public static final Double STATE_FLOAT_TIME_10 = 10.0D; diff --git a/li.strolch.model/src/main/java/li/strolch/model/State.java b/li.strolch.model/src/main/java/li/strolch/model/State.java index 9bf386425..265a59ddf 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/State.java +++ b/li.strolch.model/src/main/java/li/strolch/model/State.java @@ -23,7 +23,8 @@ public enum State { CREATED("Created"), //$NON-NLS-1$ OPEN("Open"), //$NON-NLS-1$ EXECUTION("Execution"), //$NON-NLS-1$ - CLOSED("Closed"); //$NON-NLS-1$ + CLOSED("Closed"), //$NON-NLS-1$ + PLANNED("Planned"); //$NON-NLS-1$ private String state; diff --git a/li.strolch.model/src/main/java/li/strolch/model/Tags.java b/li.strolch.model/src/main/java/li/strolch/model/Tags.java index 2152d0989..5a00079b1 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/Tags.java +++ b/li.strolch.model/src/main/java/li/strolch/model/Tags.java @@ -41,6 +41,9 @@ public class Tags { public static final String FILE = "file"; public static final String BAG = "Bag"; public static final String AUDIT = "Audit"; + + public static final String ACTIVITY = "Activity"; + public static final String ACTION = "Action"; public class Audit { public static final String ID = Tags.ID; diff --git a/li.strolch.model/src/main/java/li/strolch/model/activity/Action.java b/li.strolch.model/src/main/java/li/strolch/model/activity/Action.java index 094f85d5a..5d5c91e6d 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/activity/Action.java +++ b/li.strolch.model/src/main/java/li/strolch/model/activity/Action.java @@ -8,6 +8,7 @@ import li.strolch.model.GroupedParameterizedElement; import li.strolch.model.Locator; import li.strolch.model.Locator.LocatorBuilder; import li.strolch.model.Resource; +import li.strolch.model.State; import li.strolch.model.StrolchElement; import li.strolch.model.StrolchRootElement; import li.strolch.model.timevalue.IValueChange; @@ -21,38 +22,26 @@ import org.w3c.dom.Element; * {@link Activity} applies {@link IValueChange} objects at the start and end * time of the {@link Activity}. * - * @author Martin Smock + * @author Martin Smock */ public class Action extends GroupedParameterizedElement implements IActivityElement { protected static final long serialVersionUID = 1L; protected Long start; - protected Long end; + protected Long end; protected String resourceId; protected final List> startChanges = new ArrayList<>(); protected final List> endChanges = new ArrayList<>(); - - protected ActionState state = ActionState.CREATED; - - protected Activity parent; - /** - * no argument constructor - */ - protected Action() { - super(); - } + protected State state = State.CREATED; + + protected Activity parent; + + private String resourceType; - /** - * Default constructor - * - * @param id - * @param name - * @param type - */ public Action(String id, String name, String type) { super(id, name, type); } @@ -103,7 +92,40 @@ public class Action extends GroupedParameterizedElement implements IActivityElem } /** - * @param e + * @return the current State of the aAction + */ + public State getState() { + return state; + } + + /** + * @param state + * the target State of the aAction + */ + public void setState(State state) { + this.state = state; + } + + /** + * @return the type of the Resource this Action + * acts on + */ + public String getResourceType() { + return this.resourceType; + } + + /** + * @param resourceType + */ + public void setResourceType(String resourceType) { + this.resourceType = resourceType; + } + + /** + * @param add + * IValueChange to be applied to the + * Resource to time Action.getStart() + * * @return true (as specified by {@link Collection#add}) */ public boolean addStartChange(IValueChange change) { @@ -112,19 +134,28 @@ public class Action extends GroupedParameterizedElement implements IActivityElem /** * @param change - * the {@link IValueChange} the action applies at end time + * IValueChange to be applied to the + * Resource at time Action.getEnd() * @return true (as specified by {@link Collection#add}) */ public boolean addEndChange(IValueChange change) { return endChanges.add(change); } + /** + * @return the list of IValueChange attached to the + * Action start + */ public List> getStartChanges() { - return new ArrayList>(startChanges); + return startChanges; } + /** + * @return the list of IValueChange attached to the + * Action end + */ public List> getEndChanges() { - return new ArrayList>(endChanges); + return endChanges; } @Override @@ -135,37 +166,48 @@ public class Action extends GroupedParameterizedElement implements IActivityElem @Override public StrolchElement getParent() { - // TODO Auto-generated method stub - return null; + return parent; } @Override public StrolchRootElement getRootElement() { - // TODO Auto-generated method stub - return null; + return (parent == null) ? null : parent.getRootElement(); } - + @Override public boolean isRootElement() { - // TODO Auto-generated method stub return false; } @Override public StrolchElement getClone() { - // TODO Auto-generated method stub - return null; + Action clone = new Action(getId(), getName(), getType()); + clone.setDbid(getDbid()); + clone.setEnd(end); + clone.setResourceId(resourceId); + clone.setResourceType(resourceType); + clone.setStart(start); + clone.setState(state); + for (IValueChange change : getStartChanges()) { + clone.startChanges.add(change.getClone()); + } + for (IValueChange change : getEndChanges()) { + clone.endChanges.add(change.getClone()); + } + return clone; } @Override public Locator getLocator() { - // TODO Auto-generated method stub - return null; + LocatorBuilder lb = new LocatorBuilder(); + this.parent.fillLocator(lb); + fillLocator(lb); + return lb.build(); } @Override protected void fillLocator(LocatorBuilder locatorBuilder) { - // TODO Auto-generated method stub + locatorBuilder.append(this.id); } @Override @@ -177,6 +219,10 @@ public class Action extends GroupedParameterizedElement implements IActivityElem builder.append(this.name); builder.append(", type="); builder.append(this.type); + builder.append(", resourceId="); + builder.append(this.resourceId); + builder.append(", state="); + builder.append(this.state); builder.append(", start="); builder.append(this.start); builder.append(", end="); @@ -185,12 +231,9 @@ public class Action extends GroupedParameterizedElement implements IActivityElem return builder.toString(); } - public ActionState getState() { - return state; - } - - public void setState(ActionState state) { - this.state = state; + @Override + public void setParent(Activity activity) { + this.parent = activity; } } diff --git a/li.strolch.model/src/main/java/li/strolch/model/activity/ActionState.java b/li.strolch.model/src/main/java/li/strolch/model/activity/ActionState.java deleted file mode 100644 index f6ffe64e8..000000000 --- a/li.strolch.model/src/main/java/li/strolch/model/activity/ActionState.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2013 Martin Smock - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package li.strolch.model.activity; - - -/** - * Traces the state of the {@link Action} in the sequence of creation, scheduling and planning. - * - * @author Martin Smock - */ -public enum ActionState { - CREATED, - SCHEDULED, // when the start and end time is set and the value changes have been attached - PLANNED; // when the value changes have been registered to the states of the resources -} diff --git a/li.strolch.model/src/main/java/li/strolch/model/activity/Activity.java b/li.strolch.model/src/main/java/li/strolch/model/activity/Activity.java index e3127229e..32a69f6d7 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/activity/Activity.java +++ b/li.strolch.model/src/main/java/li/strolch/model/activity/Activity.java @@ -15,14 +15,20 @@ */ package li.strolch.model.activity; -import java.util.ArrayList; -import java.util.List; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Map.Entry; +import li.strolch.exception.StrolchException; import li.strolch.model.GroupedParameterizedElement; import li.strolch.model.Locator; import li.strolch.model.Locator.LocatorBuilder; +import li.strolch.model.State; import li.strolch.model.StrolchElement; import li.strolch.model.StrolchRootElement; +import li.strolch.model.Tags; +import li.strolch.model.visitor.StrolchRootElementVisitor; import org.w3c.dom.Document; import org.w3c.dom.Element; @@ -31,61 +37,142 @@ import org.w3c.dom.Element; * Parameterized object grouping a collection of {@link Activity} and * {@link Action} objects defining the process to be scheduled * - * @author Martin Smock + * @author Martin Smock */ -public class Activity extends GroupedParameterizedElement implements IActivityElement { +public class Activity extends GroupedParameterizedElement implements IActivityElement, StrolchRootElement { private static final long serialVersionUID = 1L; - protected List elements = new ArrayList<>(); + protected Activity parent; - public boolean addElement(IActivityElement e) { - return elements.add(e); + public Activity(String id, String name, String type) { + super(id, name, type); } - public List getElements() { + // use a LinkedHashMap since we will iterate elements in the order added and + // lookup elements by ID + protected Map elements = new LinkedHashMap(); + + /** + * add an activity element to the LinkedHashMap of + * IActivityElements + * + * @param activityElement + * @return the element added + */ + public IActivityElement addElement(IActivityElement activityElement) { + String id = activityElement.getId(); + if (id == null) + throw new StrolchException("Cannot add IActivityElement without id."); + else if (elements.containsKey(id)) + throw new StrolchException("Activiy " + getLocator() + " already contains an activity element with id = " + id); + else { + activityElement.setParent(this); + return elements.put(activityElement.getId(), activityElement); + } + } + + /** + * get IActivityElement by id + * + * @param id + * the id of the IActivityElement + * @return IActivityElement + */ + public IActivityElement getElement(String id) { + return elements.get(id); + } + + /** + * @return get the LinkedHashMap of + * IActivityElements + */ + public Map getElements() { return elements; } + /** + * @return the iterator for entries, which include the id as key and the + * {@link IActivityElement} as value + */ + public Iterator> elementIterator() { + return elements.entrySet().iterator(); + } + + public Long getStart() { + Long start = Long.MAX_VALUE; + Iterator> elementIterator = elementIterator(); + while (elementIterator.hasNext()) { + IActivityElement action = elementIterator.next().getValue(); + start = Math.min(start, action.getStart()); + } + return start; + } + + public Long getEnd() { + Long end = 0L; + Iterator> elementIterator = elementIterator(); + while (elementIterator.hasNext()) { + IActivityElement action = elementIterator.next().getValue(); + end = Math.max(end, action.getEnd()); + } + return end; + } + + public State getState() { + State state = State.PLANNED; + Iterator> elementIterator = elementIterator(); + while (elementIterator.hasNext()) { + IActivityElement child = elementIterator.next().getValue(); + State childState = child.getState(); + if (childState.ordinal() < state.ordinal()) { + state = childState; + } + } + return state; + } + @Override public Locator getLocator() { - // TODO Auto-generated method stub - return null; - } - - @Override - public Element toDom(Document doc) { - // TODO Auto-generated method stub - return null; - } - - @Override - public StrolchElement getParent() { - // TODO Auto-generated method stub - return null; - } - - @Override - public StrolchRootElement getRootElement() { - // TODO Auto-generated method stub - return null; - } - - @Override - public boolean isRootElement() { - // TODO Auto-generated method stub - return false; - } - - @Override - public StrolchElement getClone() { - // TODO Auto-generated method stub - return null; + LocatorBuilder lb = new LocatorBuilder(); + fillLocator(lb); + return lb.build(); } @Override protected void fillLocator(LocatorBuilder locatorBuilder) { - // TODO Auto-generated method stub + locatorBuilder.append(Tags.ACTIVITY).append(getType()).append(getId()); + } + + @Override + public Element toDom(Document doc) { + throw new StrolchException("not implemented yet"); + } + + @Override + public StrolchElement getParent() { + return parent; + } + + @Override + public StrolchRootElement getRootElement() { + return (parent == null) ? null : parent.getRootElement(); + } + + @Override + public boolean isRootElement() { + return (parent == null); + } + + @Override + public StrolchElement getClone() { + Activity clone = new Activity(id, name, type); + Iterator> elementIterator = elementIterator(); + while (elementIterator.hasNext()) { + Entry next = elementIterator.next(); + clone.elements.put(next.getKey(), (IActivityElement) next.getValue().getClone()); + } + return clone; } @Override @@ -97,9 +184,24 @@ public class Activity extends GroupedParameterizedElement implements IActivityEl builder.append(this.name); builder.append(", type="); builder.append(this.type); + builder.append(", state="); + builder.append(this.getState()); builder.append(", start="); + builder.append(this.getStart()); + builder.append(", end="); + builder.append(this.getEnd()); builder.append("]"); return builder.toString(); } + @Override + public T accept(StrolchRootElementVisitor visitor) { + throw new StrolchException("not implemented yet"); + } + + @Override + public void setParent(Activity activity) { + this.parent = activity; + } + } diff --git a/li.strolch.model/src/main/java/li/strolch/model/activity/IActivityElement.java b/li.strolch.model/src/main/java/li/strolch/model/activity/IActivityElement.java index 94ed3181e..582c33812 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/activity/IActivityElement.java +++ b/li.strolch.model/src/main/java/li/strolch/model/activity/IActivityElement.java @@ -15,12 +15,23 @@ */ package li.strolch.model.activity; +import li.strolch.model.State; +import li.strolch.model.StrolchElement; + /** - * Marker for all child elememts of {@link Activity} objects + * Marker for all child elements of {@link Activity} objects * - * @author Martin Smock + * @author Martin Smock * */ -public interface IActivityElement { +public interface IActivityElement extends StrolchElement { + + Long getStart(); + + Long getEnd(); + + State getState(); + + void setParent(Activity activity); } diff --git a/li.strolch.model/src/main/java/li/strolch/model/timevalue/IValueChange.java b/li.strolch.model/src/main/java/li/strolch/model/timevalue/IValueChange.java index e36ff0fcf..5fcd1c3c2 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/timevalue/IValueChange.java +++ b/li.strolch.model/src/main/java/li/strolch/model/timevalue/IValueChange.java @@ -59,5 +59,10 @@ public interface IValueChange { * made to a {@link TimeVariable}. */ IValueChange getInverse(); + + /** + * @return a copy of this + */ + IValueChange getClone(); } diff --git a/li.strolch.model/src/main/java/li/strolch/model/timevalue/impl/ValueChange.java b/li.strolch.model/src/main/java/li/strolch/model/timevalue/impl/ValueChange.java index eb7f58794..02bab84f3 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/timevalue/impl/ValueChange.java +++ b/li.strolch.model/src/main/java/li/strolch/model/timevalue/impl/ValueChange.java @@ -142,4 +142,10 @@ public class ValueChange implements IValueChange, Serializa this.stateId = id; } + @SuppressWarnings("unchecked") + @Override + public IValueChange getClone() { + return new ValueChange(time, value); + } + } diff --git a/li.strolch.model/src/test/java/li/strolch/model/activity/ActionTest.java b/li.strolch.model/src/test/java/li/strolch/model/activity/ActionTest.java new file mode 100644 index 000000000..585a45c33 --- /dev/null +++ b/li.strolch.model/src/test/java/li/strolch/model/activity/ActionTest.java @@ -0,0 +1,52 @@ +package li.strolch.model.activity; + +import static li.strolch.model.ModelGenerator.STATE_INTEGER_ID; +import static li.strolch.model.ModelGenerator.STATE_TIME_10; +import static li.strolch.model.ModelGenerator.STATE_TIME_30; +import li.strolch.model.timevalue.IValueChange; +import li.strolch.model.timevalue.impl.IntegerValue; +import li.strolch.model.timevalue.impl.ValueChange; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +public class ActionTest { + + Action action; + + /** + * initialize the resources with states and the activity with 2 actions. + */ + @Before + public void init() { + // create action + action = new Action("action_1", "Action 1", "Use"); + action.setStart(STATE_TIME_10); + action.setEnd(STATE_TIME_30); + + IValueChange startChange = new ValueChange<>(action.getStart(), new IntegerValue(1)); + startChange.setStateId(STATE_INTEGER_ID); + action.addStartChange(startChange); + + IValueChange endChange = new ValueChange<>(action.getEnd(), new IntegerValue(-1)); + endChange.setStateId(STATE_INTEGER_ID); + action.addEndChange(endChange); + } + + @Test + public void testClone() { + Action clone = (Action) action.getClone(); + Assert.assertEquals(action.toString(), clone.toString()); + Assert.assertEquals(action.startChanges.size(), clone.startChanges.size()); + Assert.assertEquals(action.endChanges.size(), clone.endChanges.size()); + for (int i = 0; i < action.startChanges.size(); i++) { + Assert.assertEquals(action.startChanges.get(i).getTime(), clone.startChanges.get(i).getTime()); + Assert.assertEquals(action.startChanges.get(i).getValue(), clone.startChanges.get(i).getValue()); + } + for (int i = 0; i < action.endChanges.size(); i++) { + Assert.assertEquals(action.endChanges.get(i).getTime(), clone.endChanges.get(i).getTime()); + Assert.assertEquals(action.endChanges.get(i).getValue(), clone.endChanges.get(i).getValue()); + } + } +} diff --git a/li.strolch.model/src/test/java/li/strolch/model/activity/ActivityTest.java b/li.strolch.model/src/test/java/li/strolch/model/activity/ActivityTest.java new file mode 100644 index 000000000..496fdfaf6 --- /dev/null +++ b/li.strolch.model/src/test/java/li/strolch/model/activity/ActivityTest.java @@ -0,0 +1,106 @@ +package li.strolch.model.activity; + +import static li.strolch.model.ModelGenerator.STATE_TIME_10; +import static li.strolch.model.ModelGenerator.STATE_TIME_20; +import static li.strolch.model.ModelGenerator.STATE_TIME_30; +import static li.strolch.model.ModelGenerator.STATE_TIME_40; + +import li.strolch.exception.StrolchException; +import li.strolch.model.State; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +public class ActivityTest { + + Activity activity, childActivity; + Action action_1, action_2, action_3; + + /** + * initialize the resources with states and the activity with 2 actions. + */ + @Before + public void init() { + + // create activity element + activity = new Activity("activity", "Activity", "mayorType"); + + // create action 1 + action_1 = new Action("action_1", "Action 1", "Use"); + action_1.setStart(STATE_TIME_10); + action_1.setEnd(STATE_TIME_20); + action_1.setState(State.CREATED); + + activity.addElement(action_1); + + childActivity = new Activity("child_activity", "Child Activity", "childType"); + + // create action 2 + action_2 = new Action("action_2", "Action 2", "Use"); + action_2.setStart(STATE_TIME_20); + action_2.setEnd(STATE_TIME_30); + action_2.setState(State.PLANNED); + + childActivity.addElement(action_2); + + // create action 3 + action_3 = new Action("action_3", "Action 3", "Use"); + action_3.setStart(STATE_TIME_20); + action_3.setEnd(STATE_TIME_40); + action_3.setState(State.CREATED); + + childActivity.addElement(action_3); + + activity.addElement(childActivity); + + Assert.assertEquals(2, activity.getElements().size()); + Assert.assertEquals(2, childActivity.getElements().size()); + } + + @Test + public void testStart() { + Assert.assertEquals(action_1.getStart(), activity.getStart()); + } + + @Test + public void testEnd() { + Assert.assertEquals(action_3.getEnd(), activity.getEnd()); + } + + @Test + public void testState() { + Assert.assertEquals(State.CREATED, activity.getState()); + } + + @Test (expected = StrolchException.class) + public void testIdNull() { + activity.addElement(new Action(null, null, null)); + } + + @Test (expected = StrolchException.class) + public void testIdAlreadyExists() { + activity.addElement(new Action("action_1", "Action 1", "Use")); + } + + @Test + public void getElementTest(){ + Assert.assertNull(activity.getElement("not contained")); + Assert.assertEquals(action_1, activity.getElement(action_1.getId())); + } + + @Test + public void cloneTest(){ + Activity clone = (Activity) activity.getClone(); + Assert.assertEquals(activity.toString(), clone.toString()); + Assert.assertEquals(activity.getElements().size(), clone.getElements().size()); + } + + @Test + public void getParentTest(){ + Assert.assertNull(activity.getParent()); + Assert.assertNull(activity.getRootElement()); + Assert.assertTrue(activity.isRootElement()); + } + +} diff --git a/li.strolch.service/pom.xml b/li.strolch.service/pom.xml index dabb788a4..21436d05f 100644 --- a/li.strolch.service/pom.xml +++ b/li.strolch.service/pom.xml @@ -1,107 +1,115 @@ - - 4.0.0 + + 4.0.0 - - li.strolch - li.strolch.parent - 1.1.0-SNAPSHOT - ../li.strolch.parent/pom.xml - + + li.strolch + li.strolch.parent + 1.1.0-SNAPSHOT + ../li.strolch.parent/pom.xml + - li.strolch.service + li.strolch.service - li.strolch.service - Service API for Strolch + li.strolch.service + Service API for Strolch - https://github.com/eitchnet/li.strolch.service + https://github.com/eitchnet/li.strolch.service - 2011 + 2011 - - Github Issues - https://github.com/eitchnet/li.strolch.service/issues - + + Github Issues + https://github.com/eitchnet/li.strolch.service/issues + - - scm:git:https://github.com/eitchnet/strolch.git - scm:git:git@github.com:eitch/strolch.git - https://github.com/eitchnet/strolch - + + scm:git:https://github.com/eitchnet/strolch.git + scm:git:git@github.com:eitch/strolch.git + https://github.com/eitchnet/strolch + - - - - li.strolch - li.strolch.model - - - li.strolch - li.strolch.agent - + + + + li.strolch + li.strolch.model + + + li.strolch + li.strolch.agent + - - ch.eitchnet - ch.eitchnet.xmlpers - - - ch.eitchnet - ch.eitchnet.privilege - + + ch.eitchnet + ch.eitchnet.xmlpers + + + ch.eitchnet + ch.eitchnet.privilege + - - - li.strolch - li.strolch.testbase - - - li.strolch - li.strolch.persistence.postgresql - test - + + + org.mockito + mockito-core + 2.0.8-beta + - + + + li.strolch + li.strolch.testbase + + + li.strolch + li.strolch.persistence.postgresql + test + - - - - src/main/resources - true - - **/componentVersion.properties - - - + - - - org.codehaus.mojo - buildnumber-maven-plugin - - - org.apache.maven.plugins - maven-eclipse-plugin - + + + + src/main/resources + true + + **/componentVersion.properties + + + - - org.apache.maven.plugins - maven-compiler-plugin - + + + org.codehaus.mojo + buildnumber-maven-plugin + + + org.apache.maven.plugins + maven-eclipse-plugin + - - org.apache.maven.plugins - maven-source-plugin - + + org.apache.maven.plugins + maven-compiler-plugin + - - org.apache.maven.plugins - maven-jar-plugin - + + org.apache.maven.plugins + maven-source-plugin + - - org.apache.maven.plugins - maven-site-plugin - - - + + org.apache.maven.plugins + maven-jar-plugin + + + + org.apache.maven.plugins + maven-site-plugin + + + diff --git a/li.strolch.service/src/main/java/li/strolch/command/plan/PlanActionCommand.java b/li.strolch.service/src/main/java/li/strolch/command/plan/PlanActionCommand.java index 8c64ef17e..5da38270e 100644 --- a/li.strolch.service/src/main/java/li/strolch/command/plan/PlanActionCommand.java +++ b/li.strolch.service/src/main/java/li/strolch/command/plan/PlanActionCommand.java @@ -1,5 +1,5 @@ /* - * Copyright 2014 Martin Smock + * Copyright 2015 Martin Smock * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,9 +18,11 @@ package li.strolch.command.plan; import java.util.List; import li.strolch.agent.api.ComponentContainer; +import li.strolch.model.Locator; import li.strolch.model.Resource; +import li.strolch.model.State; +import li.strolch.model.Tags; import li.strolch.model.activity.Action; -import li.strolch.model.activity.ActionState; import li.strolch.model.timedstate.StrolchTimedState; import li.strolch.model.timevalue.IValueChange; import li.strolch.persistence.api.StrolchTransaction; @@ -34,12 +36,11 @@ import ch.eitchnet.utils.dbc.DBC; * resulting changes on the {@link StrolchTimedState} objects assigned to the * {@link Resource}. * - * @author Martin Smock + * @author Martin Smock */ public class PlanActionCommand extends Command { protected Action action; - protected Resource resource; /** * @param container @@ -52,65 +53,61 @@ public class PlanActionCommand extends Command { @Override public void validate() { DBC.PRE.assertNotNull("Action may not be null!", this.action); - DBC.PRE.assertNotNull("Reosurce may not be null!", this.action); - // TODO validate action.start, resource.state are set + DBC.PRE.assertNotNull("Action attribute resourceId may not be null!", this.action.getResourceId()); + DBC.PRE.assertNotNull("Action attribute resourceType may not be null!", this.action.getResourceType()); + DBC.PRE.assertTrue("Action attribute start must be set!", this.action.getStart() > 0); + DBC.PRE.assertTrue("Action attribute end must later than start!", this.action.getEnd() > this.action.getStart()); } - /** - * Apply the {@link IValueChange} objects of the {@link Action} to the - * {@link Resource} states - */ @Override @SuppressWarnings({ "unchecked", "rawtypes" }) public void doCommand() { + + Locator locator = Locator.newBuilder(Tags.RESOURCE, action.getResourceType(), action.getResourceId()).build(); + Resource resource = tx().findElement(locator); + + tx().lock(resource); + final List> startChanges = action.getStartChanges(); for (IValueChange change : startChanges) { - final String stateId = change.getStateId(); - final StrolchTimedState timedState = resource.getTimedState(stateId); + final StrolchTimedState timedState = resource.getTimedState(change.getStateId()); timedState.applyChange(change); } final List> endChanges = action.getEndChanges(); for (IValueChange change : endChanges) { - final String stateId = change.getStateId(); - final StrolchTimedState timedState = resource.getTimedState(stateId); + final StrolchTimedState timedState = resource.getTimedState(change.getStateId()); timedState.applyChange(change); } // finally set the action state - action.setState(ActionState.PLANNED); + action.setState(State.PLANNED); + action.setResourceId(resource.getId()); } - /** - * Revert the changes induced by the {@link IValueChange} objects of the - * {@link Action} to the {@link Resource} states - */ @Override @SuppressWarnings({ "unchecked", "rawtypes" }) public void undo() { + Locator locator = Locator.newBuilder(Tags.RESOURCE, action.getResourceType(), action.getResourceId()).build(); + Resource resource = tx().findElement(locator); + final List> startChanges = action.getStartChanges(); for (IValueChange change : startChanges) { - final String stateId = change.getStateId(); - final StrolchTimedState timedState = resource.getTimedState(stateId); + final StrolchTimedState timedState = resource.getTimedState(change.getStateId()); timedState.applyChange(change.getInverse()); } final List> endChanges = action.getEndChanges(); for (IValueChange change : endChanges) { - final String stateId = change.getStateId(); - final StrolchTimedState timedState = resource.getTimedState(stateId); + final StrolchTimedState timedState = resource.getTimedState(change.getStateId()); timedState.applyChange(change.getInverse()); } // finally set the action state - action.setState(ActionState.CREATED); + action.setState(State.CREATED); } public void setAction(Action action) { this.action = action; } - public void setResource(Resource resource) { - this.resource = resource; - } - } diff --git a/li.strolch.service/src/main/java/li/strolch/command/plan/PlanActivityCommand.java b/li.strolch.service/src/main/java/li/strolch/command/plan/PlanActivityCommand.java new file mode 100644 index 000000000..dee04e228 --- /dev/null +++ b/li.strolch.service/src/main/java/li/strolch/command/plan/PlanActivityCommand.java @@ -0,0 +1,188 @@ +/* + * Copyright 2015 Martin Smock + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.command.plan; + +import java.util.Iterator; +import java.util.List; +import java.util.Map.Entry; + +import li.strolch.agent.api.ComponentContainer; +import li.strolch.exception.StrolchException; +import li.strolch.model.Locator; +import li.strolch.model.Resource; +import li.strolch.model.State; +import li.strolch.model.Tags; +import li.strolch.model.activity.Action; +import li.strolch.model.activity.Activity; +import li.strolch.model.activity.IActivityElement; +import li.strolch.model.timedstate.StrolchTimedState; +import li.strolch.model.timevalue.IValueChange; +import li.strolch.persistence.api.StrolchTransaction; +import li.strolch.service.api.Command; +import ch.eitchnet.utils.dbc.DBC; + +/** + * Command to plan an {@link Activity} to a {@link Resource}. This + * {@link Command} assumes that the {@link IValueChange} objects of the action + * are already constructed and {@link Action#resourceId} is set. + *

+ * It iterates the {@link IValueChange} operators and registers the resulting + * changes on the {@link StrolchTimedState} objects assigned to the + * {@link Resource}. + * + * @author Martin Smock + */ +public class PlanActivityCommand extends Command { + + protected Activity activity; + + /** + * @param container + * @param tx + */ + public PlanActivityCommand(ComponentContainer container, StrolchTransaction tx) { + super(container, tx); + } + + @Override + public void validate() { + DBC.PRE.assertNotNull("Activity may not be null!", this.activity); + validate(activity); + } + + private void validate(Action action) { + DBC.PRE.assertNotNull("Action attribute resourceId may not be null!", action.getResourceId()); + DBC.PRE.assertNotNull("Action attribute resourceType may not be null!", action.getResourceType()); + DBC.PRE.assertTrue("Action attribute start must be set!", action.getStart() > 0); + DBC.PRE.assertTrue("Action attribute end must later than start!", action.getEnd() > action.getStart()); + } + + private void validate(Activity activity) { + Iterator> elementIterator = activity.elementIterator(); + while (elementIterator.hasNext()) { + IActivityElement activityElement = elementIterator.next().getValue(); + if (activityElement instanceof Activity) + validate((Activity) activityElement); + else if (activityElement instanceof Action) + validate((Action) activityElement); + } + } + + @Override + public void doCommand() { + validate(); + tx().lock(activity); + plan(activity); + } + + /** + * plan an {@link Activity} by navigating to the {#link Action} and + * delegating the planning depending on the {@link IActivityElement} class. + */ + private void plan(Activity activity) { + + Iterator> elementIterator = activity.elementIterator(); + + while (elementIterator.hasNext()) { + IActivityElement activityElement = elementIterator.next().getValue(); + if (activityElement instanceof Activity) + plan((Activity) activityElement); + else if (activityElement instanceof Action) + plan((Action) activityElement); + } + } + + /** + * plan an {@link Action}.It iterates the {@link IValueChange} operators and + * registers the changes on the {@link StrolchTimedState} objects assigned + * to the {@link Resource} referenced by type and id. + * + * @param action + */ + @SuppressWarnings({ "unchecked", "rawtypes" }) + private void plan(Action action) { + + Locator locator = Locator.newBuilder(Tags.RESOURCE, action.getResourceType(), action.getResourceId()).build(); + Resource resource = tx().findElement(locator); + + if (resource == null) + throw new StrolchException("Resource with " + locator + " referenced by " + action.getLocator() + + " cannot be null!"); + + tx().lock(resource); + + final List> startChanges = action.getStartChanges(); + for (IValueChange change : startChanges) { + final StrolchTimedState timedState = resource.getTimedState(change.getStateId()); + timedState.applyChange(change); + } + + final List> endChanges = action.getEndChanges(); + for (IValueChange change : endChanges) { + final StrolchTimedState timedState = resource.getTimedState(change.getStateId()); + timedState.applyChange(change); + } + + action.setState(State.PLANNED); + } + + @Override + public void undo() { + tx().lock(activity); + unplanActivity(activity); + } + + private void unplanActivity(Activity activity) { + + Iterator> elementIterator = activity.elementIterator(); + while (elementIterator.hasNext()) { + + IActivityElement activityElement = elementIterator.next().getValue(); + + if (activityElement instanceof Activity) + unplanActivity((Activity) activityElement); + else if (activityElement instanceof Action) + unplanAction((Action) activityElement); + + } + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + private void unplanAction(Action action) { + + Locator locator = Locator.newBuilder(Tags.RESOURCE, action.getResourceType(), action.getResourceId()).build(); + Resource resource = tx().findElement(locator); + + final List> startChanges = action.getStartChanges(); + for (IValueChange change : startChanges) { + final StrolchTimedState timedState = resource.getTimedState(change.getStateId()); + timedState.applyChange(change.getInverse()); + } + + final List> endChanges = action.getEndChanges(); + for (IValueChange change : endChanges) { + final StrolchTimedState timedState = resource.getTimedState(change.getStateId()); + timedState.applyChange(change.getInverse()); + } + + action.setState(State.CREATED); + } + + public void setActivity(Activity activity) { + this.activity = activity; + } + +} diff --git a/li.strolch.service/src/test/java/li/strolch/command/plan/PlanActionTest.java b/li.strolch.service/src/test/java/li/strolch/command/plan/PlanActionTest.java index eec6a04cc..a8dfee491 100644 --- a/li.strolch.service/src/test/java/li/strolch/command/plan/PlanActionTest.java +++ b/li.strolch.service/src/test/java/li/strolch/command/plan/PlanActionTest.java @@ -21,14 +21,19 @@ import static li.strolch.model.ModelGenerator.STATE_INTEGER_TIME_0; import static li.strolch.model.ModelGenerator.STATE_TIME_0; import static li.strolch.model.ModelGenerator.STATE_TIME_10; import static li.strolch.model.ModelGenerator.STATE_TIME_20; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import java.util.SortedSet; +import li.strolch.model.Locator; import li.strolch.model.ModelGenerator; import li.strolch.model.ParameterBag; import li.strolch.model.Resource; +import li.strolch.model.State; +import li.strolch.model.Tags; import li.strolch.model.activity.Action; -import li.strolch.model.activity.ActionState; import li.strolch.model.parameter.IntegerParameter; import li.strolch.model.parameter.Parameter; import li.strolch.model.timedstate.IntegerTimedState; @@ -39,51 +44,62 @@ import li.strolch.model.timevalue.IValue; import li.strolch.model.timevalue.IValueChange; import li.strolch.model.timevalue.impl.IntegerValue; import li.strolch.model.timevalue.impl.ValueChange; +import li.strolch.persistence.api.StrolchTransaction; import org.junit.Assert; import org.junit.Before; import org.junit.Test; /** - * @author Martin Smock + * @author Martin Smock */ public class PlanActionTest { private Resource resource; + private Action action; @Before public void init() { + // add a resource with integer state variable resource = ModelGenerator.createResource("@1", "Test With States", "Stated"); - - // add a integer state final IntegerTimedState timedState = new IntegerTimedState(STATE_INTEGER_ID, STATE_INTEGER_NAME); timedState.applyChange(new ValueChange<>(STATE_TIME_0, new IntegerValue(STATE_INTEGER_TIME_0))); resource.addTimedState(timedState); - } - @Test - public void test() { - - final Action action = new Action("action_1", "Action 1", "Use"); + action = new Action("action_1", "Action 1", "Use"); action.setStart(STATE_TIME_10); action.setEnd(STATE_TIME_20); - - Assert.assertEquals(ActionState.CREATED, action.getState()); - final IntegerParameter iP = new IntegerParameter("quantity", "Occupation", 1); + Assert.assertEquals(State.CREATED, action.getState()); + + IntegerParameter iP = new IntegerParameter("quantity", "Occupation", 1); action.addParameterBag(new ParameterBag("objective", "Objective", "Don't know")); action.addParameter("objective", iP); createChanges(action); - final PlanActionCommand cmd = new PlanActionCommand(null, null); + action.setResourceId(resource.getId()); + action.setResourceType(resource.getType()); + } + + @Test + public void test() { + + StrolchTransaction tx = mock(StrolchTransaction.class); + + Locator locator = Locator.newBuilder(Tags.RESOURCE, "Stated", "@1").build(); + when(tx.findElement(eq(locator))).thenReturn(resource); + + final PlanActionCommand cmd = new PlanActionCommand(null, tx); cmd.setAction(action); - cmd.setResource(resource); cmd.doCommand(); - - // check the state - Assert.assertEquals(ActionState.PLANNED, action.getState()); + + // check the state + Assert.assertEquals(State.PLANNED, action.getState()); + + // check the resource Id + Assert.assertEquals(resource.getId(), action.getResourceId()); // check if we get the expected result StrolchTimedState> timedState = resource.getTimedState(STATE_INTEGER_ID); @@ -103,8 +119,8 @@ public class PlanActionTest { // call undo to clean up cmd.undo(); - - Assert.assertEquals(ActionState.CREATED, action.getState()); + + Assert.assertEquals(State.CREATED, action.getState()); // and check again values = timeEvolution.getValues(); @@ -116,23 +132,23 @@ public class PlanActionTest { } /** - * problem specific method to create the {@link IValueChange} objects for - * the {@link Action} to be planned + *

+ * add changes to action start and end time with a value defined in the + * action objective and set the stateId of the state variable to apply the change to + *

* * @param action - * the {@link Action} to create the {@link IValueChange} objects - * for */ - private void createChanges(final Action action) { + protected static void createChanges(final Action action) { - final Parameter parameter = action.getParameter("objective", "quantity"); - final Integer quantity = parameter.getValue(); + Parameter parameter = action.getParameter("objective", "quantity"); + Integer quantity = parameter.getValue(); - final IValueChange startChange = new ValueChange<>(action.getStart(), new IntegerValue(quantity)); + IValueChange startChange = new ValueChange<>(action.getStart(), new IntegerValue(quantity)); startChange.setStateId(STATE_INTEGER_ID); action.addStartChange(startChange); - final IValueChange endChange = new ValueChange<>(action.getEnd(), new IntegerValue(-quantity)); + IValueChange endChange = new ValueChange<>(action.getEnd(), new IntegerValue(-quantity)); endChange.setStateId(STATE_INTEGER_ID); action.addEndChange(endChange); } diff --git a/li.strolch.service/src/test/java/li/strolch/command/plan/PlanActivityTest.java b/li.strolch.service/src/test/java/li/strolch/command/plan/PlanActivityTest.java new file mode 100644 index 000000000..3bc935712 --- /dev/null +++ b/li.strolch.service/src/test/java/li/strolch/command/plan/PlanActivityTest.java @@ -0,0 +1,231 @@ +package li.strolch.command.plan; + +import static li.strolch.model.ModelGenerator.STATE_INTEGER_ID; +import static li.strolch.model.ModelGenerator.STATE_INTEGER_NAME; +import static li.strolch.model.ModelGenerator.STATE_INTEGER_TIME_0; +import static li.strolch.model.ModelGenerator.STATE_TIME_0; +import static li.strolch.model.ModelGenerator.STATE_TIME_10; +import static li.strolch.model.ModelGenerator.STATE_TIME_20; +import static li.strolch.model.ModelGenerator.STATE_TIME_30; +import static li.strolch.model.ModelGenerator.STATE_TIME_40; + +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.util.SortedSet; + +import li.strolch.model.Locator; +import li.strolch.model.ModelGenerator; +import li.strolch.model.ParameterBag; +import li.strolch.model.Resource; +import li.strolch.model.State; +import li.strolch.model.Tags; +import li.strolch.model.activity.Action; +import li.strolch.model.activity.Activity; +import li.strolch.model.parameter.IntegerParameter; +import li.strolch.model.parameter.Parameter; +import li.strolch.model.timedstate.IntegerTimedState; +import li.strolch.model.timedstate.StrolchTimedState; +import li.strolch.model.timevalue.ITimeValue; +import li.strolch.model.timevalue.ITimeVariable; +import li.strolch.model.timevalue.IValue; +import li.strolch.model.timevalue.IValueChange; +import li.strolch.model.timevalue.impl.IntegerValue; +import li.strolch.model.timevalue.impl.ValueChange; +import li.strolch.persistence.api.StrolchTransaction; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +/** + * + * @author Martin Smock + * + */ +public class PlanActivityTest { + + Activity activity, childActivity; + Resource resource_1, resource_2, resource_3; + IntegerTimedState timedState_1, timedState_2, timedState_3; + Action action_1, action_2, action_3; + + /** + * initialize the resources with states and the activity with 2 actions. + */ + @Before + public void init() { + + // create resource with integer state + resource_1 = ModelGenerator.createResource("@1", "Test With States 1", "Stated"); + timedState_1 = new IntegerTimedState(STATE_INTEGER_ID, STATE_INTEGER_NAME); + timedState_1.applyChange(new ValueChange<>(STATE_TIME_0, new IntegerValue(STATE_INTEGER_TIME_0))); + resource_1.addTimedState(timedState_1); + + // create resource with integer state + resource_2 = ModelGenerator.createResource("@2", "Test With States 2", "Stated"); + timedState_2 = new IntegerTimedState(STATE_INTEGER_ID, STATE_INTEGER_NAME); + timedState_2.applyChange(new ValueChange<>(STATE_TIME_0, new IntegerValue(STATE_INTEGER_TIME_0))); + resource_2.addTimedState(timedState_2); + + // create resource with integer state + resource_3 = ModelGenerator.createResource("@3", "Test With States 3", "Stated"); + timedState_3 = new IntegerTimedState(STATE_INTEGER_ID, STATE_INTEGER_NAME); + timedState_3.applyChange(new ValueChange<>(STATE_TIME_0, new IntegerValue(STATE_INTEGER_TIME_0))); + resource_3.addTimedState(timedState_3); + + // create activity element + activity = new Activity("activity", "Activity", "testType"); + + // create action 1 + action_1 = new Action("action_1", "Action 1", "Use"); + action_1.setStart(STATE_TIME_10); + action_1.setEnd(STATE_TIME_20); + + IntegerParameter iP1 = new IntegerParameter("quantity", "Occupation", 1); + action_1.addParameterBag(new ParameterBag("objective", "Objective", "Don't know")); + action_1.addParameter("objective", iP1); + + createChanges(action_1); + + action_1.setResourceId(resource_1.getId()); + action_1.setResourceType(resource_1.getType()); + + activity.addElement(action_1); + + // create child activity + childActivity = new Activity("childActivity", "Child Activity", "childType"); + + // create action 2 + action_2 = new Action("action_2", "Action 2", "Use"); + action_2.setStart(STATE_TIME_20); + action_2.setEnd(STATE_TIME_30); + + IntegerParameter iP2 = new IntegerParameter("quantity", "Occupation", 1); + action_2.addParameterBag(new ParameterBag("objective", "Objective", "Don't know")); + action_2.addParameter("objective", iP2); + + createChanges(action_2); + + action_2.setResourceId(resource_2.getId()); + action_2.setResourceType(resource_2.getType()); + + childActivity.addElement(action_2); + + // create action 3 + action_3 = new Action("action_3", "Action 3", "Use"); + action_3.setStart(STATE_TIME_20); + action_3.setEnd(STATE_TIME_40); + + IntegerParameter iP3 = new IntegerParameter("quantity", "Occupation", 1); + action_3.addParameterBag(new ParameterBag("objective", "Objective", "Don't know")); + action_3.addParameter("objective", iP3); + + createChanges(action_3); + + action_3.setResourceId(resource_3.getId()); + action_3.setResourceType(resource_3.getType()); + + childActivity.addElement(action_3); + + activity.addElement(childActivity); + + Assert.assertEquals(2, activity.getElements().size()); + + } + + /** + * The test method. Create appropriate mocks and call the command + */ + @Test + public void test() { + + StrolchTransaction tx = mock(StrolchTransaction.class); + + Locator locator1 = Locator.newBuilder(Tags.RESOURCE, "Stated", "@1").build(); + when(tx.findElement(eq(locator1))).thenReturn(resource_1); + + Locator locator2 = Locator.newBuilder(Tags.RESOURCE, "Stated", "@2").build(); + when(tx.findElement(eq(locator2))).thenReturn(resource_2); + + Locator locator3 = Locator.newBuilder(Tags.RESOURCE, "Stated", "@3").build(); + when(tx.findElement(eq(locator3))).thenReturn(resource_3); + + PlanActivityCommand planActivityCommand = new PlanActivityCommand(null, tx); + planActivityCommand.setActivity(activity); + planActivityCommand.doCommand(); + + // check the states + Assert.assertEquals(State.PLANNED, action_1.getState()); + Assert.assertEquals(State.PLANNED, action_2.getState()); + + // check the resource states + StrolchTimedState> timedState_1 = resource_1.getTimedState(STATE_INTEGER_ID); + ITimeVariable> timeEvolution_1 = timedState_1.getTimeEvolution(); + SortedSet>> values_1 = timeEvolution_1.getValues(); + + Assert.assertEquals(3, values_1.size()); + + ITimeValue> valueAt_1 = timeEvolution_1.getValueAt(STATE_TIME_0); + Assert.assertEquals(true, valueAt_1.getValue().equals(new IntegerValue(0))); + + valueAt_1 = timeEvolution_1.getValueAt(STATE_TIME_10); + Assert.assertEquals(true, valueAt_1.getValue().equals(new IntegerValue(1))); + + valueAt_1 = timeEvolution_1.getValueAt(STATE_TIME_20); + Assert.assertEquals(true, valueAt_1.getValue().equals(new IntegerValue(0))); + + // the second resource + StrolchTimedState> timedState_2 = resource_2.getTimedState(STATE_INTEGER_ID); + ITimeVariable> timeEvolution_2 = timedState_2.getTimeEvolution(); + SortedSet>> values_2 = timeEvolution_2.getValues(); + + Assert.assertEquals(3, values_2.size()); + + ITimeValue> valueAt_2 = timeEvolution_2.getValueAt(STATE_TIME_0); + Assert.assertEquals(true, valueAt_2.getValue().equals(new IntegerValue(0))); + + valueAt_2 = timeEvolution_2.getValueAt(STATE_TIME_20); + Assert.assertEquals(true, valueAt_2.getValue().equals(new IntegerValue(1))); + + valueAt_2 = timeEvolution_2.getValueAt(STATE_TIME_30); + Assert.assertEquals(true, valueAt_2.getValue().equals(new IntegerValue(0))); + + // test undo function + planActivityCommand.undo(); + + // check the states + Assert.assertEquals(State.CREATED, action_1.getState()); + Assert.assertEquals(State.CREATED, action_2.getState()); + + // check the resource states + values_1 = timeEvolution_1.getValues(); + Assert.assertEquals(1, values_1.size()); + + values_2 = timeEvolution_2.getValues(); + Assert.assertEquals(1, values_2.size()); + + } + + /** + * add changes to action start and end time with a value defined in the + * action objective and set the stateId of the state variable to apply the + * change to + */ + protected static void createChanges(final Action action) { + + Parameter parameter = action.getParameter("objective", "quantity"); + Integer quantity = parameter.getValue(); + + IValueChange startChange = new ValueChange<>(action.getStart(), new IntegerValue(quantity)); + startChange.setStateId(STATE_INTEGER_ID); + action.addStartChange(startChange); + + IValueChange endChange = new ValueChange<>(action.getEnd(), new IntegerValue(-quantity)); + endChange.setStateId(STATE_INTEGER_ID); + action.addEndChange(endChange); + + } + +}