Implemented base structure for planning and scheduling on resources

This commit is contained in:
msmock 2014-10-23 08:59:20 +02:00
parent f032319eca
commit 36b47dd971
20 changed files with 642 additions and 37 deletions

View File

@ -0,0 +1,190 @@
package li.strolch.model.activity;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
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.StrolchElement;
import li.strolch.model.StrolchRootElement;
import li.strolch.model.timevalue.IValueChange;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
/**
* An {@link Action} represents a single step within an {@link Activity}, that
* is, one that is not further decomposed within the {@link Activity}. A
* {@link Activity} applies {@link IValueChange} objects at the start and end
* time of the {@link Activity}.
*
* @author Martin Smock <smock.martin@gmail.com>
*/
public class Action extends GroupedParameterizedElement implements IActivityElement {
protected static final long serialVersionUID = 1L;
protected Long start;
protected Long end;
protected String resourceId;
protected final List<IValueChange<?>> startChanges = new ArrayList<>();
protected final List<IValueChange<?>> endChanges = new ArrayList<>();
protected ActionState state = ActionState.CREATED;
protected Activity parent;
/**
* no argument constructor
*/
protected Action() {
super();
}
/**
* Default constructor
*
* @param id
* @param name
* @param type
*/
public Action(String id, String name, String type) {
super(id, name, type);
}
/**
* @return the action start time in unix millisecond time
*/
public Long getStart() {
return start;
}
/**
* @param start
* the action start time in unix millisecond time
*/
public void setStart(Long start) {
this.start = start;
}
/**
* @return the action end time in unix millisecond time
*/
public Long getEnd() {
return end;
}
/**
* @param end
* the action end time in unix millisecond time
*/
public void setEnd(Long end) {
this.end = end;
}
/**
* @return the id of the {@link Resource} the {@link Action} acts on
*/
public String getResourceId() {
return resourceId;
}
/**
* @param resourceId
* the id of the {@link Resource} the {@link Action} acts on
*/
public void setResourceId(String resourceId) {
this.resourceId = resourceId;
}
/**
* @param e
* @return <tt>true</tt> (as specified by {@link Collection#add})
*/
public boolean addStartChange(IValueChange<?> change) {
return startChanges.add(change);
}
/**
* @param change
* the {@link IValueChange} the action applies at end time
* @return <tt>true</tt> (as specified by {@link Collection#add})
*/
public boolean addEndChange(IValueChange<?> change) {
return endChanges.add(change);
}
public List<IValueChange<?>> getStartChanges() {
return new ArrayList<IValueChange<?>>(startChanges);
}
public List<IValueChange<?>> getEndChanges() {
return new ArrayList<IValueChange<?>>(endChanges);
}
@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 StrolchElement getClone() {
// TODO Auto-generated method stub
return null;
}
@Override
public Locator getLocator() {
// TODO Auto-generated method stub
return null;
}
@Override
protected void fillLocator(LocatorBuilder locatorBuilder) {
// TODO Auto-generated method stub
}
@Override
public String toString() {
final StringBuilder builder = new StringBuilder();
builder.append("Action [id=");
builder.append(this.id);
builder.append(", name=");
builder.append(this.name);
builder.append(", type=");
builder.append(this.type);
builder.append(", start=");
builder.append(this.start);
builder.append(", end=");
builder.append(this.end);
builder.append("]");
return builder.toString();
}
public ActionState getState() {
return state;
}
public void setState(ActionState state) {
this.state = state;
}
}

View File

@ -0,0 +1,13 @@
package li.strolch.model.activity;
/**
* Traces the state of the {@link Action} in the sequence of creation, scheduling and planning.
*
* @author Martin Smock <smock.martin@gmail.com>
*/
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
}

View File

@ -0,0 +1,84 @@
package li.strolch.model.activity;
import java.util.ArrayList;
import java.util.List;
import li.strolch.model.GroupedParameterizedElement;
import li.strolch.model.Locator;
import li.strolch.model.Locator.LocatorBuilder;
import li.strolch.model.StrolchElement;
import li.strolch.model.StrolchRootElement;
import org.w3c.dom.Document;
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 <smock.martin@gmail.com>
*/
public class Activity extends GroupedParameterizedElement implements IActivityElement {
private static final long serialVersionUID = 1L;
protected List<IActivityElement> elements = new ArrayList<>();
public boolean addElement(IActivityElement e) {
return elements.add(e);
}
public List<IActivityElement> getElements() {
return elements;
}
@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 StrolchElement getClone() {
// TODO Auto-generated method stub
return null;
}
@Override
protected void fillLocator(LocatorBuilder locatorBuilder) {
// TODO Auto-generated method stub
}
@Override
public String toString() {
final StringBuilder builder = new StringBuilder();
builder.append("Activity [id=");
builder.append(this.id);
builder.append(", name=");
builder.append(this.name);
builder.append(", type=");
builder.append(this.type);
builder.append(", start=");
builder.append("]");
return builder.toString();
}
}

View File

@ -0,0 +1,11 @@
package li.strolch.model.activity;
/**
* Marker for all child elememts of {@link Activity} objects
*
* @author Martin Smock <smock.martin@gmail.com>
*
*/
public interface IActivityElement {
}

View File

@ -40,6 +40,8 @@ import org.w3c.dom.Element;
import ch.eitchnet.utils.helper.StringHelper;
/**
* Wrapper for a {@link IntegerTimedState}
*
* @author Robert von Burg <eitch@eitchnet.ch>
*/
@SuppressWarnings("rawtypes")

View File

@ -15,26 +15,48 @@
*/
package li.strolch.model.timevalue;
import li.strolch.model.timedstate.AbstractStrolchTimedState;
import li.strolch.model.timevalue.impl.TimeVariable;
/**
* Interface for operators to be used to change the values of {@link ITimeValue} in a {@link ITimeVariable}.
*
* Interface for operators to be used to change the values of {@link ITimeValue}
* in a {@link ITimeVariable} or {@link AbstractStrolchTimedState}.
*
* @author Martin Smock <smock.martin@gmail.com>
*/
@SuppressWarnings("rawtypes")
public interface IValueChange<T extends IValue> {
/**
* @return the id of the {@link AbstractStrolchTimedState} the change
* applies to
*/
String getStateId();
/**
* @param id
* the id of the {@link AbstractStrolchTimedState} the change
* applies to
*/
void setStateId(String id);
/**
* @return the time this change has to be applied
*/
Long getTime();
void setTime(Long time);
/**
* @return the value of the change
*/
T getValue();
void setValue(T value);
/**
* @return the inverse neutralizing a change. Very useful to undo changes applied.
* @return the inverse neutralizing a change. Very useful to undo changes
* made to a {@link TimeVariable}.
*/
IValueChange<T> getInverse();

View File

@ -1,6 +1,4 @@
/*
* Copyright 2013 Martin Smock <smock.martin@gmail.com>
*
* 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

View File

@ -1,6 +1,4 @@
/*
* Copyright 2013 Martin Smock <smock.martin@gmail.com>
*
* 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

View File

@ -1,6 +1,4 @@
/*
* Copyright 2013 Martin Smock <smock.martin@gmail.com>
*
* 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

View File

@ -1,6 +1,4 @@
/*
* Copyright 2013 Martin Smock <smock.martin@gmail.com>
*
* 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

View File

@ -1,6 +1,4 @@
/*
* Copyright 2013 Martin Smock <smock.martin@gmail.com>
*
* 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

View File

@ -1,6 +1,4 @@
/*
* Copyright 2013 Martin Smock <smock.martin@gmail.com>
*
* 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

View File

@ -1,6 +1,4 @@
/*
* Copyright 2013 Martin Smock <smock.martin@gmail.com>
*
/*
* 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

View File

@ -1,6 +1,4 @@
/*
* Copyright 2013 Martin Smock <smock.martin@gmail.com>
*
/*
* 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
@ -28,28 +26,53 @@ public class ValueChange<T extends IValue> implements IValueChange<T>, Serializa
private static final long serialVersionUID = 1L;
protected final Long time;
protected final T value;
protected Long time;
protected T value;
protected String stateId;
/**
* @param time
* the time the change applies
* @param value
* the value to be applied
*/
public ValueChange(final Long time, final T value) {
this.time = time;
this.value = value;
}
/**
* @param time
* the time the change applies
* @param value
* the value to be applied
* @param stateId
* the id of the state the change applies to
*/
public ValueChange(final Long time, final T value, final String stateId) {
this.time = time;
this.value = value;
this.stateId = stateId;
}
@Override
public Long getTime() {
return this.time;
}
public void setTime(Long time) {
this.time = time;
}
@Override
@SuppressWarnings("unchecked")
public T getValue() {
return (T) this.value.getCopy();
}
public void setValue(T value) {
this.value = value;
}
@Override
@SuppressWarnings("unchecked")
@ -107,4 +130,14 @@ public class ValueChange<T extends IValue> implements IValueChange<T>, Serializa
return sb.toString();
}
@Override
public String getStateId() {
return stateId;
}
@Override
public void setStateId(String id) {
this.stateId = id;
}
}

View File

@ -1,6 +1,4 @@
/*
* Copyright 2013 Martin Smock <smock.martin@gmail.com>
*
/*
* 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
@ -29,6 +27,11 @@ import li.strolch.model.timevalue.impl.ValueChange;
import org.junit.Before;
import org.junit.Test;
/**
* Basic tests for a {@link TimeVariable} with {@link FloatValue}.
*
* @author Martin Smock <smock.martin@gmail.com>
*/
public class FloatTimeVariableTest {
private static final Long MAX = 100L;

View File

@ -1,6 +1,4 @@
/*
* Copyright 2013 Martin Smock <smock.martin@gmail.com>
*
* 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
@ -33,7 +31,7 @@ import org.junit.Test;
/**
* Basic tests for a {@link TimeVariable} with integer values.
*
* @author martin_smock
* @author Martin Smock <smock.martin@gmail.com>
*/
public class IntegerTimeVariableTest {

View File

@ -1,6 +1,4 @@
/*
* Copyright 2013 Martin Smock <smock.martin@gmail.com>
*
* 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
@ -33,6 +31,11 @@ import li.strolch.model.timevalue.impl.ValueChange;
import org.junit.Before;
import org.junit.Test;
/**
* Basic tests for a {@link TimeVariable} with {@link StringValue}.
*
* @author Martin Smock <smock.martin@gmail.com>
*/
public class StringTimeVariableTest {
private static final Long MAX = 100L;

View File

@ -1,6 +1,4 @@
/*
* Copyright 2013 Martin Smock <smock.martin@gmail.com>
*
/*
* 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
@ -24,13 +22,19 @@ import li.strolch.model.timevalue.impl.AString;
import li.strolch.model.timevalue.impl.FloatValue;
import li.strolch.model.timevalue.impl.IntegerValue;
import li.strolch.model.timevalue.impl.StringSetValue;
import li.strolch.model.timevalue.impl.TimeVariable;
import org.junit.Test;
/**
* Basic tests for a {@link TimeVariable} with {@link StringValue}.
*
* @author Martin Smock <smock.martin@gmail.com>
*/
public class ValueTests {
/**
* check, that adding the inverse results in the neutral element (=0)
* check, that adding the inverse returns the neutral element (=0)
*/
@Test
public void testDoubleInverse() {
@ -41,7 +45,7 @@ public class ValueTests {
}
/**
* check, that adding the inverse results in the neutral element (=0)
* check, that adding the inverse returns the neutral element (=0)
*/
@Test
public void testIntegerInverse() {
@ -52,7 +56,7 @@ public class ValueTests {
}
/**
* check, that adding the inverse results in the neutral element (empty Set)
* check, that adding the inverse returns the neutral element (empty Set)
*/
@Test
public void testStringSetInverse() {

View File

@ -0,0 +1,116 @@
/*
* Copyright 2014 Martin Smock <smock.martin@gmail.com>
*
* 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.List;
import li.strolch.agent.api.ComponentContainer;
import li.strolch.model.Resource;
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;
import li.strolch.service.api.Command;
import ch.eitchnet.utils.dbc.DBC;
/**
* Command to plan an {@link Action} to a {@link Resource}. This {@link Command}
* assumes that the {@link IValueChange} objects of the action are already
* constructed. It iterates the {@link IValueChange} operators and registers the
* resulting changes on the {@link StrolchTimedState} objects assigned to the
* {@link Resource}.
*
* @author Martin Smock <smock.martin@gmail.com>
*/
public class PlanActionCommand extends Command {
protected Action action;
protected Resource resource;
/**
* @param container
* @param tx
*/
public PlanActionCommand(final ComponentContainer container, final StrolchTransaction tx) {
super(container, tx);
}
@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
}
/**
* Apply the {@link IValueChange} objects of the {@link Action} to the
* {@link Resource} states
*/
@Override
@SuppressWarnings({ "unchecked", "rawtypes" })
public void doCommand() {
final List<IValueChange<?>> startChanges = action.getStartChanges();
for (IValueChange<?> change : startChanges) {
final String stateId = change.getStateId();
final StrolchTimedState timedState = resource.getTimedState(stateId);
timedState.applyChange(change);
}
final List<IValueChange<?>> endChanges = action.getEndChanges();
for (IValueChange<?> change : endChanges) {
final String stateId = change.getStateId();
final StrolchTimedState timedState = resource.getTimedState(stateId);
timedState.applyChange(change);
}
// finally set the action state
action.setState(ActionState.PLANNED);
}
/**
* 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() {
final List<IValueChange<?>> startChanges = action.getStartChanges();
for (IValueChange<?> change : startChanges) {
final String stateId = change.getStateId();
final StrolchTimedState timedState = resource.getTimedState(stateId);
timedState.applyChange(change.getInverse());
}
final List<IValueChange<?>> endChanges = action.getEndChanges();
for (IValueChange<?> change : endChanges) {
final String stateId = change.getStateId();
final StrolchTimedState timedState = resource.getTimedState(stateId);
timedState.applyChange(change.getInverse());
}
// finally set the action state
action.setState(ActionState.CREATED);
}
public void setAction(Action action) {
this.action = action;
}
public void setResource(Resource resource) {
this.resource = resource;
}
}

View File

@ -0,0 +1,140 @@
/*
* Copyright 2014 Martin Smock <smock.martin@gmail.com>
*
* 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 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 java.util.SortedSet;
import li.strolch.model.ModelGenerator;
import li.strolch.model.ParameterBag;
import li.strolch.model.Resource;
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;
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 org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
/**
* @author Martin Smock <smock.martin@gmail.com>
*/
public class PlanActionTest {
private Resource resource;
@Before
public void init() {
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.setStart(STATE_TIME_10);
action.setEnd(STATE_TIME_20);
Assert.assertEquals(ActionState.CREATED, action.getState());
final 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);
cmd.setAction(action);
cmd.setResource(resource);
cmd.doCommand();
// check the state
Assert.assertEquals(ActionState.PLANNED, action.getState());
// check if we get the expected result
StrolchTimedState<IValue<Integer>> timedState = resource.getTimedState(STATE_INTEGER_ID);
ITimeVariable<IValue<Integer>> timeEvolution = timedState.getTimeEvolution();
SortedSet<ITimeValue<IValue<Integer>>> values = timeEvolution.getValues();
Assert.assertEquals(3, values.size());
ITimeValue<IValue<Integer>> valueAt = timeEvolution.getValueAt(STATE_TIME_0);
Assert.assertEquals(true, valueAt.getValue().equals(new IntegerValue(0)));
valueAt = timeEvolution.getValueAt(STATE_TIME_10);
Assert.assertEquals(true, valueAt.getValue().equals(new IntegerValue(1)));
valueAt = timeEvolution.getValueAt(STATE_TIME_20);
Assert.assertEquals(true, valueAt.getValue().equals(new IntegerValue(0)));
// call undo to clean up
cmd.undo();
Assert.assertEquals(ActionState.CREATED, action.getState());
// and check again
values = timeEvolution.getValues();
Assert.assertEquals(1, values.size());
valueAt = timeEvolution.getValueAt(STATE_TIME_0);
Assert.assertEquals(true, valueAt.getValue().equals(new IntegerValue(0)));
}
/**
* problem specific method to create the {@link IValueChange} objects for
* the {@link Action} to be planned
*
* @param action
* the {@link Action} to create the {@link IValueChange} objects
* for
*/
private void createChanges(final Action action) {
final Parameter<Integer> parameter = action.getParameter("objective", "quantity");
final Integer quantity = parameter.getValue();
final IValueChange<IntegerValue> startChange = new ValueChange<>(action.getStart(), new IntegerValue(quantity));
startChange.setStateId(STATE_INTEGER_ID);
action.addStartChange(startChange);
final IValueChange<IntegerValue> endChange = new ValueChange<>(action.getEnd(), new IntegerValue(-quantity));
endChange.setStateId(STATE_INTEGER_ID);
action.addEndChange(endChange);
}
}