diff --git a/README.md b/README.md
index dbe40dea..9d18962a 100644
--- a/README.md
+++ b/README.md
@@ -1,20 +1,16 @@
-
+
-ReatMetric is a well-documented Java-based software infrastructure for the implementation of Monitoring & Control (M&C) systems,
-with a strong focus on the space domain. ReatMetric components provide a simple but efficient implementation of the typical
-functions used in an M&C system.
+ReatMetric is a well-documented Java-based software infrastructure for the implementation of Monitoring & Control (M&C) systems.
+
+

## Documentation
The system concepts, design, configuration and usage are described in the [documentation](docs/ReatMetric%20System%20Manual.adoc).
-Suggestions on how to improve the documentation and on missing description of features can be provided opening an issue on
-GitHub.
-
## Dependencies
ReatMetric is based on a very limited set of dependencies:
-- [eu.dariolucia.ccsds](https://www.github.com/dariol83/ccsds): providing support for SLE/TM/TC/PUS handling of the _spacecraft_ driver;
- [openJFX](https://openjfx.io): for the graphical user interface of the _ui_ module;
- [ControlsFX](https://github.com/controlsfx/controlsfx): advanced UI controls for the _ui_ module;
- [eu.dariolucia.jfx.timeline](https://www.github.com/dariol83/timeline): providing support for schedule rendering in the _ui_ module;
@@ -23,71 +19,18 @@ ReatMetric is based on a very limited set of dependencies:
- [Groovy](https://groovy-lang.org): for the Groovy language support in the _processing_ and _automation_ modules (best choice);
- [GraalVM](https://www.graalvm.org): for the Javascript language support in the _automation_ modules;
- [Jython](https://www.jython.org/): for the Python language support in the _automation_ modules;
-- [Json Path](https://github.com/json-path/JsonPath): for the parsing of JSON objects and files.
-
-Including also the indirect dependencies, a typical ReatMetric backend deployment (i.e. without UI) is composed by 33 Jars,
-10 from ReatMetric and 23 from external dependencies, for a total of 19.4 MB.
-
-## Performance
-The performance of the processing model and of the spacecraft driver have been measured on the following 2 platforms:
-
-1) Zotac Magnus EN72070V: Intel Core i7-9750H, Hexa-core, 2.6 GHz without turbo boost; 32 GB DDR4 2666 MHz; Windows 10 Professional 64 bits; openJDK 11.
-2) Raspberry PI 4: Broadcom BCM2711, Quad Core Cortex-A72 (ARM v8) 64-bit SoC @ 1.5GHz, 8 GB DDR4 3200 MHz; Manjaro Linux 64 bits; openJDK 11.
-
-Each platform runs only the backend application, without UI.
-
-The data definition of the processing model included:
-- 80'000 processing parameters
-- 5'000 synthetic parameters
-- 10'000 reported events
-- 2'000 condition-based events
-- 10'000 activities
-
-The TM/TC data definition of the spacecraft included:
-- 3'600 PUS (3,25) TM packets
-- 10'000 PUS 5 TM packets
-- time packet, verification reports
-- 10'000 TC commands
-
-TM/TC setup:
-- single RAF SLE in online complete mode;
-- single CLTU SLE;
-- TM frame: 1115 bytes with CLCW, no FECF;
-- TM packets: with packet CRC.
-
-### Platform 1 results
-- Processing start-up time (as per logs - first run, no cache): 26 seconds
-- Processing start-up time (as per logs - with cache): 10 seconds
-- Max TM rate: 23.1 Mbit/sec (SLE TML level - RAF complete mode - processing backpressure propagated to the data generator)
-- Nb. of TM frames per second: ca 2.300/sec
-- Nb. of TM packets per second: ca 8.000/sec
-- Nb. of TM parameter samples decoded per second: ca 435.000/sec
-- Nb. of processed items generated per second: ca 530.000/sec
-- Memory usage (heap size): between 2 and 4 GB, Windows reports 5 GB
-- CPU load: between 35% and 45% (equivalent of almost 6 cores fully utilised)
-
-
-
-
-### Platform 2 results
-- Processing start-up time (as per logs - first run, no cache): 113 seconds
-- Processing start-up time (as per logs - with cache): 56 seconds
-- Max TM rate: 4.6 Mbit/sec (peak: 7 Mbit/sec, no backlog: 2.5 Mbit/sec)
-- Nb. of TM frames per second (peak): ca 450/sec, no backlog: 250/sec
-- Nb. of TM packets per second (peak): ca 1270/sec, no backlog: 900/sec
-- Nb. of TM parameter samples decoded per second (peak): 70.000/sec
-- Nb. of processed items generated per second (peak): 100.000/sec
-- Memory usage server (heap size): between 2 and 4 GB, top reports 4.6 GB (capped with -Xmx4G)
-- Memory usage UI (Windows Task Monitor): 1.6 GB
-- CPU load: between 320% and 350% (all 4 cores above 80%)
-
-
-
+- [eu.dariolucia.ccsds](https://www.github.com/dariol83/ccsds): providing support for SLE/TM/TC/PUS handling of the _spacecraft_ driver;
+- [Json Path](https://github.com/json-path/JsonPath): for the parsing of JSON objects and files;
+- [SNMP4J](https://www.snmp4j.org/): for the support of SNMP in the _snmp_ module;
+
+Including also the indirect dependencies, a typical ReatMetric backend deployment (i.e. without UI) is composed by 40 Jars,
+16 from ReatMetric and 24 from external dependencies, for a total of **16.5 MB**. This size can be further reduced depending
+on the needs, since some drivers and related dependencies might not be needed.
## Getting Started
### All-in-one
-If you want to quickly try ReatMetric out, I suggest the following approach:
+If you want to quickly try ReatMetric out, use the following approach:
- Build the complete tree with maven: mvn clean install
- Create a folder called 'reatmetric' inside your home folder and decompress there the configuration zip inside eu.dariolucia.reatmetric.ui.test/src/main/resources
- Update the configuration data as appropriate. There is no need to change the processing definition data
@@ -134,6 +77,9 @@ Example of remoting configuration:
+## Roadmap
+The development of ReatMetric is considered completed and no further updates will be performed.
+
## Acknowledgements and Credits
A special mention goes to Theresa Köster from the University of Gießen, who evaluated ReatMetric (among other tools)
against the Flying Laptop operational simulator. With her contributions, ideas and suggestions, she helped greatly to
diff --git a/docs/ReatMetric System Manual.adoc b/docs/ReatMetric System Manual.adoc
index 91bc3b93..2e4d8fa8 100644
--- a/docs/ReatMetric System Manual.adoc
+++ b/docs/ReatMetric System Manual.adoc
@@ -1,13 +1,13 @@
= System Manual
Dario Lucia
-v1.0.1, 2024-05-20
+v1.0.2, 2024-07-11
:title-logo-image: image:docimg/ReatMetric-Logo.png[top=42%,align=left,pdfwidth=6in]
:doctype: book
:toc:
:homepage: https://github.com/dariol83/reatmetric
== Applicable Version
-This manual described the design, behaviour and configuration of ReatMetric version 1.0.x.
+This manual described the design, behaviour and configuration of ReatMetric version 1.0.2.
== System Overview
ReatMetric is a Java-based software infrastructure for the implementation of Monitoring & Control (M&C) systems,
@@ -234,9 +234,6 @@ For instance, _raw data_ can be used to distribute and optioanlly store low leve
level between ReatMetric and the target devices. In the same way, it can be used to store changes of state or internal
states of modules and drivers, as required.
-=== ReatMetric Main Interface
-To be written
-
=== Drivers
A _driver_ is the object that connect ReatMetric with an external device or system. A driver is responsible for:
@@ -318,6 +315,9 @@ include::../eu.dariolucia.reatmetric.driver.spacecraft/Documentation.adoc[]
=== Serial
include::../eu.dariolucia.reatmetric.driver.serial/Documentation.adoc[]
+=== SNMP
+include::../eu.dariolucia.reatmetric.driver.snmp/Documentation.adoc[]
+
== User Interface
include::../eu.dariolucia.reatmetric.ui/Documentation.adoc[]
diff --git a/docs/ReatMetric System Manual.pdf b/docs/ReatMetric System Manual.pdf
index 57f2ae60..8d01d040 100644
Binary files a/docs/ReatMetric System Manual.pdf and b/docs/ReatMetric System Manual.pdf differ
diff --git a/eu.dariolucia.reatmetric.api/pom.xml b/eu.dariolucia.reatmetric.api/pom.xml
index 07ccac7d..376ba07d 100644
--- a/eu.dariolucia.reatmetric.api/pom.xml
+++ b/eu.dariolucia.reatmetric.api/pom.xml
@@ -21,7 +21,7 @@
eu.dariolucia.reatmetric
eu.dariolucia.reatmetric
- 1.0.1
+ 1.0.2
4.0.0
diff --git a/eu.dariolucia.reatmetric.core/Documentation.adoc b/eu.dariolucia.reatmetric.core/Documentation.adoc
index 29370ebf..8c707c43 100644
--- a/eu.dariolucia.reatmetric.core/Documentation.adoc
+++ b/eu.dariolucia.reatmetric.core/Documentation.adoc
@@ -62,7 +62,12 @@ eu.dariolucia.reatmetric.core.configuration. It is an XML file using namespace d
_http://dariolucia.eu/reatmetric/core/configuration_.
The elements that can contain a path support the special value $HOME, which is replaced at runtime with the contents
-of the _user.home_ system variable.
+of the _user.home_ system variable. A special value $PREFIX can also be used, which is replaced at runtime with the
+contents of the _reatmetric.prefix.dir_ system variable, which can be provided as Java property at start-up:
+
+----
+-Dreatmetric.prefix.dir=
+----
A commented example of such file is presented below.
diff --git a/eu.dariolucia.reatmetric.core/pom.xml b/eu.dariolucia.reatmetric.core/pom.xml
index d409f7fd..f671d5f1 100644
--- a/eu.dariolucia.reatmetric.core/pom.xml
+++ b/eu.dariolucia.reatmetric.core/pom.xml
@@ -21,7 +21,7 @@
eu.dariolucia.reatmetric
eu.dariolucia.reatmetric
- 1.0.1
+ 1.0.2
4.0.0
diff --git a/eu.dariolucia.reatmetric.core/src/main/java/eu/dariolucia/reatmetric/core/configuration/ServiceCoreConfiguration.java b/eu.dariolucia.reatmetric.core/src/main/java/eu/dariolucia/reatmetric/core/configuration/ServiceCoreConfiguration.java
index ab3bba70..bf0b2884 100644
--- a/eu.dariolucia.reatmetric.core/src/main/java/eu/dariolucia/reatmetric/core/configuration/ServiceCoreConfiguration.java
+++ b/eu.dariolucia.reatmetric.core/src/main/java/eu/dariolucia/reatmetric/core/configuration/ServiceCoreConfiguration.java
@@ -31,23 +31,30 @@ public class ServiceCoreConfiguration {
private static final String HOME_VAR = "$HOME";
private static final String HOME_DIR = System.getProperty("user.home");
+ private static final String PREFIX_VAR = "$PREFIX";
+ private static final String PREFIX_DIR = System.getProperty("reatmetric.prefix.dir", "");
+
public static ServiceCoreConfiguration load(InputStream is) throws JAXBException {
JAXBContext jc = JAXBContext.newInstance(ServiceCoreConfiguration.class);
Unmarshaller u = jc.createUnmarshaller();
ServiceCoreConfiguration configuration = (ServiceCoreConfiguration) u.unmarshal(is);
- // Update $HOME
+ // Update $HOME and $PREFIX
if(configuration.getArchiveLocation() != null) {
configuration.setArchiveLocation(configuration.getArchiveLocation().replace(HOME_VAR, HOME_DIR));
+ configuration.setArchiveLocation(configuration.getArchiveLocation().replace(PREFIX_VAR, PREFIX_DIR));
}
configuration.setDefinitionsLocation(configuration.getDefinitionsLocation().replace(HOME_VAR, HOME_DIR));
if(configuration.getLogPropertyFile() != null) {
configuration.setLogPropertyFile(configuration.getLogPropertyFile().replace(HOME_VAR, HOME_DIR));
+ configuration.setLogPropertyFile(configuration.getLogPropertyFile().replace(PREFIX_VAR, PREFIX_DIR));
}
if(configuration.getSchedulerConfiguration() != null) {
configuration.setSchedulerConfiguration(configuration.getSchedulerConfiguration().replace(HOME_VAR, HOME_DIR));
+ configuration.setSchedulerConfiguration(configuration.getSchedulerConfiguration().replace(PREFIX_VAR, PREFIX_DIR));
}
for(DriverConfiguration dc : configuration.getDrivers()) {
dc.setConfiguration(dc.getConfiguration().replace(HOME_VAR, HOME_DIR));
+ dc.setConfiguration(dc.getConfiguration().replace(PREFIX_VAR, PREFIX_DIR));
}
//
return configuration;
diff --git a/eu.dariolucia.reatmetric.deployment/Dockerfile b/eu.dariolucia.reatmetric.deployment/Dockerfile
new file mode 100644
index 00000000..fd88e600
--- /dev/null
+++ b/eu.dariolucia.reatmetric.deployment/Dockerfile
@@ -0,0 +1,15 @@
+# syntax=docker/dockerfile:1
+
+FROM eclipse-temurin:17-jre-alpine
+WORKDIR /reatmetric
+COPY target/deps .
+CMD ["java", "-Djava.rmi.server.hostname=127.0.0.1", "-Dreatmetric.core.config=/etc/reatmetric/configuration.xml", "-Dreatmetric.remoting.rmi.export.port=4000", "--module-path=/reatmetric", "-m", "eu.dariolucia.reatmetric.remoting/eu.dariolucia.reatmetric.remoting.ReatmetricRemotingServer", "3000"]
+# Java RMI registry
+EXPOSE 3000
+# Java RMI exported objects
+EXPOSE 4000
+# HTTP server driver port
+EXPOSE 8081
+
+# docker build -t reatmetric-1.1.0-snapshot .
+# docker run -it --mount type=bind,src="C:\Users\dario\Reatmetric\reatmetric_docker",target="/etc/reatmetric" -d -p 127.0.0.1:3000:3000 -p 127.0.0.1:4000:4000 -p 127.0.0.1:8081:8081 reatmetric-1.1.0-snapshot
\ No newline at end of file
diff --git a/eu.dariolucia.reatmetric.deployment/LICENSE b/eu.dariolucia.reatmetric.deployment/LICENSE
new file mode 100644
index 00000000..261eeb9e
--- /dev/null
+++ b/eu.dariolucia.reatmetric.deployment/LICENSE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ 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.
diff --git a/eu.dariolucia.reatmetric.deployment/NOTICE b/eu.dariolucia.reatmetric.deployment/NOTICE
new file mode 100644
index 00000000..1a586335
--- /dev/null
+++ b/eu.dariolucia.reatmetric.deployment/NOTICE
@@ -0,0 +1,18 @@
+CREDITS
+------------------------------------------------------------------------------
+------------------------------------------------------------------------------
+eu.dariolucia.reatmetric.deployment
+
+Copyright (c) 2024 Dario Lucia (https://www.dariolucia.eu)
+
+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.
diff --git a/eu.dariolucia.reatmetric.deployment/pom.xml b/eu.dariolucia.reatmetric.deployment/pom.xml
new file mode 100644
index 00000000..d9e32fa2
--- /dev/null
+++ b/eu.dariolucia.reatmetric.deployment/pom.xml
@@ -0,0 +1,136 @@
+
+
+
+
+
+ eu.dariolucia.reatmetric
+ eu.dariolucia.reatmetric
+ 1.0.2
+
+
+ 4.0.0
+ eu.dariolucia.reatmetric.deployment
+ REATMETRIC DEPLOYMENT
+ REATMETRIC full backend deployment (no UI)
+
+
+
+
+ org.apache.maven.plugins
+ maven-dependency-plugin
+
+
+ copy-dependencies
+ prepare-package
+
+ copy-dependencies
+
+
+ target/deps
+ true
+
+ org.junit.jupiter,org.apiguardian,org.junit.platform,org.opentest4j
+
+
+
+
+
+ true
+ true
+ ${project.build.directory}
+
+
+
+
+
+
+
+ eu.dariolucia.reatmetric
+ eu.dariolucia.reatmetric.api
+ ${project.parent.version}
+
+
+ eu.dariolucia.reatmetric
+ eu.dariolucia.reatmetric.core
+ ${project.parent.version}
+
+
+ eu.dariolucia.reatmetric
+ eu.dariolucia.reatmetric.remoting
+ ${project.parent.version}
+
+
+ eu.dariolucia.reatmetric
+ eu.dariolucia.reatmetric.scheduler
+ ${project.parent.version}
+
+
+ eu.dariolucia.reatmetric
+ eu.dariolucia.reatmetric.persist
+ ${project.parent.version}
+
+
+ eu.dariolucia.reatmetric
+ eu.dariolucia.reatmetric.processing
+ ${project.parent.version}
+
+
+
+ eu.dariolucia.reatmetric
+ eu.dariolucia.reatmetric.driver.serial
+ ${project.parent.version}
+
+
+ eu.dariolucia.reatmetric
+ eu.dariolucia.reatmetric.driver.httpserver
+ ${project.parent.version}
+
+
+ eu.dariolucia.reatmetric
+ eu.dariolucia.reatmetric.driver.socket
+ ${project.parent.version}
+
+
+ eu.dariolucia.reatmetric
+ eu.dariolucia.reatmetric.driver.spacecraft
+ ${project.parent.version}
+
+
+ eu.dariolucia.reatmetric
+ eu.dariolucia.reatmetric.driver.remote
+ ${project.parent.version}
+
+
+ eu.dariolucia.reatmetric
+ eu.dariolucia.reatmetric.driver.test
+ ${project.parent.version}
+
+
+ eu.dariolucia.reatmetric
+ eu.dariolucia.reatmetric.driver.automation.groovy
+ ${project.parent.version}
+
+
+ eu.dariolucia.reatmetric
+ eu.dariolucia.reatmetric.driver.snmp
+ ${project.parent.version}
+
+
+
+
\ No newline at end of file
diff --git a/eu.dariolucia.reatmetric.driver.automation.base/pom.xml b/eu.dariolucia.reatmetric.driver.automation.base/pom.xml
index 3c323eed..b92ab36c 100644
--- a/eu.dariolucia.reatmetric.driver.automation.base/pom.xml
+++ b/eu.dariolucia.reatmetric.driver.automation.base/pom.xml
@@ -21,7 +21,7 @@
eu.dariolucia.reatmetric
eu.dariolucia.reatmetric
- 1.0.1
+ 1.0.2
4.0.0
diff --git a/eu.dariolucia.reatmetric.driver.automation.base/src/main/java/eu/dariolucia/reatmetric/driver/automation/base/definition/AutomationConfiguration.java b/eu.dariolucia.reatmetric.driver.automation.base/src/main/java/eu/dariolucia/reatmetric/driver/automation/base/definition/AutomationConfiguration.java
index 2c66db5a..24cd1f2d 100644
--- a/eu.dariolucia.reatmetric.driver.automation.base/src/main/java/eu/dariolucia/reatmetric/driver/automation/base/definition/AutomationConfiguration.java
+++ b/eu.dariolucia.reatmetric.driver.automation.base/src/main/java/eu/dariolucia/reatmetric/driver/automation/base/definition/AutomationConfiguration.java
@@ -31,6 +31,9 @@ public class AutomationConfiguration {
private static final String HOME_VAR = "$HOME";
private static final String HOME_DIR = System.getProperty("user.home");
+ private static final String PREFIX_VAR = "$PREFIX";
+ private static final String PREFIX_DIR = System.getProperty("reatmetric.prefix.dir", "");
+
public static AutomationConfiguration load(InputStream is) throws IOException {
try {
JAXBContext jc = JAXBContext.newInstance(AutomationConfiguration.class);
@@ -38,6 +41,7 @@ public static AutomationConfiguration load(InputStream is) throws IOException {
AutomationConfiguration o = (AutomationConfiguration) u.unmarshal(is);
if(o.getScriptFolder() != null) {
o.setScriptFolder(o.getScriptFolder().replace(HOME_VAR, HOME_DIR));
+ o.setScriptFolder(o.getScriptFolder().replace(PREFIX_VAR, PREFIX_DIR));
}
return o;
} catch (JAXBException e) {
diff --git a/eu.dariolucia.reatmetric.driver.automation.groovy/pom.xml b/eu.dariolucia.reatmetric.driver.automation.groovy/pom.xml
index ab833635..fdf6cbd6 100644
--- a/eu.dariolucia.reatmetric.driver.automation.groovy/pom.xml
+++ b/eu.dariolucia.reatmetric.driver.automation.groovy/pom.xml
@@ -21,7 +21,7 @@
eu.dariolucia.reatmetric
eu.dariolucia.reatmetric
- 1.0.1
+ 1.0.2
4.0.0
diff --git a/eu.dariolucia.reatmetric.driver.automation.js/pom.xml b/eu.dariolucia.reatmetric.driver.automation.js/pom.xml
index 96dd98cf..f45f3781 100644
--- a/eu.dariolucia.reatmetric.driver.automation.js/pom.xml
+++ b/eu.dariolucia.reatmetric.driver.automation.js/pom.xml
@@ -21,7 +21,7 @@
eu.dariolucia.reatmetric
eu.dariolucia.reatmetric
- 1.0.1
+ 1.0.2
4.0.0
diff --git a/eu.dariolucia.reatmetric.driver.automation.python/pom.xml b/eu.dariolucia.reatmetric.driver.automation.python/pom.xml
index b3b494e2..3e2c5802 100644
--- a/eu.dariolucia.reatmetric.driver.automation.python/pom.xml
+++ b/eu.dariolucia.reatmetric.driver.automation.python/pom.xml
@@ -21,7 +21,7 @@
eu.dariolucia.reatmetric
eu.dariolucia.reatmetric
- 1.0.1
+ 1.0.2
4.0.0
diff --git a/eu.dariolucia.reatmetric.driver.example.test/Documentation.adoc b/eu.dariolucia.reatmetric.driver.example.test/Documentation.adoc
index dbcd285a..66adc544 100644
--- a/eu.dariolucia.reatmetric.driver.example.test/Documentation.adoc
+++ b/eu.dariolucia.reatmetric.driver.example.test/Documentation.adoc
@@ -25,7 +25,7 @@ required for the deployment.
eu.dariolucia.reatmetric.example
eu.dariolucia.reatmetric.driver.example.test
REATMETRIC - Example Test
- 1.0.1
+ 1.0.2
REATMETRIC Example Test for deployment
@@ -68,48 +68,48 @@ required for the deployment.
eu.dariolucia.reatmetric
eu.dariolucia.reatmetric.api
- 1.0.1
+ 1.0.2
eu.dariolucia.reatmetric
eu.dariolucia.reatmetric.core
- 1.0.1
+ 1.0.2
eu.dariolucia.reatmetric
eu.dariolucia.reatmetric.scheduler
- 1.0.1
+ 1.0.2
eu.dariolucia.reatmetric
eu.dariolucia.reatmetric.ui
- 1.0.1
+ 1.0.2
eu.dariolucia.reatmetric
eu.dariolucia.reatmetric.driver.automation.groovy
- 1.0.1
+ 1.0.2
eu.dariolucia.reatmetric
eu.dariolucia.reatmetric.persist
- 1.0.1
+ 1.0.2
eu.dariolucia.reatmetric
eu.dariolucia.reatmetric.processing
- 1.0.1
+ 1.0.2
eu.dariolucia.reatmetric
eu.dariolucia.reatmetric.driver.httpserver
- 1.0.1
+ 1.0.2
eu.dariolucia.reatmetric.example
eu.dariolucia.reatmetric.driver.example
- 1.0.1
+ 1.0.2
diff --git a/eu.dariolucia.reatmetric.driver.example.test/pom.xml b/eu.dariolucia.reatmetric.driver.example.test/pom.xml
index 28c32b7f..9679c1c7 100644
--- a/eu.dariolucia.reatmetric.driver.example.test/pom.xml
+++ b/eu.dariolucia.reatmetric.driver.example.test/pom.xml
@@ -22,7 +22,7 @@
eu.dariolucia.reatmetric.example
eu.dariolucia.reatmetric.driver.example.test
REATMETRIC - Example Test
- 1.0.1
+ 1.0.2
REATMETRIC Example Test for deployment
@@ -65,48 +65,48 @@
eu.dariolucia.reatmetric
eu.dariolucia.reatmetric.api
- 1.0.1
+ 1.0.2
eu.dariolucia.reatmetric
eu.dariolucia.reatmetric.core
- 1.0.1
+ 1.0.2
eu.dariolucia.reatmetric
eu.dariolucia.reatmetric.scheduler
- 1.0.1
+ 1.0.2
eu.dariolucia.reatmetric
eu.dariolucia.reatmetric.ui
- 1.0.1
+ 1.0.2
eu.dariolucia.reatmetric
eu.dariolucia.reatmetric.driver.automation.groovy
- 1.0.1
+ 1.0.2
eu.dariolucia.reatmetric
eu.dariolucia.reatmetric.persist
- 1.0.1
+ 1.0.2
eu.dariolucia.reatmetric
eu.dariolucia.reatmetric.processing
- 1.0.1
+ 1.0.2
eu.dariolucia.reatmetric
eu.dariolucia.reatmetric.driver.httpserver
- 1.0.1
+ 1.0.2
eu.dariolucia.reatmetric.example
eu.dariolucia.reatmetric.driver.example
- 1.0.1
+ 1.0.2
diff --git a/eu.dariolucia.reatmetric.driver.example/Documentation.adoc b/eu.dariolucia.reatmetric.driver.example/Documentation.adoc
index 997f669b..4322feb9 100644
--- a/eu.dariolucia.reatmetric.driver.example/Documentation.adoc
+++ b/eu.dariolucia.reatmetric.driver.example/Documentation.adoc
@@ -22,7 +22,7 @@ src/main/java needs to exist. The pom file must contain as a minimum the depende
eu.dariolucia.reatmetric.example
eu.dariolucia.reatmetric.driver.example
REATMETRIC DRIVER - Example driver
- 1.0.1
+ 1.0.2
REATMETRIC driver module for documentation purposes
jar
@@ -59,17 +59,17 @@ src/main/java needs to exist. The pom file must contain as a minimum the depende
eu.dariolucia.reatmetric
eu.dariolucia.reatmetric.api
- 1.0.1
+ 1.0.2
eu.dariolucia.reatmetric
eu.dariolucia.reatmetric.core
- 1.0.1
+ 1.0.2
eu.dariolucia.reatmetric
eu.dariolucia.reatmetric.processing
- 1.0.1
+ 1.0.2
diff --git a/eu.dariolucia.reatmetric.driver.example/pom.xml b/eu.dariolucia.reatmetric.driver.example/pom.xml
index f31af535..c673fde6 100644
--- a/eu.dariolucia.reatmetric.driver.example/pom.xml
+++ b/eu.dariolucia.reatmetric.driver.example/pom.xml
@@ -21,7 +21,7 @@
eu.dariolucia.reatmetric.example
eu.dariolucia.reatmetric.driver.example
REATMETRIC DRIVER - Example driver
- 1.0.1
+ 1.0.2
REATMETRIC driver module for documentation purposes
jar
@@ -58,17 +58,17 @@
eu.dariolucia.reatmetric
eu.dariolucia.reatmetric.api
- 1.0.1
+ 1.0.2
eu.dariolucia.reatmetric
eu.dariolucia.reatmetric.core
- 1.0.1
+ 1.0.2
eu.dariolucia.reatmetric
eu.dariolucia.reatmetric.processing
- 1.0.1
+ 1.0.2
\ No newline at end of file
diff --git a/eu.dariolucia.reatmetric.driver.httpserver/pom.xml b/eu.dariolucia.reatmetric.driver.httpserver/pom.xml
index 8599b0a5..6c9df7fd 100644
--- a/eu.dariolucia.reatmetric.driver.httpserver/pom.xml
+++ b/eu.dariolucia.reatmetric.driver.httpserver/pom.xml
@@ -21,7 +21,7 @@
eu.dariolucia.reatmetric
eu.dariolucia.reatmetric
- 1.0.1
+ 1.0.2
4.0.0
diff --git a/eu.dariolucia.reatmetric.driver.remote/pom.xml b/eu.dariolucia.reatmetric.driver.remote/pom.xml
index 8b8bcd0d..05c5ba37 100644
--- a/eu.dariolucia.reatmetric.driver.remote/pom.xml
+++ b/eu.dariolucia.reatmetric.driver.remote/pom.xml
@@ -21,7 +21,7 @@
eu.dariolucia.reatmetric
eu.dariolucia.reatmetric
- 1.0.1
+ 1.0.2
4.0.0
diff --git a/eu.dariolucia.reatmetric.driver.serial/pom.xml b/eu.dariolucia.reatmetric.driver.serial/pom.xml
index 727836ba..b746b3a2 100644
--- a/eu.dariolucia.reatmetric.driver.serial/pom.xml
+++ b/eu.dariolucia.reatmetric.driver.serial/pom.xml
@@ -21,7 +21,7 @@
eu.dariolucia.reatmetric
eu.dariolucia.reatmetric
- 1.0.1
+ 1.0.2
4.0.0
diff --git a/eu.dariolucia.reatmetric.driver.snmp.util/LICENSE b/eu.dariolucia.reatmetric.driver.snmp.util/LICENSE
new file mode 100644
index 00000000..261eeb9e
--- /dev/null
+++ b/eu.dariolucia.reatmetric.driver.snmp.util/LICENSE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ 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.
diff --git a/eu.dariolucia.reatmetric.driver.snmp.util/NOTICE b/eu.dariolucia.reatmetric.driver.snmp.util/NOTICE
new file mode 100644
index 00000000..56587999
--- /dev/null
+++ b/eu.dariolucia.reatmetric.driver.snmp.util/NOTICE
@@ -0,0 +1,23 @@
+CREDITS
+------------------------------------------------------------------------------
+eu.dariolucia.reatmetric.driver.snmp.util uses the SNMP4J library.
+(https://www.snmp4j.org/)
+
+SNMP4J is licensed under the Apache License 2.0
+(https://www.apache.org/licenses/LICENSE-2.0.html)
+------------------------------------------------------------------------------
+eu.dariolucia.reatmetric.driver.snmp.util
+
+Copyright (c) 2024 Dario Lucia (https://www.dariolucia.eu)
+
+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.
diff --git a/eu.dariolucia.reatmetric.driver.snmp.util/pom.xml b/eu.dariolucia.reatmetric.driver.snmp.util/pom.xml
new file mode 100644
index 00000000..73dcad37
--- /dev/null
+++ b/eu.dariolucia.reatmetric.driver.snmp.util/pom.xml
@@ -0,0 +1,65 @@
+
+
+
+
+
+ eu.dariolucia.reatmetric
+ eu.dariolucia.reatmetric
+ 1.0.2
+
+
+ 4.0.0
+ eu.dariolucia.reatmetric.driver.snmp.util
+ REATMETRIC DRIVER - SNMP driver util
+ Utility software for REATMETRIC SNMP driver
+
+
+
+ eu.dariolucia.reatmetric
+ eu.dariolucia.reatmetric.api
+ ${project.parent.version}
+
+
+ eu.dariolucia.reatmetric
+ eu.dariolucia.reatmetric.core
+ ${project.parent.version}
+
+
+ eu.dariolucia.reatmetric
+ eu.dariolucia.reatmetric.processing
+ ${project.parent.version}
+
+
+ eu.dariolucia.reatmetric
+ eu.dariolucia.reatmetric.driver.snmp
+ ${project.parent.version}
+
+
+ org.glassfish.jaxb
+ jaxb-runtime
+ ${jaxb.version}
+
+
+ org.snmp4j
+ snmp4j
+ ${snmp4j.version}
+
+
+
+
\ No newline at end of file
diff --git a/eu.dariolucia.reatmetric.driver.snmp.util/src/main/java/eu/dariolucia/reatmetric/driver/snmp/util/BasicComputerDriverGenerator.java b/eu.dariolucia.reatmetric.driver.snmp.util/src/main/java/eu/dariolucia/reatmetric/driver/snmp/util/BasicComputerDriverGenerator.java
new file mode 100644
index 00000000..ab574bb0
--- /dev/null
+++ b/eu.dariolucia.reatmetric.driver.snmp.util/src/main/java/eu/dariolucia/reatmetric/driver/snmp/util/BasicComputerDriverGenerator.java
@@ -0,0 +1,462 @@
+/*
+ * Copyright (c) 2024 Dario Lucia (https://www.dariolucia.eu)
+ *
+ * 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 eu.dariolucia.reatmetric.driver.snmp.util;
+
+import eu.dariolucia.reatmetric.api.value.ValueTypeEnum;
+import eu.dariolucia.reatmetric.driver.snmp.SnmpDriver;
+import eu.dariolucia.reatmetric.driver.snmp.configuration.GroupConfiguration;
+import eu.dariolucia.reatmetric.driver.snmp.configuration.OidEntry;
+import eu.dariolucia.reatmetric.driver.snmp.configuration.OidEntryType;
+import eu.dariolucia.reatmetric.driver.snmp.configuration.SnmpDeviceConfiguration;
+import eu.dariolucia.reatmetric.processing.definition.*;
+import org.snmp4j.CommunityTarget;
+import org.snmp4j.Snmp;
+import org.snmp4j.TransportMapping;
+import org.snmp4j.mp.SnmpConstants;
+import org.snmp4j.smi.OID;
+import org.snmp4j.smi.OctetString;
+import org.snmp4j.smi.UdpAddress;
+import org.snmp4j.smi.VariableBinding;
+import org.snmp4j.transport.DefaultUdpTransportMapping;
+import org.snmp4j.util.DefaultPDUFactory;
+import org.snmp4j.util.TableEvent;
+import org.snmp4j.util.TableUtils;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+
+public class BasicComputerDriverGenerator {
+ private static final OID systemUptimeOID = new OID(".1.3.6.1.2.1.25.1.1.0"); // system uptime
+ private static final OID systemDateOID = new OID(".1.3.6.1.2.1.25.1.2.0"); // system date
+ private static final OID numUsersOID = new OID(".1.3.6.1.2.1.25.1.5.0"); // num users
+ private static final OID systemDescrOID = new OID(".1.3.6.1.2.1.1.1.0"); // system description
+ private static final OID systemNameOID = new OID(".1.3.6.1.2.1.1.5.0"); // system name
+ private static final OID contactNameOID = new OID(".1.3.6.1.2.1.1.4.0"); // contact name
+ private static final OID memorySizeOID = new OID(".1.3.6.1.2.1.25.2.2.0"); // memory size (KB)
+ private static final OID processorTableOID = new OID(".1.3.6.1.2.1.25.3.3"); // processor table
+ private static final OID processorLoadOID = new OID(".1.3.6.1.2.1.25.3.3.1.2"); // processor load prefix
+ private static final OID diskStorageTableOID = new OID(".1.3.6.1.2.1.25.3.6"); // disk storage table
+ private static final OID diskCapacityOID = new OID(".1.3.6.1.2.1.25.3.6.1.4"); // capacity prefix (KB)
+ private static final OID storageTableOID = new OID(".1.3.6.1.2.1.25.2.3"); // storage table
+ private static final OID storageTypeOID = new OID(".1.3.6.1.2.1.25.2.3.1.2"); // storage type prefix
+ private static final OID storageDescrOID = new OID(".1.3.6.1.2.1.25.2.3.1.3"); // storage description prefix
+ private static final OID storageAllocUnitOID = new OID(".1.3.6.1.2.1.25.2.3.1.4"); // storage allocation unit prefix
+ private static final OID storageSizeOID = new OID(".1.3.6.1.2.1.25.2.3.1.5"); // storage size prefix
+ private static final OID storageUsedOID = new OID(".1.3.6.1.2.1.25.2.3.1.6"); // storage used prefix
+ private static final OID interfaceTableOID = new OID(".1.3.6.1.2.1.2.2"); // interface table
+ private static final OID interfaceDescrOID = new OID(".1.3.6.1.2.1.2.2.1.2"); // interface description prefix
+ private static final OID interfaceTypeOID = new OID(".1.3.6.1.2.1.2.2.1.3"); // interface type prefix
+ private static final OID interfaceSpeedOID = new OID(".1.3.6.1.2.1.2.2.1.5"); // interface speed prefix
+ private static final OID interfaceMacOID = new OID(".1.3.6.1.2.1.2.2.1.6"); // interface MAC prefix
+ private static final OID interfaceAdminOID = new OID(".1.3.6.1.2.1.2.2.1.7"); // interface admin prefix
+ private static final OID interfaceOperOID = new OID(".1.3.6.1.2.1.2.2.1.8"); // interface operation prefix
+ private static final OID interfaceInOctOID = new OID(".1.3.6.1.2.1.2.2.1.10"); // interface in octets prefix
+ private static final OID interfaceInDiscardOID = new OID(".1.3.6.1.2.1.2.2.1.13"); // interface in discards prefix
+ private static final OID interfaceInErrorsOID = new OID(".1.3.6.1.2.1.2.2.1.14"); // interface in errors prefix
+ private static final OID interfaceInUnknownOID = new OID(".1.3.6.1.2.1.2.2.1.15"); // interface in unknown prefix
+ private static final OID interfaceOutOctOID = new OID(".1.3.6.1.2.1.2.2.1.16"); // interface out octets prefix
+ private static final OID interfaceOutErrorsOID = new OID(".1.3.6.1.2.1.2.2.1.20"); // interface out errors prefix
+ private static final OID interfaceOutDiscardsOID = new OID(".1.3.6.1.2.1.2.2.1.20"); // interface out discards prefix
+
+ private Snmp snmp;
+ private int externalIdStart;
+ private String pathPrefix;
+ private ProcessingDefinition processingDefinition;
+ private SnmpDeviceConfiguration snmpDeviceConfiguration;
+
+ public void export(String snmpConnectionUrl, String community, int externalIdStart, String pathPrefix, String deviceName) throws IOException {
+ TransportMapping transport = new DefaultUdpTransportMapping();
+ this.snmp = new Snmp(transport);
+ transport.listen();
+
+ CommunityTarget target = buildTarget(snmpConnectionUrl, community);
+ this.externalIdStart = externalIdStart;
+ if(pathPrefix.endsWith(".")) {
+ pathPrefix = pathPrefix.substring(0, pathPrefix.length() - 1);
+ }
+ this.pathPrefix = pathPrefix;
+ initialise(deviceName);
+ processSystem(target);
+ processDevices(target);
+ processStorage(target);
+ processNetwork(target);
+ finalise();
+
+ this.snmp.close();
+ }
+
+ private void finalise() throws IOException {
+ File modelFile = new File(pathPrefix.replace(".", "_") + "_" + "model.xml");
+ if(!modelFile.exists()) {
+ modelFile.createNewFile();
+ }
+ FileOutputStream fos = new FileOutputStream(modelFile);
+ ProcessingDefinition.save(this.processingDefinition, fos);
+ fos.close();
+
+ File snmpDeviceFile = new File(pathPrefix.replace(".", "_") + "_" + "device.xml");
+ if(!snmpDeviceFile.exists()) {
+ snmpDeviceFile.createNewFile();
+ }
+ FileOutputStream fos2 = new FileOutputStream(snmpDeviceFile);
+ SnmpDeviceConfiguration.save(this.snmpDeviceConfiguration, fos2);
+ fos2.close();
+ }
+
+ private void initialise(String deviceName) {
+ processingDefinition = new ProcessingDefinition();
+ String thePathPrefix = this.pathPrefix;
+ if(!thePathPrefix.endsWith(".")) {
+ thePathPrefix += ".";
+ }
+ processingDefinition.setPathPrefix(thePathPrefix);
+ // Add setter
+ addSetter(deviceName);
+ snmpDeviceConfiguration = new SnmpDeviceConfiguration();
+ }
+
+ private void addSetter(String deviceName) {
+ ActivityProcessingDefinition apd = new ActivityProcessingDefinition();
+ apd.setLocation("Setter");
+ apd.setType(SnmpDriver.SNMP_MESSAGE_TYPE);
+ apd.setId(externalIdStart++);
+ apd.setDescription("OID setter activity");
+ apd.setDefaultRoute(deviceName);
+ apd.setArguments(new LinkedList<>());
+ // First argument: OID in string format
+ PlainArgumentDefinition pad1 = new PlainArgumentDefinition();
+ pad1.setDescription("OID to set (string)");
+ pad1.setName("OID");
+ pad1.setRawType(ValueTypeEnum.CHARACTER_STRING);
+ pad1.setEngineeringType(ValueTypeEnum.CHARACTER_STRING);
+ apd.getArguments().add(pad1);
+ // Second argument: value
+ PlainArgumentDefinition pad2 = new PlainArgumentDefinition();
+ pad2.setDescription("Value");
+ pad2.setName("Value");
+ pad2.setRawType(ValueTypeEnum.DERIVED);
+ pad2.setEngineeringType(ValueTypeEnum.DERIVED);
+ apd.getArguments().add(pad2);
+ // Add to definition
+ this.processingDefinition.getActivityDefinitions().add(apd);
+ }
+
+ private void processStorage(CommunityTarget target) {
+ String groupName = "Storage";
+ GroupConfiguration gc = new GroupConfiguration();
+ gc.setName(groupName);
+ gc.setDistributePdu(false);
+ gc.setPollingTime(2 * 60000); // Once every 2 minutes is enough
+ this.snmpDeviceConfiguration.getGroupConfigurationList().add(gc);
+
+ // Storage table
+ TableUtils tUtils = new TableUtils(this.snmp, new DefaultPDUFactory());
+ List events = tUtils.getTable(target, new OID[] { storageTableOID }, null, null);
+ for (TableEvent event : events) {
+ if (event.isError()) {
+ System.err.println("Error event when parsing storage block");
+ continue;
+ }
+ for (VariableBinding vb : event.getColumns()) {
+ OID key = vb.getOid();
+ int storageNb = key.get(key.size() - 1);
+ // Get the idx
+ if (key.startsWith(storageTypeOID)) {
+ // Type
+ addParameter(gc, groupName + storageNb, "Type", OidEntryType.OID, key, null, storageTypeCalibration());
+ } else if (key.startsWith(storageDescrOID)) {
+ // Description
+ addParameter(gc, groupName + storageNb, "Description", OidEntryType.STRING, key);
+ } else if (key.startsWith(storageAllocUnitOID)) {
+ // Allocation Unit
+ addParameter(gc, groupName + storageNb, "Allocation_Unit", OidEntryType.LONG, key);
+ } else if (key.startsWith(storageSizeOID)) {
+ // Storage size
+ addParameter(gc, groupName + storageNb, "Storage_Size", OidEntryType.LONG, key, "bytes");
+ } else if (key.startsWith(storageUsedOID)) {
+ // Storage used
+ addParameter(gc, groupName + storageNb, "Storage_Used", OidEntryType.LONG, key, "bytes");
+ }
+ }
+ }
+ }
+
+ private static EnumCalibration storageTypeCalibration() {
+ EnumCalibration calibration = new EnumCalibration();
+ calibration.setDefaultValue("Unknown");
+ calibration.setApplicability(null);
+ calibration.setPoints(new LinkedList<>());
+ calibration.getPoints().add(new EnumCalibrationPoint(1, "Other"));
+ calibration.getPoints().add(new EnumCalibrationPoint(2, "RAM"));
+ calibration.getPoints().add(new EnumCalibrationPoint(3, "Virtual Memory"));
+ calibration.getPoints().add(new EnumCalibrationPoint(4, "Fixed Disk"));
+ calibration.getPoints().add(new EnumCalibrationPoint(5, "Removable Disk"));
+ calibration.getPoints().add(new EnumCalibrationPoint(6, "Floppy Disk"));
+ calibration.getPoints().add(new EnumCalibrationPoint(7, "Compact Disk"));
+ calibration.getPoints().add(new EnumCalibrationPoint(8, "RAM Disk"));
+ return calibration;
+ }
+
+ private ParameterProcessingDefinition addParameter(GroupConfiguration gc, String parent, String name, OidEntryType type, OID key, String unit, CalibrationDefinition calibration) {
+ // Add mapping to group
+ gc.getOidEntryList().add(new OidEntry(key.format(), parent + "." + name, type));
+ // Add parameter to model
+ ParameterProcessingDefinition ppd = new ParameterProcessingDefinition();
+ ppd.setDescription(key.toString());
+ ppd.setUnit(unit);
+ ppd.setRawType(type.toValueTypeEnum());
+ ppd.setEngineeringType(type.toValueTypeEnum());
+ ppd.setId(externalIdStart++);
+ ppd.setLocation(parent + "." + name);
+ if(calibration != null) {
+ ppd.setCalibrations(new LinkedList<>(Collections.singletonList(calibration)));
+ if(calibration instanceof EnumCalibration) {
+ ppd.setEngineeringType(ValueTypeEnum.CHARACTER_STRING);
+ }
+ }
+ processingDefinition.getParameterDefinitions().add(ppd);
+ return ppd;
+ }
+
+ private ParameterProcessingDefinition addParameter(GroupConfiguration gc, String parent, String name, OidEntryType type, OID key, String unit) {
+ return addParameter(gc, parent, name, type, key, unit, null);
+ }
+
+ private ParameterProcessingDefinition addParameter(GroupConfiguration gc, String parent, String name, OidEntryType type, OID key) {
+ return addParameter(gc, parent, name, type, key, null, null);
+ }
+
+ private void processNetwork(CommunityTarget target) {
+ String groupName = "Network";
+ GroupConfiguration gc = new GroupConfiguration();
+ gc.setName(groupName);
+ gc.setDistributePdu(false);
+ gc.setPollingTime(2 * 60000); // Once every 2 minutes is enough
+ this.snmpDeviceConfiguration.getGroupConfigurationList().add(gc);
+
+ // Network table
+ TableUtils tUtils = new TableUtils(this.snmp, new DefaultPDUFactory());
+ List events = tUtils.getTable(target, new OID[] { interfaceTableOID }, null, null);
+ for (TableEvent event : events) {
+ if (event.isError()) {
+ System.err.println("Error event when parsing network block");
+ continue;
+ }
+ for (VariableBinding vb : event.getColumns()) {
+ OID key = vb.getOid();
+ int networkNb = key.get(key.size() - 1);
+ // Get the idx
+ if (key.startsWith(interfaceDescrOID)) {
+ addParameter(gc, groupName + networkNb, "Description", OidEntryType.STRING, key);
+ } else if (key.startsWith(interfaceMacOID)) {
+ addParameter(gc, groupName + networkNb, "MAC", OidEntryType.STRING, key);
+ } else if (key.startsWith(interfaceSpeedOID)) {
+ addParameter(gc, groupName + networkNb, "Speed", OidEntryType.LONG, key);
+ } else if (key.startsWith(interfaceTypeOID)) {
+ addParameter(gc, groupName + networkNb, "Type", OidEntryType.INTEGER, key, null, interfaceTypeCalibration());
+ } else if (key.startsWith(interfaceAdminOID)) {
+ addParameter(gc, groupName + networkNb, "Admin_Status", OidEntryType.INTEGER, key, null, networkStatusCalibration()); // 0: down; 1: up
+ } else if (key.startsWith(interfaceOperOID)) {
+ addParameter(gc, groupName + networkNb, "Operational_Status", OidEntryType.INTEGER, key, null, networkStatusCalibration()); // 0: down; 1: up
+ } else if (key.startsWith(interfaceInOctOID)) {
+ addParameter(gc, groupName + networkNb, "In_Octets", OidEntryType.LONG, key, "bytes");
+ } else if (key.startsWith(interfaceInErrorsOID)) {
+ addParameter(gc, groupName + networkNb, "In_Errors", OidEntryType.LONG, key, "bytes");
+ } else if (key.startsWith(interfaceInDiscardOID)) {
+ addParameter(gc, groupName + networkNb, "In_Discards", OidEntryType.LONG, key, "bytes");
+ } else if (key.startsWith(interfaceInUnknownOID)) {
+ addParameter(gc, groupName + networkNb, "In_Unknown", OidEntryType.LONG, key, "bytes");
+ } else if (key.startsWith(interfaceOutOctOID)) {
+ addParameter(gc, groupName + networkNb, "Out_Octets", OidEntryType.LONG, key, "bytes");
+ } else if (key.startsWith(interfaceOutDiscardsOID)) {
+ addParameter(gc, groupName + networkNb, "Out_Discards", OidEntryType.LONG, key, "bytes");
+ } else if (key.startsWith(interfaceOutErrorsOID)) {
+ addParameter(gc, groupName + networkNb, "Out_Errors", OidEntryType.LONG, key, "bytes");
+ }
+ }
+ }
+ }
+
+ private EnumCalibration interfaceTypeCalibration() {
+ EnumCalibration calibration = new EnumCalibration();
+ calibration.setDefaultValue("Unknown");
+ calibration.setApplicability(null);
+ calibration.setPoints(new LinkedList<>());
+ calibration.getPoints().add(new EnumCalibrationPoint(1, "other"));
+ calibration.getPoints().add(new EnumCalibrationPoint(2, "regular1822"));
+ calibration.getPoints().add(new EnumCalibrationPoint(3, "hdh1822"));
+ calibration.getPoints().add(new EnumCalibrationPoint(4, "ddn-x25"));
+ calibration.getPoints().add(new EnumCalibrationPoint(5, "rfc877-x25"));
+ calibration.getPoints().add(new EnumCalibrationPoint(6, "ethernet-csmacd"));
+ calibration.getPoints().add(new EnumCalibrationPoint(7, "iso88023-csmacd"));
+ calibration.getPoints().add(new EnumCalibrationPoint(8, "iso88024-tokenBus"));
+ calibration.getPoints().add(new EnumCalibrationPoint(9, "iso88025-tokenRing"));
+ calibration.getPoints().add(new EnumCalibrationPoint(10, "iso88026-man"));
+ calibration.getPoints().add(new EnumCalibrationPoint(11, "starLan"));
+ calibration.getPoints().add(new EnumCalibrationPoint(12, "proteon-10Mbit"));
+ calibration.getPoints().add(new EnumCalibrationPoint(13, "proteon-80Mbit"));
+ calibration.getPoints().add(new EnumCalibrationPoint(14, "hyperchannel"));
+ calibration.getPoints().add(new EnumCalibrationPoint(15, "fddi"));
+ calibration.getPoints().add(new EnumCalibrationPoint(16, "lapb"));
+ calibration.getPoints().add(new EnumCalibrationPoint(17, "sdlc"));
+ calibration.getPoints().add(new EnumCalibrationPoint(18, "ds1"));
+ calibration.getPoints().add(new EnumCalibrationPoint(19, "e1"));
+ calibration.getPoints().add(new EnumCalibrationPoint(20, "basicISDN"));
+ calibration.getPoints().add(new EnumCalibrationPoint(21, "primaryISDN"));
+ calibration.getPoints().add(new EnumCalibrationPoint(22, "propPointToPointSerial"));
+ calibration.getPoints().add(new EnumCalibrationPoint(23, "ppp"));
+ calibration.getPoints().add(new EnumCalibrationPoint(24, "softwareLoopback"));
+ calibration.getPoints().add(new EnumCalibrationPoint(25, "eon"));
+ calibration.getPoints().add(new EnumCalibrationPoint(26, "ethernet-3Mbit"));
+ calibration.getPoints().add(new EnumCalibrationPoint(27, "nsip"));
+ calibration.getPoints().add(new EnumCalibrationPoint(28, "slip"));
+ calibration.getPoints().add(new EnumCalibrationPoint(29, "ultra"));
+ calibration.getPoints().add(new EnumCalibrationPoint(30, "ds3"));
+ calibration.getPoints().add(new EnumCalibrationPoint(31, "sip"));
+ calibration.getPoints().add(new EnumCalibrationPoint(32, "frame-relay"));
+ return calibration;
+ }
+
+ private static EnumCalibration networkStatusCalibration() {
+ EnumCalibration calibration = new EnumCalibration();
+ calibration.setDefaultValue("Unknown");
+ calibration.setApplicability(null);
+ calibration.setPoints(new LinkedList<>());
+ calibration.getPoints().add(new EnumCalibrationPoint(0, "Down"));
+ calibration.getPoints().add(new EnumCalibrationPoint(1, "Up"));
+ return calibration;
+ }
+
+ private void processDevices(CommunityTarget target) {
+ String groupName = "CPU";
+ GroupConfiguration gc = new GroupConfiguration();
+ gc.setName(groupName);
+ gc.setDistributePdu(false);
+ gc.setPollingTime(60000); // Once per minute
+ this.snmpDeviceConfiguration.getGroupConfigurationList().add(gc);
+
+ // Processor table
+ TableUtils tUtils = new TableUtils(this.snmp, new DefaultPDUFactory());
+ List events = tUtils.getTable(target, new OID[] { processorTableOID }, null, null);
+ for (TableEvent event : events) {
+ if (event.isError()) {
+ System.err.println("Error event when parsing processor block");
+ continue;
+ }
+ int processorNb = 0;
+ for (VariableBinding vb : event.getColumns()) {
+ OID key = vb.getOid();
+ if (key.startsWith(processorLoadOID)) {
+ addParameter(gc, groupName + processorNb, "Load", OidEntryType.LONG, key);
+ }
+ ++processorNb;
+ }
+ }
+
+ groupName = "Disk";
+ gc = new GroupConfiguration();
+ gc.setName(groupName);
+ gc.setDistributePdu(false);
+ gc.setPollingTime(60 * 60000); // Once every hour, this value never changes
+ this.snmpDeviceConfiguration.getGroupConfigurationList().add(gc);
+
+ // Disk table
+ events = tUtils.getTable(target, new OID[] { diskStorageTableOID }, null, null);
+
+ for (TableEvent event : events) {
+ if (event.isError()) {
+ System.err.println("Error event when parsing disk block");
+ continue;
+ }
+ int diskNb = 0;
+ for (VariableBinding vb : event.getColumns()) {
+ OID key = vb.getOid();
+ if (key.startsWith(diskCapacityOID)) {
+ addParameter(gc, groupName + diskNb, "Capacity", OidEntryType.LONG, key, "KB");
+ }
+ ++diskNb;
+ }
+ }
+ }
+
+ private void processSystem(CommunityTarget target) {
+ String groupName = "System";
+ GroupConfiguration gc = new GroupConfiguration();
+ gc.setName(groupName);
+ gc.setDistributePdu(true);
+ gc.setPollingTime(60000); // Once per minute
+ this.snmpDeviceConfiguration.getGroupConfigurationList().add(gc);
+
+ addParameter(gc, groupName, "Uptime", OidEntryType.LONG, systemUptimeOID, "seconds");
+ addParameter(gc, groupName, "Date", OidEntryType.STRING, systemDateOID, null);
+ addParameter(gc, groupName, "Nb_Users", OidEntryType.LONG, numUsersOID, null);
+ addParameter(gc, groupName, "Description", OidEntryType.STRING, systemDescrOID, null);
+ addParameter(gc, groupName, "Name", OidEntryType.STRING, systemNameOID, null);
+ addWritableParameter(gc, groupName, "Contact", OidEntryType.STRING, contactNameOID, null);
+ addParameter(gc, groupName, "Memory", OidEntryType.LONG, memorySizeOID, "bytes");
+ }
+
+ private ParameterProcessingDefinition addWritableParameter(GroupConfiguration gc, String groupName, String name, OidEntryType oidType, OID oid, String unit) {
+ ParameterProcessingDefinition ppd = addParameter(gc, groupName, name, oidType, oid, unit);
+ ParameterSetterDefinition setter = new ParameterSetterDefinition();
+ setter.setActivity(this.processingDefinition.getActivityDefinitions().get(0)); // only one defined
+ PlainArgumentInvocationDefinition oidArg = new PlainArgumentInvocationDefinition();
+ oidArg.setName("OID");
+ oidArg.setRawValue(true);
+ oidArg.setValue(oid.toString());
+ setter.getArguments().add(oidArg);
+ setter.setSetArgument("Value");
+ ppd.setSetter(setter);
+ return ppd;
+ }
+
+ private CommunityTarget buildTarget(String snmpConnectionUrl, String community) {
+ CommunityTarget target = new CommunityTarget<>();
+ UdpAddress targetAddress = new UdpAddress(snmpConnectionUrl);
+ target.setCommunity(new OctetString(community));
+ target.setAddress(targetAddress);
+ target.setRetries(2);
+ target.setTimeout(5000);
+ target.setVersion(SnmpConstants.version2c);
+ return target;
+ }
+
+ public static void main(String[] args) throws IOException {
+ if(args.length != 5) {
+ System.err.println("Usage: BasicComputerDriverGenerator ");
+ System.err.println("- e.g. 192.168.0.1/161 (UDP protocol used)");
+ System.err.println("- must be provided;");
+ System.err.println("- is the location prefix to be used for processing model parameters (e.g. \"SYSTEM.SERVERS\").");
+ System.err.println("- is the first ID to be used when creating processing model parameters.");
+ System.err.println("- is the name of the device (used as default route for setter activity)");
+ System.exit(1);
+ }
+ String connectionUrl = args[0];
+ String community = args[1];
+ String pathPrefix = args[2];
+ String deviceName = args[4];
+ int firstExternalId = Integer.parseInt(args[3]);
+ BasicComputerDriverGenerator generator = new BasicComputerDriverGenerator();
+ generator.export(connectionUrl, community, firstExternalId, pathPrefix, deviceName);
+ // Files are generated in the current working directory
+ }
+}
diff --git a/eu.dariolucia.reatmetric.driver.snmp.util/src/main/java/eu/dariolucia/reatmetric/driver/snmp/util/SnmpWalker.java b/eu.dariolucia.reatmetric.driver.snmp.util/src/main/java/eu/dariolucia/reatmetric/driver/snmp/util/SnmpWalker.java
new file mode 100644
index 00000000..88a9cdbb
--- /dev/null
+++ b/eu.dariolucia.reatmetric.driver.snmp.util/src/main/java/eu/dariolucia/reatmetric/driver/snmp/util/SnmpWalker.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2024 Dario Lucia (https://www.dariolucia.eu)
+ *
+ * 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.
+ *
+ */
+
+/*
+ * Original work: https://github.com/micmiu/snmp-tutorial/blob/master/snmp4j-1x-demo/src/main/java/com/micmiu/snmp4j/demo1x/SnmpWalk.java
+ * Released under Apache License 2.0.
+ * Author: Michael
+ *
+ */
+package eu.dariolucia.reatmetric.driver.snmp.util;
+
+import org.snmp4j.CommunityTarget;
+import org.snmp4j.PDU;
+import org.snmp4j.Snmp;
+import org.snmp4j.TransportMapping;
+import org.snmp4j.event.ResponseEvent;
+import org.snmp4j.mp.SnmpConstants;
+import org.snmp4j.smi.*;
+import org.snmp4j.transport.DefaultUdpTransportMapping;
+
+import java.io.IOException;
+
+public class SnmpWalker {
+
+ public static void snmpWalk(String ip, String community, String targetOid) {
+ Address address = GenericAddress.parse("udp:" + ip + "/" + 161);
+ CommunityTarget target = new CommunityTarget<>();
+ target.setCommunity(new OctetString(community));
+ target.setAddress(address);
+ target.setVersion(SnmpConstants.version2c);
+ target.setTimeout(5000); // milliseconds
+ target.setRetries(3);
+
+ Snmp snmp = null;
+ try(TransportMapping transport = new DefaultUdpTransportMapping()) {
+ snmp = new Snmp(transport);
+ transport.listen();
+
+ PDU pdu = new PDU();
+ OID targetOID = new OID(targetOid);
+ pdu.add(new VariableBinding(targetOID));
+
+ boolean finished = false;
+ while (!finished) {
+ VariableBinding vb = null;
+ ResponseEvent respEvent = snmp.getNext(pdu, target);
+ PDU response = respEvent.getResponse();
+ if (null == response) {
+ break;
+ } else {
+ vb = response.get(0);
+ }
+ // check finish
+ finished = walkFinished(targetOID, pdu, vb);
+ if (!finished) {
+ System.out.println(vb.getOid() + " (" + vb.getVariable().getSyntaxString() + ") = " + vb.getVariable());
+ pdu.setRequestID(new Integer32(0));
+ pdu.set(0, vb);
+ } else {
+ snmp.close();
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ if (snmp != null) {
+ try {
+ snmp.close();
+ } catch (IOException ex1) {
+ snmp = null;
+ }
+ }
+ }
+ }
+
+ private static boolean walkFinished(OID targetOID, PDU pdu,
+ VariableBinding vb) {
+ boolean finished = false;
+ if (pdu.getErrorStatus() != 0) {
+ System.out.println("responsePDU.getErrorStatus() != 0");
+ System.out.println(pdu.getErrorStatusText());
+ finished = true;
+ } else if (vb.getOid() == null) {
+ System.out.println("vb.getOid() == null");
+ finished = true;
+ } else if (vb.getOid().size() < targetOID.size()) {
+ System.out.println("vb.getOid().size() < targetOID.size()");
+ finished = true;
+ } else if (targetOID.leftMostCompare(targetOID.size(), vb.getOid()) != 0) {
+ System.out.println("targetOID.leftMostCompare() != 0");
+ finished = true;
+ } else if (Null.isExceptionSyntax(vb.getVariable().getSyntax())) {
+ System.out
+ .println("Null.isExceptionSyntax(vb.getVariable().getSyntax())");
+ finished = true;
+ } else if (vb.getOid().compareTo(targetOID) <= 0) {
+ System.out.println("[true] Variable received is not successor of requested one:");
+ System.out.println(vb + " <= " + targetOID);
+ finished = true;
+ }
+ return finished;
+ }
+
+ public static void main(String[] args) {
+ if(args.length != 3) {
+ System.err.println("Usage: SnmpWalker ");
+ System.err.println("- can be a name or IP address. UDP on port 161 is used by default;");
+ System.err.println("- must be provided;");
+ System.err.println("- is the starting OID (e.g. \"1.3.6.1.2.1\").");
+ System.exit(1);
+ }
+ String ip = args[0];
+ String community = args[1];
+ String targetOid = args[2];
+ SnmpWalker.snmpWalk(ip, community, targetOid);
+ }
+}
diff --git a/eu.dariolucia.reatmetric.driver.snmp.util/src/main/java/module-info.java b/eu.dariolucia.reatmetric.driver.snmp.util/src/main/java/module-info.java
new file mode 100644
index 00000000..23aaf7b8
--- /dev/null
+++ b/eu.dariolucia.reatmetric.driver.snmp.util/src/main/java/module-info.java
@@ -0,0 +1,12 @@
+open module eu.dariolucia.reatmetric.driver.snmp.util {
+ requires java.logging;
+ requires java.rmi;
+ requires jakarta.xml.bind;
+
+ requires eu.dariolucia.reatmetric.api;
+ requires eu.dariolucia.reatmetric.core;
+ requires eu.dariolucia.reatmetric.processing;
+ requires eu.dariolucia.reatmetric.driver.snmp;
+
+ requires org.snmp4j;
+}
\ No newline at end of file
diff --git a/eu.dariolucia.reatmetric.driver.snmp/Documentation.adoc b/eu.dariolucia.reatmetric.driver.snmp/Documentation.adoc
new file mode 100644
index 00000000..94e8f458
--- /dev/null
+++ b/eu.dariolucia.reatmetric.driver.snmp/Documentation.adoc
@@ -0,0 +1,155 @@
+==== Overview
+The eu.dariolucia.reatmetric.driver.snmp module provides a driver that allows the access to devices via SNMP protocol.
+
+Being a driver, a _snmp_ module must be registered as such in the system Core's configuration.
+
+==== General Concepts
+A single instance of the _snmp_ driver can monitor and control several SNMP devices, as specified by the configuration
+of the driver. For each device, the driver periodically polls the specified OID parameters. Such parameters are partitioned
+in groups: each group can have a different polling period and a different raw data distribution behaviour.
+
+The driver also supports the setting of SNMP values of type string and integer.
+
+The _snmp_ driver supports version 1 and version 2c. SNMP version 3 is at the moment not supported: the support can be
+added if there is a request for it.
+
+==== Configuration
+Being a driver, the _snmp_ module must be registered as such in the system configuration file. You need to have a
+snmp module registration for each endpoint that requires such driver.
+
+[source,xml]
+----
+
+ Test System
+ $HOME\Reatmetric\reatmetric_test\log.properties
+ $HOME\Reatmetric\reatmetric_test\processing
+
+
+----
+
+The folder specified in the _configuration_ attribute of the _driver_ element must contain a file named _configuration.xml_,
+which defines the configuration properties of the driver.
+
+===== Main Configuration File
+The configuration structure of the eu.dariolucia.reatmetric.driver.snmp module is defined in the package
+eu.dariolucia.reatmetric.driver.snmp.configuration. It is an XML file named _configuration.xml_ using
+namespace definition _http://dariolucia.eu/reatmetric/driver/snmp_.
+
+[source,xml]
+----
+
+
+
+ $HOME\Reatmetric\reatmetric_snmp\snmp\STATION_OPENSUSE15_3_device.xml
+
+
+
+ $HOME\Reatmetric\reatmetric_snmp\snmp\STATION_MANJARO_device.xml
+
+
+
+----
+
+Element **: this element defines a UDP or TCP SNMP connection to a device with the provided characteristics.
+
+The following attributes are defined:
+
+* _name_ (mandatory, string): the name of the device. This string will be used also as route and source of incoming SNMP
+messages and as route for outgoing SNMP SET commands.
+* _connection-string_ (mandatory, string): the connection string in the form _:/port.
+* _community_ (optional, string, default: public): the community name for SNMP version V1 and V2.
+* _version_ (optional, enum: V1, V2, default: V2): the community name for SNMP version V1 and V2.
+* _timeout_ (optional, integer, default: 2000): the response timeout in milliseconds.
+* _retries_ (optional, integer, default: 2): the number of retries before considering the SNMP request as failed.
+* _security-name_ (optional, string): the security name (only SNMP V3 - currently not supported).
+* _security-level_ (optional, string): the security level (only SNMP V3 - currently not supported.
+* _path_ (mandatory, string): the location of the device in the processing model. This information will be attached as prefix
+to the mapping paths specified in the specified device configuration file.
+
+The ** element has the following two sub-elements:
+
+* **: absolute path to the device configuration file.
+* **: the absolute location in the processing model of the activity that can be used to set OID values for
+this device. Each device must have its own setter specified in the processing model.
+
+Each ** element will cause the creation of a specific _connector_ that can be used to enable or disable the SNMP
+connection to the linked device.
+
+===== Device Configuration File
+The configuration structure of the device configuration file is defined in the package
+eu.dariolucia.reatmetric.driver.snmp.configuration. It is an XML file using
+namespace definition _http://dariolucia.eu/reatmetric/driver/snmp/device_.
+
+[source,xml]
+----
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ...
+
+
+ ...
+
+
+----
+
+The structure is very simple and self-explanatory: the file specifies groups, with related name, polling time (in milliseconds)
+and attribute (_distribute-pdu_) to specify whether the response PDU must be distributed and stored as raw data item.
+Upon establishing of the connection, polling PDUs for each group are constructed and sent with the specified period.
+Returned OID values are mapped to the parameters specified the _path_ attribute, prefixed with the _path_ value specified
+for the device inside the _configuration.xml_ file of the SNMP driver. In this way, the same device configuration file can be
+actually re-used for many devices, if they all share the same SNMP configuration.
+
+One point to consider is the mapping between the attribute _type_ and the raw type of the parameter in the processing model.
+The following mapping is defined:
+
+* OID -> ValueTypeEnum.ENUMERATED (the last OID field is used)
+* STRING -> return ValueTypeEnum.CHARACTER_STRING
+* BYTE_ARRAY -> ValueTypeEnum.OCTET_STRING
+* INTEGER -> ValueTypeEnum.ENUMERATED
+* LONG -> ValueTypeEnum.SIGNED_INTEGER
+* DOUBLE -> ValueTypeEnum.REAL
+
+===== Utility for generation of device configuration file and corresponding processing model
+The eu.dariolucia.reatmetric.driver.snmp.util module contains a utility program called BasicComputerDriverGenerator,
+which allows the rapid generation of a SNMP configuration for a computer. It is sufficient to run the program.
+
+----
+BasicComputerDriverGenerator
+
+ e.g. 192.168.0.1/161 (UDP protocol used)
+ must be provided
+ is the location prefix to be used for processing model parameters (e.g. "SYSTEM.SERVERS").
+ is the first ID to be used when creating processing model parameters.
+ is the name of the device (used as default route for setter activity)
+----
+
+The utility program creates two files:
+
+* the device configuration file
+* the processing model file
+
+It is of course important to remember, to update the configuration.xml file of the _snmp_ driver to include the device
+and the location of the device configuration file, and to copy the processing model file inside the folder that ReatMetric
+will inspect when loading the processing model.
+
+As final note: it is important that the utility program has access to the device, because it will make some queries to
+identify e.g. how many CPU parameters will have to create.
\ No newline at end of file
diff --git a/eu.dariolucia.reatmetric.driver.snmp/LICENSE b/eu.dariolucia.reatmetric.driver.snmp/LICENSE
new file mode 100644
index 00000000..261eeb9e
--- /dev/null
+++ b/eu.dariolucia.reatmetric.driver.snmp/LICENSE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ 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.
diff --git a/eu.dariolucia.reatmetric.driver.snmp/NOTICE b/eu.dariolucia.reatmetric.driver.snmp/NOTICE
new file mode 100644
index 00000000..5e79225b
--- /dev/null
+++ b/eu.dariolucia.reatmetric.driver.snmp/NOTICE
@@ -0,0 +1,23 @@
+CREDITS
+------------------------------------------------------------------------------
+eu.dariolucia.reatmetric.driver.snmp uses the SNMP4J library.
+(https://www.snmp4j.org/)
+
+SNMP4J is licensed under the Apache License 2.0
+(https://www.apache.org/licenses/LICENSE-2.0.html)
+------------------------------------------------------------------------------
+eu.dariolucia.reatmetric.driver.snmp
+
+Copyright (c) 2024 Dario Lucia (https://www.dariolucia.eu)
+
+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.
diff --git a/eu.dariolucia.reatmetric.driver.snmp/pom.xml b/eu.dariolucia.reatmetric.driver.snmp/pom.xml
new file mode 100644
index 00000000..901659b4
--- /dev/null
+++ b/eu.dariolucia.reatmetric.driver.snmp/pom.xml
@@ -0,0 +1,55 @@
+
+
+
+
+
+ eu.dariolucia.reatmetric
+ eu.dariolucia.reatmetric
+ 1.0.2
+
+
+ 4.0.0
+ eu.dariolucia.reatmetric.driver.snmp
+ REATMETRIC DRIVER - SNMP driver
+ REATMETRIC driver module for SNMP-based communication protocols
+
+
+
+ eu.dariolucia.reatmetric
+ eu.dariolucia.reatmetric.api
+ ${project.parent.version}
+
+
+ eu.dariolucia.reatmetric
+ eu.dariolucia.reatmetric.core
+ ${project.parent.version}
+
+
+ org.glassfish.jaxb
+ jaxb-runtime
+ ${jaxb.version}
+
+
+ org.snmp4j
+ snmp4j
+ ${snmp4j.version}
+
+
+
+
\ No newline at end of file
diff --git a/eu.dariolucia.reatmetric.driver.snmp/src/main/java/eu/dariolucia/reatmetric/driver/snmp/SnmpActivityHandler.java b/eu.dariolucia.reatmetric.driver.snmp/src/main/java/eu/dariolucia/reatmetric/driver/snmp/SnmpActivityHandler.java
new file mode 100644
index 00000000..ea3dd1c3
--- /dev/null
+++ b/eu.dariolucia.reatmetric.driver.snmp/src/main/java/eu/dariolucia/reatmetric/driver/snmp/SnmpActivityHandler.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2023 Dario Lucia (https://www.dariolucia.eu)
+ *
+ * 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 eu.dariolucia.reatmetric.driver.snmp;
+
+import eu.dariolucia.reatmetric.api.common.IUniqueId;
+import eu.dariolucia.reatmetric.api.processing.IActivityHandler;
+import eu.dariolucia.reatmetric.api.processing.IProcessingModel;
+import eu.dariolucia.reatmetric.api.processing.exceptions.ActivityHandlingException;
+import eu.dariolucia.reatmetric.api.transport.TransportConnectionStatus;
+import eu.dariolucia.reatmetric.driver.snmp.configuration.SnmpConfiguration;
+import eu.dariolucia.reatmetric.driver.snmp.configuration.SnmpDevice;
+
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+public class SnmpActivityHandler implements IActivityHandler {
+
+ private final List supportedRoutes;
+ private final List supportedActivityTypes;
+ private final SnmpConfiguration configuration;
+ private final Map connectors;
+
+ public SnmpActivityHandler(SnmpConfiguration configuration, Map connectors) {
+ this.configuration = configuration;
+ this.connectors = connectors;
+ // Collect the list of routes
+ this.supportedRoutes = configuration.getSnmpDeviceList().stream().map(SnmpDevice::getName).collect(Collectors.toList());
+ // Activity type
+ this.supportedActivityTypes = new LinkedList<>(Collections.singletonList(SnmpDriver.SNMP_MESSAGE_TYPE));
+ }
+
+ @Override
+ public void registerModel(IProcessingModel model) {
+ // Not needed
+ }
+
+ @Override
+ public void deregisterModel(IProcessingModel model) {
+ // Not needed
+ }
+
+ @Override
+ public List getSupportedRoutes() {
+ return Collections.unmodifiableList(this.supportedRoutes);
+ }
+
+ @Override
+ public List getSupportedActivityTypes() {
+ return Collections.unmodifiableList(this.supportedActivityTypes);
+ }
+
+ @Override
+ public void executeActivity(ActivityInvocation activityInvocation) throws ActivityHandlingException {
+ // Get the right connector and simply forward this information to the connector
+ String route = activityInvocation.getRoute();
+ SnmpTransportConnector connector = this.connectors.get(route);
+ if(connector == null) {
+ throw new ActivityHandlingException("SNMP connector for route " + route + " on driver " + configuration.getName() + " not present");
+ } else {
+ connector.executeActivity(activityInvocation);
+ }
+ }
+
+ @Override
+ public boolean getRouteAvailability(String route) throws ActivityHandlingException {
+ SnmpTransportConnector connector = this.connectors.get(route);
+ if(connector == null) {
+ return false;
+ } else {
+ // The route is available if the connector is started
+ return connector.getConnectionStatus() == TransportConnectionStatus.OPEN;
+ // You can try to send
+ }
+ }
+
+ @Override
+ public void abortActivity(int activityId, IUniqueId activityOccurrenceId) throws ActivityHandlingException {
+ // Not supported for this driver
+ throw new ActivityHandlingException("Operation not supported");
+ }
+}
diff --git a/eu.dariolucia.reatmetric.driver.snmp/src/main/java/eu/dariolucia/reatmetric/driver/snmp/SnmpDriver.java b/eu.dariolucia.reatmetric.driver.snmp/src/main/java/eu/dariolucia/reatmetric/driver/snmp/SnmpDriver.java
new file mode 100644
index 00000000..d031c932
--- /dev/null
+++ b/eu.dariolucia.reatmetric.driver.snmp/src/main/java/eu/dariolucia/reatmetric/driver/snmp/SnmpDriver.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2024 Dario Lucia (https://www.dariolucia.eu)
+ *
+ * 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 eu.dariolucia.reatmetric.driver.snmp;
+
+import eu.dariolucia.reatmetric.api.common.DebugInformation;
+import eu.dariolucia.reatmetric.api.common.SystemStatus;
+import eu.dariolucia.reatmetric.api.common.exceptions.ReatmetricException;
+import eu.dariolucia.reatmetric.api.processing.IActivityHandler;
+import eu.dariolucia.reatmetric.api.rawdata.RawData;
+import eu.dariolucia.reatmetric.api.transport.ITransportConnector;
+import eu.dariolucia.reatmetric.core.api.AbstractDriver;
+import eu.dariolucia.reatmetric.core.api.IRawDataRenderer;
+import eu.dariolucia.reatmetric.core.api.IServiceCoreContext;
+import eu.dariolucia.reatmetric.core.api.exceptions.DriverException;
+import eu.dariolucia.reatmetric.core.configuration.ServiceCoreConfiguration;
+import eu.dariolucia.reatmetric.driver.snmp.configuration.SnmpConfiguration;
+import eu.dariolucia.reatmetric.driver.snmp.configuration.SnmpDevice;
+import org.snmp4j.PDU;
+import org.snmp4j.asn1.BERInputStream;
+import org.snmp4j.smi.VariableBinding;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.*;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ *
+ */
+public class SnmpDriver extends AbstractDriver implements IRawDataRenderer {
+
+ private static final Logger LOG = Logger.getLogger(SnmpDriver.class.getName());
+
+ public static final String SNMP_MESSAGE_TYPE = "SNMP";
+ public static final String CONFIGURATION_FILE_NAME = "configuration.xml";
+
+ private SnmpConfiguration configuration;
+ private final Map transportConnectorMap = new LinkedHashMap<>();
+
+ private SnmpActivityHandler activityHandler;
+
+ @Override
+ public List currentDebugInfo() {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public List getTransportConnectors() {
+ return new LinkedList<>(transportConnectorMap.values());
+ }
+
+ @Override
+ public List getRawDataRenderers() {
+ return Collections.singletonList(this);
+ }
+
+ @Override
+ public List getActivityHandlers() {
+ return Collections.singletonList(this.activityHandler);
+ }
+
+ @Override
+ protected SystemStatus startProcessing() {
+ // Create the transport connectors
+ createTransportConnectors();
+ // Create the activity handler
+ createActivityHandler();
+ // Done
+ return SystemStatus.NOMINAL;
+ }
+
+ private void createActivityHandler() {
+ this.activityHandler = new SnmpActivityHandler(configuration, transportConnectorMap);
+ }
+
+ private void createTransportConnectors() {
+ for(SnmpDevice device : this.configuration.getSnmpDeviceList()) {
+ SnmpTransportConnector connector = new SnmpTransportConnector(getName(),
+ device,
+ getContext().getRawDataBroker(),
+ getContext().getProcessingModel());
+ connector.prepare();
+ transportConnectorMap.put(device.getName(), connector);
+ }
+ }
+
+ @Override
+ protected SystemStatus processConfiguration(String driverConfiguration, ServiceCoreConfiguration coreConfiguration, IServiceCoreContext context) throws DriverException {
+ if(LOG.isLoggable(Level.INFO)) {
+ LOG.info(String.format("Loading driver configuration at %s", driverConfiguration));
+ }
+ try {
+ this.configuration = SnmpConfiguration.load(new FileInputStream(driverConfiguration + File.separator + CONFIGURATION_FILE_NAME));
+ return SystemStatus.NOMINAL;
+ } catch (IOException e) {
+ throw new DriverException(e);
+ }
+ }
+
+ @Override
+ public String getHandler() {
+ return getName();
+ }
+
+ @Override
+ public List getSupportedTypes() {
+ return Collections.singletonList(SNMP_MESSAGE_TYPE);
+ }
+
+ @Override
+ public LinkedHashMap render(RawData rawData) throws ReatmetricException {
+ if (!rawData.getHandler().equals(getHandler())) {
+ throw new ReatmetricException("Raw data with handler " + rawData.getHandler() + " cannot be processed by driver " + configuration.getName() + ", expecting handler " + getHandler());
+ }
+ if (!rawData.getType().equals(SNMP_MESSAGE_TYPE)) {
+ throw new ReatmetricException("Raw data with type " + rawData.getType() + " cannot be processed by driver " + configuration.getName() + ", expecting types " + getSupportedTypes());
+ }
+ LinkedHashMap toReturn = new LinkedHashMap<>();
+ PDU message = (PDU) rawData.getData();
+ if(message == null) {
+ byte[] contents = rawData.getContents();
+ message = new PDU();
+ try {
+ message.decodeBER(new BERInputStream(ByteBuffer.wrap(contents)));
+ } catch (IOException e) {
+ LOG.log(Level.WARNING, "Cannot decode SNMP PDU message from raw data: " + e.getMessage(), e);
+ return toReturn;
+ }
+ }
+ // Now message has all the info
+ toReturn.put("Message Type", String.valueOf(message.getType()));
+ toReturn.put("Error Status", message.getErrorStatusText());
+ toReturn.put("Request ID", String.valueOf(message.getRequestID().getValue()));
+ int nums = 0;
+ for(VariableBinding vb : message.getVariableBindings()) {
+ toReturn.put("OID #" + nums, vb.getOid().toString());
+ toReturn.put("Value #" + nums, vb.getVariable().toString());
+ toReturn.put("Type #" + nums, vb.getVariable().getSyntaxString());
+ ++nums;
+ }
+ return toReturn;
+ }
+}
diff --git a/eu.dariolucia.reatmetric.driver.snmp/src/main/java/eu/dariolucia/reatmetric/driver/snmp/SnmpTransportConnector.java b/eu.dariolucia.reatmetric.driver.snmp/src/main/java/eu/dariolucia/reatmetric/driver/snmp/SnmpTransportConnector.java
new file mode 100644
index 00000000..2df6e0a1
--- /dev/null
+++ b/eu.dariolucia.reatmetric.driver.snmp/src/main/java/eu/dariolucia/reatmetric/driver/snmp/SnmpTransportConnector.java
@@ -0,0 +1,350 @@
+/*
+ * Copyright (c) 2024 Dario Lucia (https://www.dariolucia.eu)
+ *
+ * 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 eu.dariolucia.reatmetric.driver.snmp;
+
+import eu.dariolucia.reatmetric.api.activity.ActivityOccurrenceReport;
+import eu.dariolucia.reatmetric.api.activity.ActivityOccurrenceState;
+import eu.dariolucia.reatmetric.api.activity.ActivityReportState;
+import eu.dariolucia.reatmetric.api.common.IUniqueId;
+import eu.dariolucia.reatmetric.api.common.Pair;
+import eu.dariolucia.reatmetric.api.common.exceptions.ReatmetricException;
+import eu.dariolucia.reatmetric.api.model.AlarmState;
+import eu.dariolucia.reatmetric.api.processing.IActivityHandler;
+import eu.dariolucia.reatmetric.api.processing.IProcessingModel;
+import eu.dariolucia.reatmetric.api.processing.exceptions.ActivityHandlingException;
+import eu.dariolucia.reatmetric.api.processing.input.ActivityProgress;
+import eu.dariolucia.reatmetric.api.processing.input.ParameterSample;
+import eu.dariolucia.reatmetric.api.rawdata.Quality;
+import eu.dariolucia.reatmetric.api.rawdata.RawData;
+import eu.dariolucia.reatmetric.api.transport.AbstractTransportConnector;
+import eu.dariolucia.reatmetric.api.transport.TransportConnectionStatus;
+import eu.dariolucia.reatmetric.api.transport.exceptions.TransportException;
+import eu.dariolucia.reatmetric.core.api.IRawDataBroker;
+import eu.dariolucia.reatmetric.driver.snmp.configuration.GroupConfiguration;
+import eu.dariolucia.reatmetric.driver.snmp.configuration.SnmpDevice;
+import org.snmp4j.CommunityTarget;
+import org.snmp4j.PDU;
+import org.snmp4j.Snmp;
+import org.snmp4j.TransportMapping;
+import org.snmp4j.event.ResponseEvent;
+import org.snmp4j.smi.*;
+import org.snmp4j.transport.DefaultUdpTransportMapping;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectOutputStream;
+import java.rmi.RemoteException;
+import java.time.Instant;
+import java.util.*;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+public class SnmpTransportConnector extends AbstractTransportConnector {
+
+ private static final Logger LOG = Logger.getLogger(SnmpTransportConnector.class.getName());
+ public static final String EXECUTION_REPORT_NAME = "Execution";
+
+ private final String driverName;
+ private final SnmpDevice device;
+ private final IRawDataBroker rawDataBroker;
+ private final IProcessingModel processingModel;
+ private final Timer deviceTimer;
+ private final CommunityTarget target;
+ private volatile Snmp connection;
+
+ private final List pollingTasks = new LinkedList<>();
+
+ protected SnmpTransportConnector(String driverName, SnmpDevice device, IRawDataBroker rawDataBroker, IProcessingModel processingModel) {
+ super(device.getName(), "");
+ this.driverName = driverName;
+ this.device = device;
+ this.rawDataBroker = rawDataBroker;
+ this.processingModel = processingModel;
+ this.deviceTimer = new Timer("SNMP Device " + getName() + " Timer Service", true);
+ // Initialise
+ this.device.getDeviceConfiguration().initialise(device.getPath(), this.processingModel);
+ // Build the target
+ this.target = new CommunityTarget<>();
+ Address targetAddress = GenericAddress.parse(device.getConnectionString());
+ this.target.setCommunity(new OctetString(device.getCommunity()));
+ this.target.setAddress(targetAddress);
+ this.target.setRetries(device.getRetries());
+ this.target.setTimeout(device.getTimeout());
+ this.target.setVersion(device.getVersion().toValue());
+ }
+
+ @Override
+ protected Pair computeBitrate() {
+ return null;
+ }
+
+ @Override
+ protected synchronized void doConnect() {
+ if(this.connection != null) {
+ return;
+ }
+ updateAlarmState(AlarmState.NOT_APPLICABLE);
+ updateConnectionStatus(TransportConnectionStatus.CONNECTING);
+ try {
+ TransportMapping transport = new DefaultUdpTransportMapping();
+ this.connection = new Snmp(transport);
+ // Do not forget this line!
+ transport.listen();
+ // Check
+ updateConnectionStatus(TransportConnectionStatus.OPEN);
+ // Now activate the periodic pollings
+ for(GroupConfiguration gc : device.getDeviceConfiguration().getGroupConfigurationList()) {
+ TimerTask task = buildTimerTask(gc);
+ // Remember timer tasks, so that disconnect can stop these tasks
+ this.pollingTasks.add(task);
+ this.deviceTimer.schedule(task, 0, gc.getPollingTime());
+ }
+ } catch (IOException e) {
+ updateConnectionStatus(TransportConnectionStatus.ERROR);
+ updateAlarmState(AlarmState.ERROR);
+ if(this.connection != null) {
+ try {
+ this.connection.close();
+ } catch (IOException ex) {
+ // Ignore
+ }
+ }
+ this.connection = null;
+ }
+ }
+
+ private TimerTask buildTimerTask(GroupConfiguration group) {
+ return new TimerTask() {
+ @Override
+ public void run() {
+ Snmp theConnection = null;
+ synchronized (SnmpTransportConnector.this) {
+ theConnection = connection;
+ if (theConnection == null) {
+ // This is weird, do nothing
+ LOG.log(Level.WARNING, "SNMP Polling Task for group " + group.getName() + " started but no connection is available");
+ return;
+ }
+ }
+ PDU request = group.preparePollRequest();
+ try {
+ ResponseEvent> responseEvent = sendRequest(theConnection, request);
+ if ((responseEvent != null) && (responseEvent.getResponse() != null)) {
+ Instant generationTime = Instant.now();
+ distributeRawData(responseEvent, generationTime, group);
+ List parameterSamples = group.mapResponse(device, responseEvent, generationTime);
+ injectSamples(parameterSamples);
+ updateAlarmState(AlarmState.NOMINAL);
+ } else {
+ if(LOG.isLoggable(Level.WARNING)) {
+ LOG.log(Level.WARNING, "Response from endpoint " + device.getConnectionString() + " not received/null for group " + group.getName(), new Object[] { device.getName() });
+ }
+ updateAlarmState(AlarmState.ALARM);
+ }
+ } catch (IOException e) {
+ LOG.log(Level.WARNING, "Request to endpoint " + device.getConnectionString() + " returned an exception for group " + group.getName() + ": " + e.getMessage(), e);
+ updateAlarmState(AlarmState.ALARM);
+ } catch (Exception e) {
+ LOG.log(Level.WARNING, "Request to endpoint " + device.getConnectionString() + " returned an unknown exception for group " + group.getName() + ": " + e.getMessage(), e);
+ updateAlarmState(AlarmState.ALARM);
+ }
+ }
+ };
+ }
+
+ private void distributeRawData(ResponseEvent> responseEvent, Instant generationTime, GroupConfiguration group) {
+ if(!group.isDistributePdu()) {
+ return;
+ }
+ try {
+ PDU response = responseEvent.getResponse();
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ response.encodeBER(bos);
+ bos.close();
+ byte[] serialize = bos.toByteArray();
+ RawData rd = new RawData(rawDataBroker.nextRawDataId(), generationTime, group.getName(),
+ SnmpDriver.SNMP_MESSAGE_TYPE, device.getName(), device.getName(), Quality.GOOD, null, serialize,
+ generationTime, driverName, null);
+ rd.setData(response);
+ rawDataBroker.distribute(Collections.singletonList(rd));
+ } catch (ReatmetricException e) {
+ LOG.log(Level.SEVERE, "Error while distributing SNMP PDU from route " + device.getName(), e);
+ } catch (IOException e) {
+ LOG.log(Level.SEVERE, "Error while encoding SNMP PDU for distribution from route " + device.getName(), e);
+ }
+ }
+
+ private void injectSamples(List parameterSamples) {
+ this.processingModel.injectParameters(parameterSamples);
+ }
+
+ private ResponseEvent> sendRequest(Snmp theConnection, PDU request) throws IOException {
+ synchronized (theConnection) {
+ return theConnection.send(request, target);
+ }
+ }
+
+ @Override
+ protected synchronized void doDisconnect() {
+ if(this.connection == null) {
+ return;
+ }
+ updateAlarmState(AlarmState.NOT_APPLICABLE);
+ updateConnectionStatus(TransportConnectionStatus.DISCONNECTING);
+ this.pollingTasks.forEach(TimerTask::cancel);
+ this.pollingTasks.clear();
+ try {
+ this.connection.close();
+ } catch (IOException ex) {
+ // Ignore
+ }
+ this.connection = null;
+ updateConnectionStatus(TransportConnectionStatus.IDLE);
+ updateAlarmState(AlarmState.NOMINAL);
+ }
+
+ @Override
+ protected synchronized void doDispose() {
+ this.deviceTimer.purge();
+ this.deviceTimer.cancel();
+ try {
+ if(this.connection != null) {
+ this.connection.close();
+ }
+ } catch (IOException ex) {
+ // Ignore
+ }
+ this.connection = null;
+ }
+
+ @Override
+ public void abort() throws TransportException, RemoteException {
+ disconnect();
+ }
+
+ public synchronized void executeActivity(IActivityHandler.ActivityInvocation activityInvocation) throws ActivityHandlingException {
+ if(device.getSetCommandConfiguration() == null) {
+ throw new ActivityHandlingException("No device set-command configuration provided, connector " + getName() + " cannot forward");
+ }
+ if(connection == null || getConnectionStatus() != TransportConnectionStatus.OPEN) {
+ throw new ActivityHandlingException("Connector " + getName() + " not started");
+ }
+ if(!activityInvocation.getPath().asString().equals(device.getSetCommandConfiguration().getPath())) {
+ throw new ActivityHandlingException("Activity occurrence of path " + activityInvocation.getPath() + " provided to connector " + getName() + ", " +
+ "but the device configuration set command is specified as " + device.getSetCommandConfiguration().getPath() + ": activity occurrence cannot be " +
+ "processed by this connector");
+ }
+ // OK, forward in separate task, use timer, one-off
+ this.deviceTimer.schedule(new TimerTask() {
+ @Override
+ public void run() {
+ dispatchActivity(activityInvocation);
+ }
+ }, 0);
+ }
+
+ private void dispatchActivity(IActivityHandler.ActivityInvocation activityInvocation) {
+ Instant time = Instant.now();
+ // Notify attempt to dispatch
+ reportActivityState(activityInvocation.getActivityId(), activityInvocation.getActivityOccurrenceId(), time,
+ ActivityOccurrenceState.RELEASE, ActivityOccurrenceReport.RELEASE_REPORT_NAME, ActivityReportState.PENDING,
+ ActivityOccurrenceState.TRANSMISSION);
+ // Get the connection
+ Snmp theConnection = null;
+ synchronized (SnmpTransportConnector.this) {
+ theConnection = connection;
+ if (theConnection == null) {
+ // No connection, release failed
+ reportActivityState(activityInvocation.getActivityId(), activityInvocation.getActivityOccurrenceId(), time,
+ ActivityOccurrenceState.RELEASE, ActivityOccurrenceReport.RELEASE_REPORT_NAME, ActivityReportState.FATAL,
+ ActivityOccurrenceState.RELEASE);
+ return;
+ }
+ }
+
+ PDU request = encodeSetRequest(activityInvocation);
+ if(request == null) {
+ LOG.log(Level.SEVERE, "Response from endpoint " + device.getConnectionString() + " not received/null for activity " + activityInvocation.getPath(), new Object[] { device.getName() });
+ // Cannot encode request
+ reportActivityState(activityInvocation.getActivityId(), activityInvocation.getActivityOccurrenceId(), time,
+ ActivityOccurrenceState.RELEASE, ActivityOccurrenceReport.RELEASE_REPORT_NAME, ActivityReportState.FATAL,
+ ActivityOccurrenceState.RELEASE);
+ return;
+ }
+ try {
+ reportActivityState(activityInvocation.getActivityId(), activityInvocation.getActivityOccurrenceId(), time,
+ ActivityOccurrenceState.RELEASE, ActivityOccurrenceReport.RELEASE_REPORT_NAME, ActivityReportState.OK,
+ ActivityOccurrenceState.EXECUTION);
+ reportActivityState(activityInvocation.getActivityId(), activityInvocation.getActivityOccurrenceId(), time,
+ ActivityOccurrenceState.EXECUTION, EXECUTION_REPORT_NAME, ActivityReportState.PENDING,
+ ActivityOccurrenceState.EXECUTION);
+ ResponseEvent> responseEvent = sendRequest(theConnection, request);
+ if ((responseEvent != null) && (responseEvent.getResponse() != null)) {
+ reportActivityState(activityInvocation.getActivityId(), activityInvocation.getActivityOccurrenceId(), time,
+ ActivityOccurrenceState.EXECUTION, EXECUTION_REPORT_NAME, ActivityReportState.OK,
+ ActivityOccurrenceState.VERIFICATION);
+ } else {
+ reportActivityState(activityInvocation.getActivityId(), activityInvocation.getActivityOccurrenceId(), time,
+ ActivityOccurrenceState.EXECUTION, EXECUTION_REPORT_NAME, ActivityReportState.FATAL,
+ ActivityOccurrenceState.EXECUTION);
+ if(LOG.isLoggable(Level.WARNING)) {
+ LOG.log(Level.SEVERE, "Response from endpoint " + device.getConnectionString() + " not received/null for activity " + activityInvocation.getPath(), new Object[] { device.getName() });
+ }
+ }
+ } catch (IOException e) {
+ reportActivityState(activityInvocation.getActivityId(), activityInvocation.getActivityOccurrenceId(), time,
+ ActivityOccurrenceState.EXECUTION, EXECUTION_REPORT_NAME, ActivityReportState.FATAL,
+ ActivityOccurrenceState.EXECUTION);
+ LOG.log(Level.SEVERE, "Request to endpoint " + device.getConnectionString() + " returned an exception for activity " + activityInvocation.getPath() + ": " + e.getMessage(), e);
+ } catch (Exception e) {
+ reportActivityState(activityInvocation.getActivityId(), activityInvocation.getActivityOccurrenceId(), time,
+ ActivityOccurrenceState.EXECUTION, EXECUTION_REPORT_NAME, ActivityReportState.FATAL,
+ ActivityOccurrenceState.EXECUTION);
+ LOG.log(Level.SEVERE, "Request to endpoint " + device.getConnectionString() + " returned an unknown exception for activity " + activityInvocation.getPath() + ": " + e.getMessage(), e);
+ }
+ }
+
+ private PDU encodeSetRequest(IActivityHandler.ActivityInvocation activityInvocation) {
+ try {
+ PDU pdu = new PDU();
+ String oid = activityInvocation.getArguments().get("OID").toString();
+ OID theOid = new OID(oid);
+ Object value = activityInvocation.getArguments().get("Value");
+ Variable theVar;
+ if(value == null) {
+ theVar = new Null();
+ } else if(value instanceof String) {
+ theVar = new OctetString((String) value);
+ } else if(value instanceof Number) {
+ theVar = new Integer32(((Number) value).intValue());
+ } else {
+ throw new IllegalArgumentException("value type " + value.getClass().getSimpleName() + " not supported");
+ }
+ pdu.setVariableBindings(Collections.singletonList(new VariableBinding(theOid, theVar)));
+ pdu.setType(PDU.SET);
+ return pdu;
+ } catch (Exception e) {
+ LOG.log(Level.SEVERE, "Cannot encode SNMP set request: " + e.getMessage(), e);
+ return null;
+ }
+ }
+
+ public void reportActivityState(int activityId, IUniqueId activityOccurrenceId, Instant time, ActivityOccurrenceState state, String releaseReportName, ActivityReportState status, ActivityOccurrenceState nextState) {
+ processingModel.reportActivityProgress(ActivityProgress.of(activityId, activityOccurrenceId, releaseReportName, time, state, null, status, nextState, null));
+ }
+}
diff --git a/eu.dariolucia.reatmetric.driver.snmp/src/main/java/eu/dariolucia/reatmetric/driver/snmp/configuration/GroupConfiguration.java b/eu.dariolucia.reatmetric.driver.snmp/src/main/java/eu/dariolucia/reatmetric/driver/snmp/configuration/GroupConfiguration.java
new file mode 100644
index 00000000..bdf22cf7
--- /dev/null
+++ b/eu.dariolucia.reatmetric.driver.snmp/src/main/java/eu/dariolucia/reatmetric/driver/snmp/configuration/GroupConfiguration.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2024 Dario Lucia (https://www.dariolucia.eu)
+ *
+ * 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 eu.dariolucia.reatmetric.driver.snmp.configuration;
+
+import eu.dariolucia.reatmetric.api.common.exceptions.ReatmetricException;
+import eu.dariolucia.reatmetric.api.model.SystemEntityPath;
+import eu.dariolucia.reatmetric.api.processing.IProcessingModel;
+import eu.dariolucia.reatmetric.api.processing.input.ParameterSample;
+import jakarta.xml.bind.annotation.*;
+import org.snmp4j.PDU;
+import org.snmp4j.event.ResponseEvent;
+import org.snmp4j.smi.OID;
+import org.snmp4j.smi.VariableBinding;
+
+import java.time.Instant;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+@XmlAccessorType(XmlAccessType.FIELD)
+public class GroupConfiguration {
+
+ private static final Logger LOG = Logger.getLogger(GroupConfiguration.class.getName());
+
+ @XmlAttribute(name = "name", required = true)
+ private String name;
+
+ @XmlAttribute(name = "polling-time")
+ private int pollingTime = 2000;
+
+ @XmlAttribute(name = "distribute-pdu")
+ private boolean distributePdu = false;
+
+ @XmlElement(name = "entry")
+ private List oidEntryList = new LinkedList<>();
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public int getPollingTime() {
+ return pollingTime;
+ }
+
+ public void setPollingTime(int pollingTime) {
+ this.pollingTime = pollingTime;
+ }
+
+ public List getOidEntryList() {
+ return oidEntryList;
+ }
+
+ public void setOidEntryList(List oidEntryList) {
+ this.oidEntryList = oidEntryList;
+ }
+
+ public boolean isDistributePdu() {
+ return distributePdu;
+ }
+
+ public void setDistributePdu(boolean distributePdu) {
+ this.distributePdu = distributePdu;
+ }
+
+ @XmlTransient
+ private final Map oid2parameterMap = new HashMap<>();
+
+ public void initialise(String prefix, IProcessingModel processingModel) {
+ // Map all OIDs to parameter IDs
+ for(OidEntry e : getOidEntryList()) {
+ // Build path
+ SystemEntityPath path = SystemEntityPath.fromString(prefix + "." + e.getPath());
+ try {
+ int id = processingModel.getExternalIdOf(path);
+ e.setExternalId(id);
+ oid2parameterMap.put(e.toOid(), e);
+ } catch (ReatmetricException ex) {
+ LOG.log(Level.SEVERE, "Cannot resolve parameter path " + path + " linked to OID " + e.getOid() + " to external ID: " + ex.getMessage(), e);
+ }
+ }
+ }
+
+ public PDU preparePollRequest() {
+ PDU pdu = new PDU();
+ for(OidEntry oid : oidEntryList) {
+ pdu.add(new VariableBinding(oid.toOid()));
+ }
+ pdu.setType(PDU.GET);
+ return pdu;
+ }
+
+ public List mapResponse(SnmpDevice device, ResponseEvent> responseEvent, Instant generationTime) {
+ List toReturn = new LinkedList<>();
+ String route = device.getName();
+ for(VariableBinding vb : responseEvent.getResponse().getAll()) {
+ OID theOid = vb.getOid();
+ OidEntry theEntry = oid2parameterMap.get(theOid);
+ if(theEntry != null) {
+ Object value = theEntry.extractValue(vb.getVariable());
+ if(value != null) {
+ ParameterSample sample = ParameterSample.of(theEntry.getExternalId(), generationTime, generationTime, null, value, route, null);
+ toReturn.add(sample);
+ } else {
+ if(LOG.isLoggable(Level.WARNING)) {
+ LOG.log(Level.WARNING, String.format("OID %s value is null, actual value was %s", theOid, vb.getVariable().toString()));
+ }
+ }
+ } else {
+ if(LOG.isLoggable(Level.WARNING)) {
+ LOG.log(Level.WARNING, String.format("OID %s not known, ignoring...", theOid));
+ }
+ }
+ }
+ return toReturn;
+ }
+}
diff --git a/eu.dariolucia.reatmetric.driver.snmp/src/main/java/eu/dariolucia/reatmetric/driver/snmp/configuration/OidEntry.java b/eu.dariolucia.reatmetric.driver.snmp/src/main/java/eu/dariolucia/reatmetric/driver/snmp/configuration/OidEntry.java
new file mode 100644
index 00000000..b93c5adb
--- /dev/null
+++ b/eu.dariolucia.reatmetric.driver.snmp/src/main/java/eu/dariolucia/reatmetric/driver/snmp/configuration/OidEntry.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2024 Dario Lucia (https://www.dariolucia.eu)
+ *
+ * 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 eu.dariolucia.reatmetric.driver.snmp.configuration;
+
+import eu.dariolucia.reatmetric.api.value.ValueTypeEnum;
+import jakarta.xml.bind.annotation.XmlAccessType;
+import jakarta.xml.bind.annotation.XmlAccessorType;
+import jakarta.xml.bind.annotation.XmlAttribute;
+import jakarta.xml.bind.annotation.XmlTransient;
+import org.snmp4j.smi.OID;
+import org.snmp4j.smi.OctetString;
+import org.snmp4j.smi.Variable;
+
+import java.util.logging.Level;
+
+@XmlAccessorType(XmlAccessType.FIELD)
+public class OidEntry {
+
+ @XmlAttribute(name = "oid", required = true)
+ private String oid;
+
+ @XmlAttribute(name = "path", required = true)
+ private String path;
+
+ @XmlAttribute(name = "type", required = true)
+ private OidEntryType type;
+
+ public OidEntry() {
+ // Nothing
+ }
+
+ public OidEntry(String oid, String path, OidEntryType type) {
+ this.oid = oid;
+ this.path = path;
+ this.type = type;
+ }
+
+ public String getOid() {
+ return oid;
+ }
+
+ public void setOid(String oid) {
+ this.oid = oid;
+ }
+
+ public OID toOid() {
+ return new OID(oid);
+ }
+
+ public String getPath() {
+ return path;
+ }
+
+ public void setPath(String path) {
+ this.path = path;
+ }
+
+ public OidEntryType getType() {
+ return type;
+ }
+
+ public void setType(OidEntryType type) {
+ this.type = type;
+ }
+
+ @Override
+ public String toString() {
+ return "{'" + oid + "' -> " + path + " (" + type + ')';
+ }
+
+ @XmlTransient
+ private int externalId;
+
+ public void setExternalId(int id) {
+ this.externalId = id;
+ }
+
+ public int getExternalId() {
+ return externalId;
+ }
+
+ public Object extractValue(Variable variable) {
+ switch (type) {
+ case INTEGER: return extractInt(variable);
+ case LONG: return extractLong(variable);
+ case BYTE_ARRAY: return extractByteArray(variable);
+ case STRING: return extractString(variable);
+ case DOUBLE: return extractReal(variable);
+ case OID: return extractOidLastValue(variable);
+ default: return null;
+ }
+ }
+
+ private Object extractOidLastValue(Variable variable) {
+ String typeString = variable.toString();
+ return Integer.parseInt(typeString.substring(typeString.lastIndexOf('.') + 1));
+ }
+
+ private Object extractReal(Variable variable) {
+ if (variable instanceof OctetString) {
+ String itemValue = variable.toString();
+ try {
+ return Double.parseDouble(itemValue);
+ } catch (Exception e) {
+ return null;
+ }
+ }
+ return null;
+ }
+
+ private Object extractByteArray(Variable variable) {
+ if (variable instanceof OctetString) {
+ return ((OctetString) variable).toByteArray();
+ }
+ return null;
+ }
+
+ private Object extractString(Variable variable) {
+ if (variable instanceof OctetString) {
+ return variable.toString();
+ }
+ return null;
+ }
+
+ private Object extractLong(Variable variable) {
+ if (variable instanceof OctetString) {
+ String itemValue = variable.toString();
+ try {
+ return Long.parseLong(itemValue);
+ } catch (Exception e) {
+ return null;
+ }
+ }
+ return variable.toLong();
+ }
+
+ private Object extractInt(Variable variable) {
+ if (variable instanceof OctetString) {
+ String itemValue = variable.toString();
+ try {
+ return Integer.parseInt(itemValue);
+ } catch (Exception e) {
+ return null;
+ }
+ }
+ return variable.toInt();
+ }
+}
diff --git a/eu.dariolucia.reatmetric.driver.snmp/src/main/java/eu/dariolucia/reatmetric/driver/snmp/configuration/OidEntryType.java b/eu.dariolucia.reatmetric.driver.snmp/src/main/java/eu/dariolucia/reatmetric/driver/snmp/configuration/OidEntryType.java
new file mode 100644
index 00000000..bb38a1ef
--- /dev/null
+++ b/eu.dariolucia.reatmetric.driver.snmp/src/main/java/eu/dariolucia/reatmetric/driver/snmp/configuration/OidEntryType.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2024 Dario Lucia (https://www.dariolucia.eu)
+ *
+ * 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 eu.dariolucia.reatmetric.driver.snmp.configuration;
+
+import eu.dariolucia.reatmetric.api.value.ValueTypeEnum;
+
+public enum OidEntryType {
+ STRING,
+ INTEGER,
+ OID,
+ LONG,
+ DOUBLE,
+ BYTE_ARRAY;
+
+ public ValueTypeEnum toValueTypeEnum() {
+ switch (this) {
+ case OID: return ValueTypeEnum.ENUMERATED;
+ case STRING: return ValueTypeEnum.CHARACTER_STRING;
+ case BYTE_ARRAY: return ValueTypeEnum.OCTET_STRING;
+ case INTEGER: return ValueTypeEnum.ENUMERATED;
+ case LONG: return ValueTypeEnum.SIGNED_INTEGER;
+ case DOUBLE: return ValueTypeEnum.REAL;
+ default: throw new IllegalStateException("Type " + this + " cannot be mapped to ValueTypeEnum");
+ }
+ }
+}
diff --git a/eu.dariolucia.reatmetric.driver.snmp/src/main/java/eu/dariolucia/reatmetric/driver/snmp/configuration/SetCommandConfiguration.java b/eu.dariolucia.reatmetric.driver.snmp/src/main/java/eu/dariolucia/reatmetric/driver/snmp/configuration/SetCommandConfiguration.java
new file mode 100644
index 00000000..503206f8
--- /dev/null
+++ b/eu.dariolucia.reatmetric.driver.snmp/src/main/java/eu/dariolucia/reatmetric/driver/snmp/configuration/SetCommandConfiguration.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2024 Dario Lucia (https://www.dariolucia.eu)
+ *
+ * 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 eu.dariolucia.reatmetric.driver.snmp.configuration;
+
+import jakarta.xml.bind.annotation.XmlAccessType;
+import jakarta.xml.bind.annotation.XmlAccessorType;
+import jakarta.xml.bind.annotation.XmlAttribute;
+
+@XmlAccessorType(XmlAccessType.FIELD)
+public class SetCommandConfiguration {
+
+ @XmlAttribute(name = "path", required = true)
+ private String path;
+
+ public String getPath() {
+ return path;
+ }
+
+ public void setPath(String path) {
+ this.path = path;
+ }
+}
diff --git a/eu.dariolucia.reatmetric.driver.snmp/src/main/java/eu/dariolucia/reatmetric/driver/snmp/configuration/SnmpConfiguration.java b/eu.dariolucia.reatmetric.driver.snmp/src/main/java/eu/dariolucia/reatmetric/driver/snmp/configuration/SnmpConfiguration.java
new file mode 100644
index 00000000..a18eac0b
--- /dev/null
+++ b/eu.dariolucia.reatmetric.driver.snmp/src/main/java/eu/dariolucia/reatmetric/driver/snmp/configuration/SnmpConfiguration.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2024 Dario Lucia (https://www.dariolucia.eu)
+ *
+ * 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 eu.dariolucia.reatmetric.driver.snmp.configuration;
+
+import eu.dariolucia.reatmetric.api.common.exceptions.ReatmetricException;
+import jakarta.xml.bind.JAXBContext;
+import jakarta.xml.bind.JAXBException;
+import jakarta.xml.bind.Unmarshaller;
+import jakarta.xml.bind.annotation.*;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.LinkedList;
+import java.util.List;
+
+@XmlRootElement(name = "snmp-configuration", namespace = "http://dariolucia.eu/reatmetric/driver/snmp")
+@XmlAccessorType(XmlAccessType.FIELD)
+public class SnmpConfiguration {
+
+ private static final String HOME_VAR = "$HOME";
+ private static final String HOME_DIR = System.getProperty("user.home");
+
+ private static final String PREFIX_VAR = "$PREFIX";
+ private static final String PREFIX_DIR = System.getProperty("reatmetric.prefix.dir", "");
+
+ public static SnmpConfiguration load(InputStream is) throws IOException {
+ try {
+ JAXBContext jc = JAXBContext.newInstance(SnmpConfiguration.class);
+ Unmarshaller u = jc.createUnmarshaller();
+ SnmpConfiguration sc = (SnmpConfiguration) u.unmarshal(is);
+ for (SnmpDevice d : sc.getSnmpDeviceList()) {
+ d.setConfiguration(d.getConfiguration().replace(HOME_VAR, HOME_DIR));
+ d.setConfiguration(d.getConfiguration().replace(PREFIX_VAR, PREFIX_DIR));
+ }
+ sc.initialise();
+ return sc;
+ } catch (JAXBException | ReatmetricException e) {
+ throw new IOException(e);
+ }
+ }
+
+ @XmlAttribute(name = "name", required = true)
+ private String name;
+
+ @XmlElement(name="device")
+ private List snmpDeviceList = new LinkedList<>();
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public List getSnmpDeviceList() {
+ return snmpDeviceList;
+ }
+
+ public void setSnmpDeviceList(List snmpDeviceList) {
+ this.snmpDeviceList = snmpDeviceList;
+ }
+
+ private void initialise() throws ReatmetricException {
+ this.snmpDeviceList.forEach(d -> d.initialise());
+ }
+}
diff --git a/eu.dariolucia.reatmetric.driver.snmp/src/main/java/eu/dariolucia/reatmetric/driver/snmp/configuration/SnmpDevice.java b/eu.dariolucia.reatmetric.driver.snmp/src/main/java/eu/dariolucia/reatmetric/driver/snmp/configuration/SnmpDevice.java
new file mode 100644
index 00000000..a78d8034
--- /dev/null
+++ b/eu.dariolucia.reatmetric.driver.snmp/src/main/java/eu/dariolucia/reatmetric/driver/snmp/configuration/SnmpDevice.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2024 Dario Lucia (https://www.dariolucia.eu)
+ *
+ * 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 eu.dariolucia.reatmetric.driver.snmp.configuration;
+
+import jakarta.xml.bind.annotation.*;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+@XmlAccessorType(XmlAccessType.FIELD)
+public class SnmpDevice {
+
+ private static final Logger LOG = Logger.getLogger(SnmpDevice.class.getName());
+
+ @XmlAttribute(name = "name", required = true)
+ private String name;
+
+ @XmlAttribute(name = "connection-string", required = true)
+ private String connectionString; // example: udp:192.168.0.1/161
+
+ @XmlAttribute(name = "timeout")
+ private int timeout = 2000; // in ms
+
+ @XmlAttribute(name = "retries")
+ private int retries = 2;
+
+ @XmlAttribute(name = "community")
+ private String community = "public";
+
+ @XmlAttribute(name = "version")
+ private SnmpVersionEnum version = SnmpVersionEnum.V2;
+
+ @XmlAttribute(name = "path", required = true)
+ private String path;
+
+ @XmlElement(name="configuration", required = true)
+ private String configuration;
+
+ @XmlElement(name="set-command", required = true)
+ private SetCommandConfiguration setCommandConfiguration;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getConnectionString() {
+ return connectionString;
+ }
+
+ public void setConnectionString(String connectionString) {
+ this.connectionString = connectionString;
+ }
+
+ public String getCommunity() {
+ return community;
+ }
+
+ public void setCommunity(String community) {
+ this.community = community;
+ }
+
+ public SnmpVersionEnum getVersion() {
+ return version;
+ }
+
+ public void setVersion(SnmpVersionEnum version) {
+ this.version = version;
+ }
+
+ public String getPath() {
+ return path;
+ }
+
+ public void setPath(String path) {
+ this.path = path;
+ }
+
+ public String getConfiguration() {
+ return configuration;
+ }
+
+ public void setConfiguration(String configuration) {
+ this.configuration = configuration;
+ }
+
+ public SetCommandConfiguration getSetCommandConfiguration() {
+ return setCommandConfiguration;
+ }
+
+ public void setSetCommandConfiguration(SetCommandConfiguration setCommandConfiguration) {
+ this.setCommandConfiguration = setCommandConfiguration;
+ }
+
+ public int getTimeout() {
+ return timeout;
+ }
+
+ public void setTimeout(int timeout) {
+ this.timeout = timeout;
+ }
+
+ public int getRetries() {
+ return retries;
+ }
+
+ public void setRetries(int retries) {
+ this.retries = retries;
+ }
+
+ @XmlTransient
+ private SnmpDeviceConfiguration deviceConfiguration = null;
+
+ public void initialise() {
+ try {
+ this.deviceConfiguration = SnmpDeviceConfiguration.load(new FileInputStream(getConfiguration()));
+ } catch (IOException e) {
+ LOG.log(Level.SEVERE, "Cannot initialise device configuration file " + getConfiguration() + ": " + e.getMessage(), e);
+ }
+ }
+
+ public SnmpDeviceConfiguration getDeviceConfiguration() {
+ return deviceConfiguration;
+ }
+}
diff --git a/eu.dariolucia.reatmetric.driver.snmp/src/main/java/eu/dariolucia/reatmetric/driver/snmp/configuration/SnmpDeviceConfiguration.java b/eu.dariolucia.reatmetric.driver.snmp/src/main/java/eu/dariolucia/reatmetric/driver/snmp/configuration/SnmpDeviceConfiguration.java
new file mode 100644
index 00000000..851b838e
--- /dev/null
+++ b/eu.dariolucia.reatmetric.driver.snmp/src/main/java/eu/dariolucia/reatmetric/driver/snmp/configuration/SnmpDeviceConfiguration.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2020 Dario Lucia (https://www.dariolucia.eu)
+ *
+ * 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 eu.dariolucia.reatmetric.driver.snmp.configuration;
+
+import eu.dariolucia.reatmetric.api.processing.IProcessingModel;
+import jakarta.xml.bind.JAXBContext;
+import jakarta.xml.bind.JAXBException;
+import jakarta.xml.bind.Marshaller;
+import jakarta.xml.bind.Unmarshaller;
+import jakarta.xml.bind.annotation.XmlAccessType;
+import jakarta.xml.bind.annotation.XmlAccessorType;
+import jakarta.xml.bind.annotation.XmlElement;
+import jakarta.xml.bind.annotation.XmlRootElement;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.LinkedList;
+import java.util.List;
+
+@XmlRootElement(name = "snmp-device", namespace = "http://dariolucia.eu/reatmetric/driver/snmp/device")
+@XmlAccessorType(XmlAccessType.FIELD)
+public class SnmpDeviceConfiguration {
+
+ public static SnmpDeviceConfiguration load(InputStream is) throws IOException {
+ try {
+ JAXBContext jc = JAXBContext.newInstance(SnmpDeviceConfiguration.class);
+ Unmarshaller u = jc.createUnmarshaller();
+ return (SnmpDeviceConfiguration) u.unmarshal(is);
+ } catch (JAXBException e) {
+ throw new IOException(e);
+ }
+ }
+
+ public static void save(SnmpDeviceConfiguration d, OutputStream out) throws IOException {
+ try {
+ JAXBContext context = JAXBContext.newInstance(SnmpDeviceConfiguration.class);
+ Marshaller marshaller = context.createMarshaller();
+ marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
+ marshaller.marshal(d, out);
+ } catch (JAXBException e) {
+ throw new IOException(e);
+ }
+ }
+
+ @XmlElement(name="group")
+ private List groupConfigurationList = new LinkedList<>();
+
+ public List getGroupConfigurationList() {
+ return groupConfigurationList;
+ }
+
+ public void setGroupConfigurationList(List groupConfigurationList) {
+ this.groupConfigurationList = groupConfigurationList;
+ }
+
+ public void initialise(String prefix, IProcessingModel theModel) {
+ this.groupConfigurationList.forEach(gc -> gc.initialise(prefix, theModel));
+ }
+}
diff --git a/eu.dariolucia.reatmetric.driver.snmp/src/main/java/eu/dariolucia/reatmetric/driver/snmp/configuration/SnmpVersionEnum.java b/eu.dariolucia.reatmetric.driver.snmp/src/main/java/eu/dariolucia/reatmetric/driver/snmp/configuration/SnmpVersionEnum.java
new file mode 100644
index 00000000..7d4d9343
--- /dev/null
+++ b/eu.dariolucia.reatmetric.driver.snmp/src/main/java/eu/dariolucia/reatmetric/driver/snmp/configuration/SnmpVersionEnum.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2024 Dario Lucia (https://www.dariolucia.eu)
+ *
+ * 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 eu.dariolucia.reatmetric.driver.snmp.configuration;
+
+import org.snmp4j.mp.SnmpConstants;
+
+public enum SnmpVersionEnum {
+ V1(SnmpConstants.version1),
+ V2(SnmpConstants.version2c),
+ V3(SnmpConstants.version3);
+
+ private final int value;
+
+ SnmpVersionEnum(int value) {
+ this.value = value;
+ }
+
+ public int toValue() {
+ return value;
+ }
+}
diff --git a/eu.dariolucia.reatmetric.driver.snmp/src/main/java/module-info.java b/eu.dariolucia.reatmetric.driver.snmp/src/main/java/module-info.java
new file mode 100644
index 00000000..877fadab
--- /dev/null
+++ b/eu.dariolucia.reatmetric.driver.snmp/src/main/java/module-info.java
@@ -0,0 +1,17 @@
+import eu.dariolucia.reatmetric.driver.snmp.SnmpDriver;
+
+open module eu.dariolucia.reatmetric.driver.snmp {
+ requires java.logging;
+ requires java.rmi;
+ requires jakarta.xml.bind;
+
+ requires eu.dariolucia.reatmetric.api;
+ requires eu.dariolucia.reatmetric.core;
+
+ requires org.snmp4j;
+
+ exports eu.dariolucia.reatmetric.driver.snmp;
+ exports eu.dariolucia.reatmetric.driver.snmp.configuration;
+
+ provides eu.dariolucia.reatmetric.core.api.IDriver with SnmpDriver;
+}
\ No newline at end of file
diff --git a/eu.dariolucia.reatmetric.driver.socket/pom.xml b/eu.dariolucia.reatmetric.driver.socket/pom.xml
index bfbc7afa..c2b85571 100644
--- a/eu.dariolucia.reatmetric.driver.socket/pom.xml
+++ b/eu.dariolucia.reatmetric.driver.socket/pom.xml
@@ -21,7 +21,7 @@
eu.dariolucia.reatmetric
eu.dariolucia.reatmetric
- 1.0.1
+ 1.0.2
4.0.0
diff --git a/eu.dariolucia.reatmetric.driver.socket/src/main/java/eu/dariolucia/reatmetric/driver/socket/SocketDriver.java b/eu.dariolucia.reatmetric.driver.socket/src/main/java/eu/dariolucia/reatmetric/driver/socket/SocketDriver.java
index d4471595..c24932b9 100644
--- a/eu.dariolucia.reatmetric.driver.socket/src/main/java/eu/dariolucia/reatmetric/driver/socket/SocketDriver.java
+++ b/eu.dariolucia.reatmetric.driver.socket/src/main/java/eu/dariolucia/reatmetric/driver/socket/SocketDriver.java
@@ -104,7 +104,7 @@ protected SystemStatus startProcessing() {
// Init data
this.rawDataArchive = getContext().getArchive() != null ? getContext().getArchive().getArchive(IRawDataArchive.class) : null;
this.globalDriverTimer = new Timer(getName() + " Timer Service", true);
- this.actionThreadPool = Executors.newSingleThreadExecutor((r) -> {
+ this.actionThreadPool = Executors.newSingleThreadExecutor(r -> {
Thread t = new Thread(r);
t.setDaemon(true);
t.setName(getName() + " Worker Thread");
diff --git a/eu.dariolucia.reatmetric.driver.socket/src/main/java/eu/dariolucia/reatmetric/driver/socket/SocketDriverConnector.java b/eu.dariolucia.reatmetric.driver.socket/src/main/java/eu/dariolucia/reatmetric/driver/socket/SocketDriverConnector.java
index ff58b214..0d1481c5 100644
--- a/eu.dariolucia.reatmetric.driver.socket/src/main/java/eu/dariolucia/reatmetric/driver/socket/SocketDriverConnector.java
+++ b/eu.dariolucia.reatmetric.driver.socket/src/main/java/eu/dariolucia/reatmetric/driver/socket/SocketDriverConnector.java
@@ -28,16 +28,11 @@
import eu.dariolucia.reatmetric.driver.socket.configuration.connection.AbstractConnectionConfiguration;
import eu.dariolucia.reatmetric.driver.socket.configuration.connection.IConnectionStatusListener;
import eu.dariolucia.reatmetric.driver.socket.configuration.connection.InitType;
-import eu.dariolucia.reatmetric.driver.socket.configuration.protocol.OutboundMessageMapping;
-import eu.dariolucia.reatmetric.driver.socket.configuration.protocol.OutboundMessageType;
import java.rmi.RemoteException;
-import java.util.logging.Logger;
public class SocketDriverConnector extends AbstractTransportConnector implements IConnectionStatusListener {
- private static final Logger LOG = Logger.getLogger(SocketDriverConnector.class.getName());
-
private final SocketConfiguration configuration;
public SocketDriverConnector(SocketConfiguration configuration) {
super(configuration.getName(), configuration.getDescription());
diff --git a/eu.dariolucia.reatmetric.driver.socket/src/main/java/eu/dariolucia/reatmetric/driver/socket/configuration/SocketConfiguration.java b/eu.dariolucia.reatmetric.driver.socket/src/main/java/eu/dariolucia/reatmetric/driver/socket/configuration/SocketConfiguration.java
index bf445b83..0004f5c2 100644
--- a/eu.dariolucia.reatmetric.driver.socket/src/main/java/eu/dariolucia/reatmetric/driver/socket/configuration/SocketConfiguration.java
+++ b/eu.dariolucia.reatmetric.driver.socket/src/main/java/eu/dariolucia/reatmetric/driver/socket/configuration/SocketConfiguration.java
@@ -40,6 +40,9 @@ public class SocketConfiguration {
private static final String HOME_VAR = "$HOME";
private static final String HOME_DIR = System.getProperty("user.home");
+ private static final String PREFIX_VAR = "$PREFIX";
+ private static final String PREFIX_DIR = System.getProperty("reatmetric.prefix.dir", "");
+
public static SocketConfiguration load(InputStream is) throws IOException {
try {
JAXBContext jc = JAXBContext.newInstance(SocketConfiguration.class);
@@ -49,6 +52,7 @@ public static SocketConfiguration load(InputStream is) throws IOException {
for (MessageDefinition> md : sc.getMessageDefinitions()) {
if(md instanceof BinaryMessageDefinition) {
((BinaryMessageDefinition) md).setLocation(((BinaryMessageDefinition) md).getLocation().replace(HOME_VAR, HOME_DIR));
+ ((BinaryMessageDefinition) md).setLocation(((BinaryMessageDefinition) md).getLocation().replace(PREFIX_VAR, PREFIX_DIR));
}
}
}
diff --git a/eu.dariolucia.reatmetric.driver.spacecraft.test/pom.xml b/eu.dariolucia.reatmetric.driver.spacecraft.test/pom.xml
index caa8d071..5faa3d9c 100644
--- a/eu.dariolucia.reatmetric.driver.spacecraft.test/pom.xml
+++ b/eu.dariolucia.reatmetric.driver.spacecraft.test/pom.xml
@@ -21,7 +21,7 @@
eu.dariolucia.reatmetric
eu.dariolucia.reatmetric
- 1.0.1
+ 1.0.2
4.0.0
diff --git a/eu.dariolucia.reatmetric.driver.spacecraft/pom.xml b/eu.dariolucia.reatmetric.driver.spacecraft/pom.xml
index 58bd6c9b..08753efc 100644
--- a/eu.dariolucia.reatmetric.driver.spacecraft/pom.xml
+++ b/eu.dariolucia.reatmetric.driver.spacecraft/pom.xml
@@ -21,7 +21,7 @@
eu.dariolucia.reatmetric
eu.dariolucia.reatmetric
- 1.0.1
+ 1.0.2
4.0.0
diff --git a/eu.dariolucia.reatmetric.driver.spacecraft/src/main/java/eu/dariolucia/reatmetric/driver/spacecraft/definition/SpacecraftConfiguration.java b/eu.dariolucia.reatmetric.driver.spacecraft/src/main/java/eu/dariolucia/reatmetric/driver/spacecraft/definition/SpacecraftConfiguration.java
index 13cd3f3d..26a63a83 100644
--- a/eu.dariolucia.reatmetric.driver.spacecraft/src/main/java/eu/dariolucia/reatmetric/driver/spacecraft/definition/SpacecraftConfiguration.java
+++ b/eu.dariolucia.reatmetric.driver.spacecraft/src/main/java/eu/dariolucia/reatmetric/driver/spacecraft/definition/SpacecraftConfiguration.java
@@ -32,6 +32,10 @@ public class SpacecraftConfiguration {
private static final String HOME_VAR = "$HOME";
private static final String HOME_DIR = System.getProperty("user.home");
+
+ private static final String PREFIX_VAR = "$PREFIX";
+ private static final String PREFIX_DIR = System.getProperty("reatmetric.prefix.dir", "");
+
public static SpacecraftConfiguration load(InputStream is) throws IOException {
try {
JAXBContext jc = JAXBContext.newInstance(SpacecraftConfiguration.class);
@@ -40,6 +44,7 @@ public static SpacecraftConfiguration load(InputStream is) throws IOException {
if(o.getPacketServiceConfiguration() != null) {
for (ServiceConfiguration sc : o.getPacketServiceConfiguration().getServices()) {
sc.setConfiguration(sc.getConfiguration().replace(HOME_VAR, HOME_DIR));
+ sc.setConfiguration(sc.getConfiguration().replace(PREFIX_VAR, PREFIX_DIR));
}
}
return o;
diff --git a/eu.dariolucia.reatmetric.driver.test/pom.xml b/eu.dariolucia.reatmetric.driver.test/pom.xml
index 531e627a..fd9ef29b 100644
--- a/eu.dariolucia.reatmetric.driver.test/pom.xml
+++ b/eu.dariolucia.reatmetric.driver.test/pom.xml
@@ -21,7 +21,7 @@
eu.dariolucia.reatmetric
eu.dariolucia.reatmetric
- 1.0.1
+ 1.0.2
4.0.0
diff --git a/eu.dariolucia.reatmetric.persist/pom.xml b/eu.dariolucia.reatmetric.persist/pom.xml
index b6722d85..76ab1c5b 100644
--- a/eu.dariolucia.reatmetric.persist/pom.xml
+++ b/eu.dariolucia.reatmetric.persist/pom.xml
@@ -21,7 +21,7 @@
eu.dariolucia.reatmetric
eu.dariolucia.reatmetric
- 1.0.1
+ 1.0.2
4.0.0
diff --git a/eu.dariolucia.reatmetric.processing/Documentation.adoc b/eu.dariolucia.reatmetric.processing/Documentation.adoc
index 79455080..8749d00f 100644
--- a/eu.dariolucia.reatmetric.processing/Documentation.adoc
+++ b/eu.dariolucia.reatmetric.processing/Documentation.adoc
@@ -281,6 +281,15 @@ not via a setter element, which is mapped to an activity for dispatching and rem
considered 'internal' parameters, which can be useful to define globally available values and properties, with all the
processing capabilities of validity, calibrations, checks and triggers available for standard parameters.
+_weak_consistency_: default is 'false'. A weakly consistent parameter (applicable only for synthetic parameters) is a parameter that
+will not be considered to compute overlaps in the working set processing of the processing model, and will not add itself and its
+dependant objects to the working set during normal (input-based) processing.
+Weakly consistent parameters are computed in an "inconsistent" way, i.e. access the status of the objects they depend
+on, without blocking the normal processing of the working set. Their processing is organised independently of the
+processing of the inputs to the processing model: when an inconsistent object is processed, all its dependant (hard-consistent) objects are also processed and this is done via the standard update process of the processing models.
+Only synthetic parameters can have this flag set to true. If this is set on other types of parameters, the flag is
+simply ignored.
+
The _parameter_ node has the following sub-elements:
_validity_: optional, if not provided the parameter is always considered valid. The _validity_ element can contain either
diff --git a/eu.dariolucia.reatmetric.processing/pom.xml b/eu.dariolucia.reatmetric.processing/pom.xml
index 273a0486..929e7ace 100644
--- a/eu.dariolucia.reatmetric.processing/pom.xml
+++ b/eu.dariolucia.reatmetric.processing/pom.xml
@@ -21,7 +21,7 @@
eu.dariolucia.reatmetric
eu.dariolucia.reatmetric
- 1.0.1
+ 1.0.2
4.0.0
diff --git a/eu.dariolucia.reatmetric.processing/src/main/java/eu/dariolucia/reatmetric/processing/definition/ParameterProcessingDefinition.java b/eu.dariolucia.reatmetric.processing/src/main/java/eu/dariolucia/reatmetric/processing/definition/ParameterProcessingDefinition.java
index b3a84e08..c034e389 100644
--- a/eu.dariolucia.reatmetric.processing/src/main/java/eu/dariolucia/reatmetric/processing/definition/ParameterProcessingDefinition.java
+++ b/eu.dariolucia.reatmetric.processing/src/main/java/eu/dariolucia/reatmetric/processing/definition/ParameterProcessingDefinition.java
@@ -58,6 +58,9 @@ public class ParameterProcessingDefinition extends AbstractProcessingDefinition
@XmlAttribute(name = "user_parameter")
private boolean userParameter = false;
+ @XmlAttribute(name = "weak_consistency")
+ private boolean weakConsistency = false;
+
@XmlElement(name = "validity")
private ValidityCondition validity;
@@ -300,6 +303,32 @@ public void setUserParameter(boolean userParameter) {
this.userParameter = userParameter;
}
+ /**
+ * A weakly consistent parameter (applicable only for synthetic parameters) is a parameter that:
+ *
+ * - will not be considered to compute overlaps in the working set processing of the processing model
+ * - will not add itself and its dependant objects to the working set during normal (input-based) processing
+ *
+ *
+ * Weakly consistent parameters are computed at most according to the timeout expressed in the related attribute, in an
+ * "inconsistent" way, i.e. access the status of the objects they depend on, without blocking the normal processing
+ * of the working set. Their processing is organised independently of the processing of the inputs to the processing
+ * model: when an inconsistent object is processed, all its dependant objects are also processed and this is done via
+ * the standard update process of the processing models.
+ *
+ * Only synthetic parameters can have this flag set to true. If this is set on other types of parameters, the flag is
+ * simply ignored.
+ *
+ * @return true if the parameter is weakly consistent, otherwise false.
+ */
+ public boolean isWeakConsistency() {
+ return weakConsistency;
+ }
+
+ public void setWeakConsistency(boolean weakConsistency) {
+ this.weakConsistency = weakConsistency;
+ }
+
/**
* Internally used by the processing model.
*
diff --git a/eu.dariolucia.reatmetric.processing/src/main/java/eu/dariolucia/reatmetric/processing/impl/ProcessingModelImpl.java b/eu.dariolucia.reatmetric.processing/src/main/java/eu/dariolucia/reatmetric/processing/impl/ProcessingModelImpl.java
index eb383b8d..b3d6499f 100644
--- a/eu.dariolucia.reatmetric.processing/src/main/java/eu/dariolucia/reatmetric/processing/impl/ProcessingModelImpl.java
+++ b/eu.dariolucia.reatmetric.processing/src/main/java/eu/dariolucia/reatmetric/processing/impl/ProcessingModelImpl.java
@@ -115,6 +115,11 @@ public class ProcessingModelImpl implements IBindingResolver, IProcessingModel {
*/
private final Set activeActivityProcessors = new HashSet<>();
+ /**
+ * Set of parameter IDs that are reported as currently dirty.
+ */
+ private final Set dirtyParametersSet = new HashSet<>();
+
public ProcessingModelImpl(ProcessingDefinition processingDefinition, IProcessingModelOutput output, Map, Long> initialSequencerMap, IProcessingModelInitialiser initialiser) throws ProcessingModelException {
this.processingDefinition = processingDefinition;
// Start off the preloader thread: one off, using internal executor for parallel preloading
@@ -254,12 +259,12 @@ public long getNextId(Class extends AbstractDataItem> type) {
}
public ProcessingTask scheduleTask(List> operations, int dispatchingQueue) {
- return scheduleTask(operations, dispatchingQueue, false);
+ return scheduleTask(operations, dispatchingQueue, false, false);
}
- public ProcessingTask scheduleTask(List> operations, int dispatchingQueue, boolean internalRequest) {
+ public ProcessingTask scheduleTask(List> operations, int dispatchingQueue, boolean internalRequest, boolean includeWeaklyConsistent) {
// Create the processing task
- ProcessingTask taskToRun = new ProcessingTask(new ProcessingTask.Job(operations, outputRedirector, workingSet));
+ ProcessingTask taskToRun = new ProcessingTask(new ProcessingTask.Job(operations, outputRedirector, workingSet), includeWeaklyConsistent);
// Add the task to be done to the queue
switch(dispatchingQueue) {
case COMMAND_DISPATCHING_QUEUE:
@@ -395,6 +400,39 @@ public ProcessingDefinition getDefinitions() {
return this.processingDefinition;
}
+ public void newDirtyParameter(int systemEntityId) {
+ boolean wasEmpty;
+ synchronized (this.dirtyParametersSet) {
+ wasEmpty = this.dirtyParametersSet.isEmpty();
+ this.dirtyParametersSet.add(systemEntityId);
+ }
+ if(wasEmpty) {
+ TimerTask task = new TimerTask() {
+ @Override
+ public void run() {
+ refreshDirtyParameters();
+ }
+ };
+ // Schedule task to run in 1 second (hardcoded)
+ scheduleAt(Instant.now().plusSeconds(1), task);
+ }
+ }
+
+ private void refreshDirtyParameters() {
+ Set parametersToRefresh;
+ synchronized (this.dirtyParametersSet) {
+ parametersToRefresh = new HashSet<>(this.dirtyParametersSet);
+ this.dirtyParametersSet.clear();
+ }
+ if(LOG.isLoggable(Level.FINEST)) {
+ LOG.log(Level.FINEST, "Refreshing dirty parameters " + parametersToRefresh);
+ }
+ // Build the list of operations to be performed
+ List> operations = parametersToRefresh.stream().map(WeaklyConsistentRefreshOperation::new).collect(Collectors.toList());
+ // Schedule task
+ scheduleTask(operations, REPORTING_DISPATCHING_QUEUE, false, true);
+ }
+
@Override
public void injectParameters(List sampleList) {
// Build the list of operations to be performed
diff --git a/eu.dariolucia.reatmetric.processing/src/main/java/eu/dariolucia/reatmetric/processing/impl/ProcessingTask.java b/eu.dariolucia.reatmetric.processing/src/main/java/eu/dariolucia/reatmetric/processing/impl/ProcessingTask.java
index a3d95eaa..e223f778 100644
--- a/eu.dariolucia.reatmetric.processing/src/main/java/eu/dariolucia/reatmetric/processing/impl/ProcessingTask.java
+++ b/eu.dariolucia.reatmetric.processing/src/main/java/eu/dariolucia/reatmetric/processing/impl/ProcessingTask.java
@@ -33,14 +33,17 @@ public class ProcessingTask extends FutureTask> {
private final Job job;
- ProcessingTask(Job toRun) {
+ private final boolean includeWeaklyConsistent;
+
+ ProcessingTask(Job toRun, boolean includeWeaklyConsistent) {
super(toRun);
this.job = toRun;
+ this.includeWeaklyConsistent = includeWeaklyConsistent;
}
void prepareTask(GraphModel graphModel) {
// Delegate
- job.prepareTask(graphModel);
+ job.prepareTask(graphModel, this.includeWeaklyConsistent);
}
Set getAffectedItems() {
@@ -88,14 +91,28 @@ public List call() throws Exception {
return result;
}
- void prepareTask(GraphModel graphModel) {
+ void prepareTask(GraphModel graphModel, boolean includeWeakConsistent) {
// Finalize the list by extending it with the necessary re-evaluations, the setting of the processors
// and order by topological sort
- operations = graphModel.finalizeOperationList(operations);
- // Build the set of affected items by ID
+ List> newOperations = graphModel.finalizeOperationList(operations, includeWeakConsistent);
+ // Build the set of affected items by ID: do not put items that are weakly consistent,
+ // unless they appear in the original request
+ for (AbstractModelOperation> amo : newOperations) {
+ if (!amo.getProcessor().isWeaklyConsistent() || (includeWeakConsistent && isInOriginalOperations(amo.getProcessor().getSystemEntityId()))) {
+ this.affectedItems.add(amo.getSystemEntityId());
+ }
+ }
+ // Assign the new operations list
+ operations = newOperations;
+ }
+
+ private boolean isInOriginalOperations(int systemEntityId) {
for (AbstractModelOperation> amo : operations) {
- this.affectedItems.add(amo.getSystemEntityId());
+ if (amo.getProcessor().getSystemEntityId() == systemEntityId) {
+ return true;
+ }
}
+ return false;
}
public Set getAffectedItems() {
diff --git a/eu.dariolucia.reatmetric.processing/src/main/java/eu/dariolucia/reatmetric/processing/impl/graph/EntityVertex.java b/eu.dariolucia.reatmetric.processing/src/main/java/eu/dariolucia/reatmetric/processing/impl/graph/EntityVertex.java
index 258e6420..f64d1c98 100644
--- a/eu.dariolucia.reatmetric.processing/src/main/java/eu/dariolucia/reatmetric/processing/impl/graph/EntityVertex.java
+++ b/eu.dariolucia.reatmetric.processing/src/main/java/eu/dariolucia/reatmetric/processing/impl/graph/EntityVertex.java
@@ -20,14 +20,11 @@
import eu.dariolucia.reatmetric.processing.impl.operations.SystemEntityUpdateOperation;
import eu.dariolucia.reatmetric.processing.impl.processors.AbstractSystemEntityProcessor;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Set;
+import java.util.*;
public class EntityVertex {
- private List updateOperationsForAffectedEntities = null;
+ private List> updateOperationsForAffectedEntities = null;
private int orderingId;
private final AbstractSystemEntityProcessor processor;
@@ -39,6 +36,7 @@ public EntityVertex(AbstractSystemEntityProcessor processor) {
this.processor = processor;
this.updateOperation = new SystemEntityUpdateOperation();
this.updateOperation.setProcessor(this.processor);
+ this.processor.setEntityVertex(this);
}
public int getSystemEntityId() {
@@ -71,7 +69,12 @@ public void assignProcessor(AbstractModelOperation operation) {
operation.setProcessor(processor);
}
- public synchronized List getUpdateOperationsForAffectedEntities() {
+ public synchronized List> getUpdateOperationsForAffectedEntities(boolean includeWeaklyConsistent) {
+ // If we are processing only consistent system elements, then this object, being weakly consistent, will be evaluated,
+ // but it will not contribute with update operations to affected entities
+ if(!includeWeaklyConsistent && getProcessor().isWeaklyConsistent()) {
+ return Collections.emptyList();
+ }
// The method is synchronized to avoid double computation
if(updateOperationsForAffectedEntities == null) {
// The affected entities are the vertex's predecessors + their affected entities
@@ -82,9 +85,9 @@ public synchronized List getUpdateOperationsForAffectedE
// The direct predecessor
updateOperationsForAffectedEntities.add(de.getSource().getUpdateOperation());
processed.add(de.getSource().getSystemEntityId());
- // The items affected by the predecessor
- for(AbstractModelOperation amd : de.getSource().getUpdateOperationsForAffectedEntities()) {
- if(!processed.contains(amd.getSystemEntityId())) {
+ // The items affected by the predecessor: we always force the exclusion of weakly consistent parameters here: this is right, do not modify it! :)
+ for (AbstractModelOperation> amd : de.getSource().getUpdateOperationsForAffectedEntities(false)) {
+ if (!processed.contains(amd.getSystemEntityId())) {
processed.add(amd.getSystemEntityId());
updateOperationsForAffectedEntities.add(amd);
}
diff --git a/eu.dariolucia.reatmetric.processing/src/main/java/eu/dariolucia/reatmetric/processing/impl/graph/GraphModel.java b/eu.dariolucia.reatmetric.processing/src/main/java/eu/dariolucia/reatmetric/processing/impl/graph/GraphModel.java
index ec6d62f4..860c8c7b 100644
--- a/eu.dariolucia.reatmetric.processing/src/main/java/eu/dariolucia/reatmetric/processing/impl/graph/GraphModel.java
+++ b/eu.dariolucia.reatmetric.processing/src/main/java/eu/dariolucia/reatmetric/processing/impl/graph/GraphModel.java
@@ -366,17 +366,18 @@ private int generateContainerId(SystemEntityPath location) {
/**
* This method expands the provided list of operations adding the required object re-evaluations, depending on the
- * dependencies of the affected processors.
+ * dependencies of the affected processors. Objects that are weakly consistent remain in this list but do not trigger
+ * expansions, i.e. dependant objects are not added.
*
* @param operations the list of operations to be performed
* @return the extended list of operations to be performed, including dependency re-evaluation
*/
- public List> finalizeOperationList(List> operations) {
+ public List> finalizeOperationList(List> operations, boolean includeWeaklyConsistent) {
Set alreadyPresent = new HashSet<>();
List> extendedOperations = new LinkedList<>();
// Add the entity IDs to the alreadyPresent set
operations.forEach(o -> alreadyPresent.add(o.getSystemEntityId()));
- for(AbstractModelOperation operation : operations) {
+ for(AbstractModelOperation> operation : operations) {
EntityVertex entityVertex = getVertexOf(operation.getSystemEntityId());
if(entityVertex == null) {
LOG.log(Level.SEVERE, "Cannot locate entity with ID " + operation.getSystemEntityId() + ", processing skipped");
@@ -384,10 +385,10 @@ public List> finalizeOperationList(List updateOperationsForProvidedOperation = entityVertex.getUpdateOperationsForAffectedEntities();
- for(AbstractModelOperation updateOperation : updateOperationsForProvidedOperation) {
- if(!alreadyPresent.contains(updateOperation.getSystemEntityId())) {
+ // Add the affected processors for evaluation, if the processor of the operation is not weakly consistent
+ List> updateOperationsForProvidedOperation = entityVertex.getUpdateOperationsForAffectedEntities(includeWeaklyConsistent);
+ for (AbstractModelOperation> updateOperation : updateOperationsForProvidedOperation) {
+ if (!alreadyPresent.contains(updateOperation.getSystemEntityId())) {
alreadyPresent.add(updateOperation.getSystemEntityId());
extendedOperations.add(updateOperation);
}
diff --git a/eu.dariolucia.reatmetric.processing/src/main/java/eu/dariolucia/reatmetric/processing/impl/operations/AbstractModelOperation.java b/eu.dariolucia.reatmetric.processing/src/main/java/eu/dariolucia/reatmetric/processing/impl/operations/AbstractModelOperation.java
index afd326fd..245ff22b 100644
--- a/eu.dariolucia.reatmetric.processing/src/main/java/eu/dariolucia/reatmetric/processing/impl/operations/AbstractModelOperation.java
+++ b/eu.dariolucia.reatmetric.processing/src/main/java/eu/dariolucia/reatmetric/processing/impl/operations/AbstractModelOperation.java
@@ -31,7 +31,7 @@ public abstract class AbstractModelOperation doProcess() throws ProcessingModelException {
- return getProcessor().evaluate();
+ return getProcessor().evaluate(!getProcessor().isWeaklyConsistent());
}
@Override
diff --git a/eu.dariolucia.reatmetric.processing/src/main/java/eu/dariolucia/reatmetric/processing/impl/operations/WeaklyConsistentRefreshOperation.java b/eu.dariolucia.reatmetric.processing/src/main/java/eu/dariolucia/reatmetric/processing/impl/operations/WeaklyConsistentRefreshOperation.java
new file mode 100644
index 00000000..a23eb5f2
--- /dev/null
+++ b/eu.dariolucia.reatmetric.processing/src/main/java/eu/dariolucia/reatmetric/processing/impl/operations/WeaklyConsistentRefreshOperation.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2024 Dario Lucia (https://www.dariolucia.eu)
+ *
+ * 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 eu.dariolucia.reatmetric.processing.impl.operations;
+
+import eu.dariolucia.reatmetric.api.common.AbstractDataItem;
+import eu.dariolucia.reatmetric.api.processing.exceptions.ProcessingModelException;
+import eu.dariolucia.reatmetric.processing.impl.processors.AbstractSystemEntityProcessor;
+
+import java.time.Instant;
+import java.util.List;
+
+public class WeaklyConsistentRefreshOperation extends AbstractModelOperation> {
+
+ private final Instant creationTime = Instant.now();
+
+ private final int systemEntityId;
+
+ public WeaklyConsistentRefreshOperation(int id) {
+ this.systemEntityId = id;
+ }
+
+ @Override
+ public Instant getTime() {
+ return creationTime;
+ }
+
+ @Override
+ protected List doProcess() throws ProcessingModelException {
+ return getProcessor().evaluate(true);
+ }
+
+ @Override
+ public int getSystemEntityId() {
+ return systemEntityId;
+ }
+
+ @Override
+ public String toString() {
+ return "'Refresh weakly consistent system entity " + getSystemEntityId() + " state'";
+ }
+}
diff --git a/eu.dariolucia.reatmetric.processing/src/main/java/eu/dariolucia/reatmetric/processing/impl/processors/AbstractSystemEntityProcessor.java b/eu.dariolucia.reatmetric.processing/src/main/java/eu/dariolucia/reatmetric/processing/impl/processors/AbstractSystemEntityProcessor.java
index aa8f64e0..c68d00df 100644
--- a/eu.dariolucia.reatmetric.processing/src/main/java/eu/dariolucia/reatmetric/processing/impl/processors/AbstractSystemEntityProcessor.java
+++ b/eu.dariolucia.reatmetric.processing/src/main/java/eu/dariolucia/reatmetric/processing/impl/processors/AbstractSystemEntityProcessor.java
@@ -24,10 +24,12 @@
import eu.dariolucia.reatmetric.api.processing.input.AbstractInputDataItem;
import eu.dariolucia.reatmetric.processing.definition.AbstractProcessingDefinition;
import eu.dariolucia.reatmetric.processing.impl.ProcessingModelImpl;
+import eu.dariolucia.reatmetric.processing.impl.graph.EntityVertex;
import eu.dariolucia.reatmetric.processing.impl.processors.builders.SystemEntityBuilder;
import java.util.Collections;
import java.util.List;
+import java.util.concurrent.atomic.AtomicReference;
/**
* This class is the parent class of all processing elements of the system entity model. A processing class is defined
@@ -45,7 +47,7 @@ public abstract class AbstractSystemEntityProcessor state = new AtomicReference<>();
protected volatile Status entityStatus;
@@ -56,6 +58,7 @@ public abstract class AbstractSystemEntityProcessor enable() throws ProcessingModelException {
if(this.entityStatus != Status.ENABLED) {
this.entityStatus = Status.ENABLED;
- return evaluate();
+ return evaluate(true);
} else {
return Collections.emptyList();
}
@@ -95,7 +98,7 @@ public List enable() throws ProcessingModelException {
public List disable() throws ProcessingModelException {
if(this.entityStatus != Status.DISABLED) {
this.entityStatus = Status.DISABLED;
- return evaluate();
+ return evaluate(true);
} else {
return Collections.emptyList();
}
@@ -104,7 +107,7 @@ public List disable() throws ProcessingModelException {
public List ignore() throws ProcessingModelException {
if(this.entityStatus != Status.IGNORED) {
this.entityStatus = Status.IGNORED;
- return evaluate();
+ return evaluate(true);
} else {
return Collections.emptyList();
}
@@ -112,14 +115,23 @@ public List ignore() throws ProcessingModelException {
public abstract List process(K input) throws ProcessingModelException;
- public abstract List evaluate() throws ProcessingModelException;
+ public abstract List evaluate(boolean includeWeakly) throws ProcessingModelException;
+
+ /**
+ * Override when necessary.
+ *
+ * @return true if weakly consistent.
+ */
+ public boolean isWeaklyConsistent() {
+ return false;
+ }
public final int getSystemEntityId() {
return definition.getId();
}
public final T getState() {
- return state;
+ return state.get();
}
public final SystemEntity getEntityState() {
@@ -131,4 +143,12 @@ public final SystemEntity getEntityState() {
public abstract void putCurrentStates(List items);
public abstract AbstractSystemEntityDescriptor getDescriptor();
+
+ public void setEntityVertex(EntityVertex entityVertex) {
+ this.entityVertex = entityVertex;
+ }
+
+ protected EntityVertex getEntityVertex() {
+ return this.entityVertex;
+ }
}
diff --git a/eu.dariolucia.reatmetric.processing/src/main/java/eu/dariolucia/reatmetric/processing/impl/processors/ActivityOccurrenceProcessor.java b/eu.dariolucia.reatmetric.processing/src/main/java/eu/dariolucia/reatmetric/processing/impl/processors/ActivityOccurrenceProcessor.java
index d182d955..69419062 100644
--- a/eu.dariolucia.reatmetric.processing/src/main/java/eu/dariolucia/reatmetric/processing/impl/processors/ActivityOccurrenceProcessor.java
+++ b/eu.dariolucia.reatmetric.processing/src/main/java/eu/dariolucia/reatmetric/processing/impl/processors/ActivityOccurrenceProcessor.java
@@ -394,7 +394,7 @@ private void startTimeout(ActivityOccurrenceState theState, int transmissionTime
@Override
public void run() {
if (currentTimeoutTask == this) {
- parent.processor.scheduleTask(Collections.singletonList(new ActivityOccurrenceUpdateOperation(parent.getSystemEntityId(), occurrenceId)), ProcessingModelImpl.COMMAND_DISPATCHING_QUEUE, true);
+ parent.processor.scheduleTask(Collections.singletonList(new ActivityOccurrenceUpdateOperation(parent.getSystemEntityId(), occurrenceId)), ProcessingModelImpl.COMMAND_DISPATCHING_QUEUE, true, false);
}
}
};
diff --git a/eu.dariolucia.reatmetric.processing/src/main/java/eu/dariolucia/reatmetric/processing/impl/processors/ActivityProcessor.java b/eu.dariolucia.reatmetric.processing/src/main/java/eu/dariolucia/reatmetric/processing/impl/processors/ActivityProcessor.java
index 88c9a262..e8c45170 100644
--- a/eu.dariolucia.reatmetric.processing/src/main/java/eu/dariolucia/reatmetric/processing/impl/processors/ActivityProcessor.java
+++ b/eu.dariolucia.reatmetric.processing/src/main/java/eu/dariolucia/reatmetric/processing/impl/processors/ActivityProcessor.java
@@ -43,7 +43,7 @@
public class ActivityProcessor extends AbstractSystemEntityProcessor {
- private final static Logger LOG = Logger.getLogger(ActivityProcessor.class.getName());
+ private static final Logger LOG = Logger.getLogger(ActivityProcessor.class.getName());
private final Map id2occurrence = new ConcurrentHashMap<>();
private final Map name2argumentDefinition = new TreeMap<>();
@@ -488,7 +488,7 @@ public List process(ActivityProgress input) {
}
@Override
- public List evaluate() {
+ public List evaluate(boolean includeWeakly) {
if(LOG.isLoggable(Level.FINER)) {
LOG.finer("Evaluating all activity occurrences for activity " + getSystemEntityId());
}
diff --git a/eu.dariolucia.reatmetric.processing/src/main/java/eu/dariolucia/reatmetric/processing/impl/processors/ContainerProcessor.java b/eu.dariolucia.reatmetric.processing/src/main/java/eu/dariolucia/reatmetric/processing/impl/processors/ContainerProcessor.java
index 5387ceef..e9b681dc 100644
--- a/eu.dariolucia.reatmetric.processing/src/main/java/eu/dariolucia/reatmetric/processing/impl/processors/ContainerProcessor.java
+++ b/eu.dariolucia.reatmetric.processing/src/main/java/eu/dariolucia/reatmetric/processing/impl/processors/ContainerProcessor.java
@@ -40,7 +40,7 @@ public class ContainerProcessor extends AbstractSystemEntityProcessor childProcessors = new ArrayList<>();
+ private final List> childProcessors = new ArrayList<>();
private final ContainerDescriptor descriptor;
@@ -52,7 +52,7 @@ public ContainerProcessor(Definition definition, ProcessingModelImpl processingM
this.descriptor = new ContainerDescriptor(getPath());
}
- public void addChildProcessor(AbstractSystemEntityProcessor processor) {
+ public void addChildProcessor(AbstractSystemEntityProcessor,?,?> processor) {
if(!this.childProcessors.contains(processor)) {
this.childProcessors.add(processor);
}
@@ -63,8 +63,9 @@ public List process(VoidInputDataItem input) {
this.systemEntityBuilder.setStatus(entityStatus);
this.systemEntityBuilder.setAlarmState(AlarmState.NOT_APPLICABLE);
if(this.systemEntityBuilder.isChangedSinceLastBuild()) {
- this.state = this.systemEntityBuilder.build(new LongUniqueId(processor.getNextId(SystemEntity.class)));
- this.entityState = this.state;
+ SystemEntity newState = this.systemEntityBuilder.build(new LongUniqueId(processor.getNextId(SystemEntity.class)));
+ this.state.set(newState);
+ this.entityState = newState;
return List.of(this.entityState);
} else {
// No reason to send out anything relevant
@@ -73,13 +74,13 @@ public List process(VoidInputDataItem input) {
}
@Override
- public List evaluate() {
+ public List evaluate(boolean includeWeakly) {
return process(VoidInputDataItem.instance());
}
@Override
public void visit(IProcessingModelVisitor visitor) {
- for(AbstractSystemEntityProcessor proc : childProcessors) {
+ for(AbstractSystemEntityProcessor,?,?> proc : childProcessors) {
SystemEntity toVisit = proc.getEntityState();
if(visitor.shouldDescend(toVisit)) {
visitor.startVisit(toVisit);
@@ -118,11 +119,11 @@ public List disable() throws ProcessingModelException {
private void propagateEnablement(Status toBeApplied) {
// One layer only
List> ops = new ArrayList<>(childProcessors.size());
- for(AbstractSystemEntityProcessor proc : childProcessors) {
+ for(AbstractSystemEntityProcessor,?,?> proc : childProcessors) {
ops.add(new EnableDisableOperation(proc.getSystemEntityId(), toBeApplied));
}
// Schedule operation
- processor.scheduleTask(ops, ProcessingModelImpl.COMMAND_DISPATCHING_QUEUE, true);
+ processor.scheduleTask(ops, ProcessingModelImpl.COMMAND_DISPATCHING_QUEUE, true, true);
}
@Override
@@ -135,7 +136,7 @@ public List ignore() throws ProcessingModelException {
public List getContainedEntities() {
List states = new ArrayList<>(childProcessors.size());
- for(AbstractSystemEntityProcessor proc : childProcessors) {
+ for(AbstractSystemEntityProcessor,?,?> proc : childProcessors) {
states.add(proc.getEntityState());
}
return states;
diff --git a/eu.dariolucia.reatmetric.processing/src/main/java/eu/dariolucia/reatmetric/processing/impl/processors/EventProcessor.java b/eu.dariolucia.reatmetric.processing/src/main/java/eu/dariolucia/reatmetric/processing/impl/processors/EventProcessor.java
index e29385cf..ca41f7cb 100644
--- a/eu.dariolucia.reatmetric.processing/src/main/java/eu/dariolucia/reatmetric/processing/impl/processors/EventProcessor.java
+++ b/eu.dariolucia.reatmetric.processing/src/main/java/eu/dariolucia/reatmetric/processing/impl/processors/EventProcessor.java
@@ -25,7 +25,6 @@
import eu.dariolucia.reatmetric.api.events.EventDescriptor;
import eu.dariolucia.reatmetric.api.messages.Severity;
import eu.dariolucia.reatmetric.api.model.*;
-import eu.dariolucia.reatmetric.api.parameters.ParameterData;
import eu.dariolucia.reatmetric.api.processing.IProcessingModelInitialiser;
import eu.dariolucia.reatmetric.api.processing.IProcessingModelVisitor;
import eu.dariolucia.reatmetric.api.processing.input.EventOccurrence;
@@ -85,8 +84,9 @@ public EventProcessor(EventProcessingDefinition definition, ProcessingModelImpl
private void initialise(IProcessingModelInitialiser initialiser) throws ReatmetricException {
List stateList = initialiser.getState(getSystemEntityId(), SystemEntityType.EVENT);
if(!stateList.isEmpty()) {
- this.state = (EventData) stateList.get(0);
- builder.setInitialisation(this.state);
+ EventData toSet = (EventData) stateList.get(0);
+ this.state.set(toSet);
+ builder.setInitialisation(toSet);
}
}
@@ -118,8 +118,9 @@ public List process(EventOccurrence newValue) {
}
// If the object is enabled, then you have to process it as usual
if(entityStatus == Status.ENABLED || entityStatus == Status.IGNORED) {
+ EventData currentState = getState();
// Prepare the time values
- Instant generationTime = this.state == null ? Instant.now() : this.state.getGenerationTime();
+ Instant generationTime = currentState == null ? Instant.now() : currentState.getGenerationTime();
generationTime = newValue != null ? newValue.getGenerationTime() : generationTime;
if(definition.getCondition() != null) {
// If there is an expression, then evaluate the expression and check for a transition false -> true
@@ -181,8 +182,9 @@ public List process(EventOccurrence newValue) {
Instant receptionTime = newValue != null ? newValue.getReceptionTime() : now;
this.builder.setReceptionTime(receptionTime);
// Replace the state
- this.state = this.builder.build(new LongUniqueId(processor.getNextId(EventData.class)));
- generatedStates.add(this.state);
+ EventData newState = this.builder.build(new LongUniqueId(processor.getNextId(EventData.class)));
+ this.state.set(newState);
+ generatedStates.add(newState);
// Log the event if log is not suppressed and you are not ignoring this event
generateLogMessage(now);
}
@@ -204,7 +206,7 @@ public List process(EventOccurrence newValue) {
private void generateLogMessage(Instant now) {
if(definition.isLogEnabled() && getEntityStatus() != Status.IGNORED) {
if(lastReportedLogTime == null || lastReportedLogTime.plusMillis(definition.getLogRepetitionPeriod()).isBefore(now)) {
- String logSource = definition.getLocation(); // this.state.getSource();
+ String logSource = definition.getLocation(); //
String suffix = skippedLogMessagesCounter == 0 ? "" : " (skipped: " + skippedLogMessagesCounter + ")";
switch (definition.getSeverity()) {
case ALARM:
@@ -251,7 +253,7 @@ void raiseEvent(String source) {
}
@Override
- public List evaluate() {
+ public List evaluate(boolean includeWeakly) {
return process(null);
}
@@ -272,37 +274,44 @@ public AbstractSystemEntityDescriptor getDescriptor() {
@Override
public Severity severity() {
- return this.state == null ? null : this.state.getSeverity();
+ EventData currentState = getState();
+ return currentState == null ? null : currentState.getSeverity();
}
@Override
public String route() {
- return this.state == null ? null : this.state.getRoute();
+ EventData currentState = getState();
+ return currentState == null ? null : currentState.getRoute();
}
@Override
public String source() {
- return this.state == null ? null : this.state.getSource();
+ EventData currentState = getState();
+ return currentState == null ? null : currentState.getSource();
}
@Override
public String type() {
- return this.state == null ? null : this.state.getType();
+ EventData currentState = getState();
+ return currentState == null ? null : currentState.getType();
}
@Override
public String qualifier() {
- return this.state == null ? null : this.state.getQualifier();
+ EventData currentState = getState();
+ return currentState == null ? null : currentState.getQualifier();
}
@Override
public Object report() {
- return this.state == null ? null : this.state.getReport();
+ EventData currentState = getState();
+ return currentState == null ? null : currentState.getReport();
}
@Override
public Long containerId() {
- return this.state == null || this.state.getRawDataContainerId() == null ? null : this.state.getRawDataContainerId().asLong();
+ EventData currentState = getState();
+ return currentState == null || currentState.getRawDataContainerId() == null ? null : currentState.getRawDataContainerId().asLong();
}
@Override
@@ -317,12 +326,14 @@ public String path() {
@Override
public Instant generationTime() {
- return this.state == null ? null : this.state.getGenerationTime();
+ EventData currentState = getState();
+ return currentState == null ? null : currentState.getGenerationTime();
}
@Override
public Instant receptionTime() {
- return this.state == null ? null : this.state.getReceptionTime();
+ EventData currentState = getState();
+ return currentState == null ? null : currentState.getReceptionTime();
}
public List mirror(EventData itemToMirror) {
@@ -338,8 +349,9 @@ public List mirror(EventData itemToMirror) {
// Copy the status into the builder
this.builder.setInitialisation(itemToMirror);
// You must always build an update
- this.state = this.builder.build(new LongUniqueId(processor.getNextId(EventData.class)));
- generatedStates.add(this.state);
+ EventData newState = this.builder.build(new LongUniqueId(processor.getNextId(EventData.class)));
+ this.state.set(newState);
+ generatedStates.add(newState);
// Finalize entity state and prepare for the returned list of data items
computeEntityState(generatedStates);
// Check if a log message must be raised (using the properties defined in the definition)
diff --git a/eu.dariolucia.reatmetric.processing/src/main/java/eu/dariolucia/reatmetric/processing/impl/processors/ParameterProcessor.java b/eu.dariolucia.reatmetric.processing/src/main/java/eu/dariolucia/reatmetric/processing/impl/processors/ParameterProcessor.java
index 0c661f4c..f4420627 100644
--- a/eu.dariolucia.reatmetric.processing/src/main/java/eu/dariolucia/reatmetric/processing/impl/processors/ParameterProcessor.java
+++ b/eu.dariolucia.reatmetric.processing/src/main/java/eu/dariolucia/reatmetric/processing/impl/processors/ParameterProcessor.java
@@ -35,12 +35,14 @@
import eu.dariolucia.reatmetric.api.value.ValueUtil;
import eu.dariolucia.reatmetric.processing.definition.*;
import eu.dariolucia.reatmetric.processing.impl.ProcessingModelImpl;
+import eu.dariolucia.reatmetric.processing.impl.graph.DependencyEdge;
import eu.dariolucia.reatmetric.processing.impl.processors.builders.AlarmParameterDataBuilder;
import eu.dariolucia.reatmetric.processing.impl.processors.builders.ParameterDataBuilder;
import java.time.Instant;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
@@ -56,7 +58,7 @@ public class ParameterProcessor extends AbstractSystemEntityProcessor currentAlarmData = new AtomicReference<>();
private final ParameterDescriptor descriptor;
@@ -64,6 +66,11 @@ public class ParameterProcessor extends AbstractSystemEntityProcessor referenceTimeMap;
+
+ private Map lastDependingElementState = null;
+
+ private boolean dirty;
public ParameterProcessor(ParameterProcessingDefinition definition, ProcessingModelImpl processor) {
super(definition, processor, SystemEntityType.PARAMETER);
@@ -130,17 +137,18 @@ private void buildDefaultState() {
// Sanitize the reception time
this.builder.setReceptionTime(Instant.EPOCH);
// Replace the state
- this.state = this.builder.build(new LongUniqueId(processor.getNextId(ParameterData.class)));
+ this.state.set(this.builder.build(new LongUniqueId(processor.getNextId(ParameterData.class))));
}
private void initialise(IProcessingModelInitialiser initialiser) throws ReatmetricException {
List stateList = initialiser.getState(getSystemEntityId(), SystemEntityType.PARAMETER);
if(!stateList.isEmpty()) {
- this.state = (ParameterData) stateList.get(0);
- this.builder.setInitialisation(this.state);
+ ParameterData toSet = (ParameterData) stateList.get(0);
+ this.state.set(toSet);
+ this.builder.setInitialisation(toSet);
if (stateList.size() > 1) {
AlarmParameterData alarmData = (AlarmParameterData) stateList.get(1);
- this.currentAlarmData = alarmData;
+ this.currentAlarmData.set(alarmData);
this.alarmBuilder.setInitialisation(alarmData);
}
}
@@ -148,10 +156,11 @@ private void initialise(IProcessingModelInitialiser initialiser) throws Reatmetr
@Override
protected AlarmState getInitialAlarmState() {
- if(state == null) {
+ ParameterData currentState = getState();
+ if(currentState == null) {
return AlarmState.UNKNOWN;
} else {
- return state.getAlarmState();
+ return currentState.getAlarmState();
}
}
@@ -177,7 +186,15 @@ public synchronized List process(ParameterSample newValue) thr
computeSystemEntityState(false, generatedStates);
return generatedStates;
}
- if(newValue == null && definition.getExpression() == null && (this.state == null || this.state.getSourceValue() == null)) {
+ // Optimisation: if weakly and not dirty...
+ if(isWeaklyConsistent() && !this.dirty) {
+ // ... no update needed, no change, just recompute entity state
+ computeSystemEntityState(false, generatedStates);
+ return generatedStates;
+ }
+ //
+ ParameterData currentState = getState();
+ if(newValue == null && definition.getExpression() == null && (currentState == null || currentState.getSourceValue() == null)) {
if(LOG.isLoggable(Level.FINEST)) {
LOG.log(Level.FINEST, String.format("Skipping re-evaluation of parameter %d (%s) as there is no previous sample", definition.getId(), definition.getLocation()));
}
@@ -186,9 +203,9 @@ public synchronized List process(ParameterSample newValue) thr
return generatedStates;
}
// Previous value
- Object previousValue = this.state == null ? null : this.state.getEngValue();
+ Object previousValue = currentState == null ? null : currentState.getEngValue();
// Was in alarm?
- boolean wasInAlarm = this.state != null && this.state.getAlarmState().isAlarm();
+ boolean wasInAlarm = currentState != null && currentState.getAlarmState().isAlarm();
// Required to take decision at the end
boolean stateChanged = false;
// The placeholder for the AlarmParameterData to be created, if needed
@@ -199,14 +216,14 @@ public synchronized List process(ParameterSample newValue) thr
AlarmState alarmState = AlarmState.UNKNOWN;
Object engValue = null;
// Derive the source value to use and the times
- Object previousSourceValue = this.state == null ? null : this.state.getSourceValue();
+ Object previousSourceValue = currentState == null ? null : currentState.getSourceValue();
Object sourceValue = newValue != null ? verifySourceValue(newValue.getValue()) : previousSourceValue;
- Instant generationTime = this.state == null ? null : this.state.getGenerationTime();
+ Instant generationTime = currentState == null ? null : currentState.getGenerationTime();
generationTime = newValue != null ? newValue.getGenerationTime() : generationTime;
// Immediate check: if there is a sample and its generation time is before the current (not null) one, then exist now
- if(this.state != null && newValue != null && newValue.getGenerationTime().isBefore(state.getGenerationTime())) {
+ if(currentState != null && newValue != null && newValue.getGenerationTime().isBefore(currentState.getGenerationTime())) {
if(LOG.isLoggable(Level.FINE)) {
- LOG.log(Level.FINE, String.format("Sample of parameter %d (%s) discarded, generation time %s is before current time %s", definition.getId(), definition.getLocation(), newValue.getGenerationTime(), state.getGenerationTime()));
+ LOG.log(Level.FINE, String.format("Sample of parameter %d (%s) discarded, generation time %s is before current time %s", definition.getId(), definition.getLocation(), newValue.getGenerationTime(), currentState.getGenerationTime()));
}
// Before existing, compute the system entity state if needed
computeSystemEntityState(false, generatedStates);
@@ -219,19 +236,25 @@ public synchronized List process(ParameterSample newValue) thr
if(validity == Validity.VALID) {
// If there is an expression, derive the sourceValue from the expression and also the generation time
if(definition.getExpression() != null) {
+ // This map is used to store the generation time of all the reference parameters
+ Map reference2genTime = new HashMap<>();
// Check if re-evalutation is needed: for each mapping item in the expression, get the newest generation time
Instant latestGenerationTime = null;
for(SymbolDefinition sd : definition.getExpression().getSymbols()) {
Instant theGenTime = processor.resolve(sd.getReference()).generationTime();
+ // Remember the generation time of the reference
+ reference2genTime.put(sd.getReference(), theGenTime);
if(latestGenerationTime == null || (theGenTime != null && theGenTime.isAfter(latestGenerationTime))) {
latestGenerationTime = theGenTime;
}
}
// At this stage, if latestGenerationTime is null, it means that there is no value coming from the depending samples. So skip.
// If latestGenerationTime is after the current generation time, then expression shall be re-evaluated.
- if(latestGenerationTime != null && (generationTime == null || latestGenerationTime.isAfter(generationTime))) {
+ if(latestGenerationTime != null && (generationTime == null || latestGenerationTime.isAfter(generationTime) || checkWithLastEvaluationTimeMap(reference2genTime))) {
// Use the latest generation time
generationTime = latestGenerationTime;
+ // Remember the reference-gentime map
+ this.referenceTimeMap = reference2genTime;
try {
sourceValue = definition.getExpression().execute(processor, null, definition.getRawType());
sourceValue = ValueUtil.convert(sourceValue, definition.getRawType());
@@ -285,23 +308,24 @@ public synchronized List process(ParameterSample newValue) thr
receptionTime = newValue.getReceptionTime(); // This can never be null
} else {
// We are in the case of re-evaluation
- this.builder.setRoute(state == null ? null : state.getRoute());
- this.builder.setContainerId(state == null ? null : state.getRawDataContainerId());
+ this.builder.setRoute(currentState == null ? null : currentState.getRoute());
+ this.builder.setContainerId(currentState == null ? null : currentState.getRawDataContainerId());
// What is the reception time?
if(definition.getExpression() != null && this.builder.isChangedSinceLastBuild()) {
// Re-evaluation, set reception time to now if it is an expression and if the builder is in a changed state.
receptionTime = Instant.now();
} else {
// Re-evaluation, do not change the reception time if it is not an expression.
- receptionTime = state == null || state.getReceptionTime() == null ? generationTime : state.getReceptionTime();
+ receptionTime = currentState == null || currentState.getReceptionTime() == null ? generationTime : currentState.getReceptionTime();
}
}
// Set the reception time
this.builder.setReceptionTime(receptionTime);
// Replace the state
if(this.builder.isChangedSinceLastBuild()) {
- this.state = this.builder.build(new LongUniqueId(processor.getNextId(ParameterData.class)));
- generatedStates.add(this.state);
+ ParameterData newState = this.builder.build(new LongUniqueId(processor.getNextId(ParameterData.class)));
+ this.state.set(newState);
+ generatedStates.add(newState);
stateChanged = true;
} else {
if(LOG.isLoggable(Level.FINEST)) {
@@ -315,8 +339,9 @@ public synchronized List process(ParameterSample newValue) thr
this.builder.setValidity(Validity.DISABLED);
// Replace the state
if(this.builder.isChangedSinceLastBuild()) {
- this.state = this.builder.build(new LongUniqueId(processor.getNextId(ParameterData.class)));
- generatedStates.add(this.state);
+ ParameterData newState = this.builder.build(new LongUniqueId(processor.getNextId(ParameterData.class)));
+ this.state.set(newState);
+ generatedStates.add(newState);
stateChanged = true;
}
// Completely ignore the processing
@@ -324,7 +349,7 @@ public synchronized List process(ParameterSample newValue) thr
LOG.log(Level.FINE, "Parameter sample not computed for parameter " + path() + ": parameter processing is disabled");
}
}
- // Finalize entity state and prepare for the returned list of data items
+ // Finalize entity state and prepare for the returned list of data items, clearing the dirty state
computeSystemEntityState(stateChanged, generatedStates);
// If there is an AlarmParameterData, then report it and save it
finalizeAlarmParameterData(generatedStates, alarmData);
@@ -334,28 +359,42 @@ public synchronized List process(ParameterSample newValue) thr
return generatedStates;
}
+ private boolean checkWithLastEvaluationTimeMap(Map reference2genTime) {
+ if(this.referenceTimeMap == null) {
+ return true;
+ }
+ for(Map.Entry refEntry : reference2genTime.entrySet()) {
+ Instant oldTime = this.referenceTimeMap.get(refEntry.getKey());
+ if(oldTime == null || oldTime.isBefore(refEntry.getValue())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
private void finalizeAlarmParameterData(List generatedStates, AlarmParameterData alarmData) {
if(alarmData != null) {
generatedStates.add(alarmData);
- currentAlarmData = alarmData;
+ currentAlarmData.set(alarmData);
// Generate alarm message
generateAlarmMessage(alarmData);
} else {
// Remove the alarm data
- currentAlarmData = null;
+ currentAlarmData.set(null);
latestGeneratedAlarmSeverityMessage = null;
}
}
private AlarmParameterData computeAlarmParameterData(boolean stateChanged) {
+ ParameterData currentState = getState();
AlarmParameterData alarmData = null;
if(stateChanged && valid()) {
// If nominal, set the last nominal value
if(!inAlarm()) {
- this.alarmBuilder.setLastNominalValue(this.state.getEngValue(), this.state.getGenerationTime());
+ this.alarmBuilder.setLastNominalValue(currentState.getEngValue(), currentState.getGenerationTime());
}
// Set current values
- this.alarmBuilder.setCurrentValue(this.state.getAlarmState(), this.state.getEngValue(), this.state.getGenerationTime(), this.state.getReceptionTime());
+ this.alarmBuilder.setCurrentValue(currentState.getAlarmState(), currentState.getEngValue(), currentState.getGenerationTime(), currentState.getReceptionTime());
if(this.alarmBuilder.isChangedSinceLastBuild()) {
alarmData = this.alarmBuilder.build(new LongUniqueId(processor.getNextId(AlarmParameterData.class)));
if(LOG.isLoggable(Level.FINER)) {
@@ -384,8 +423,9 @@ public synchronized List mirror(ParameterData itemToMirror) {
this.builder.setAlarmState(AlarmState.IGNORED);
}
// You must always build an update
- this.state = this.builder.build(new LongUniqueId(processor.getNextId(ParameterData.class)));
- generatedStates.add(this.state);
+ ParameterData newState = this.builder.build(new LongUniqueId(processor.getNextId(ParameterData.class)));
+ this.state.set(newState);
+ generatedStates.add(newState);
// Compute alarm state
alarmData = computeAlarmParameterData(true);
// Finalize entity state and prepare for the returned list of data items
@@ -431,6 +471,9 @@ private void generateAlarmMessage(AlarmParameterData alarmData) {
}
}
break;
+ default:
+ // Nothing to be done here
+ break;
}
lastReportedLogTime = now;
skippedLogMessagesCounter = 0;
@@ -441,22 +484,25 @@ private void generateAlarmMessage(AlarmParameterData alarmData) {
private void computeSystemEntityState(boolean stateChanged, List generatedStates) {
if(stateChanged) {
- this.systemEntityBuilder.setAlarmState(this.state.getAlarmState());
+ this.systemEntityBuilder.setAlarmState(getState().getAlarmState());
}
this.systemEntityBuilder.setStatus(entityStatus);
if(this.systemEntityBuilder.isChangedSinceLastBuild()) {
this.entityState = this.systemEntityBuilder.build(new LongUniqueId(processor.getNextId(SystemEntity.class)));
generatedStates.add(this.entityState);
}
+ // Clear the dirty state here
+ this.dirty = false;
}
private void activateTriggers(ParameterSample sample, Object previousValue, boolean wasInAlarm, boolean stateChanged) {
+ ParameterData currentState = getState();
for(ParameterTriggerDefinition ptd : definition.getTriggers()) {
try {
if ((ptd.getTriggerCondition() == TriggerCondition.ON_NEW_SAMPLE && sample != null && stateChanged) ||
(ptd.getTriggerCondition() == TriggerCondition.ON_ALARM_RAISED && !wasInAlarm && inAlarm()) ||
(ptd.getTriggerCondition() == TriggerCondition.ON_BACK_TO_NOMINAL && wasInAlarm && !inAlarm()) ||
- (ptd.getTriggerCondition() == TriggerCondition.ON_VALUE_CHANGE && !Objects.equals(previousValue, this.state == null ? null : this.state.getEngValue()))) {
+ (ptd.getTriggerCondition() == TriggerCondition.ON_VALUE_CHANGE && !Objects.equals(previousValue, currentState == null ? null : currentState.getEngValue()))) {
// Raise event
raiseEvent(ptd.getEvent().getId());
}
@@ -592,9 +638,7 @@ public AbstractInputDataItem generateSetRequest(SetParameterRequest request) thr
}
}
// Overwrite with the setter properties
- for (Map.Entry kv : request.getProperties().entrySet()) {
- propertyMap.put(kv.getKey(), kv.getValue());
- }
+ propertyMap.putAll(request.getProperties());
return new ActivityRequest(setter.getActivity().getId(), SystemEntityPath.fromString(setter.getActivity().getLocation()), buildSetArgumentList(request, setter), propertyMap, request.getRoute(), request.getSource());
}
}
@@ -714,14 +758,71 @@ private PlainActivityArgument createSimpleArgumentInvocation(PlainArgumentInvoca
}
@Override
- public List evaluate() throws ProcessingModelException {
- return process(null);
+ public boolean isWeaklyConsistent() {
+ return getDefinition().isWeakConsistency() && getDefinition().getExpression() != null;
+ }
+
+ @Override
+ public List evaluate(boolean includeWeakly) throws ProcessingModelException {
+ if(!includeWeakly && isWeaklyConsistent()) {
+ return computeDirtyState();
+ } else {
+ return process(null);
+ }
+ }
+
+ private synchronized List computeDirtyState() {
+ // Already marked as dirty, do nothing
+ if(this.dirty) {
+ return Collections.emptyList();
+ }
+ if(lastDependingElementState == null) {
+ lastDependingElementState = new HashMap<>();
+ }
+ boolean dirtyFlag = false;
+ Set successorEdges = getEntityVertex().getSuccessors();
+ for(DependencyEdge edge : successorEdges) {
+ if(edge.getDestination().getProcessor().getDescriptor().getType() == SystemEntityType.PARAMETER) {
+ // Get current state
+ ParameterData currentState = (ParameterData) edge.getDestination().getProcessor().getState();
+ // Get old state
+ ParameterData oldState = lastDependingElementState.get(edge.getDestination().getSystemEntityId());
+ // Check if recomputation is required
+ boolean isDirty = checkDirty(currentState, oldState);
+ lastDependingElementState.put(edge.getDestination().getSystemEntityId(), currentState);
+ if(isDirty) {
+ dirtyFlag = true;
+ break;
+ }
+ }
+ }
+ if(dirtyFlag && !this.dirty) {
+ this.dirty = true;
+ this.processor.newDirtyParameter(getSystemEntityId());
+ }
+ return Collections.emptyList();
+ }
+
+ private boolean checkDirty(ParameterData currentState, ParameterData oldState) {
+ if(oldState == null) {
+ return true;
+ }
+ if(!Objects.equals(currentState.getSourceValue(), oldState.getSourceValue())) {
+ return true;
+ }
+ if(!Objects.equals(currentState.getEngValue(), oldState.getEngValue())) {
+ return true;
+ }
+ if(!Objects.equals(currentState.getValidity(), oldState.getValidity())) {
+ return true;
+ }
+ return !Objects.equals(currentState.getAlarmState(), oldState.getAlarmState());
}
@Override
public void visit(IProcessingModelVisitor visitor) {
visitor.onVisit(getState());
- AlarmParameterData currAlarmData = currentAlarmData;
+ AlarmParameterData currAlarmData = currentAlarmData.get();
if(currAlarmData != null) {
visitor.onVisit(currAlarmData);
}
@@ -730,7 +831,7 @@ public void visit(IProcessingModelVisitor visitor) {
@Override
public void putCurrentStates(List items) {
items.add(getState());
- AlarmParameterData currAlarmData = currentAlarmData;
+ AlarmParameterData currAlarmData = currentAlarmData.get();
if(currAlarmData != null) {
items.add(currAlarmData);
}
@@ -743,38 +844,45 @@ public AbstractSystemEntityDescriptor getDescriptor() {
@Override
public Object rawValue() {
- return this.state == null ? null : this.state.getSourceValue();
+ ParameterData currentState = getState();
+ return currentState == null ? null : currentState.getSourceValue();
}
@Override
public Object value() {
- return this.state == null ? null : this.state.getEngValue();
+ ParameterData currentState = getState();
+ return currentState == null ? null : currentState.getEngValue();
}
@Override
public AlarmState alarmState() {
- return this.state == null ? AlarmState.UNKNOWN : this.state.getAlarmState();
+ ParameterData currentState = getState();
+ return currentState == null ? AlarmState.UNKNOWN : currentState.getAlarmState();
}
@Override
public boolean inAlarm() {
- return this.state != null &&
- this.state.getAlarmState().isAlarm();
+ ParameterData currentState = getState();
+ return currentState != null &&
+ currentState.getAlarmState().isAlarm();
}
@Override
public boolean valid() {
- return this.state != null && this.state.getValidity() == Validity.VALID;
+ ParameterData currentState = getState();
+ return currentState != null && currentState.getValidity() == Validity.VALID;
}
@Override
public Validity validity() {
- return this.state == null ? Validity.UNKNOWN : this.state.getValidity();
+ ParameterData currentState = getState();
+ return currentState == null ? Validity.UNKNOWN : currentState.getValidity();
}
@Override
public Long containerId() {
- return this.state == null || this.state.getRawDataContainerId() == null ? null : this.state.getRawDataContainerId().asLong();
+ ParameterData currentState = getState();
+ return currentState == null || currentState.getRawDataContainerId() == null ? null : currentState.getRawDataContainerId().asLong();
}
@Override
@@ -789,16 +897,19 @@ public String path() {
@Override
public String route() {
- return this.state == null ? null : this.state.getRoute();
+ ParameterData currentState = getState();
+ return currentState == null ? null : currentState.getRoute();
}
@Override
public Instant generationTime() {
- return this.state == null ? null : this.state.getGenerationTime();
+ ParameterData currentState = getState();
+ return currentState == null ? null : currentState.getGenerationTime();
}
@Override
public Instant receptionTime() {
- return this.state == null ? null : this.state.getReceptionTime();
+ ParameterData currentState = getState();
+ return currentState == null ? null : currentState.getReceptionTime();
}
}
diff --git a/eu.dariolucia.reatmetric.processing/src/test/java/eu/dariolucia/reatmetric/processing/impl/ParameterWeakTest.java b/eu.dariolucia.reatmetric.processing/src/test/java/eu/dariolucia/reatmetric/processing/impl/ParameterWeakTest.java
new file mode 100644
index 00000000..feebdc42
--- /dev/null
+++ b/eu.dariolucia.reatmetric.processing/src/test/java/eu/dariolucia/reatmetric/processing/impl/ParameterWeakTest.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2020 Dario Lucia (https://www.dariolucia.eu)
+ *
+ * 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 eu.dariolucia.reatmetric.processing.impl;
+
+import eu.dariolucia.reatmetric.api.common.AbstractDataItem;
+import eu.dariolucia.reatmetric.api.parameters.ParameterData;
+import eu.dariolucia.reatmetric.api.processing.IProcessingModel;
+import eu.dariolucia.reatmetric.api.processing.IProcessingModelOutput;
+import eu.dariolucia.reatmetric.api.processing.exceptions.ProcessingModelException;
+import eu.dariolucia.reatmetric.api.processing.input.ParameterSample;
+import eu.dariolucia.reatmetric.processing.definition.ProcessingDefinition;
+import jakarta.xml.bind.JAXBException;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+class ParameterWeakTest {
+
+ @BeforeEach
+ void setup() {
+ Logger packageLogger = Logger.getLogger("eu.dariolucia.reatmetric.processing");
+ packageLogger.setLevel(Level.ALL);
+ Arrays.stream(Logger.getLogger("").getHandlers()).forEach(o -> o.setLevel(Level.ALL));
+ }
+
+ @Test
+ void testWeakParameterUpdate() throws JAXBException, ProcessingModelException, InterruptedException {
+ Logger testLogger = Logger.getLogger(getClass().getName());
+ ProcessingDefinition pd = ProcessingDefinition.load(this.getClass().getClassLoader().getResourceAsStream("processing_definitions_parameters_weak.xml"));
+ ProcessingModelFactoryImpl factory = new ProcessingModelFactoryImpl();
+ List> outList = new CopyOnWriteArrayList<>();
+ // All output data items go in the outList
+ IProcessingModelOutput output = outList::add;
+ IProcessingModel model = factory.build(pd, output, null);
+
+ testLogger.info("Injection - Batch 1");
+ ParameterSample p1 = ParameterSample.of(101, true);
+ model.injectParameters(List.of(p1));
+
+ testLogger.info("Injection - Batch 2");
+ ParameterSample p2 = ParameterSample.of(104, 3);
+ ParameterSample p3 = ParameterSample.of(106, 9);
+ model.injectParameters(List.of(p2));
+ model.injectParameters(List.of(p3));
+ AwaitUtil.awaitCondition(10000, () -> outList.size() == 3);
+
+ testLogger.info("Injection - Batch 3");
+ ParameterSample p4 = ParameterSample.of(105, 1.0);
+ ParameterSample p5 = ParameterSample.of(107, 2.0);
+ ParameterSample p6 = ParameterSample.of(108, 3.0);
+ ParameterSample p7 = ParameterSample.of(102, 2);
+ model.injectParameters(List.of(p4));
+ model.injectParameters(List.of(p5, p6));
+ model.injectParameters(List.of(p7));
+
+ AwaitUtil.awaitCondition(10000, () -> outList.size() == 8);
+
+ // Check values
+ assertEquals(2, rawValueOf(102, model));
+ assertEquals(144.0, rawValueOf(1034, model));
+ assertEquals(12.0, rawValueOf(1033, model));
+ assertEquals(6.0, rawValueOf(1032, model));
+ assertEquals(12L, rawValueOf(1031, model));
+
+ assertEquals(8, outList.size());
+ }
+
+ private Object rawValueOf(int id, IProcessingModel model) throws ProcessingModelException {
+ List items = model.getById(List.of(id));
+ return ((ParameterData) items.get(0)).getSourceValue();
+ }
+}
\ No newline at end of file
diff --git a/eu.dariolucia.reatmetric.processing/src/test/resources/processing_definitions_parameters_weak.xml b/eu.dariolucia.reatmetric.processing/src/test/resources/processing_definitions_parameters_weak.xml
new file mode 100644
index 00000000..3f0ebd12
--- /dev/null
+++ b/eu.dariolucia.reatmetric.processing/src/test/resources/processing_definitions_parameters_weak.xml
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ A + B
+
+
+
+
+
+
+ A + B + C
+
+
+
+
+
+
+
+ A * K
+
+
+
+
+
+
+ A * A
+
+
+
+
+
\ No newline at end of file
diff --git a/eu.dariolucia.reatmetric.remoting.connector/pom.xml b/eu.dariolucia.reatmetric.remoting.connector/pom.xml
index 7031f0bb..18529e00 100644
--- a/eu.dariolucia.reatmetric.remoting.connector/pom.xml
+++ b/eu.dariolucia.reatmetric.remoting.connector/pom.xml
@@ -21,7 +21,7 @@
eu.dariolucia.reatmetric
eu.dariolucia.reatmetric
- 1.0.1
+ 1.0.2
4.0.0
diff --git a/eu.dariolucia.reatmetric.remoting.spacecraft/pom.xml b/eu.dariolucia.reatmetric.remoting.spacecraft/pom.xml
index 314616f1..e2620503 100644
--- a/eu.dariolucia.reatmetric.remoting.spacecraft/pom.xml
+++ b/eu.dariolucia.reatmetric.remoting.spacecraft/pom.xml
@@ -22,7 +22,7 @@
eu.dariolucia.reatmetric
eu.dariolucia.reatmetric
- 1.0.1
+ 1.0.2
4.0.0
diff --git a/eu.dariolucia.reatmetric.remoting.test/pom.xml b/eu.dariolucia.reatmetric.remoting.test/pom.xml
index 0d9e3677..22f989f3 100644
--- a/eu.dariolucia.reatmetric.remoting.test/pom.xml
+++ b/eu.dariolucia.reatmetric.remoting.test/pom.xml
@@ -22,7 +22,7 @@
eu.dariolucia.reatmetric
eu.dariolucia.reatmetric
- 1.0.1
+ 1.0.2
4.0.0
diff --git a/eu.dariolucia.reatmetric.remoting/pom.xml b/eu.dariolucia.reatmetric.remoting/pom.xml
index bf3cdd59..c049b530 100644
--- a/eu.dariolucia.reatmetric.remoting/pom.xml
+++ b/eu.dariolucia.reatmetric.remoting/pom.xml
@@ -21,7 +21,7 @@
eu.dariolucia.reatmetric
eu.dariolucia.reatmetric
- 1.0.1
+ 1.0.2
4.0.0
diff --git a/eu.dariolucia.reatmetric.scheduler/pom.xml b/eu.dariolucia.reatmetric.scheduler/pom.xml
index ba9b9cbd..416d3e90 100644
--- a/eu.dariolucia.reatmetric.scheduler/pom.xml
+++ b/eu.dariolucia.reatmetric.scheduler/pom.xml
@@ -21,7 +21,7 @@
eu.dariolucia.reatmetric
eu.dariolucia.reatmetric
- 1.0.1
+ 1.0.2
4.0.0
diff --git a/eu.dariolucia.reatmetric.ui.remoting/pom.xml b/eu.dariolucia.reatmetric.ui.remoting/pom.xml
index da2dd4b1..787560ce 100644
--- a/eu.dariolucia.reatmetric.ui.remoting/pom.xml
+++ b/eu.dariolucia.reatmetric.ui.remoting/pom.xml
@@ -22,7 +22,7 @@
eu.dariolucia.reatmetric
eu.dariolucia.reatmetric
- 1.0.1
+ 1.0.2
4.0.0
diff --git a/eu.dariolucia.reatmetric.ui.snmp/LICENSE b/eu.dariolucia.reatmetric.ui.snmp/LICENSE
new file mode 100644
index 00000000..261eeb9e
--- /dev/null
+++ b/eu.dariolucia.reatmetric.ui.snmp/LICENSE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ 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.
diff --git a/eu.dariolucia.reatmetric.ui.snmp/pom.xml b/eu.dariolucia.reatmetric.ui.snmp/pom.xml
new file mode 100644
index 00000000..7ea4d001
--- /dev/null
+++ b/eu.dariolucia.reatmetric.ui.snmp/pom.xml
@@ -0,0 +1,125 @@
+
+
+
+
+
+
+ eu.dariolucia.reatmetric
+ eu.dariolucia.reatmetric
+ 1.0.2
+
+
+ 4.0.0
+ eu.dariolucia.reatmetric.ui.snmp
+ REATMETRIC UI - SNMP Test
+ REATMETRIC JavaFX graphical interface - SNMP Test
+
+
+
+
+ org.apache.maven.plugins
+ maven-dependency-plugin
+
+
+ copy-dependencies
+ prepare-package
+
+ copy-dependencies
+
+
+ target/deps
+ true
+
+ org.junit.jupiter,org.apiguardian,org.junit.platform,org.opentest4j
+
+
+
+
+
+ true
+ true
+ ${project.build.directory}
+
+
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+ ${maven.jar.version}
+
+
+
+ true
+ deps/
+
+
+ ${project.build.directory}
+
+
+
+
+
+
+
+ eu.dariolucia.reatmetric
+ eu.dariolucia.reatmetric.api
+ ${project.parent.version}
+
+
+ eu.dariolucia.reatmetric
+ eu.dariolucia.reatmetric.core
+ ${project.parent.version}
+
+
+ eu.dariolucia.reatmetric
+ eu.dariolucia.reatmetric.scheduler
+ ${project.parent.version}
+
+
+ eu.dariolucia.reatmetric
+ eu.dariolucia.reatmetric.ui
+ ${project.parent.version}
+
+
+ eu.dariolucia.reatmetric
+ eu.dariolucia.reatmetric.driver.automation.groovy
+ ${project.parent.version}
+
+
+ eu.dariolucia.reatmetric
+ eu.dariolucia.reatmetric.driver.snmp
+ ${project.parent.version}
+
+
+ eu.dariolucia.reatmetric
+ eu.dariolucia.reatmetric.persist
+ ${project.parent.version}
+
+
+ eu.dariolucia.reatmetric
+ eu.dariolucia.reatmetric.processing
+ ${project.parent.version}
+
+
+ eu.dariolucia.reatmetric
+ eu.dariolucia.reatmetric.driver.httpserver
+ ${project.parent.version}
+
+
+
diff --git a/eu.dariolucia.reatmetric.ui.socket/pom.xml b/eu.dariolucia.reatmetric.ui.socket/pom.xml
index 3c40749f..804c8bdf 100644
--- a/eu.dariolucia.reatmetric.ui.socket/pom.xml
+++ b/eu.dariolucia.reatmetric.ui.socket/pom.xml
@@ -22,7 +22,7 @@
eu.dariolucia.reatmetric
eu.dariolucia.reatmetric
- 1.0.1
+ 1.0.2
4.0.0
diff --git a/eu.dariolucia.reatmetric.ui.spacecraft/pom.xml b/eu.dariolucia.reatmetric.ui.spacecraft/pom.xml
index b16f5011..175a4e76 100644
--- a/eu.dariolucia.reatmetric.ui.spacecraft/pom.xml
+++ b/eu.dariolucia.reatmetric.ui.spacecraft/pom.xml
@@ -22,7 +22,7 @@
eu.dariolucia.reatmetric
eu.dariolucia.reatmetric
- 1.0.1
+ 1.0.2
4.0.0
diff --git a/eu.dariolucia.reatmetric.ui.test/pom.xml b/eu.dariolucia.reatmetric.ui.test/pom.xml
index 16e640e9..5e4a3462 100644
--- a/eu.dariolucia.reatmetric.ui.test/pom.xml
+++ b/eu.dariolucia.reatmetric.ui.test/pom.xml
@@ -22,7 +22,7 @@
eu.dariolucia.reatmetric
eu.dariolucia.reatmetric
- 1.0.1
+ 1.0.2
4.0.0
diff --git a/eu.dariolucia.reatmetric.ui/pom.xml b/eu.dariolucia.reatmetric.ui/pom.xml
index 8c38cb79..49d021d3 100644
--- a/eu.dariolucia.reatmetric.ui/pom.xml
+++ b/eu.dariolucia.reatmetric.ui/pom.xml
@@ -22,7 +22,7 @@
eu.dariolucia.reatmetric
eu.dariolucia.reatmetric
- 1.0.1
+ 1.0.2
4.0.0
diff --git a/eu.dariolucia.reatmetric.ui/src/main/java/eu/dariolucia/reatmetric/ui/controller/MainViewController.java b/eu.dariolucia.reatmetric.ui/src/main/java/eu/dariolucia/reatmetric/ui/controller/MainViewController.java
index 2abac08c..6f89606a 100644
--- a/eu.dariolucia.reatmetric.ui/src/main/java/eu/dariolucia/reatmetric/ui/controller/MainViewController.java
+++ b/eu.dariolucia.reatmetric.ui/src/main/java/eu/dariolucia/reatmetric/ui/controller/MainViewController.java
@@ -67,7 +67,7 @@
import java.util.logging.Logger;
/**
- * TODO: implement activity occurrence visualisation details
+ * Main view class
*
* @author Dario Lucia
*/
diff --git a/pom.xml b/pom.xml
index b16b1a89..06a457c8 100644
--- a/pom.xml
+++ b/pom.xml
@@ -22,7 +22,7 @@
eu.dariolucia.reatmetric
eu.dariolucia.reatmetric
- 1.0.1
+ 1.0.2
pom
REATMETRIC
@@ -73,6 +73,7 @@
1.3.0
2.8.0
2.7.0
+ 3.8.2
@@ -111,11 +112,15 @@
eu.dariolucia.reatmetric.driver.remote
eu.dariolucia.reatmetric.driver.httpserver
eu.dariolucia.reatmetric.driver.socket
+ eu.dariolucia.reatmetric.driver.snmp
+ eu.dariolucia.reatmetric.driver.snmp.util
eu.dariolucia.reatmetric.ui
eu.dariolucia.reatmetric.ui.test
eu.dariolucia.reatmetric.ui.remoting
eu.dariolucia.reatmetric.ui.spacecraft
eu.dariolucia.reatmetric.ui.socket
+ eu.dariolucia.reatmetric.ui.snmp
+ eu.dariolucia.reatmetric.deployment
@@ -162,48 +167,6 @@
-
-
-
-