From 8e0aed0711a26fec5c0497cee9777744f1d48663 Mon Sep 17 00:00:00 2001 From: Marcin Chrzanowski Date: Sat, 28 Dec 2019 15:47:06 +0100 Subject: Apply only fresher attributes --- .../edu/mimuw/cloudatlas/agent/modules/Stanik.java | 83 +++++++++++++++++++--- .../mimuw/cloudatlas/agent/modules/StanikTest.java | 42 ++++++++--- 2 files changed, 107 insertions(+), 18 deletions(-) diff --git a/src/main/java/pl/edu/mimuw/cloudatlas/agent/modules/Stanik.java b/src/main/java/pl/edu/mimuw/cloudatlas/agent/modules/Stanik.java index a457a94..76ca0b6 100644 --- a/src/main/java/pl/edu/mimuw/cloudatlas/agent/modules/Stanik.java +++ b/src/main/java/pl/edu/mimuw/cloudatlas/agent/modules/Stanik.java @@ -1,5 +1,6 @@ package pl.edu.mimuw.cloudatlas.agent.modules; +import java.util.Iterator; import java.util.Map.Entry; import pl.edu.mimuw.cloudatlas.agent.messages.AgentMessage; @@ -10,16 +11,27 @@ import pl.edu.mimuw.cloudatlas.agent.messages.UpdateAttributesMessage; import pl.edu.mimuw.cloudatlas.model.AttributesMap; import pl.edu.mimuw.cloudatlas.model.Attribute; import pl.edu.mimuw.cloudatlas.model.PathName; +import pl.edu.mimuw.cloudatlas.model.Type; +import pl.edu.mimuw.cloudatlas.model.TypePrimitive; import pl.edu.mimuw.cloudatlas.model.Value; +import pl.edu.mimuw.cloudatlas.model.ValueBoolean; import pl.edu.mimuw.cloudatlas.model.ValueString; +import pl.edu.mimuw.cloudatlas.model.ValueTime; import pl.edu.mimuw.cloudatlas.model.ZMI; public class Stanik extends Module { + private class InvalidUpdateAttributesMessage extends Exception { + public InvalidUpdateAttributesMessage(String message) { + super(message); + } + } + private ZMI hierarchy; public Stanik() { super(ModuleType.STATE); hierarchy = new ZMI(); + hierarchy.getAttributes().add("timestamp", new ValueTime(0l)); } public void handleTyped(StanikMessage message) throws InterruptedException, InvalidMessageType { @@ -42,23 +54,75 @@ public class Stanik extends Module { public void handleUpdateAttributes(UpdateAttributesMessage message) { try { + validateUpdateAttributesMessage(message); addMissingZones(new PathName(message.getPathName())); ZMI zone = hierarchy.findDescendant(message.getPathName()); - for (Entry entry : zone.getAttributes()) { - Attribute attribute = entry.getKey(); - Value newValue = message.getAttributes().getOrNull(attribute); - if (newValue == null) { - zone.getAttributes().remove(attribute); - } - } - for (Entry entry : message.getAttributes()) { - zone.getAttributes().addOrChange(entry.getKey(), entry.getValue()); + AttributesMap attributes = zone.getAttributes(); + if (valueLower(attributes.get("timestamp"), message.getAttributes().get("timestamp"))) { + transferAttributes(message.getAttributes(), attributes); + } else { + System.out.println("DEBUG: not applying update with older attributes"); } + } catch (InvalidUpdateAttributesMessage e) { + System.out.println("ERROR: invalid UpdateAttributesMessage " + e.getMessage()); } catch (ZMI.NoSuchZoneException e) { System.out.println("ERROR: zone should exist after being added"); } } + private boolean valueLower(Value a, Value b) { + return ((ValueBoolean) a.isLowerThan(b)).getValue(); + } + + private void validateUpdateAttributesMessage(UpdateAttributesMessage message) throws InvalidUpdateAttributesMessage { + validateZoneName(message); + validateHasTimeStamp(message); + } + + private void validateZoneName(UpdateAttributesMessage message) throws InvalidUpdateAttributesMessage { + Value name = message.getAttributes().getOrNull("name"); + if (message.getPathName().equals("/")) { + if (name != null && !name.isNull()) { + throw new InvalidUpdateAttributesMessage("The root zone should have a null name"); + } + } else { + if (valueNonNullOfType(name, TypePrimitive.STRING)) { + ValueString nameString = (ValueString) name; + String expectedName = (new PathName(message.getPathName())).getSingletonName(); + if (!nameString.getValue().equals(expectedName)) { + throw new InvalidUpdateAttributesMessage("The zone's name attribute should match its path name"); + } + } else { + throw new InvalidUpdateAttributesMessage("Zone attributes should have a name attribute of type String"); + } + } + } + + private void validateHasTimeStamp(UpdateAttributesMessage message) throws InvalidUpdateAttributesMessage { + if (!valueNonNullOfType(message.getAttributes().getOrNull("timestamp"), TypePrimitive.TIME)) { + throw new InvalidUpdateAttributesMessage("Zone attriutes should have a timestamp attribute of type Time"); + } + } + + private boolean valueNonNullOfType(Value value, Type type) { + return value != null && !value.isNull() && value.getType().isCompatible(type); + } + + private void transferAttributes(AttributesMap fromAttributes, AttributesMap toAttributes) { + Iterator> iterator = toAttributes.iterator(); + while (iterator.hasNext()) { + Entry entry = iterator.next(); + Attribute attribute = entry.getKey(); + Value newValue = fromAttributes.getOrNull(attribute); + if (newValue == null) { + iterator.remove(); + } + } + for (Entry entry : fromAttributes) { + toAttributes.addOrChange(entry.getKey(), entry.getValue()); + } + } + private void addMissingZones(PathName path) { try { if (!hierarchy.descendantExists(path)) { @@ -66,6 +130,7 @@ public class Stanik extends Module { ZMI parent = hierarchy.findDescendant(path.levelUp()); ZMI newSon = new ZMI(parent); newSon.getAttributes().add("name", new ValueString(path.getSingletonName())); + newSon.getAttributes().add("timestamp", new ValueTime(0l)); parent.addSon(newSon); } } catch (ZMI.NoSuchZoneException e) { diff --git a/src/test/java/pl/edu/mimuw/cloudatlas/agent/modules/StanikTest.java b/src/test/java/pl/edu/mimuw/cloudatlas/agent/modules/StanikTest.java index 869dc1c..12fa531 100644 --- a/src/test/java/pl/edu/mimuw/cloudatlas/agent/modules/StanikTest.java +++ b/src/test/java/pl/edu/mimuw/cloudatlas/agent/modules/StanikTest.java @@ -14,6 +14,7 @@ import pl.edu.mimuw.cloudatlas.model.AttributesMap; import pl.edu.mimuw.cloudatlas.model.Value; import pl.edu.mimuw.cloudatlas.model.ValueInt; import pl.edu.mimuw.cloudatlas.model.ValueString; +import pl.edu.mimuw.cloudatlas.model.ValueTime; import pl.edu.mimuw.cloudatlas.model.ZMI; import org.junit.Before; @@ -43,12 +44,7 @@ public class StanikTest { ZMI zmi = hierarchyMessage.getZMI(); assertNull(zmi.getFather()); assertTrue(zmi.getSons().isEmpty()); - boolean empty = true; - for (Entry entry : zmi.getAttributes()) { - empty = false; - break; - } - assertTrue(empty); + assertEquals(1, countAttributes(zmi.getAttributes())); } @Test @@ -73,12 +69,14 @@ public class StanikTest { AttributesMap attributes = new AttributesMap(); attributes.add("foo", new ValueInt(1337l)); attributes.add("bar", new ValueString("baz")); + attributes.add("timestamp", new ValueTime("2012/12/21 04:20:00.000")); UpdateAttributesMessage message = new UpdateAttributesMessage("test_msg", 0, "/", attributes); stanik.handleTyped(message); AttributesMap actualAttributes = stanik.getHierarchy().getAttributes(); - assertEquals(2, countAttributes(actualAttributes)); + assertEquals(3, countAttributes(actualAttributes)); assertEquals(new ValueInt(1337l), actualAttributes.get("foo")); assertEquals(new ValueString("baz"), actualAttributes.get("bar")); + assertEquals(new ValueTime("2012/12/21 04:20:00.000"), actualAttributes.getOrNull("timestamp")); } @Test @@ -87,12 +85,15 @@ public class StanikTest { attributes.add("foo", new ValueInt(1337l)); attributes.add("bar", new ValueString("baz")); attributes.add("name", new ValueString("new")); + attributes.add("timestamp", new ValueTime("2012/12/21 04:20:00.000")); UpdateAttributesMessage message = new UpdateAttributesMessage("test_msg", 0, "/new", attributes); stanik.handleTyped(message); AttributesMap actualAttributes = stanik.getHierarchy().findDescendant("/new").getAttributes(); - assertEquals(3, countAttributes(actualAttributes)); + assertEquals(4, countAttributes(actualAttributes)); assertEquals(new ValueInt(1337l), actualAttributes.getOrNull("foo")); assertEquals(new ValueString("baz"), actualAttributes.getOrNull("bar")); + assertEquals(new ValueString("new"), actualAttributes.getOrNull("name")); + assertEquals(new ValueTime("2012/12/21 04:20:00.000"), actualAttributes.getOrNull("timestamp")); } @Test @@ -101,16 +102,39 @@ public class StanikTest { attributes.add("foo", new ValueInt(1337l)); attributes.add("bar", new ValueString("baz")); UpdateAttributesMessage message = new UpdateAttributesMessage("test_msg", 0, "/", attributes); + attributes.add("timestamp", new ValueTime("2012/12/21 04:20:00.000")); stanik.handleTyped(message); AttributesMap newAttributes = new AttributesMap(); + newAttributes.add("timestamp", new ValueTime("2012/12/21 04:20:42.000")); newAttributes.add("foo", new ValueInt(1338l)); UpdateAttributesMessage newMessage = new UpdateAttributesMessage("test_msg2", 0, "/", newAttributes); stanik.handleTyped(newMessage); AttributesMap actualAttributes = stanik.getHierarchy().getAttributes(); - assertEquals(1, countAttributes(actualAttributes)); + assertEquals(2, countAttributes(actualAttributes)); assertEquals(new ValueInt(1338l), actualAttributes.getOrNull("foo")); + assertEquals(new ValueTime("2012/12/21 04:20:42.000"), actualAttributes.getOrNull("timestamp")); + } + + @Test + public void dontApplyUpdateWithOlderTimestamp() throws Exception { + AttributesMap attributes = new AttributesMap(); + attributes.add("foo", new ValueInt(1337l)); + attributes.add("timestamp", new ValueTime("2012/12/21 04:20:00.000")); + UpdateAttributesMessage message = new UpdateAttributesMessage("test_msg", 0, "/", attributes); + stanik.handleTyped(message); + + AttributesMap oldAttributes = new AttributesMap(); + oldAttributes.add("foo", new ValueInt(1336l)); + oldAttributes.add("timestamp", new ValueTime("2012/12/21 04:19:00.000")); + UpdateAttributesMessage newMessage = new UpdateAttributesMessage("test_msg2", 0, "/", oldAttributes); + stanik.handleTyped(newMessage); + + AttributesMap actualAttributes = stanik.getHierarchy().getAttributes(); + assertEquals(2, countAttributes(actualAttributes)); + assertEquals(new ValueInt(1337l), actualAttributes.getOrNull("foo")); + assertEquals(new ValueTime("2012/12/21 04:20:00.000"), actualAttributes.getOrNull("timestamp")); } public int countAttributes(AttributesMap attributes) { -- cgit v1.2.3