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); + + } + +}