Skip to content
Snippets Groups Projects
Commit 1e649090 authored by René Schöne's avatar René Schöne
Browse files

Change DateTime to Instant, and rework ActivityItem.

- Resolves issue #14
- Fix bug when setting item state with initial null state
- Simplify ItemObserver
- Remove Item.copy_state()
parent 41902a6e
No related branches found
No related tags found
No related merge requests found
import java.util.*;
import java.time.Instant;
import de.tudresden.inf.st.eraser.util.MemberPrinter;
import de.tudresden.inf.st.eraser.util.JavaUtils;
......
aspect ItemHandling {
protected static final java.text.DateFormat Item.FORMAT = new java.text.SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS") {{
setTimeZone(TimeZone.getTimeZone("UTC"));
}};
protected boolean Item.isFrozen = false;
public void Item.freeze() { isFrozen = true; }
public void Item.unfreeze() { isFrozen = false; }
......@@ -16,7 +13,7 @@ aspect ItemHandling {
//--- getStateAsString ---
syn String Item.getStateAsString();
eq ColorItem.getStateAsString() = getState().toString();
eq DateTimeItem.getStateAsString() = FORMAT.format(getState());
eq DateTimeItem.getStateAsString() = getState().toString();
eq ItemWithBooleanState.getStateAsString() = Boolean.toString(getState());
eq ItemWithDoubleState.getStateAsString() = Double.toString(getState());
eq ItemWithStringState.getStateAsString() = getState();
......@@ -28,7 +25,7 @@ aspect ItemHandling {
logger.warn("getStateAsDouble called on item " + getLabel() + ". Using brightness.");
return getState().getBrightness();
}
eq DateTimeItem.getStateAsDouble() = getState().getTime();
eq DateTimeItem.getStateAsDouble() = getState().toEpochMilli();
eq ItemWithBooleanState.getStateAsDouble() = getState() ? 1 : 0;
eq ItemWithDoubleState.getStateAsDouble() = getState();
eq ItemWithStringState.getStateAsDouble() {
......@@ -53,12 +50,12 @@ aspect ItemHandling {
}
public void DateTimeItem.setStateFromString(String value) {
try{
this.setState(FORMAT.parse(value));
} catch (java.text.ParseException e1) {
this.setState(Instant.parse(value));
} catch (java.time.format.DateTimeParseException e1) {
// try to read input as number and use that
try {
long time = Long.parseLong(value);
this.setState(new Date(time));
this.setStateFromLong(time);
// exit the method to avoid printing the error message for e1
return;
} catch (NumberFormatException e2) {
......@@ -90,7 +87,7 @@ aspect ItemHandling {
this.setState(getState().withDifferentBrightness(Math.toIntExact(value)));
}
public void DateTimeItem.setStateFromLong(long value) {
this.setState(new Date(value));
this.setState(Instant.ofEpochMilli(value));
}
public void ItemWithBooleanState.setStateFromLong(long value) {
this.setState(value != 0);
......@@ -115,7 +112,7 @@ aspect ItemHandling {
}
public void DateTimeItem.setStateFromBoolean(boolean value) {
// there is no good way here
logger.warn("Ignoring color update using {} for {}", this, value);
logger.warn("Ignoring boolean update using {} for {}", value, this);
}
public void ItemWithBooleanState.setStateFromBoolean(boolean value) {
this.setState(value);
......@@ -139,7 +136,7 @@ aspect ItemHandling {
setBrightness((int) value);
}
public void DateTimeItem.setStateFromDouble(double value) {
this.setState(new Date((int) value));
this.setStateFromLong((long) value);
}
public void ItemWithBooleanState.setStateFromDouble(double value) {
this.setState(value != 0);
......@@ -164,7 +161,7 @@ aspect ItemHandling {
}
public void DateTimeItem.setStateFromColor(TupleHSB value) {
// there is no good way here
logger.warn("Ignoring color update using {} for {}", this, value);
logger.warn("Ignoring color update using {} for {}", value, this);
}
public void ItemWithBooleanState.setStateFromColor(TupleHSB value) {
this.setState(value != null && value.getBrightness() > 0);
......@@ -182,28 +179,28 @@ aspect ItemHandling {
sendState = before;
}
//--- setStateFromDate ---
public abstract void Item.setStateFromDate(Date value);
public void ColorItem.setStateFromDate(Date value) {
//--- setStateFromInstant ---
public abstract void Item.setStateFromInstant(Instant value);
public void ColorItem.setStateFromInstant(Instant value) {
// there is no good way here
logger.warn("Ignoring date update using {} for {}", this, value);
}
public void DateTimeItem.setStateFromDate(Date value) {
this.setState(new Date(value.getTime()));
public void DateTimeItem.setStateFromInstant(Instant value) {
this.setState(value);
}
public void ItemWithBooleanState.setStateFromDate(Date value) {
public void ItemWithBooleanState.setStateFromInstant(Instant value) {
this.setState(value != null);
}
public void ItemWithDoubleState.setStateFromDate(Date value) {
this.setState(value.getTime());
public void ItemWithDoubleState.setStateFromInstant(Instant value) {
this.setState(value.toEpochMilli());
}
public void ItemWithStringState.setStateFromDate(Date value) {
this.setState(FORMAT.format(value));
public void ItemWithStringState.setStateFromInstant(Instant value) {
this.setState(value.toString());
}
public void Item.setStateFromDate(Date value, boolean shouldSendState) {
public void Item.setStateFromInstant(Instant value, boolean shouldSendState) {
boolean before = sendState;
sendState = shouldSendState;
setStateFromDate(value);
setStateFromInstant(value);
sendState = before;
}
......@@ -212,52 +209,42 @@ aspect ItemHandling {
public String ItemWithStringState.getState() { return get_state(); }
public double ItemWithDoubleState.getState() { return get_state(); }
public TupleHSB ColorItem.getState() { return get_state(); }
public Date DateTimeItem.getState() { return get_state(); }
//--- copyState ---
public abstract Object Item.copyState();
// boolean can be copied
public Boolean ItemWithBooleanState.copyState() { return get_state(); }
public String ItemWithStringState.copyState() { return get_state(); }
// double can be copied
public Double ItemWithDoubleState.copyState() { return get_state(); }
public TupleHSB ColorItem.copyState() { return get_state().clone(); }
public Object DateTimeItem.copyState() { return get_state().clone(); }
public Instant DateTimeItem.getState() { return get_state(); }
//--- setState(value) ---
public void ItemWithBooleanState.setState(boolean value) { setState(value, sendState); }
public void ItemWithStringState.setState(String value) { setState(value, sendState); }
public void ItemWithDoubleState.setState(double value) { setState(value, sendState); }
public void ColorItem.setState(TupleHSB value) { setState(value, sendState); }
public void DateTimeItem.setState(Date value) { setState(value, sendState); }
public void DateTimeItem.setState(Instant value) { setState(value, sendState); }
//--- setState(value,shouldSendState) ---
public void ItemWithBooleanState.setState(boolean value, boolean shouldSendState) {
if (isFrozen) { return; }
if (isFrozen || stateEquals(value)) { return; }
set_state(value);
stateUpdated(shouldSendState);
}
public void ItemWithStringState.setState(String value, boolean shouldSendState) {
if (isFrozen) { return; }
if (isFrozen || stateEquals(value)) { return; }
set_state(value);
stateUpdated(shouldSendState);
}
public void ItemWithDoubleState.setState(double value, boolean shouldSendState) {
if (isFrozen) { return; }
if (isFrozen || stateEquals(value)) { return; }
set_state(value);
stateUpdated(shouldSendState);
}
public void ColorItem.setState(TupleHSB value, boolean shouldSendState) {
if (isFrozen) { return; }
if (isFrozen || stateEquals(value)) { return; }
set_state(value);
stateUpdated(shouldSendState);
}
public void DateTimeItem.setState(Date value, boolean shouldSendState) {
if (isFrozen) { return; }
public void DateTimeItem.setState(Instant value, boolean shouldSendState) {
if (isFrozen || stateEquals(value)) { return; }
set_state(value);
stateUpdated(shouldSendState);
}
......@@ -300,6 +287,9 @@ aspect ItemHandling {
}
public boolean ItemWithStringState.stateEquals(Object otherState) {
if (getState() == null) {
return otherState == null;
}
return getState().equals(otherState);
}
......@@ -311,23 +301,29 @@ aspect ItemHandling {
}
public boolean ColorItem.stateEquals(Object otherState) {
if (getState() == null) {
return otherState == null;
}
return getState().equals(otherState);
}
public boolean DateTimeItem.stateEquals(Object otherState) {
if (getState() == null) {
return otherState == null;
}
return getState().equals(otherState);
}
//--- setStateToDefault ---
public abstract void Item.setStateToDefault();
public void ColorItem.setStateToDefault() { this.setState(TupleHSB.of(0, 0, 0)); }
public void DateTimeItem.setStateToDefault() { this.setState(new Date(0)); }
public void DateTimeItem.setStateToDefault() { this.setState(Instant.ofEpochSecond(0)); }
public void ItemWithBooleanState.setStateToDefault() { this.setState(false); }
public void ItemWithDoubleState.setStateToDefault() { this.setState(0.0); }
public void ItemWithStringState.setStateToDefault() { this.setState(""); }
//--- as$ItemType ---
// those attributes will raise a ClassCastException if called on the wrong item type. But else can we do?
// those attributes will raise a ClassCastException if called on the wrong item type. But what else can we do?
syn ColorItem Item.asColorItem() = (ColorItem) this;
syn ColorItem ColorItem.asColorItem() = this;
syn ItemWithBooleanState Item.asItemWithBooleanState() = (ItemWithBooleanState) this;
......@@ -354,7 +350,7 @@ aspect ItemHandling {
controlling.setStateFromColor(this.getState());
}
protected void DateTimeItem.doUpdateFor(Item controlling) {
controlling.setStateFromDate(this.getState());
controlling.setStateFromInstant(this.getState());
}
private void ColorItem.setBrightness(int value) {
......
......@@ -8,8 +8,8 @@ aspect ItemHistory{
.build();
}
protected abstract org.influxdb.dto.Point.Builder createMeasurement();
public abstract java.time.Instant getTime();
public abstract void setTime(java.time.Instant time);
public abstract Instant getTime();
public abstract void setTime(Instant time);
public abstract String getId();
public abstract void setId(String id);
public abstract T getState();
......@@ -23,18 +23,18 @@ aspect ItemHistory{
@org.influxdb.annotation.Measurement(name = BooleanStatePoint.NAME)
public class BooleanStatePoint extends AbstractItemPoint<Boolean> {
@org.influxdb.annotation.Column(name = "time") protected java.time.Instant time;
@org.influxdb.annotation.Column(name = "time") protected Instant time;
@org.influxdb.annotation.Column(name = "state") protected Boolean state;
@org.influxdb.annotation.Column(name = "id", tag = true) protected String id;
public java.time.Instant getTime() { return time; }
public void setTime(java.time.Instant time) { this.time = time; }
public Instant getTime() { return time; }
public void setTime(Instant time) { this.time = time; }
public String getId() { return id; }
public void setId(String id) { this.id = id; }
public void setState(Boolean state) { this.state = state; }
public Boolean getState() { return state; }
public static final String NAME = "ItemB";
public static BooleanStatePoint of(java.time.Instant time, Boolean state, String id) {
public static BooleanStatePoint of(Instant time, Boolean state, String id) {
BooleanStatePoint result = new BooleanStatePoint();
result.setTime(time); result.setState(state); result.setId(id);
return result;
......@@ -46,18 +46,18 @@ aspect ItemHistory{
@org.influxdb.annotation.Measurement(name = StringStatePoint.NAME)
public class StringStatePoint extends AbstractItemPoint<String> {
@org.influxdb.annotation.Column(name = "time") protected java.time.Instant time;
@org.influxdb.annotation.Column(name = "time") protected Instant time;
@org.influxdb.annotation.Column(name = "state") protected String state;
@org.influxdb.annotation.Column(name = "id", tag = true) protected String id;
public java.time.Instant getTime() { return time; }
public void setTime(java.time.Instant time) { this.time = time; }
public Instant getTime() { return time; }
public void setTime(Instant time) { this.time = time; }
public String getId() { return id; }
public void setId(String id) { this.id = id; }
public void setState(String state) { this.state = state; }
public String getState() { return state; }
public static final String NAME = "ItemS";
public static StringStatePoint of(java.time.Instant time, String state, String id) {
public static StringStatePoint of(Instant time, String state, String id) {
StringStatePoint result = new StringStatePoint();
result.setTime(time); result.setState(state); result.setId(id);
return result;
......@@ -69,18 +69,18 @@ aspect ItemHistory{
@org.influxdb.annotation.Measurement(name = DoubleStatePoint.NAME)
public class DoubleStatePoint extends AbstractItemPoint<Double> {
@org.influxdb.annotation.Column(name = "time") protected java.time.Instant time;
@org.influxdb.annotation.Column(name = "time") protected Instant time;
@org.influxdb.annotation.Column(name = "state") protected Double state;
@org.influxdb.annotation.Column(name = "id", tag = true) protected String id;
public java.time.Instant getTime() { return time; }
public void setTime(java.time.Instant time) { this.time = time; }
public Instant getTime() { return time; }
public void setTime(Instant time) { this.time = time; }
public String getId() { return id; }
public void setId(String id) { this.id = id; }
public void setState(Double state) { this.state = state; }
public Double getState() { return state; }
public static final String NAME = "ItemD";
public static DoubleStatePoint of(java.time.Instant time, Double state, String id) {
public static DoubleStatePoint of(Instant time, Double state, String id) {
DoubleStatePoint result = new DoubleStatePoint();
result.setTime(time); result.setState(state); result.setId(id);
return result;
......@@ -92,18 +92,18 @@ aspect ItemHistory{
@org.influxdb.annotation.Measurement(name = ColorStatePoint.NAME)
public class ColorStatePoint extends AbstractItemPoint<TupleHSB> {
@org.influxdb.annotation.Column(name = "time") protected java.time.Instant time;
@org.influxdb.annotation.Column(name = "time") protected Instant time;
@org.influxdb.annotation.Column(name = "state") protected String state;
@org.influxdb.annotation.Column(name = "id", tag = true) protected String id;
public java.time.Instant getTime() { return time; }
public void setTime(java.time.Instant time) { this.time = time; }
public Instant getTime() { return time; }
public void setTime(Instant time) { this.time = time; }
public String getId() { return id; }
public void setId(String id) { this.id = id; }
public void setState(TupleHSB state) { this.state = state.toString(); }
public TupleHSB getState() { return TupleHSB.parse(state); }
public static final String NAME = "ItemC";
public static ColorStatePoint of(java.time.Instant time, TupleHSB state, String id) {
public static ColorStatePoint of(Instant time, TupleHSB state, String id) {
ColorStatePoint result = new ColorStatePoint();
result.setTime(time); result.setState(state); result.setId(id);
return result;
......@@ -114,19 +114,19 @@ aspect ItemHistory{
}
@org.influxdb.annotation.Measurement(name = DateTimeStatePoint.NAME)
public class DateTimeStatePoint extends AbstractItemPoint<Date> {
@org.influxdb.annotation.Column(name = "time") protected java.time.Instant time;
public class DateTimeStatePoint extends AbstractItemPoint<Instant> {
@org.influxdb.annotation.Column(name = "time") protected Instant time;
@org.influxdb.annotation.Column(name = "state") protected long state;
@org.influxdb.annotation.Column(name = "id", tag = true) protected String id;
public java.time.Instant getTime() { return time; }
public void setTime(java.time.Instant time) { this.time = time; }
public Instant getTime() { return time; }
public void setTime(Instant time) { this.time = time; }
public String getId() { return id; }
public void setId(String id) { this.id = id; }
public void setState(Date state) { this.state = state.getTime(); }
public Date getState() { return new Date(state); }
public void setState(Instant state) { this.state = state.toEpochMilli(); }
public Instant getState() { return Instant.ofEpochMilli(state); }
public static final String NAME = "ItemT";
public static DateTimeStatePoint of(java.time.Instant time, Date state, String id) {
public static DateTimeStatePoint of(Instant time, Instant state, String id) {
DateTimeStatePoint result = new DateTimeStatePoint();
result.setTime(time); result.setState(state); result.setId(id);
return result;
......
......@@ -22,9 +22,7 @@ aspect MachineLearning {
//--- currentActivity ---
syn java.util.Optional<Activity> Root.currentActivity() {
return resolveActivity(getMachineLearningRoot().hasActivityRecognition() ?
extractActivityIdentifier(getMachineLearningRoot().getActivityRecognition().getDecoder().classify().getPreferences()) :
-1);
return resolveActivity((int) getOpenHAB2Model().getActivityItem().getState());
}
private int Root.extractActivityIdentifier(List<ItemPreference> preferences) {
if (preferences.isEmpty()) {
......@@ -122,16 +120,6 @@ aspect MachineLearning {
eq MachineLearningRoot.getActivityRecognition().mlKind() = "ActivityRecognition";
eq MachineLearningRoot.getPreferenceLearning().mlKind() = "PreferenceLearning";
//--- ActivityItem ---
@Override
public double ActivityItem.getState() {
return JavaUtils.ifPresentOrElseReturn(
getRoot().currentActivity(),
activity -> (double) activity.getIdentifier(),
() -> super.getState()
);
}
//... ExternalMachineLearningModel ...
private MachineLearningEncoder ExternalMachineLearningModel.encoder;
public void ExternalMachineLearningModel.setEncoder(MachineLearningEncoder encoder) {
......
aspect Rules {
Object ItemObserver.last_known_state = null;
// idea: abuse dependency tracking to trigger rule only iff item state has changed
syn boolean ItemObserver.apply() {
if (!observedItem().stateEquals(last_known_state)) {
// state has changed
last_known_state = observedItem().copyState();
public void ItemObserver.apply() {
// state has changed, so trigger rules
for (Rule rule : getTriggeredRuleList()) {
rule.trigger(observedItem());
}
return true;
}
return false;
}
public void Rule.trigger(Item triggeringItem) {
......@@ -46,7 +38,6 @@ aspect Rules {
} else {
itemObserver = new ItemObserver();
item.setItemObserver(itemObserver);
itemObserver.last_known_state = item.copyState();
}
// 2) Link event and itemObserver
itemObserver.addTriggeredRule(this);
......
......@@ -33,7 +33,7 @@ abstract ItemWithBooleanState : Item ::= <_state:boolean> ;
abstract ItemWithStringState : Item ::= <_state:String> ;
abstract ItemWithDoubleState : Item ::= <_state:double> ;
ColorItem : Item ::= <_state:TupleHSB> ;
DateTimeItem : Item ::= <_state:Date> ;
DateTimeItem : Item ::= <_state:Instant> ;
ContactItem : ItemWithBooleanState ;
DimmerItem : ItemWithDoubleState ;
ImageItem : ItemWithStringState ;
......
......@@ -284,6 +284,7 @@ public class EraserParserHelper {
itemWithCorrectType.setID(prototype.getID());
itemWithCorrectType.setLabel(prototype.getLabel());
itemWithCorrectType.setMetaDataList(prototype.getMetaDataList());
if (!(itemWithCorrectType instanceof ActivityItem)) {
String state = prototype.getStateAsString();
itemWithCorrectType.disableSendState();
if (state.isEmpty()) {
......@@ -292,6 +293,7 @@ public class EraserParserHelper {
itemWithCorrectType.setStateFromString(state);
}
itemWithCorrectType.enableSendState();
}
moveMissingForRetype(itemWithCorrectType, prototype, missingTopicMap);
moveMissingForRetype(itemWithCorrectType, prototype, missingControllingListMap);
......
......@@ -6,6 +6,7 @@ import de.tudresden.inf.st.eraser.util.TestUtils.ModelAndItem;
import org.junit.Assert;
import org.junit.Test;
import java.time.Instant;
import java.util.Date;
/**
......@@ -75,71 +76,11 @@ public class ItemTests {
public void testItemWithDateStateEquals() {
DateTimeItem sut = createItem(DateTimeItem::new);
sut.setState(new Date(1543415826));
sut.setState(Instant.ofEpochMilli(1543415826));
Assert.assertTrue("State 'Date(1543415826)' should match 'Date(1543415826)'",
sut.stateEquals(new Date(1543415826)));
sut.stateEquals(Instant.ofEpochMilli(1543415826)));
Assert.assertFalse("State 'Date(1543415826)' should not match 'Date(4)'",
sut.stateEquals(new Date(4)));
}
@Test
public void testItemWithBooleanCopyEquals() {
ItemWithBooleanState sut = createItem(SwitchItem::new);
sut.setState(true);
Object copiedState = sut.copyState();
Assert.assertTrue("State 'true' should match copy", sut.stateEquals(copiedState));
sut.setState(false);
Assert.assertFalse("State 'false' should not match copy", sut.stateEquals(copiedState));
}
@Test
public void testItemWithStringCopyEquals() {
ItemWithStringState sut = createItem(ImageItem::new);
sut.setState("correct");
Object copiedState = sut.copyState();
Assert.assertTrue("State 'correct' should match copy", sut.stateEquals(copiedState));
sut.setState("something else");
Assert.assertFalse("State 'something else' should not match copy", sut.stateEquals(copiedState));
}
@Test
public void testItemWithLongCopyEquals() {
ItemWithDoubleState sut = createItem(NumberItem::new);
sut.setState(3.0);
Object copiedState = sut.copyState();
Assert.assertTrue("State '3.0' should match copy", sut.stateEquals(copiedState));
sut.setState(4.0);
Assert.assertFalse("State '4.0' should not match copy", sut.stateEquals(copiedState));
}
@Test
public void testItemWithTupleHSBCopyEquals() {
ColorItem sut = createItem(ColorItem::new);
sut.setState(TupleHSB.of(1, 2, 3));
Object copiedState = sut.copyState();
Assert.assertTrue("State 'TupleHSB(1,2,3)' should match copy", sut.stateEquals(copiedState));
sut.setState(TupleHSB.of(5,5,5));
Assert.assertFalse("State 'TupleHSB(5,5,5)' should not match copy", sut.stateEquals(copiedState));
}
@Test
public void testItemWithDateCopyEquals() {
DateTimeItem sut = createItem(DateTimeItem::new);
sut.setState(new Date(1543415826));
Object copiedState = sut.copyState();
Assert.assertTrue("State 'Date(1543415826' should match copy", sut.stateEquals(copiedState));
sut.setState(new Date(4));
Assert.assertFalse("State 'Date(4)' should not match copy", sut.stateEquals(copiedState));
sut.stateEquals(Instant.ofEpochMilli(4)));
}
@FunctionalInterface
......
......@@ -2,7 +2,7 @@ Color Item: id="color1" label="a Color Item" state="1,2,3" topic="item/hsb/color
Contact Item: id="contact1" label="a Contact Item" state="true" topic="item/bool/contact1/state" ;
Image Item: id="image1" label="an Image Item" state="def" topic="item/str/image1/state" ;
Location Item: id="location1" label="a Location Item" state="ghi" topic="item/str/location1/state" ;
DateTime Item: id="datetime1" label="a DateTime Item" state="1970-01-18T20:43:35.826" topic="item/date/datetime1/state" ;
DateTime Item: id="datetime1" label="a DateTime Item" state="1970-01-18T20:43:35.826Z" topic="item/date/datetime1/state" ;
Item: id="default1" label="a Default Item" state="pqr" topic="item/str/default1/state" ;
Dimmer Item: id="dimmer1" label="a Dimmer Item" state="123.0" topic="item/double/dimmer1/state" ;
Player Item: id="player1" label="a Player Item" state="jkl" topic="item/str/player1/state" ;
......
......@@ -2,7 +2,7 @@ Color Item: id="color1" label="a Color Item" state="1,2,3" topic="item/hsb/color
Contact Item: id="contact1" label="a Contact Item" state="true" topic="item/bool/contact1/state" ;
Image Item: id="image1" label="an Image Item" state="def" topic="item/str/image1/state" ;
Location Item: id="location1" label="a Location Item" state="ghi" topic="item/str/location1/state" ;
DateTime Item: id="datetime1" label="a DateTime Item" state="1970-01-18T20:43:35.826" topic="item/date/datetime1/state" ;
DateTime Item: id="datetime1" label="a DateTime Item" state="1970-01-18T20:43:35.826Z" topic="item/date/datetime1/state" ;
Item: id="default1" label="a Default Item" state="pqr" topic="item/str/default1/state" ;
Dimmer Item: id="dimmer1" label="a Dimmer Item" state="123.0" topic="item/double/dimmer1/state" controls=["color1", "datetime1"] ;
Player Item: id="player1" label="a Player Item" state="jkl" topic="item/str/player1/state" ;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment