From a441e1982db0dded2872c73822d95dfb0d8417b8 Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Wed, 26 Feb 2025 00:56:33 +0000 Subject: [PATCH] Create Factory for loading FieldMessageBus dynamically --- .../field_interface/agents/agents.py | 8 ++--- .../field_interface/gridappsd_field_bus.py | 2 +- .../field_interface/interfaces.py | 23 ++++++++++++- gridappsd-field-bus-lib/pyproject.toml | 2 +- .../tests/test_message_bus_factory.py | 34 +++++++++++++++++++ gridappsd-python-lib/pyproject.toml | 2 +- pyproject.toml | 2 +- 7 files changed, 64 insertions(+), 9 deletions(-) create mode 100644 gridappsd-field-bus-lib/tests/test_message_bus_factory.py diff --git a/gridappsd-field-bus-lib/gridappsd_field_bus/field_interface/agents/agents.py b/gridappsd-field-bus-lib/gridappsd_field_bus/field_interface/agents/agents.py index ffbc971..c5ecc19 100644 --- a/gridappsd-field-bus-lib/gridappsd_field_bus/field_interface/agents/agents.py +++ b/gridappsd-field-bus-lib/gridappsd_field_bus/field_interface/agents/agents.py @@ -15,7 +15,7 @@ import gridappsd.topics as t from gridappsd_field_bus.field_interface.context import LocalContext from gridappsd_field_bus.field_interface.gridappsd_field_bus import GridAPPSDMessageBus -from gridappsd_field_bus.field_interface.interfaces import (FieldMessageBus, MessageBusDefinition) +from gridappsd_field_bus.field_interface.interfaces import (FieldMessageBus, MessageBusDefinition, MessageBusFactory) CIM_PROFILE = None IEC61970_301 = None @@ -80,13 +80,13 @@ def __init__(self, if upstream_message_bus_def is not None: if upstream_message_bus_def.is_ot_bus: - self.upstream_message_bus = GridAPPSDMessageBus(upstream_message_bus_def) + self.upstream_message_bus = MessageBusFactory.create(upstream_message_bus_def) # else: # self.upstream_message_bus = VolttronMessageBus(upstream_message_bus_def) if downstream_message_bus_def is not None: if downstream_message_bus_def.is_ot_bus: - self.downstream_message_bus = GridAPPSDMessageBus(downstream_message_bus_def) + self.downstream_message_bus = MessageBusFactory.create(downstream_message_bus_def) # else: # self.downstream_message_bus = VolttronMessageBus(downstream_message_bus_def) @@ -346,7 +346,7 @@ def __init__(self, self.feeder_id = feeder_id self.distributed_agents = [] - self.system_message_bus = GridAPPSDMessageBus(system_message_bus_def) + self.system_message_bus = MessageBusFactory.create(system_message_bus_def) self.system_message_bus.connect() # This will change when we have multiple feeders per system diff --git a/gridappsd-field-bus-lib/gridappsd_field_bus/field_interface/gridappsd_field_bus.py b/gridappsd-field-bus-lib/gridappsd_field_bus/field_interface/gridappsd_field_bus.py index db4a8a2..724d6e0 100644 --- a/gridappsd-field-bus-lib/gridappsd_field_bus/field_interface/gridappsd_field_bus.py +++ b/gridappsd-field-bus-lib/gridappsd_field_bus/field_interface/gridappsd_field_bus.py @@ -7,7 +7,7 @@ class GridAPPSDMessageBus(FieldMessageBus): def __init__(self, definition: MessageBusDefinition): - super(GridAPPSDMessageBus, self).__init__(definition) + super().__init__(definition) self._id = definition.id self._user = definition.connection_args["GRIDAPPSD_USER"] diff --git a/gridappsd-field-bus-lib/gridappsd_field_bus/field_interface/interfaces.py b/gridappsd-field-bus-lib/gridappsd_field_bus/field_interface/interfaces.py index c7d0b39..bac7db1 100644 --- a/gridappsd-field-bus-lib/gridappsd_field_bus/field_interface/interfaces.py +++ b/gridappsd-field-bus-lib/gridappsd_field_bus/field_interface/interfaces.py @@ -3,6 +3,7 @@ from abc import ABC, abstractmethod from dataclasses import dataclass from enum import Enum +import importlib import gridappsd.topics as t import logging from os import PathLike @@ -32,7 +33,7 @@ class ConnectionType(Enum): # CONNECTION_TYPE_HTTP = "HTTP" # CONNECTION_TYPE_TCP = "TCP" CONNECTION_TYPE = "STOMP" - CONNECTION_TYPE_GRIDAPPSD = "CONNECTION_TYPE_GRIDAPPSD" + CONNECTION_TYPE_GRIDAPPSD = "gridappsd_field_bus.field_interface.gridappsd_field_bus.GridAPPSDMessageBus" class ProtocolTransformer(ABC): @@ -191,6 +192,26 @@ def disconnect(self): pass +class MessageBusFactory(ABC): + """ + A factory class for creating message bus objects. + """ + + def create(self, config: MessageBusDefinition) -> FieldMessageBus: + """ + Create a message bus based upon the configuration passed. + """ + try: + module_name, class_name = config.connection_type.value.rsplit('.', 1) + except AttributeError: + module_name, class_name = config.connection_type.rsplit('.', 1) + + module = importlib.import_module(module_name) + bus_class = getattr(module, class_name) + return bus_class(config) + + + class MessageBusDefinitions: def __init__( diff --git a/gridappsd-field-bus-lib/pyproject.toml b/gridappsd-field-bus-lib/pyproject.toml index 0bba014..bc9cdf6 100644 --- a/gridappsd-field-bus-lib/pyproject.toml +++ b/gridappsd-field-bus-lib/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "gridappsd-field-bus" -version = "2025.2.1a2" +version = "2025.2.1a3" description = "GridAPPS-D Field Bus Implementation" authors = [ "C. Allwardt <3979063+craig8@users.noreply.github.com>", diff --git a/gridappsd-field-bus-lib/tests/test_message_bus_factory.py b/gridappsd-field-bus-lib/tests/test_message_bus_factory.py new file mode 100644 index 0000000..4e298b3 --- /dev/null +++ b/gridappsd-field-bus-lib/tests/test_message_bus_factory.py @@ -0,0 +1,34 @@ +import unittest +import subprocess +from gridappsd_field_bus.field_interface.interfaces import MessageBusFactory, MessageBusDefinition, ConnectionType + +class TestMessageBusFactory(unittest.TestCase): + + @classmethod + def setUpClass(cls): + # Start Artemis Docker container + subprocess.run(["docker", "run", "-d", "--name", "artemis", "-p", "61616:61616", "-p", "8161:8161", "vromero/activemq-artemis"]) + + @classmethod + def tearDownClass(cls): + # Stop and remove Artemis Docker container + subprocess.run(["docker", "stop", "artemis"]) + subprocess.run(["docker", "rm", "artemis"]) + + def setUp(self): + self.factory = MessageBusFactory() + self.config = MessageBusDefinition( + id="test_bus", + connection_type=ConnectionType.CONNECTION_TYPE_GRIDAPPSD, + connection_args={"GRIDAPPSD_USER": "artemis", "GRIDAPPSD_PASSWORD": "aretemis", + "GRIDAPPSD_PORT": 61613, "GRIDAPPSD_ADDRESS": "localhost"} + ) + + def test_create_message_bus(self): + message_bus = self.factory.create(self.config) + self.assertIsNotNone(message_bus) + self.assertEqual(message_bus.id, "test_bus") + self.assertEqual(message_bus.is_ot_bus, False) + +if __name__ == '__main__': + unittest.main() diff --git a/gridappsd-python-lib/pyproject.toml b/gridappsd-python-lib/pyproject.toml index 52214b1..f9374ee 100644 --- a/gridappsd-python-lib/pyproject.toml +++ b/gridappsd-python-lib/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "gridappsd-python" -version = "2025.2.1a2" +version = "2025.2.1a3" description = "A GridAPPS-D Python Adapter" authors = [ "C. Allwardt <3979063+craig8@users.noreply.github.com>", diff --git a/pyproject.toml b/pyproject.toml index 7c76a81..ac5ae89 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "gridappsd-python-workspace" -version = "2025.2.1a2" +version = "2025.2.1a3" description = "A GridAPPS-D Python Adapter" authors = [ "C. Allwardt <3979063+craig8@users.noreply.github.com>",