Permalink
Browse files

Implemented agent/thing deployment with simulator protocol

  • Loading branch information...
1 parent 4972a0b commit 49fea2fa0c855c060c8bdc6846cdef02f4a6c1b0 @christianbauer christianbauer committed Dec 20, 2016
Showing with 1,684 additions and 662 deletions.
  1. +0 −18 agent/src/main/java/org/openremote/agent3/ProtocolConfiguration.java
  2. +147 −0 agent/src/main/java/org/openremote/agent3/protocol/AbstractProtocol.java
  3. +46 −0 agent/src/main/java/org/openremote/agent3/protocol/Protocol.java
  4. +136 −0 agent/src/main/java/org/openremote/agent3/protocol/simulator/SimulatorProtocol.java
  5. +29 −24 ...→ agent/src/main/java/org/openremote/agent3/protocol/simulator/element/ColorSimulatorElement.java
  6. +30 −0 agent/src/main/java/org/openremote/agent3/protocol/simulator/element/DecimalSimulatorElement.java
  7. +59 −0 agent/src/main/java/org/openremote/agent3/protocol/simulator/element/IntegerSimulatorElement.java
  8. +56 −0 agent/src/main/java/org/openremote/agent3/protocol/simulator/element/SimulatorElement.java
  9. +29 −0 agent/src/main/java/org/openremote/agent3/protocol/simulator/element/SwitchSimulatorElement.java
  10. +1 −0 agent/src/main/resources/META-INF/services/org.openremote.agent3.protocol.Protocol
  11. +1 −2 agent/src/test/groovy/org/openremote/test/rules/ClimateControlTest.groovy
  12. +1 −2 agent/src/test/groovy/org/openremote/test/rules/MixedWithErrorsTest.groovy
  13. +1 −2 agent/src/test/groovy/org/openremote/test/rules/SimpleRuleTest.groovy
  14. +1 −2 agent/src/test/groovy/org/openremote/test/rules/VacationTest.groovy
  15. +1 −1 container/src/main/groovy/org/openremote/test/ContainerTrait.groovy
  16. +20 −23 container/src/main/java/org/openremote/container/Container.java
  17. +19 −1 container/src/main/java/org/openremote/container/ContainerService.java
  18. +2 −2 container/src/main/java/org/openremote/container/persistence/PersistenceEvent.java
  19. +1 −1 manager/client/src/main/java/org/openremote/manager/client/assets/AssetInfoArrayMapper.java
  20. +1 −1 manager/client/src/main/java/org/openremote/manager/client/assets/AssetMapper.java
  21. +1 −1 manager/client/src/main/java/org/openremote/manager/client/assets/AssetsDashboardActivity.java
  22. +1 −1 manager/client/src/main/java/org/openremote/manager/client/assets/agent/AgentAttributesEditor.java
  23. +3 −3 manager/client/src/main/java/org/openremote/manager/client/assets/asset/AssetActivity.java
  24. +1 −1 manager/client/src/main/java/org/openremote/manager/client/assets/asset/AssetView.java
  25. +1 −1 manager/client/src/main/java/org/openremote/manager/client/assets/asset/AssetViewImpl.java
  26. +2 −2 manager/client/src/main/java/org/openremote/manager/client/assets/browser/AssetBrowser.java
  27. +1 −2 manager/client/src/main/java/org/openremote/manager/client/assets/browser/AssetBrowserImpl.java
  28. +3 −0 manager/client/src/main/java/org/openremote/manager/client/assets/browser/AssetBrowserPresenter.java
  29. +3 −3 manager/client/src/main/java/org/openremote/manager/client/assets/browser/AssetBrowsingActivity.java
  30. +2 −2 manager/client/src/main/java/org/openremote/manager/client/assets/browser/AssetCell.java
  31. +1 −1 manager/client/src/main/java/org/openremote/manager/client/assets/browser/AssetDataProvider.java
  32. +1 −1 manager/client/src/main/java/org/openremote/manager/client/assets/browser/AssetSelectedEvent.java
  33. +1 −1 manager/client/src/main/java/org/openremote/manager/client/assets/browser/AssetTree.java
  34. +2 −2 manager/client/src/main/java/org/openremote/manager/client/assets/browser/AssetTreeModel.java
  35. +1 −1 manager/client/src/main/java/org/openremote/manager/client/flows/FlowsActivity.java
  36. +1 −1 manager/client/src/main/java/org/openremote/manager/client/flows/FlowsView.java
  37. +1 −1 manager/client/src/main/java/org/openremote/manager/client/flows/FlowsViewImpl.java
  38. +1 −1 manager/client/src/main/java/org/openremote/manager/client/map/MapActivity.java
  39. +1 −1 manager/client/src/main/java/org/openremote/manager/client/widget/AttributesEditor.java
  40. +104 −49 manager/server/src/main/java/org/openremote/manager/server/DemoDataService.java
  41. +27 −14 manager/server/src/main/java/org/openremote/manager/server/Main.java
  42. +100 −146 manager/server/src/main/java/org/openremote/manager/server/agent/AgentService.java
  43. +12 −6 manager/server/src/main/java/org/openremote/manager/server/asset/AssetListenerSubscriptions.java
  44. +2 −2 manager/server/src/main/java/org/openremote/manager/server/asset/AssetPredicates.java
  45. +2 −2 manager/server/src/main/java/org/openremote/manager/server/asset/AssetResourceImpl.java
  46. +19 −3 manager/server/src/main/java/org/openremote/manager/server/asset/AssetService.java
  47. +1 −1 manager/server/src/main/java/org/openremote/manager/server/asset/ServerAsset.java
  48. +1 −1 manager/server/src/main/java/org/openremote/manager/server/asset/ServerAssetInfo.java
  49. +0 −2 manager/shared/build.gradle
  50. +0 −4 manager/shared/src/main/java/org/openremote/manager/shared/Constants.java
  51. +2 −1 manager/shared/src/main/java/org/openremote/manager/shared/agent/Agent.java
  52. +1 −1 manager/shared/src/main/java/org/openremote/manager/shared/agent/InventoryModifiedEvent.java
  53. +2 −1 manager/shared/src/main/java/org/openremote/manager/shared/agent/RefreshInventoryEvent.java
  54. +2 −0 manager/shared/src/main/java/org/openremote/manager/shared/asset/AssetModifiedEvent.java
  55. +2 −0 manager/shared/src/main/java/org/openremote/manager/shared/asset/AssetResource.java
  56. +1 −1 manager/shared/src/main/java/org/openremote/manager/shared/connector/ConnectorComponentNG.java
  57. +22 −20 manager/test/src/test/groovy/org/openremote/test/ManagerContainerTrait.groovy
  58. +87 −0 manager/test/src/test/groovy/org/openremote/test/agent/AgentDeploymentTest.groovy
  59. +0 −194 manager/test/src/test/groovy/org/openremote/test/agent/AgentProvisioningTest.groovy
  60. +2 −2 manager/test/src/test/groovy/org/openremote/test/controller2/Controller2Test.groovy
  61. +2 −0 shared/build.gradle
  62. +30 −0 shared/src/main/java/org/openremote/Constants.java
  63. +91 −0 shared/src/main/java/org/openremote/model/AbstractValueHolder.java
  64. +29 −68 shared/src/main/java/org/openremote/model/Attribute.java
  65. +76 −0 shared/src/main/java/org/openremote/model/AttributeRef.java
  66. +0 −8 shared/src/main/java/org/openremote/model/AttributeType.java
  67. +49 −0 shared/src/main/java/org/openremote/model/AttributeValueChange.java
  68. +3 −23 shared/src/main/java/org/openremote/model/MetadataItem.java
  69. +76 −0 shared/src/main/java/org/openremote/model/asset/AgentAttributes.java
  70. +4 −3 .../java/org/openremote/manager/shared → shared/src/main/java/org/openremote/model}/asset/Asset.java
  71. +2 −2 ...nremote/manager/shared → shared/src/main/java/org/openremote/model}/asset/AssetAttributeMeta.java
  72. +1 −1 ...a/org/openremote/manager/shared → shared/src/main/java/org/openremote/model}/asset/AssetInfo.java
  73. +2 −2 ...a/org/openremote/manager/shared → shared/src/main/java/org/openremote/model}/asset/AssetType.java
  74. +105 −0 shared/src/main/java/org/openremote/model/asset/Color.java
  75. +52 −0 shared/src/main/java/org/openremote/model/asset/ProtocolConfiguration.java
  76. +74 −0 shared/src/main/java/org/openremote/model/asset/ThingAttribute.java
  77. +90 −0 shared/src/main/java/org/openremote/model/asset/ThingAttributes.java
@@ -1,18 +0,0 @@
-package org.openremote.agent3;
-
-import elemental.json.Json;
-import elemental.json.JsonObject;
-import org.openremote.model.Attribute;
-import org.openremote.model.AttributeType;
-
-public class ProtocolConfiguration extends Attribute {
-
- public ProtocolConfiguration(String name, JsonObject jsonObject) {
- super(name, AttributeType.STRING, jsonObject);
- }
-
- public ProtocolConfiguration(String name, String protocol) {
- super(name, AttributeType.STRING, Json.create(protocol));
- }
-
-}
@@ -0,0 +1,147 @@
+/*
+ * Copyright 2016, OpenRemote Inc.
+ *
+ * See the CONTRIBUTORS.txt file in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.openremote.agent3.protocol;
+
+import org.apache.camel.Predicate;
+import org.apache.camel.ProducerTemplate;
+import org.apache.camel.builder.RouteBuilder;
+import org.openremote.model.asset.ThingAttribute;
+import org.openremote.container.Container;
+import org.openremote.container.message.MessageBrokerContext;
+import org.openremote.container.message.MessageBrokerService;
+import org.openremote.model.AttributeRef;
+import org.openremote.model.AttributeValueChange;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.logging.Logger;
+
+public abstract class AbstractProtocol implements Protocol {
+
+ private static final Logger LOG = Logger.getLogger(AbstractProtocol.class.getName());
+
+ static Predicate isAttributeValueChangeIn(Collection<AttributeRef> attributeRefs) {
+ return exchange -> {
+ if (!(exchange.getIn().getBody() instanceof AttributeValueChange))
+ return false;
+ AttributeValueChange valueChange = exchange.getIn().getBody(AttributeValueChange.class);
+ return attributeRefs.contains(valueChange.getAttributeRef());
+ };
+ }
+
+ final protected Map<AttributeRef, ThingAttribute> linkedAttributes = new HashMap<>();
+ protected MessageBrokerContext messageBrokerContext;
+ protected ProducerTemplate producerTemplate;
+
+ @Override
+ public void init(Container container) throws Exception {
+ LOG.info("Initializing protocol: " + getProtocolName());
+ }
+
+ @Override
+ public void configure(Container container) throws Exception {
+ this.messageBrokerContext = container.getService(MessageBrokerService.class).getContext();
+ this.producerTemplate = messageBrokerContext.createProducerTemplate();
+ }
+
+ @Override
+ public void start(Container container) throws Exception {
+ synchronized (linkedAttributes) {
+ LOG.fine("Starting: " + getProtocolName());
+ messageBrokerContext.addRoutes(new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ from(ACTUATOR_TOPIC)
+ .routeId("Actuator-" + getProtocolName())
+ .process(exchange -> {
+ synchronized (linkedAttributes) {
+ // TODO This could be optimized, we must avoid inspecting all messages (maybe tag with protocol name in header?)
+ if (isAttributeValueChangeIn(linkedAttributes.keySet()).matches(exchange)) {
+ sendToActuator(exchange.getIn().getBody(AttributeValueChange.class));
+ }
+ }
+ });
+ }
+ });
+ }
+ }
+
+ @Override
+ public void stop(Container container) throws Exception {
+ synchronized (linkedAttributes) {
+ linkedAttributes.clear();
+ messageBrokerContext.stopRoute("Actuator-" + getProtocolName());
+ messageBrokerContext.removeRoute("Actuator-" + getProtocolName());
+ }
+ }
+
+ @Override
+ public void linkAttributes(Collection<ThingAttribute> attributes) throws Exception {
+ synchronized (linkedAttributes) {
+ for (ThingAttribute attribute : attributes) {
+ if (linkedAttributes.containsKey(attribute.getAttributeRef())) {
+ LOG.fine("Attribute updated on '" + getProtocolName() + "': " + attribute);
+ onAttributeUpdated(attribute);
+ linkedAttributes.put(attribute.getAttributeRef(), attribute);
+ } else {
+ LOG.fine("Attribute added on '" + getProtocolName() + "': " + attribute);
+ onAttributeAdded(attribute);
+ linkedAttributes.put(attribute.getAttributeRef(), attribute);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void unlinkAttributes(String entityId) throws Exception {
+ synchronized (linkedAttributes) {
+ Iterator<Map.Entry<AttributeRef, ThingAttribute>> entryIterator = linkedAttributes.entrySet().iterator();
+ while (entryIterator.hasNext()) {
+ Map.Entry<AttributeRef, ThingAttribute> entry = entryIterator.next();
+ if (entry.getKey().getEntityId().equals(entityId)) {
+ LOG.fine("Attribute moved on '" + getProtocolName() + "': " + entry.getValue());
+ onAttributeRemoved(entry.getValue());
+ entryIterator.remove();
+ }
+ }
+ }
+ }
+
+ protected ThingAttribute getLinkedAttribute(AttributeRef attributeRef) {
+ synchronized (linkedAttributes) {
+ return linkedAttributes.get(attributeRef);
+ }
+ }
+
+ protected void onSensorUpdate(AttributeValueChange attributeValueChange) {
+ producerTemplate.sendBody(SENSOR_TOPIC, attributeValueChange);
+ }
+
+ abstract protected void sendToActuator(AttributeValueChange attributeValueChange);
+
+ abstract protected void onAttributeAdded(ThingAttribute attribute);
+
+ abstract protected void onAttributeUpdated(ThingAttribute attribute);
+
+ abstract protected void onAttributeRemoved(ThingAttribute attribute);
+
+}
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2016, OpenRemote Inc.
+ *
+ * See the CONTRIBUTORS.txt file in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.openremote.agent3.protocol;
+
+import org.openremote.model.asset.ThingAttribute;
+import org.openremote.container.ContainerService;
+
+import java.util.Collection;
+import java.util.logging.Logger;
+
+public interface Protocol extends ContainerService {
+
+ Logger LOG = Logger.getLogger(Protocol.class.getName());
+
+ // TODO: Some of these options should be configurable depending on expected load etc.
+
+ // Message topic for communicating from thing to protocol layer (thing attribute changed, trigger actuator)
+ String ACTUATOR_TOPIC = "seda://ActuatorTopic?multipleConsumers=true&concurrentConsumers=10&waitForTaskToComplete=NEVER&purgeWhenStopping=true&discardIfNoConsumers=true&limitConcurrentConsumers=false&size=1000";
+
+ // Message topic for communicating from protocol to thing layer (sensor changed, trigger thing attribute update)
+ String SENSOR_TOPIC = "seda://SensorTopic?waitForTaskToComplete=NEVER&purgeWhenStopping=true&discardIfNoConsumers=true&size=1000";
+
+ String getProtocolName();
+
+ void linkAttributes(Collection<ThingAttribute> attributes) throws Exception;
+
+ void unlinkAttributes(String entityId) throws Exception;
+
+}
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2016, OpenRemote Inc.
+ *
+ * See the CONTRIBUTORS.txt file in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.openremote.agent3.protocol.simulator;
+
+import elemental.json.Json;
+import elemental.json.JsonNumber;
+import elemental.json.JsonString;
+import elemental.json.JsonValue;
+import org.openremote.agent3.protocol.AbstractProtocol;
+import org.openremote.agent3.protocol.simulator.element.*;
+import org.openremote.model.AttributeRef;
+import org.openremote.model.AttributeValueChange;
+import org.openremote.model.asset.ThingAttribute;
+
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.logging.Logger;
+
+import static org.openremote.Constants.PROTOCOL_NAMESPACE;
+import static org.openremote.model.asset.AssetAttributeMeta.RANGE_MAX;
+import static org.openremote.model.asset.AssetAttributeMeta.RANGE_MIN;
+
+public class SimulatorProtocol extends AbstractProtocol {
+
+ private static final Logger LOG = Logger.getLogger(org.openremote.agent3.protocol.simulator.SimulatorProtocol.class.getName());
+
+ public static final String PROTOCOL_NAME = PROTOCOL_NAMESPACE + ":simulator";
+ public static final String META_NAME_ELEMENT = PROTOCOL_NAME + ":element";
+
+ static final protected Map<AttributeRef, SimulatorElement> elements = new HashMap<>();
+
+ @Override
+ public String getProtocolName() {
+ return PROTOCOL_NAME;
+ }
+
+ @Override
+ protected void onAttributeAdded(ThingAttribute attribute) {
+ JsonString elementType = attribute.firstMetaItemOrThrow(JsonString.class, META_NAME_ELEMENT);
+ SimulatorElement element = createElement(elementType.asString(), attribute);
+ JsonValue initialState = attribute.getValue();
+ element.setState(initialState);
+ LOG.fine("Putting element '" + element + "' for: " + attribute);
+ elements.put(attribute.getAttributeRef(), element);
+ }
+
+ @Override
+ protected void onAttributeUpdated(ThingAttribute attribute) {
+ onAttributeAdded(attribute);
+ }
+
+ @Override
+ protected void onAttributeRemoved(ThingAttribute attribute) {
+ elements.remove(attribute.getAttributeRef());
+ }
+
+ @Override
+ protected void sendToActuator(AttributeValueChange attributeValueChange) {
+ putState(attributeValueChange.getAttributeRef(), attributeValueChange.getValue(), false);
+ }
+
+ public void putState(String entityId, String attributeName, JsonValue value) {
+ putState(new AttributeRef(entityId, attributeName), value, true);
+ }
+
+ public void putState(AttributeRef attributeRef, JsonValue value) {
+ putState(attributeRef, value, true);
+ }
+
+ public void putState(AttributeRef attributeRef, JsonValue value, boolean isSensorUpdate) {
+ synchronized (elements) {
+ LOG.fine("Put state '" + attributeRef + "': " + (value != null ? value.asString() : "null"));
+
+ SimulatorElement element = elements.get(attributeRef);
+ if (element == null)
+ throw new IllegalArgumentException("No simulated element for: " + attributeRef);
+
+ element.setState(value);
+
+ if (isSensorUpdate) {
+ LOG.fine("Propagating state change as sensor update: " + element);
+ onSensorUpdate(new AttributeValueChange(attributeRef, value));
+ }
+ }
+ }
+
+ public JsonValue getState(String entityId, String attributeName) {
+ return getState(new AttributeRef(entityId, attributeName));
+ }
+
+ public JsonValue getState(AttributeRef attributeRef) {
+ synchronized (elements) {
+ SimulatorElement element = elements.get(attributeRef);
+ if (element == null)
+ throw new IllegalArgumentException("No simulated element for: " + attributeRef);
+ return element.getState();
+ }
+ }
+
+ protected SimulatorElement createElement(String elementType, ThingAttribute attribute) {
+ switch (elementType.toLowerCase(Locale.ROOT)) {
+ case "switch":
+ return new SwitchSimulatorElement();
+ case "integer":
+ return new IntegerSimulatorElement();
+ case "decimal":
+ return new DecimalSimulatorElement();
+ case "range":
+ JsonNumber min = attribute.firstMetaItem(JsonNumber.class, RANGE_MIN.getName(), Json.create(0));
+ JsonNumber max = attribute.firstMetaItem(JsonNumber.class, RANGE_MAX.getName(), Json.create(100));
+ return new IntegerSimulatorElement(min.asNumber(), max.asNumber());
+ case "color":
+ return new ColorSimulatorElement();
+ default:
+ throw new UnsupportedOperationException("Can't simulate element '" + elementType + "': " + attribute);
+ }
+ }
+}
Oops, something went wrong.

0 comments on commit 49fea2f

Please sign in to comment.