diff --git a/.github/workflows/reuse.yml b/.github/workflows/reuse.yml index 897b6d0..02d113f 100644 --- a/.github/workflows/reuse.yml +++ b/.github/workflows/reuse.yml @@ -1,6 +1,5 @@ -# SPDX-FileCopyrightText: 2022 Free Software Foundation Europe e.V. -# -# SPDX-License-Identifier: CC0-1.0 +#SPDX-FileCopyrightText: 2025 Enedis Smarties team +#SPDX-License-Identifier: Apache-2.0 --- name: REUSE Compliance Check diff --git a/.gitignore b/.gitignore index 29a63cf..8787fe0 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,8 @@ # # SPDX-License-Identifier: Apache-2.0 +.vscode/ +.DS_Store src/main/resources/TIC2WebSocket.properties +target/ +var/ diff --git a/CHANGELOG.fr.md b/CHANGELOG.fr.md index 90c0bfe..8f52ad7 100644 --- a/CHANGELOG.fr.md +++ b/CHANGELOG.fr.md @@ -9,6 +9,16 @@ [🇫🇷 Français](CHANGELOG.fr.md) | [🇺🇸 English](CHANGELOG.md) +## [v2.0.0](https://github.com/Enedis-OSS/TIC2WebSocket/tree/v2.0.0) +### ✨ Nouvelles fonctionnalités: +- Ajout de la découverte des ports série sous macOS (`SerialPortFinderForMacOsX`) +- Nouveaux utilitaires CLI de diagnostic (core, modem, port série, USB) +- Ajout d'une interface de test via une page HTML + +### 🔧 Améliorations & corrections: +- Refactorisation de l'architecture du projet et simplification de la structure de code +- Correction des avertissements du logger + ## [v1.0.0](https://github.com/Enedis-OSS/TIC2WebSocket/tree/v1.0.0) ### ✨ Nouvelles fonctionnalités: - Connexion et lecture des trames TIC (Télé-Information Client) via port série diff --git a/CHANGELOG.md b/CHANGELOG.md index ca39601..617bed3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,16 @@ [🇫🇷 Français](CHANGELOG.fr.md) | [🇺🇸 English](CHANGELOG.md) +## [v2.0.0](https://github.com/Enedis-OSS/TIC2WebSocket/tree/v2.0.0) +### ✨ New features: +- Added macOS serial port discovery (`SerialPortFinderForMacOsX`) +- New diagnostic CLI utilities (core, modem, serial port, USB) +- Added a test interface via an HTML page + +### 🔧 Improvements & fixes: +- Refactored project architecture and simplified code structure +- Fixed logger warnings + ## [v1.0.0](https://github.com/Enedis-OSS/TIC2WebSocket/tree/v1.0.0) ### ✨ New features: - Serial port connection and reading of TIC (Télé-Information Client) frames diff --git a/LICENSES/CC0-1.0.txt b/LICENSES/CC0-1.0.txt deleted file mode 100644 index 0e259d4..0000000 --- a/LICENSES/CC0-1.0.txt +++ /dev/null @@ -1,121 +0,0 @@ -Creative Commons Legal Code - -CC0 1.0 Universal - - CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE - LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN - ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS - INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES - REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS - PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM - THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED - HEREUNDER. - -Statement of Purpose - -The laws of most jurisdictions throughout the world automatically confer -exclusive Copyright and Related Rights (defined below) upon the creator -and subsequent owner(s) (each and all, an "owner") of an original work of -authorship and/or a database (each, a "Work"). - -Certain owners wish to permanently relinquish those rights to a Work for -the purpose of contributing to a commons of creative, cultural and -scientific works ("Commons") that the public can reliably and without fear -of later claims of infringement build upon, modify, incorporate in other -works, reuse and redistribute as freely as possible in any form whatsoever -and for any purposes, including without limitation commercial purposes. -These owners may contribute to the Commons to promote the ideal of a free -culture and the further production of creative, cultural and scientific -works, or to gain reputation or greater distribution for their Work in -part through the use and efforts of others. - -For these and/or other purposes and motivations, and without any -expectation of additional consideration or compensation, the person -associating CC0 with a Work (the "Affirmer"), to the extent that he or she -is an owner of Copyright and Related Rights in the Work, voluntarily -elects to apply CC0 to the Work and publicly distribute the Work under its -terms, with knowledge of his or her Copyright and Related Rights in the -Work and the meaning and intended legal effect of CC0 on those rights. - -1. Copyright and Related Rights. A Work made available under CC0 may be -protected by copyright and related or neighboring rights ("Copyright and -Related Rights"). Copyright and Related Rights include, but are not -limited to, the following: - - i. the right to reproduce, adapt, distribute, perform, display, - communicate, and translate a Work; - ii. moral rights retained by the original author(s) and/or performer(s); -iii. publicity and privacy rights pertaining to a person's image or - likeness depicted in a Work; - iv. rights protecting against unfair competition in regards to a Work, - subject to the limitations in paragraph 4(a), below; - v. rights protecting the extraction, dissemination, use and reuse of data - in a Work; - vi. database rights (such as those arising under Directive 96/9/EC of the - European Parliament and of the Council of 11 March 1996 on the legal - protection of databases, and under any national implementation - thereof, including any amended or successor version of such - directive); and -vii. other similar, equivalent or corresponding rights throughout the - world based on applicable law or treaty, and any national - implementations thereof. - -2. Waiver. To the greatest extent permitted by, but not in contravention -of, applicable law, Affirmer hereby overtly, fully, permanently, -irrevocably and unconditionally waives, abandons, and surrenders all of -Affirmer's Copyright and Related Rights and associated claims and causes -of action, whether now known or unknown (including existing as well as -future claims and causes of action), in the Work (i) in all territories -worldwide, (ii) for the maximum duration provided by applicable law or -treaty (including future time extensions), (iii) in any current or future -medium and for any number of copies, and (iv) for any purpose whatsoever, -including without limitation commercial, advertising or promotional -purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each -member of the public at large and to the detriment of Affirmer's heirs and -successors, fully intending that such Waiver shall not be subject to -revocation, rescission, cancellation, termination, or any other legal or -equitable action to disrupt the quiet enjoyment of the Work by the public -as contemplated by Affirmer's express Statement of Purpose. - -3. Public License Fallback. Should any part of the Waiver for any reason -be judged legally invalid or ineffective under applicable law, then the -Waiver shall be preserved to the maximum extent permitted taking into -account Affirmer's express Statement of Purpose. In addition, to the -extent the Waiver is so judged Affirmer hereby grants to each affected -person a royalty-free, non transferable, non sublicensable, non exclusive, -irrevocable and unconditional license to exercise Affirmer's Copyright and -Related Rights in the Work (i) in all territories worldwide, (ii) for the -maximum duration provided by applicable law or treaty (including future -time extensions), (iii) in any current or future medium and for any number -of copies, and (iv) for any purpose whatsoever, including without -limitation commercial, advertising or promotional purposes (the -"License"). The License shall be deemed effective as of the date CC0 was -applied by Affirmer to the Work. Should any part of the License for any -reason be judged legally invalid or ineffective under applicable law, such -partial invalidity or ineffectiveness shall not invalidate the remainder -of the License, and in such case Affirmer hereby affirms that he or she -will not (i) exercise any of his or her remaining Copyright and Related -Rights in the Work or (ii) assert any associated claims and causes of -action with respect to the Work, in either case contrary to Affirmer's -express Statement of Purpose. - -4. Limitations and Disclaimers. - - a. No trademark or patent rights held by Affirmer are waived, abandoned, - surrendered, licensed or otherwise affected by this document. - b. Affirmer offers the Work as-is and makes no representations or - warranties of any kind concerning the Work, express, implied, - statutory or otherwise, including without limitation warranties of - title, merchantability, fitness for a particular purpose, non - infringement, or the absence of latent or other defects, accuracy, or - the present or absence of errors, whether or not discoverable, all to - the greatest extent permissible under applicable law. - c. Affirmer disclaims responsibility for clearing rights of other persons - that may apply to the Work or any use thereof, including without - limitation any person's Copyright and Related Rights in the Work. - Further, Affirmer disclaims responsibility for obtaining any necessary - consents, permissions or other rights required for any use of the - Work. - d. Affirmer understands and acknowledges that Creative Commons is not a - party to this document and has no duty or obligation with respect to - this CC0 or use of the Work. diff --git a/README.fr.md b/README.fr.md index d261e98..3de3070 100644 --- a/README.fr.md +++ b/README.fr.md @@ -91,7 +91,20 @@ Ajoutez l'option `--help` pour obtenir des informations de base sur l'utilisatio ## Documentation -[TODO] +### Page HTML de test WebSocket + +Une page HTML autonome est disponible pour tester rapidement l’API WebSocket : + +- Fichier : [docs/ws-tester.html](docs/ws-tester.html) +- URL par défaut : `ws://localhost:19584/` + +Fonctionnement : + +- Ouvrez la page dans un navigateur (optionnel : servez le dossier `docs/` via un serveur HTTP statique). +- Renseignez l’URL WebSocket (ou host/port), puis cliquez sur `Connect`. +- Choisissez une requête prédéfinie (`GetModemsInfo`, `GetAvailableTICs`, `ReadTIC`, `SubscribeTIC`, `UnsubscribeTIC`) puis cliquez sur `Send`. +- Les filtres d’identifiant (SerialNumber / PortId / PortName) permettent de cibler un TIC. +- Les messages entrants s’affichent dans Logs ; les messages de type `EVENT` sont regroupés par `(nom d’événement + identifiant)`. ## Contribuer ? diff --git a/README.md b/README.md index 297cad2..5a75266 100644 --- a/README.md +++ b/README.md @@ -91,7 +91,20 @@ Add `--help` option to get basic information on how to use the launcher. ## Documentation -[TODO] +### WebSocket tester (HTML) + +A small, self-contained HTML page is available to quickly test the WebSocket API: + +- File: [docs/ws-tester.html](docs/ws-tester.html) +- Default URL: `ws://localhost:19584/` + +How it works: + +- Open the page in a browser (optionally serve the `docs/` folder with any static server). +- Set the WebSocket URL (or host/port), click `Connect`. +- Pick a request preset (`GetModemsInfo`, `GetAvailableTICs`, `ReadTIC`, `SubscribeTIC`, `UnsubscribeTIC`) and click `Send`. +- Optional identifier filters (SerialNumber / PortId / PortName) help target a specific TIC. +- Incoming messages are displayed in the Logs panel; `EVENT` messages are grouped by `(event name + identifier)` for readability. ## Contributing ? diff --git a/REUSE.toml b/REUSE.toml new file mode 100644 index 0000000..b5c7366 --- /dev/null +++ b/REUSE.toml @@ -0,0 +1,20 @@ +# SPDX-FileCopyrightText: 2025 Enedis Smarties team +# SPDX-FileContributor: Jehan BOUSCH +# SPDX-FileContributor: Mathieu SABARTHES +# +# SPDX-License-Identifier: Apache-2.0 + +version = 1 + +# A simple glob of all excluded file types in the project +[[annotations]] +path = [ + "**/*.txt", + "**/*.json", + "**/*.woff", + "**/*.woff2", + "**/*.html", + "**/*.svg" +] +SPDX-FileCopyrightText = "2025 Enedis Smarties team " +SPDX-License-Identifier = "Apache-2.0" \ No newline at end of file diff --git a/docs/assets/enedis-logo.svg b/docs/assets/enedis-logo.svg new file mode 100644 index 0000000..53c68c7 --- /dev/null +++ b/docs/assets/enedis-logo.svg @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/assets/fonts/Enedis-Black.woff b/docs/assets/fonts/Enedis-Black.woff new file mode 100644 index 0000000..8e6d337 Binary files /dev/null and b/docs/assets/fonts/Enedis-Black.woff differ diff --git a/docs/assets/fonts/Enedis-Black.woff2 b/docs/assets/fonts/Enedis-Black.woff2 new file mode 100644 index 0000000..b7fe548 Binary files /dev/null and b/docs/assets/fonts/Enedis-Black.woff2 differ diff --git a/docs/assets/fonts/Enedis-Bold.woff b/docs/assets/fonts/Enedis-Bold.woff new file mode 100644 index 0000000..8634486 Binary files /dev/null and b/docs/assets/fonts/Enedis-Bold.woff differ diff --git a/docs/assets/fonts/Enedis-Bold.woff2 b/docs/assets/fonts/Enedis-Bold.woff2 new file mode 100644 index 0000000..f7efc5c Binary files /dev/null and b/docs/assets/fonts/Enedis-Bold.woff2 differ diff --git a/docs/assets/fonts/Enedis-Light.woff b/docs/assets/fonts/Enedis-Light.woff new file mode 100644 index 0000000..168b1f2 Binary files /dev/null and b/docs/assets/fonts/Enedis-Light.woff differ diff --git a/docs/assets/fonts/Enedis-Light.woff2 b/docs/assets/fonts/Enedis-Light.woff2 new file mode 100644 index 0000000..aea44b7 Binary files /dev/null and b/docs/assets/fonts/Enedis-Light.woff2 differ diff --git a/docs/assets/fonts/Enedis-Medium.woff b/docs/assets/fonts/Enedis-Medium.woff new file mode 100644 index 0000000..22b5e6d Binary files /dev/null and b/docs/assets/fonts/Enedis-Medium.woff differ diff --git a/docs/assets/fonts/Enedis-Medium.woff2 b/docs/assets/fonts/Enedis-Medium.woff2 new file mode 100644 index 0000000..21e5790 Binary files /dev/null and b/docs/assets/fonts/Enedis-Medium.woff2 differ diff --git a/docs/assets/fonts/Enedis-Regular.woff b/docs/assets/fonts/Enedis-Regular.woff new file mode 100644 index 0000000..e0cbd9c Binary files /dev/null and b/docs/assets/fonts/Enedis-Regular.woff differ diff --git a/docs/assets/fonts/Enedis-Regular.woff2 b/docs/assets/fonts/Enedis-Regular.woff2 new file mode 100644 index 0000000..27c7cbb Binary files /dev/null and b/docs/assets/fonts/Enedis-Regular.woff2 differ diff --git a/docs/assets/fonts/Enedis-Thin.woff b/docs/assets/fonts/Enedis-Thin.woff new file mode 100644 index 0000000..1532664 Binary files /dev/null and b/docs/assets/fonts/Enedis-Thin.woff differ diff --git a/docs/assets/fonts/Enedis-Thin.woff2 b/docs/assets/fonts/Enedis-Thin.woff2 new file mode 100644 index 0000000..ab09464 Binary files /dev/null and b/docs/assets/fonts/Enedis-Thin.woff2 differ diff --git a/docs/ws-tester.html b/docs/ws-tester.html new file mode 100644 index 0000000..4a6e1b6 --- /dev/null +++ b/docs/ws-tester.html @@ -0,0 +1,1179 @@ + + + + + + + TIC2WebSocket Tester + + + + +
+
+
+
+ +
+

TIC2WebSocket Tester

+

Connect to ws://localhost:19584/ then pick a request (e.g. + GetModemsInfo, + GetAvailableTICs, ReadTIC, SubscribeTIC...). +

+
+
+
+
+ +
+
+

Connection

+
+ + + +
+
+ + +
+
+ + +
+
+ +
+
+ + +
+
+ + +
+
+ +
+
+ +

+ Select 0 to 3 fields. If none is selected, the request is sent as the all + variant (except ReadTIC which requires one identifier). + Priority: SerialNumber > PortId > + PortName. + Lower-priority fields are disabled when a higher-priority one is active. +

+ +
+
+ 1 + + +
+
+ 2 + + +
+
+ 3 + + +
+
+ +

+
+
+ + + + +
+ + + + +
+ +
+ + Disconnected +
+ +

+ Tip: open your browser console to see JS errors. +

+
+
+ +
+

Logs

+
+
+
+ + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml index 1b9a087..2839092 100644 --- a/pom.xml +++ b/pom.xml @@ -6,26 +6,25 @@ SPDX-License-Identifier: Apache-2.0 --> + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - + fr.enedis TIC2WebSocket - 1.0.0 + 2.0.0 jar ${project.artifactId} - Tele Information Client (TIC) WebSocket Interface + Tele Information Client (TIC) WebSocket Interface Enedis http://www.enedis.fr/ - + Apache-2.0 @@ -35,7 +34,7 @@ SPDX-License-Identifier: Apache-2.0 - + Jehan BOUSCH @@ -61,25 +60,25 @@ SPDX-License-Identifier: Apache-2.0 - - + + - - + + - - + + - - + + - - + + - - + + - + UTF-8 UTF-8 @@ -90,10 +89,10 @@ SPDX-License-Identifier: Apache-2.0 ${project.name} ${project.version} ${project.description} - ./images/team + ./images/team - + junit @@ -101,6 +100,18 @@ SPDX-License-Identifier: Apache-2.0 4.13.2 test + + org.skyscreamer + jsonassert + 1.5.1 + test + + + com.vaadin.external.google + android-json + + + org.json json @@ -111,6 +122,12 @@ SPDX-License-Identifier: Apache-2.0 log4j-core 2.17.2 + + org.apache.logging.log4j + log4j-slf4j-impl + 2.17.2 + runtime + io.github.java-native jssc @@ -143,7 +160,7 @@ SPDX-License-Identifier: Apache-2.0 - + @@ -312,10 +329,20 @@ SPDX-License-Identifier: Apache-2.0 + + com.diffplug.spotless + spotless-maven-plugin + 2.43.0 + + + + + + - + @@ -326,13 +353,13 @@ SPDX-License-Identifier: Apache-2.0 - - + + - - + + - - + + diff --git a/src/assembly/all.xml b/src/assembly/all.xml index 1e81400..86768ec 100644 --- a/src/assembly/all.xml +++ b/src/assembly/all.xml @@ -8,76 +8,121 @@ SPDX-License-Identifier: Apache-2.0 --> + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd"> all zip tar.gz false + true - lib + app/lib false + CHANGELOG.md - CHANGELOG.md + app/CHANGELOG.md LICENCE.txt LICENCE.txt + + + + ${project.build.scriptSourceDirectory}/launcher/${project.name}.bat + app/${project.name}.bat + + + ${project.build.scriptSourceDirectory}/launcher/${project.name}.sh + app/${project.name}.sh + 0755 + + + + + ${project.build.scriptSourceDirectory}/debug/${project.name}_remote_debug.sh + debug/${project.name}_remote_debug.sh + 0755 + + + + + ${project.build.scriptSourceDirectory}/diagnostic/SerialPortFinder.bat + diagnostic/SerialPortFinder.bat + - ${project.build.scriptSourceDirectory}/${project.name}.bat - ${project.name}.bat + ${project.build.scriptSourceDirectory}/diagnostic/SerialPortFinder.sh + diagnostic/SerialPortFinder.sh + 0755 + + + ${project.build.scriptSourceDirectory}/diagnostic/UsbPortFinder.bat + diagnostic/UsbPortFinder.bat + + + ${project.build.scriptSourceDirectory}/diagnostic/UsbPortFinder.sh + diagnostic/UsbPortFinder.sh + 0755 + + + ${project.build.scriptSourceDirectory}/diagnostic/ModemFinder.bat + diagnostic/ModemFinder.bat - ${project.build.scriptSourceDirectory}/${project.name}.sh - ${project.name}.sh + ${project.build.scriptSourceDirectory}/diagnostic/ModemFinder.sh + diagnostic/ModemFinder.sh 0755 - ${project.build.scriptSourceDirectory}/SerialPortPlugNotifier.bat - SerialPortPlugNotifier.bat + ${project.build.scriptSourceDirectory}/diagnostic/ModemPlugNotifier.bat + diagnostic/ModemPlugNotifier.bat - ${project.build.scriptSourceDirectory}/SerialPortPlugNotifier.sh - SerialPortPlugNotifier.sh + ${project.build.scriptSourceDirectory}/diagnostic/ModemPlugNotifier.sh + diagnostic/ModemPlugNotifier.sh 0755 - ${project.build.scriptSourceDirectory}/TICPortPlugNotifier.bat - TICPortPlugNotifier.bat + ${project.build.scriptSourceDirectory}/diagnostic/TICCore.bat + diagnostic/TICCore.bat - ${project.build.scriptSourceDirectory}/TICPortPlugNotifier.sh - TICPortPlugNotifier.sh + ${project.build.scriptSourceDirectory}/diagnostic/TICCore.sh + diagnostic/TICCore.sh 0755 - ${project.build.scriptSourceDirectory}/TICPortDump.bat - TICPortDump.bat + ${project.build.scriptSourceDirectory}/diagnostic/TICPortDump.bat + diagnostic/TICPortDump.bat - ${project.build.scriptSourceDirectory}/TICPortDump.ps1 - TICPortDump.ps1 + ${project.build.scriptSourceDirectory}/diagnostic/TICPortDump.ps1 + diagnostic/TICPortDump.ps1 - ${project.build.scriptSourceDirectory}/TICPortDump.sh - TICPortDump.sh + ${project.build.scriptSourceDirectory}/diagnostic/TICPortDump.sh + diagnostic/TICPortDump.sh 0755 + ${basedir}/src/main/resources/config - var/config + app/var/config + true + + + ${basedir}/LICENSES + app/LICENSES true @@ -86,10 +131,18 @@ SPDX-License-Identifier: Apache-2.0 **/*.log **/.settings/** + CHANGELOG.md + LICENSES/** + docs/** **/var/** **/${project.build.directory}/** + + ${basedir}/docs + tester + true + ${project.build.directory}/site doc @@ -99,4 +152,4 @@ SPDX-License-Identifier: Apache-2.0 - + \ No newline at end of file diff --git a/src/assembly/bin.xml b/src/assembly/bin.xml index efe8df6..42b17b9 100644 --- a/src/assembly/bin.xml +++ b/src/assembly/bin.xml @@ -8,9 +8,8 @@ SPDX-License-Identifier: Apache-2.0 --> + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3 http://maven.apache.org/xsd/assembly-1.1.3.xsd"> bin @@ -19,67 +18,114 @@ SPDX-License-Identifier: Apache-2.0 tar.gz false + true - lib + app/lib false + CHANGELOG.md - CHANGELOG.md + app/CHANGELOG.md + + + + + ${project.build.scriptSourceDirectory}/launcher/${project.name}.bat + app/${project.name}.bat + + + ${project.build.scriptSourceDirectory}/launcher/${project.name}.sh + app/${project.name}.sh + 0755 + + + + + ${project.build.scriptSourceDirectory}/debug/${project.name}_remote_debug.sh + debug/${project.name}_remote_debug.sh + 0755 + + + + + ${project.build.scriptSourceDirectory}/diagnostic/SerialPortFinder.bat + diagnostic/SerialPortFinder.bat + + + ${project.build.scriptSourceDirectory}/diagnostic/SerialPortFinder.sh + diagnostic/SerialPortFinder.sh + 0755 + + + ${project.build.scriptSourceDirectory}/diagnostic/UsbPortFinder.bat + diagnostic/UsbPortFinder.bat + + + ${project.build.scriptSourceDirectory}/diagnostic/UsbPortFinder.sh + diagnostic/UsbPortFinder.sh + 0755 - - ${project.build.scriptSourceDirectory}/${project.name}.bat - ${project.name}.bat + + ${project.build.scriptSourceDirectory}/diagnostic/ModemFinder.bat + diagnostic/ModemFinder.bat - ${project.build.scriptSourceDirectory}/${project.name}.sh - ${project.name}.sh + ${project.build.scriptSourceDirectory}/diagnostic/ModemFinder.sh + diagnostic/ModemFinder.sh 0755 - ${project.build.scriptSourceDirectory}/SerialPortPlugNotifier.bat - SerialPortPlugNotifier.bat + ${project.build.scriptSourceDirectory}/diagnostic/ModemPlugNotifier.bat + diagnostic/ModemPlugNotifier.bat - ${project.build.scriptSourceDirectory}/SerialPortPlugNotifier.sh - SerialPortPlugNotifier.sh + ${project.build.scriptSourceDirectory}/diagnostic/ModemPlugNotifier.sh + diagnostic/ModemPlugNotifier.sh 0755 - ${project.build.scriptSourceDirectory}/TICPortPlugNotifier.bat - TICPortPlugNotifier.bat + ${project.build.scriptSourceDirectory}/diagnostic/TICCore.bat + diagnostic/TICCore.bat - ${project.build.scriptSourceDirectory}/TICPortPlugNotifier.sh - TICPortPlugNotifier.sh + ${project.build.scriptSourceDirectory}/diagnostic/TICCore.sh + diagnostic/TICCore.sh 0755 - ${project.build.scriptSourceDirectory}/TICPortDump.bat - TICPortDump.bat + ${project.build.scriptSourceDirectory}/diagnostic/TICPortDump.bat + diagnostic/TICPortDump.bat - ${project.build.scriptSourceDirectory}/TICPortDump.ps1 - TICPortDump.ps1 + ${project.build.scriptSourceDirectory}/diagnostic/TICPortDump.ps1 + diagnostic/TICPortDump.ps1 - ${project.build.scriptSourceDirectory}/TICPortDump.sh - TICPortDump.sh + ${project.build.scriptSourceDirectory}/diagnostic/TICPortDump.sh + diagnostic/TICPortDump.sh 0755 + ${basedir}/src/main/resources/config - var/config + app/var/config + true + + + ${basedir}/docs + tester true ${basedir}/LICENSES + app/LICENSES \ No newline at end of file diff --git a/src/assembly/doc.xml b/src/assembly/doc.xml index 9a2fe16..47ec092 100644 --- a/src/assembly/doc.xml +++ b/src/assembly/doc.xml @@ -8,9 +8,8 @@ SPDX-License-Identifier: Apache-2.0 --> + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3 http://maven.apache.org/xsd/assembly-1.1.3.xsd"> doc zip @@ -20,7 +19,7 @@ SPDX-License-Identifier: Apache-2.0 ${project.build.directory}/site - . + . true **/*.log diff --git a/src/assembly/src.xml b/src/assembly/src.xml index 9769f18..28de888 100644 --- a/src/assembly/src.xml +++ b/src/assembly/src.xml @@ -8,9 +8,8 @@ SPDX-License-Identifier: Apache-2.0 --> + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3 http://maven.apache.org/xsd/assembly-1.1.3.xsd"> src zip @@ -23,9 +22,9 @@ SPDX-License-Identifier: Apache-2.0 true **/*.log - **/var/** + **/var/** **/${project.build.directory}/** - + \ No newline at end of file diff --git a/src/dataDictionaryDescriptors/config/TIC2WebSocketConfiguration.json b/src/dataDictionaryDescriptors/config/TIC2WebSocketConfiguration.json deleted file mode 100644 index f15c099..0000000 --- a/src/dataDictionaryDescriptors/config/TIC2WebSocketConfiguration.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "package" : "enedis.tic.service.config", - "name": "TIC2WebSocketConfiguration", - "type": "ConfigurationBase", - "attributes": [ - { - "name": "serverPort", - "mandatory": true, - "type": "Number", - "constraint": "MinMax", - "min": 1, - "max": 65535 - }, - { - "name": "ticMode", - "mandatory": false, - "type": "Enum", - "enumType": "TICMode" - }, - { - "name": "ticPortNames", - "mandatory": false, - "type": "List", - "listType": "String", - "constraint": "MinMaxSize", - "min": 1 - } - ] -} diff --git a/src/dataDictionaryDescriptors/config/TIC2WebSocketConfiguration.json.license b/src/dataDictionaryDescriptors/config/TIC2WebSocketConfiguration.json.license deleted file mode 100644 index 18bf6d4..0000000 --- a/src/dataDictionaryDescriptors/config/TIC2WebSocketConfiguration.json.license +++ /dev/null @@ -1,6 +0,0 @@ -Copyright (C) 2025 Enedis Smarties team - -SPDX-FileContributor: Jehan BOUSCH -SPDX-FileContributor: Mathieu SABARTHES - -SPDX-License-Identifier: Apache-2.0 diff --git a/src/dataDictionaryDescriptors/message/EventOnError.json b/src/dataDictionaryDescriptors/message/EventOnError.json deleted file mode 100644 index a00674f..0000000 --- a/src/dataDictionaryDescriptors/message/EventOnError.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "package": "enedis.tic.service.message", - "name": "EventOnError", - "extends" : "Event", - "type": "DataDictionaryBase", - "superAttributes": [ - { - "name": "name", - "type": "String", - "acceptedValues": "\"OnError\"", - "removeFromConstructor" : true - }, - { - "name": "dateTime", - "type": "LocalDateTime" - } - ], - "attributes": [ - { - "name": "data", - "mandatory" : false, - "type": "DataDictionary", - "dataDictionaryType": "TICCoreError" - } - ] -} \ No newline at end of file diff --git a/src/dataDictionaryDescriptors/message/EventOnError.json.license b/src/dataDictionaryDescriptors/message/EventOnError.json.license deleted file mode 100644 index 18bf6d4..0000000 --- a/src/dataDictionaryDescriptors/message/EventOnError.json.license +++ /dev/null @@ -1,6 +0,0 @@ -Copyright (C) 2025 Enedis Smarties team - -SPDX-FileContributor: Jehan BOUSCH -SPDX-FileContributor: Mathieu SABARTHES - -SPDX-License-Identifier: Apache-2.0 diff --git a/src/dataDictionaryDescriptors/message/EventOnTICData.json b/src/dataDictionaryDescriptors/message/EventOnTICData.json deleted file mode 100644 index 180d5fd..0000000 --- a/src/dataDictionaryDescriptors/message/EventOnTICData.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "package": "enedis.tic.service.message", - "name": "EventOnTICData", - "extends" : "Event", - "type": "DataDictionaryBase", - "superAttributes": [ - { - "name": "name", - "type": "String", - "acceptedValues": "\"OnTICData\"", - "removeFromConstructor" : true - }, - { - "name": "dateTime", - "type": "LocalDateTime" - } - ], - "attributes": [ - { - "name": "data", - "mandatory" : true, - "type": "DataDictionary", - "dataDictionaryType": "TICCoreFrame" - } - ] -} \ No newline at end of file diff --git a/src/dataDictionaryDescriptors/message/EventOnTICData.json.license b/src/dataDictionaryDescriptors/message/EventOnTICData.json.license deleted file mode 100644 index 18bf6d4..0000000 --- a/src/dataDictionaryDescriptors/message/EventOnTICData.json.license +++ /dev/null @@ -1,6 +0,0 @@ -Copyright (C) 2025 Enedis Smarties team - -SPDX-FileContributor: Jehan BOUSCH -SPDX-FileContributor: Mathieu SABARTHES - -SPDX-License-Identifier: Apache-2.0 diff --git a/src/dataDictionaryDescriptors/message/RequestGetAvailableTICs.json b/src/dataDictionaryDescriptors/message/RequestGetAvailableTICs.json deleted file mode 100644 index afa0795..0000000 --- a/src/dataDictionaryDescriptors/message/RequestGetAvailableTICs.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "package": "enedis.tic.service.message", - "name": "RequestGetAvailableTICs", - "extends" : "Request", - "type": "DataDictionaryBase", - "superAttributes": [ - { - "name": "name", - "type": "String", - "acceptedValues": "\"GetAvailableTICs\"", - "removeFromConstructor" : true - } - ] -} \ No newline at end of file diff --git a/src/dataDictionaryDescriptors/message/RequestGetAvailableTICs.json.license b/src/dataDictionaryDescriptors/message/RequestGetAvailableTICs.json.license deleted file mode 100644 index 18bf6d4..0000000 --- a/src/dataDictionaryDescriptors/message/RequestGetAvailableTICs.json.license +++ /dev/null @@ -1,6 +0,0 @@ -Copyright (C) 2025 Enedis Smarties team - -SPDX-FileContributor: Jehan BOUSCH -SPDX-FileContributor: Mathieu SABARTHES - -SPDX-License-Identifier: Apache-2.0 diff --git a/src/dataDictionaryDescriptors/message/RequestGetModemsInfo.json b/src/dataDictionaryDescriptors/message/RequestGetModemsInfo.json deleted file mode 100644 index 2846109..0000000 --- a/src/dataDictionaryDescriptors/message/RequestGetModemsInfo.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "package": "enedis.tic.service.message", - "name": "RequestGetModemsInfo", - "extends" : "Request", - "type": "DataDictionaryBase", - "superAttributes": [ - { - "name": "name", - "type": "String", - "acceptedValues": "\"GetModemsInfo\"", - "removeFromConstructor" : true - } - ] -} \ No newline at end of file diff --git a/src/dataDictionaryDescriptors/message/RequestGetModemsInfo.json.license b/src/dataDictionaryDescriptors/message/RequestGetModemsInfo.json.license deleted file mode 100644 index 18bf6d4..0000000 --- a/src/dataDictionaryDescriptors/message/RequestGetModemsInfo.json.license +++ /dev/null @@ -1,6 +0,0 @@ -Copyright (C) 2025 Enedis Smarties team - -SPDX-FileContributor: Jehan BOUSCH -SPDX-FileContributor: Mathieu SABARTHES - -SPDX-License-Identifier: Apache-2.0 diff --git a/src/dataDictionaryDescriptors/message/RequestReadTIC.json b/src/dataDictionaryDescriptors/message/RequestReadTIC.json deleted file mode 100644 index 30ca65a..0000000 --- a/src/dataDictionaryDescriptors/message/RequestReadTIC.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "package": "enedis.tic.service.message", - "name": "RequestReadTIC", - "extends" : "Request", - "type": "DataDictionaryBase", - "superAttributes": [ - { - "name": "name", - "type": "String", - "acceptedValues": "\"ReadTIC\"", - "removeFromConstructor" : true - } - ], - "attributes": [ - { - "name": "data", - "mandatory" : true, - "type": "DataDictionary", - "dataDictionaryType": "TICIdentifier" - } - ] -} \ No newline at end of file diff --git a/src/dataDictionaryDescriptors/message/RequestReadTIC.json.license b/src/dataDictionaryDescriptors/message/RequestReadTIC.json.license deleted file mode 100644 index 18bf6d4..0000000 --- a/src/dataDictionaryDescriptors/message/RequestReadTIC.json.license +++ /dev/null @@ -1,6 +0,0 @@ -Copyright (C) 2025 Enedis Smarties team - -SPDX-FileContributor: Jehan BOUSCH -SPDX-FileContributor: Mathieu SABARTHES - -SPDX-License-Identifier: Apache-2.0 diff --git a/src/dataDictionaryDescriptors/message/RequestSubscribeTIC.json b/src/dataDictionaryDescriptors/message/RequestSubscribeTIC.json deleted file mode 100644 index f97b2fb..0000000 --- a/src/dataDictionaryDescriptors/message/RequestSubscribeTIC.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "package": "enedis.tic.service.message", - "name": "RequestSubscribeTIC", - "extends" : "Request", - "type": "DataDictionaryBase", - "superAttributes": [ - { - "name": "name", - "type": "String", - "acceptedValues": "\"SubscribeTIC\"", - "removeFromConstructor" : true - } - ], - "attributes": [ - { - "name": "data", - "mandatory" : false, - "type": "List", - "listType": "TICIdentifier" - } - ] -} \ No newline at end of file diff --git a/src/dataDictionaryDescriptors/message/RequestSubscribeTIC.json.license b/src/dataDictionaryDescriptors/message/RequestSubscribeTIC.json.license deleted file mode 100644 index 18bf6d4..0000000 --- a/src/dataDictionaryDescriptors/message/RequestSubscribeTIC.json.license +++ /dev/null @@ -1,6 +0,0 @@ -Copyright (C) 2025 Enedis Smarties team - -SPDX-FileContributor: Jehan BOUSCH -SPDX-FileContributor: Mathieu SABARTHES - -SPDX-License-Identifier: Apache-2.0 diff --git a/src/dataDictionaryDescriptors/message/RequestUnsubscribeTIC.json b/src/dataDictionaryDescriptors/message/RequestUnsubscribeTIC.json deleted file mode 100644 index fd33cd9..0000000 --- a/src/dataDictionaryDescriptors/message/RequestUnsubscribeTIC.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "package": "enedis.tic.service.message", - "name": "RequestUnsubscribeTIC", - "extends" : "Request", - "type": "DataDictionaryBase", - "superAttributes": [ - { - "name": "name", - "type": "String", - "acceptedValues": "\"UnsubscribeTIC\"", - "removeFromConstructor" : true - } - ], - "attributes": [ - { - "name": "data", - "mandatory" : false, - "type": "List", - "listType": "TICIdentifier" - } - ] -} \ No newline at end of file diff --git a/src/dataDictionaryDescriptors/message/RequestUnsubscribeTIC.json.license b/src/dataDictionaryDescriptors/message/RequestUnsubscribeTIC.json.license deleted file mode 100644 index 18bf6d4..0000000 --- a/src/dataDictionaryDescriptors/message/RequestUnsubscribeTIC.json.license +++ /dev/null @@ -1,6 +0,0 @@ -Copyright (C) 2025 Enedis Smarties team - -SPDX-FileContributor: Jehan BOUSCH -SPDX-FileContributor: Mathieu SABARTHES - -SPDX-License-Identifier: Apache-2.0 diff --git a/src/dataDictionaryDescriptors/message/ResponseGetAvailableTICs.json b/src/dataDictionaryDescriptors/message/ResponseGetAvailableTICs.json deleted file mode 100644 index cb53f58..0000000 --- a/src/dataDictionaryDescriptors/message/ResponseGetAvailableTICs.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "package": "enedis.tic.service.message", - "name": "ResponseGetAvailableTICs", - "extends" : "Response", - "type": "DataDictionaryBase", - "superAttributes": [ - { - "name": "name", - "type": "String", - "acceptedValues": "\"GetAvailableTICs\"", - "removeFromConstructor" : true - }, - { - "name": "dateTime", - "type": "LocalDateTime" - }, - { - "name": "errorCode", - "type": "Number" - }, - { - "name": "errorMessage", - "type": "String" - } - ], - "attributes": [ - { - "name": "data", - "mandatory" : false, - "type": "List", - "listType": "TICIdentifier" - } - ] -} \ No newline at end of file diff --git a/src/dataDictionaryDescriptors/message/ResponseGetAvailableTICs.json.license b/src/dataDictionaryDescriptors/message/ResponseGetAvailableTICs.json.license deleted file mode 100644 index 18bf6d4..0000000 --- a/src/dataDictionaryDescriptors/message/ResponseGetAvailableTICs.json.license +++ /dev/null @@ -1,6 +0,0 @@ -Copyright (C) 2025 Enedis Smarties team - -SPDX-FileContributor: Jehan BOUSCH -SPDX-FileContributor: Mathieu SABARTHES - -SPDX-License-Identifier: Apache-2.0 diff --git a/src/dataDictionaryDescriptors/message/ResponseGetModemsInfo.json b/src/dataDictionaryDescriptors/message/ResponseGetModemsInfo.json deleted file mode 100644 index dbc7c86..0000000 --- a/src/dataDictionaryDescriptors/message/ResponseGetModemsInfo.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "package": "enedis.tic.service.message", - "name": "ResponseGetModemsInfo", - "extends" : "Response", - "type": "DataDictionaryBase", - "superAttributes": [ - { - "name": "name", - "type": "String", - "acceptedValues": "\"GetModemsInfo\"", - "removeFromConstructor" : true - }, - { - "name": "dateTime", - "type": "LocalDateTime" - }, - { - "name": "errorCode", - "type": "Number" - }, - { - "name": "errorMessage", - "type": "String" - } - ], - "attributes": [ - { - "name": "data", - "mandatory" : false, - "type": "List", - "listType": "TICPortDescriptor" - } - ] -} \ No newline at end of file diff --git a/src/dataDictionaryDescriptors/message/ResponseGetModemsInfo.json.license b/src/dataDictionaryDescriptors/message/ResponseGetModemsInfo.json.license deleted file mode 100644 index 18bf6d4..0000000 --- a/src/dataDictionaryDescriptors/message/ResponseGetModemsInfo.json.license +++ /dev/null @@ -1,6 +0,0 @@ -Copyright (C) 2025 Enedis Smarties team - -SPDX-FileContributor: Jehan BOUSCH -SPDX-FileContributor: Mathieu SABARTHES - -SPDX-License-Identifier: Apache-2.0 diff --git a/src/dataDictionaryDescriptors/message/ResponseReadTIC.json b/src/dataDictionaryDescriptors/message/ResponseReadTIC.json deleted file mode 100644 index 9498969..0000000 --- a/src/dataDictionaryDescriptors/message/ResponseReadTIC.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "package": "enedis.tic.service.message", - "name": "ResponseReadTIC", - "extends" : "Response", - "type": "DataDictionaryBase", - "superAttributes": [ - { - "name": "name", - "type": "String", - "acceptedValues": "\"ReadTIC\"", - "removeFromConstructor" : true - }, - { - "name": "dateTime", - "type": "LocalDateTime" - }, - { - "name": "errorCode", - "type": "Number" - }, - { - "name": "errorMessage", - "type": "String" - } - ], - "attributes": [ - { - "name": "data", - "mandatory" : false, - "type": "DataDictionary", - "dataDictionaryType": "TICCoreFrame" - } - ] -} \ No newline at end of file diff --git a/src/dataDictionaryDescriptors/message/ResponseReadTIC.json.license b/src/dataDictionaryDescriptors/message/ResponseReadTIC.json.license deleted file mode 100644 index 18bf6d4..0000000 --- a/src/dataDictionaryDescriptors/message/ResponseReadTIC.json.license +++ /dev/null @@ -1,6 +0,0 @@ -Copyright (C) 2025 Enedis Smarties team - -SPDX-FileContributor: Jehan BOUSCH -SPDX-FileContributor: Mathieu SABARTHES - -SPDX-License-Identifier: Apache-2.0 diff --git a/src/dataDictionaryDescriptors/message/ResponseSubscribeTIC.json b/src/dataDictionaryDescriptors/message/ResponseSubscribeTIC.json deleted file mode 100644 index 7de0ca3..0000000 --- a/src/dataDictionaryDescriptors/message/ResponseSubscribeTIC.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "package": "enedis.tic.service.message", - "name": "ResponseSubscribeTIC", - "extends" : "Response", - "type": "DataDictionaryBase", - "superAttributes": [ - { - "name": "name", - "type": "String", - "acceptedValues": "\"SubscribeTIC\"", - "removeFromConstructor" : true - }, - { - "name": "dateTime", - "type": "LocalDateTime" - }, - { - "name": "errorCode", - "type": "Number" - }, - { - "name": "errorMessage", - "type": "String" - } - ] -} \ No newline at end of file diff --git a/src/dataDictionaryDescriptors/message/ResponseSubscribeTIC.json.license b/src/dataDictionaryDescriptors/message/ResponseSubscribeTIC.json.license deleted file mode 100644 index 18bf6d4..0000000 --- a/src/dataDictionaryDescriptors/message/ResponseSubscribeTIC.json.license +++ /dev/null @@ -1,6 +0,0 @@ -Copyright (C) 2025 Enedis Smarties team - -SPDX-FileContributor: Jehan BOUSCH -SPDX-FileContributor: Mathieu SABARTHES - -SPDX-License-Identifier: Apache-2.0 diff --git a/src/dataDictionaryDescriptors/message/ResponseUnsubscribeTIC.json b/src/dataDictionaryDescriptors/message/ResponseUnsubscribeTIC.json deleted file mode 100644 index 834ed75..0000000 --- a/src/dataDictionaryDescriptors/message/ResponseUnsubscribeTIC.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "package": "enedis.tic.service.message", - "name": "ResponseUnsubscribeTIC", - "extends" : "Response", - "type": "DataDictionaryBase", - "superAttributes": [ - { - "name": "name", - "type": "String", - "acceptedValues": "\"UnsubscribeTIC\"", - "removeFromConstructor" : true - }, - { - "name": "dateTime", - "type": "LocalDateTime" - }, - { - "name": "errorCode", - "type": "Number" - }, - { - "name": "errorMessage", - "type": "String" - } - ] -} \ No newline at end of file diff --git a/src/dataDictionaryDescriptors/message/ResponseUnsubscribeTIC.json.license b/src/dataDictionaryDescriptors/message/ResponseUnsubscribeTIC.json.license deleted file mode 100644 index 18bf6d4..0000000 --- a/src/dataDictionaryDescriptors/message/ResponseUnsubscribeTIC.json.license +++ /dev/null @@ -1,6 +0,0 @@ -Copyright (C) 2025 Enedis Smarties team - -SPDX-FileContributor: Jehan BOUSCH -SPDX-FileContributor: Mathieu SABARTHES - -SPDX-License-Identifier: Apache-2.0 diff --git a/src/dataDictionaryDescriptors/tic/core/TICCoreError.json b/src/dataDictionaryDescriptors/tic/core/TICCoreError.json deleted file mode 100644 index 04569e7..0000000 --- a/src/dataDictionaryDescriptors/tic/core/TICCoreError.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "package" : "enedis.tic.core", - "name": "TICCoreError", - "type": "DataDictionaryBase", - "attributes": [ - { - "name": "identifier", - "mandatory": true, - "type": "DataDictionary", - "dataDictionaryType": "TICIdentifier" - }, - { - "name": "errorCode", - "mandatory": true, - "type": "Number" - }, - { - "name": "errorMessage", - "mandatory": true, - "type": "String", - "emptyAllow": false - }, - { - "name": "data", - "mandatory": false, - "type": "DataDictionary", - "dataDictionaryType": "DataDictionaryBase" - } - ] -} \ No newline at end of file diff --git a/src/dataDictionaryDescriptors/tic/core/TICCoreError.json.license b/src/dataDictionaryDescriptors/tic/core/TICCoreError.json.license deleted file mode 100644 index 18bf6d4..0000000 --- a/src/dataDictionaryDescriptors/tic/core/TICCoreError.json.license +++ /dev/null @@ -1,6 +0,0 @@ -Copyright (C) 2025 Enedis Smarties team - -SPDX-FileContributor: Jehan BOUSCH -SPDX-FileContributor: Mathieu SABARTHES - -SPDX-License-Identifier: Apache-2.0 diff --git a/src/dataDictionaryDescriptors/tic/core/TICCoreFrame.json b/src/dataDictionaryDescriptors/tic/core/TICCoreFrame.json deleted file mode 100644 index 73b606a..0000000 --- a/src/dataDictionaryDescriptors/tic/core/TICCoreFrame.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "package" : "enedis.tic.core", - "name": "TICCoreFrame", - "type": "DataDictionaryBase", - "attributes": [ - { - "name": "identifier", - "mandatory": true, - "type": "DataDictionary", - "dataDictionaryType": "TICIdentifier" - }, - { - "name": "mode", - "mandatory": true, - "type": "Enum", - "enumType": "TICMode" - }, - { - "name": "captureDateTime", - "mandatory": true, - "type": "LocalDateTime" - }, - { - "name": "content", - "mandatory": true, - "type": "DataDictionary", - "dataDictionaryType": "DataDictionaryBase" - } - ] -} \ No newline at end of file diff --git a/src/dataDictionaryDescriptors/tic/core/TICCoreFrame.json.license b/src/dataDictionaryDescriptors/tic/core/TICCoreFrame.json.license deleted file mode 100644 index 18bf6d4..0000000 --- a/src/dataDictionaryDescriptors/tic/core/TICCoreFrame.json.license +++ /dev/null @@ -1,6 +0,0 @@ -Copyright (C) 2025 Enedis Smarties team - -SPDX-FileContributor: Jehan BOUSCH -SPDX-FileContributor: Mathieu SABARTHES - -SPDX-License-Identifier: Apache-2.0 diff --git a/src/dataDictionaryDescriptors/tic/core/TICIdentifier.json b/src/dataDictionaryDescriptors/tic/core/TICIdentifier.json deleted file mode 100644 index fbd5bda..0000000 --- a/src/dataDictionaryDescriptors/tic/core/TICIdentifier.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "package" : "enedis.tic.core", - "name": "TICIdentifier", - "type": "DataDictionaryBase", - "attributes": [ - { - "name": "portId", - "mandatory": false, - "type": "String", - "emptyAllow": false - }, - { - "name": "portName", - "mandatory": false, - "type": "String", - "emptyAllow": false - }, - { - "name": "serialNumber", - "mandatory": false, - "type": "String", - "emptyAllow": false - } - ] -} \ No newline at end of file diff --git a/src/dataDictionaryDescriptors/tic/core/TICIdentifier.json.license b/src/dataDictionaryDescriptors/tic/core/TICIdentifier.json.license deleted file mode 100644 index 18bf6d4..0000000 --- a/src/dataDictionaryDescriptors/tic/core/TICIdentifier.json.license +++ /dev/null @@ -1,6 +0,0 @@ -Copyright (C) 2025 Enedis Smarties team - -SPDX-FileContributor: Jehan BOUSCH -SPDX-FileContributor: Mathieu SABARTHES - -SPDX-License-Identifier: Apache-2.0 diff --git a/src/main/java/enedis/lab/codec/Codec.java b/src/main/java/enedis/lab/codec/Codec.java deleted file mode 100644 index e7932f8..0000000 --- a/src/main/java/enedis/lab/codec/Codec.java +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.codec; - -/** - * Codec interface - * - * @param - * @param - * - */ -public interface Codec -{ - /** - * Decode type K to type T - * - * @param object - * @return instance of T - * @throws CodecException - */ - public T decode(K object) throws CodecException; - - /** - * Encode type T to type K - * - * @param object - * @return instance of K - * @throws CodecException - */ - public K encode(T object) throws CodecException; -} diff --git a/src/main/java/enedis/lab/codec/CodecException.java b/src/main/java/enedis/lab/codec/CodecException.java deleted file mode 100644 index 678524d..0000000 --- a/src/main/java/enedis/lab/codec/CodecException.java +++ /dev/null @@ -1,169 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.codec; - -/** - * Codec exception - */ -public class CodecException extends Exception -{ - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private static final long serialVersionUID = 6029680699870915485L; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private Object data; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Default constructor - */ - public CodecException() - { - super(); - } - - /** - * Constructor - * - * @param message - * @param cause - */ - public CodecException(String message, Throwable cause) - { - super(message, cause); - } - - /** - * Constructor - * - * @param message - */ - public CodecException(String message) - { - super(message); - } - - /** - * Constructor - * - * @param message - * @param data - */ - public CodecException(String message, Object data) - { - super(message); - this.data = data; - } - - /** - * Constructor - * - * @param cause - */ - public CodecException(Throwable cause) - { - super(cause); - } - - /** - * Raise CodecException invalid value - * - * @param info - * @throws CodecException - */ - public static void raiseInvalidValue(String info) throws CodecException - { - throw new CodecException("Invalid value : " + info); - } - - /** - * Raise CodecException missing value - * - * @param value - * @throws CodecException - */ - public static void raiseMissingValue(String value) throws CodecException - { - throw new CodecException("Missing value : " + value); - } - - /** - * Raise CodecException inconsistency - * - * @param info - * @throws CodecException - */ - public static void raiseInconsistency(String info) throws CodecException - { - throw new CodecException("Inconsistency : " + info); - } - - /** - * Get data - * - * @return data - */ - public Object getData() - { - return this.data; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// interfaceName - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -} diff --git a/src/main/java/enedis/lab/io/PlugSubscriber.java b/src/main/java/enedis/lab/io/PlugSubscriber.java deleted file mode 100644 index 41f007a..0000000 --- a/src/main/java/enedis/lab/io/PlugSubscriber.java +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.io; - -import enedis.lab.util.task.Subscriber; - -/** - * Interface used to be notified when something has been plugged or unplugged - * - * @param the information class associated with plugged or unplugged notification - */ -public interface PlugSubscriber extends Subscriber -{ - /** - * Notification when something has been plugged - * - * @param info the information on what has been plugged - */ - public void onPlugged(T info); - /** - * Notification when something has been unplugged - * - * @param info the information on what has been unplugged - */ - public void onUnplugged(T info); -} diff --git a/src/main/java/enedis/lab/io/PortFinder.java b/src/main/java/enedis/lab/io/PortFinder.java deleted file mode 100644 index eda1e69..0000000 --- a/src/main/java/enedis/lab/io/PortFinder.java +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.io; - -import enedis.lab.types.DataList; - -/** - * Interface used to find all port descriptor - * @param the port descriptor class - */ -public interface PortFinder -{ - /** - * Find all port descriptor - * - * @return The port descriptor list found - */ - public DataList findAll(); -} diff --git a/src/main/java/enedis/lab/io/PortPlugNotifier.java b/src/main/java/enedis/lab/io/PortPlugNotifier.java deleted file mode 100644 index 9b4a8fd..0000000 --- a/src/main/java/enedis/lab/io/PortPlugNotifier.java +++ /dev/null @@ -1,214 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.io; - -import java.util.Iterator; -import java.util.concurrent.atomic.AtomicReference; - -import enedis.lab.types.DataArrayList; -import enedis.lab.types.DataList; -import enedis.lab.util.task.TaskPeriodicWithSubscribers; -import enedis.lab.util.time.Time; - -/** - * Class used to notify when a port has been plugged or unplugged - * - * @param - * the port finder interface - * @param - * the port descriptor class - */ -public class PortPlugNotifier, T> extends TaskPeriodicWithSubscribers> -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Program writing on the output stream when a port has been plugged or unplugged - * - * @param - * the port finder interface - * @param - * the port descriptor class - * @param notifier - * the port plug notifier instance - * @param subscriber - * the port plus subscriber instance - */ - public static , T> void main(PortPlugNotifier notifier, PlugSubscriber subscriber) - { - /* 1. Add program shutdown hook when CTRL+C is pressed to exit program properly */ - Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() - { - @Override - public void run() - { - notifier.unsubscribe(subscriber); - notifier.stop(); - } - })); - /* 4. Add a subscriber to notification service */ - notifier.subscribe(subscriber); - /* 5. Start the notification service */ - notifier.start(); - /* 6. Execute forever loop until CTRL+C is pressed */ - while (notifier.isRunning()) - { - Time.sleep(1000); - } - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private AtomicReference finder = new AtomicReference(); - private DataList descriptors = new DataArrayList(); - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Constructor with all parameters - * - * @param period - * the period (in milliseconds) used to look for plugged or unplugged serial port - * @param finder - * the serial port finder interface used to find all serial port descriptors - */ - public PortPlugNotifier(long period, F finder) - { - super(period); - this.setFinder(finder); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// interfaceName - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Set the finder - * - * @param finder - * the serial port finder interface used to find all serial port descriptors - * @throws IllegalArgumentException - * if finder is null - */ - public void setFinder(F finder) - { - if (finder == null) - { - throw new IllegalArgumentException("Cannot set null finder"); - } - this.finder.set(finder); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - protected void process() - { - DataList newDescriptors = this.finder.get().findAll(); - - this.checkAndNotifyIfUnplugged(newDescriptors); - this.checkAndNotifyIfPlugged(newDescriptors); - this.updateDescriptors(newDescriptors); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private void checkAndNotifyIfUnplugged(DataList newDescriptors) - { - Iterator it = this.descriptors.iterator(); - - while (it.hasNext()) - { - T descriptor = it.next(); - if (!newDescriptors.contains(descriptor)) - { - this.notifyOnUnplugged(descriptor); - } - } - } - - private void checkAndNotifyIfPlugged(DataList newDescriptors) - { - Iterator it = newDescriptors.iterator(); - - while (it.hasNext()) - { - T newDescriptor = it.next(); - if (!this.descriptors.contains(newDescriptor)) - { - this.notifyOnPlugged(newDescriptor); - } - } - } - - private void updateDescriptors(DataList newDescriptors) - { - synchronized (this.descriptors) - { - this.descriptors.clear(); - this.descriptors.addAll(newDescriptors); - } - } - - private void notifyOnPlugged(T info) - { - for (PlugSubscriber subscriber : this.notifier.getSubscribers()) - { - subscriber.onPlugged(info); - } - } - - private void notifyOnUnplugged(T info) - { - for (PlugSubscriber subscriber : this.notifier.getSubscribers()) - { - subscriber.onUnplugged(info); - } - } -} diff --git a/src/main/java/enedis/lab/io/channels/Channel.java b/src/main/java/enedis/lab/io/channels/Channel.java deleted file mode 100644 index 45ee2ec..0000000 --- a/src/main/java/enedis/lab/io/channels/Channel.java +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.io.channels; - -import enedis.lab.util.task.Notifier; -import enedis.lab.util.task.Task; - -/** - * Channel interface - */ -public interface Channel extends Task, Notifier -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Setup the channel from a configuration - * - * @param configuration - * the channel configuration - * - * @throws ChannelException - */ - public void setup(ChannelConfiguration configuration) throws ChannelException; - - /** - * Read data on the channel - * - * @return bytes - * @throws ChannelException - */ - public byte[] read() throws ChannelException; - - /** - * Write data on the channel - * - * @param data - * @throws ChannelException - */ - public void write(byte[] data) throws ChannelException; - - /** - * Get the channel name - * - * @return the channel's name - */ - public String getName(); - - /** - * Get the channel protocol - * - * @return the protocol used by the channel - */ - public ChannelProtocol getProtocol(); - - /** - * Get the channel direction - * - * @return the direction of the channel - */ - public ChannelDirection getDirection(); - - /** - * Get channel status - * - * @return the channel's status - */ - public ChannelStatus getStatus(); - - /** - * Get channel configuration - * - * @return channel configuration - */ - public ChannelConfiguration getConfiguration(); - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // none - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // none -} diff --git a/src/main/java/enedis/lab/io/channels/ChannelBase.java b/src/main/java/enedis/lab/io/channels/ChannelBase.java deleted file mode 100644 index 140687a..0000000 --- a/src/main/java/enedis/lab/io/channels/ChannelBase.java +++ /dev/null @@ -1,143 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.io.channels; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import enedis.lab.types.DataDictionaryException; -import enedis.lab.util.task.TaskPeriodic; - -/** - * Channel base - */ -public abstract class ChannelBase extends TaskPeriodic implements Channel -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected Logger logger; - protected ChannelConfiguration configuration; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Constructor - * - * @param configuration - * configuration used to set the channel - * @throws ChannelException - */ - protected ChannelBase(ChannelConfiguration configuration) throws ChannelException - { - this.logger = LogManager.getLogger(this.getClass()); - this.setup(configuration); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// Channel - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public void setup(ChannelConfiguration configuration) throws ChannelException - { - /* 1. Check configuration */ - if (configuration == null) - { - ChannelException.raiseInvalidConfiguration("null"); - } - /* 2. Copy configuration */ - ChannelConfiguration configurationBackUp = null; - try - { - if (this.configuration == null) - { - this.configuration = (ChannelConfiguration) configuration.clone(); - } - else - { - configurationBackUp = (ChannelConfiguration) this.configuration.clone(); - this.configuration.copy(configuration); - } - } - catch (DataDictionaryException exception) - { - ChannelException.raiseInvalidConfiguration(exception.getMessage()); - } - /* 3. Set up from internal configuration */ - try - { - this.setup(); - } - catch (Exception exception) - { - /* 4. Restore internal configuration */ - if (configurationBackUp != null) - { - try - { - this.configuration.copy(configurationBackUp); - } - catch (DataDictionaryException dataDictionaryException) - { - this.logger.error("", dataDictionaryException); - } - } - } - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected void setup() throws ChannelException - { - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -} diff --git a/src/main/java/enedis/lab/io/channels/ChannelConfiguration.java b/src/main/java/enedis/lab/io/channels/ChannelConfiguration.java deleted file mode 100644 index 18fac19..0000000 --- a/src/main/java/enedis/lab/io/channels/ChannelConfiguration.java +++ /dev/null @@ -1,296 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.io.channels; - -import java.io.File; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import enedis.lab.types.DataDictionary; -import enedis.lab.types.DataDictionaryException; -import enedis.lab.types.configuration.ConfigurationBase; -import enedis.lab.types.datadictionary.KeyDescriptor; -import enedis.lab.types.datadictionary.KeyDescriptorEnum; -import enedis.lab.types.datadictionary.KeyDescriptorString; - -/** - * ChannelConfiguration class - * - * Generated - */ -public class ChannelConfiguration extends ConfigurationBase -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected static final String KEY_NAME = "name"; - protected static final String KEY_PROTOCOL = "protocol"; - protected static final String KEY_DIRECTION = "direction"; - protected static final String KEY_ALIAS = "alias"; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private List> keys = new ArrayList>(); - - protected KeyDescriptorString kName; - protected KeyDescriptorEnum kProtocol; - protected KeyDescriptorEnum kDirection; - protected KeyDescriptorString kAlias; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected ChannelConfiguration() - { - super(); - this.loadKeyDescriptors(); - - } - - /** - * Constructor using map - * - * @param map - * @throws DataDictionaryException - */ - public ChannelConfiguration(Map map) throws DataDictionaryException - { - this(); - this.copy(fromMap(map)); - } - - /** - * Constructor using datadictionary - * - * @param other - * @throws DataDictionaryException - */ - public ChannelConfiguration(DataDictionary other) throws DataDictionaryException - { - this(); - this.copy(other); - } - - /** - * - * Constructor setting configuration name/file and parameters to default values - * - * @param name - * the configuration name - * @param file - * the configuration file - */ - public ChannelConfiguration(String name, File file) - { - this(); - this.init(name, file); - } - - /** - * Constructor setting parameters to specific values - * - * @param name - * @param protocol - * @param direction - * @param alias - * @throws DataDictionaryException - */ - public ChannelConfiguration(String name, ChannelProtocol protocol, ChannelDirection direction, String alias) throws DataDictionaryException - { - this(); - - this.setName(name); - this.setProtocol(protocol); - this.setDirection(direction); - this.setAlias(alias); - - this.checkAndUpdate(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// ConfigurationBase - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - protected void updateOptionalParameters() throws DataDictionaryException - { - super.updateOptionalParameters(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Get name - * - * @return the name - */ - public String getName() - { - return (String) this.data.get(KEY_NAME); - } - - /** - * Get protocol - * - * @return the protocol - */ - public ChannelProtocol getProtocol() - { - return (ChannelProtocol) this.data.get(KEY_PROTOCOL); - } - - /** - * Get direction - * - * @return the direction - */ - public ChannelDirection getDirection() - { - return (ChannelDirection) this.data.get(KEY_DIRECTION); - } - - /** - * Get alias - * - * @return the alias - */ - public String getAlias() - { - return (String) this.data.get(KEY_ALIAS); - } - - /** - * Set name - * - * @param name - * @throws DataDictionaryException - */ - public void setName(String name) throws DataDictionaryException - { - this.setName((Object) name); - } - - /** - * Set protocol - * - * @param protocol - * @throws DataDictionaryException - */ - public void setProtocol(ChannelProtocol protocol) throws DataDictionaryException - { - this.setProtocol((Object) protocol); - } - - /** - * Set direction - * - * @param direction - * @throws DataDictionaryException - */ - public void setDirection(ChannelDirection direction) throws DataDictionaryException - { - this.setDirection((Object) direction); - } - - /** - * Set alias - * - * @param alias - * @throws DataDictionaryException - */ - public void setAlias(String alias) throws DataDictionaryException - { - this.setAlias((Object) alias); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected void setName(Object name) throws DataDictionaryException - { - this.data.put(KEY_NAME, this.kName.convert(name)); - } - - protected void setProtocol(Object protocol) throws DataDictionaryException - { - this.data.put(KEY_PROTOCOL, this.kProtocol.convert(protocol)); - } - - protected void setDirection(Object direction) throws DataDictionaryException - { - this.data.put(KEY_DIRECTION, this.kDirection.convert(direction)); - } - - protected void setAlias(Object alias) throws DataDictionaryException - { - this.data.put(KEY_ALIAS, this.kAlias.convert(alias)); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private void loadKeyDescriptors() - { - try - { - this.kName = new KeyDescriptorString(KEY_NAME, true, false); - this.keys.add(this.kName); - - this.kProtocol = new KeyDescriptorEnum(KEY_PROTOCOL, true, ChannelProtocol.class); - this.keys.add(this.kProtocol); - - this.kDirection = new KeyDescriptorEnum(KEY_DIRECTION, true, ChannelDirection.class); - this.keys.add(this.kDirection); - - this.kAlias = new KeyDescriptorString(KEY_ALIAS, false, false); - this.keys.add(this.kAlias); - - this.addAllKeyDescriptor(this.keys); - } - catch (DataDictionaryException e) - { - throw new RuntimeException(e.getMessage(), e); - } - } -} diff --git a/src/main/java/enedis/lab/io/channels/ChannelDirection.java b/src/main/java/enedis/lab/io/channels/ChannelDirection.java deleted file mode 100644 index 95398f3..0000000 --- a/src/main/java/enedis/lab/io/channels/ChannelDirection.java +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.io.channels; - -/** - * Enumeration of channel direction - * - */ -public enum ChannelDirection -{ - /** Reception */ - RX, - /** Sending */ - TX, - /** Reception and sending */ - RXTX -} diff --git a/src/main/java/enedis/lab/io/channels/ChannelException.java b/src/main/java/enedis/lab/io/channels/ChannelException.java deleted file mode 100644 index 18ff7c0..0000000 --- a/src/main/java/enedis/lab/io/channels/ChannelException.java +++ /dev/null @@ -1,194 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.io.channels; - -import enedis.lab.types.ExceptionBase; - -/** - * Class used for the channel exceptions - */ -public class ChannelException extends ExceptionBase -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private static final long serialVersionUID = -3507876436535833098L; - - /** Invalid channel error code */ - public static final int ERRCODE_INVALID_CHANNEL = -5; - /** Already exists error code */ - public static final int ERRCODE_ALREADY_EXISTS = -6; - /** Internal error error code */ - public static final int ERRCODE_INTERNAL_ERROR = -7; - /** Channel not ready error code */ - public static final int ERRCODE_CHANNEL_NOT_READY = -8; - /** Invalid configuration type error code */ - public static final int ERRCODE_INVALID_CONFIGURATION_TYPE = -9; - /** Invalid configuration error code */ - public static final int ERRCODE_INVALID_CONFIGURATION = -10; - /** Operation denied error code */ - public static final int ERRCODE_OPERATION_DENIED = -11; - /** Channel doesn't exist error code */ - public static final int ERRCODE_CHANNEL_DOESNT_EXIST = -12; - /** Unexpected error code */ - public static final int ERRCODE_UNEXPECTED = -99; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * @param channelType - * @throws ChannelException - */ - public static void raiseUnhandledChannelType(String channelType) throws ChannelException - { - throw new ChannelException(ERRCODE_INVALID_CHANNEL, channelType + " channel is not handled"); - } - - /** - * @param channelType - * @param expectedChannelType - * @throws ChannelException - */ - public static void raiseConflictingChannelType(String channelType, String expectedChannelType) throws ChannelException - { - throw new ChannelException(ERRCODE_INVALID_CHANNEL, channelType + " channel is conflicting with " + expectedChannelType); - } - - /** - * @param info - * @throws ChannelException - */ - public static void raiseInternalError(String info) throws ChannelException - { - throw new ChannelException(ERRCODE_INTERNAL_ERROR, info); - } - - /** - * @param info - * @throws ChannelException - */ - public static void raiseChannelNotReady(String info) throws ChannelException - { - throw new ChannelException(ERRCODE_CHANNEL_NOT_READY, info); - } - - /** - * @param configuration - * @param expected_configuration_name - * @throws ChannelException - */ - public static void raiseInvalidConfigurationType(ChannelConfiguration configuration, String expected_configuration_name) throws ChannelException - { - throw new ChannelException(ERRCODE_INVALID_CONFIGURATION_TYPE, - "Configuration " + configuration.getClass().getSimpleName() + " is not a valid type (" + expected_configuration_name + " expected)"); - } - - /** - * @param info - * @throws ChannelException - */ - public static void raiseInvalidConfiguration(String info) throws ChannelException - { - throw new ChannelException(ERRCODE_INVALID_CONFIGURATION, "Configuration is invalid (" + info + ")"); - } - - /** - * @param operation - * @throws ChannelException - */ - public static void raiseOperationDenied(String operation) throws ChannelException - { - throw new ChannelException(ERRCODE_OPERATION_DENIED, "Operation \'" + operation + "\' is not allowed"); - } - - /** - * @param info - * @throws ChannelException - */ - public static void raiseUnexpectedError(String info) throws ChannelException - { - throw new ChannelException(ERRCODE_UNEXPECTED, "Unexpected error occurs : " + info); - } - - /** - * @param channelName - * @throws ChannelException - */ - public static void raiseAlreadyExists(String channelName) throws ChannelException - { - throw new ChannelException(ERRCODE_ALREADY_EXISTS, "Channel " + channelName + " already exists"); - } - - /** - * @param channelName - * @throws ChannelException - */ - public static void raiseDoesntExist(String channelName) throws ChannelException - { - throw new ChannelException(ERRCODE_CHANNEL_DOESNT_EXIST, "Channel " + channelName + " doesn't exist"); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * @param code - * @param info - */ - public ChannelException(int code, String info) - { - super(code, info); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// interfaceName - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -} diff --git a/src/main/java/enedis/lab/io/channels/ChannelListener.java b/src/main/java/enedis/lab/io/channels/ChannelListener.java deleted file mode 100644 index e31a37d..0000000 --- a/src/main/java/enedis/lab/io/channels/ChannelListener.java +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.io.channels; - -import enedis.lab.types.DataDictionary; -import enedis.lab.util.task.Subscriber; - -/** - * Channel listener - */ -public interface ChannelListener extends Subscriber -{ - /** - * On data read - * - * @param channelName - * the channel name - * @param data - * the bytes read - */ - public void onDataRead(String channelName, byte[] data); - - /** - * On data written - * - * @param channelName - * the channel name - * @param data - * the bytes written - */ - public void onDataWritten(String channelName, byte[] data); - - /** - * On status changed - * - * @param channelName - * the channel name - * @param status - * the new status - */ - public void onStatusChanged(String channelName, ChannelStatus status); - - /** - * On error detected - * - * @param channelName - * the channel name - * @param errorCode - * the error code - * @param errorMessage - * the error message - */ - public void onErrorDetected(String channelName, int errorCode, String errorMessage); - - /** - * On error detected - * - * @param channelName - * the channel name - * @param errorCode - * the error code - * @param errorMessage - * the error message - * @param data - * the data associated with error message - */ - public void onErrorDetected(String channelName, int errorCode, String errorMessage, DataDictionary data); -} diff --git a/src/main/java/enedis/lab/io/channels/ChannelPhysical.java b/src/main/java/enedis/lab/io/channels/ChannelPhysical.java deleted file mode 100644 index 5295653..0000000 --- a/src/main/java/enedis/lab/io/channels/ChannelPhysical.java +++ /dev/null @@ -1,227 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.io.channels; - -import java.util.Collection; - -import enedis.lab.util.task.NotifierBase; - -/** - * Channel physical - */ -public abstract class ChannelPhysical extends ChannelBase -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private NotifierBase notifier; - protected ChannelStatus status; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Constructor - * - * @param configuration - * configuration used to set the channel - * @throws ChannelException - */ - protected ChannelPhysical(ChannelConfiguration configuration) throws ChannelException - { - super(configuration); - this.init(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// Channel - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public void subscribe(ChannelListener listener) - { - this.notifier.subscribe(listener); - } - - @Override - public void unsubscribe(ChannelListener listener) - { - this.notifier.unsubscribe(listener); - } - - @Override - public boolean hasSubscriber(ChannelListener subscriber) - { - return this.notifier.hasSubscriber(subscriber); - } - - @Override - public Collection getSubscribers() - { - return this.notifier.getSubscribers(); - } - - @Override - public String getName() - { - return this.configuration.getName(); - } - - @Override - public ChannelProtocol getProtocol() - { - return this.configuration.getProtocol(); - } - - @Override - public ChannelDirection getDirection() - { - return this.configuration.getDirection(); - } - - @Override - public ChannelStatus getStatus() - { - return this.status; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public ChannelConfiguration getConfiguration() - { - return this.configuration; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Set the channel status - * - * @param status - * channel status - */ - protected void setStatus(ChannelStatus status) - { - this.setStatus(status, true); - } - - /** - * Set the channel status. If 'notify' argument is false, no channel listener will be notified about a new status, - * otherwise, the will - * - * @param status - * channel status - * @param notify - * if 'true', the channel's listener will be notified, else it will not - */ - protected void setStatus(ChannelStatus status, boolean notify) - { - if (status != this.status) - { - this.status = status; - if (status == ChannelStatus.ERROR) - { - this.logger.error("Channel " + this.getName() + " new status : " + status.name()); - } - else - { - this.logger.info("Channel " + this.getName() + " new status : " + status.name()); - } - if (true == notify) - { - this.notifyOnStatusChanged(); - } - } - } - - protected void notifyOnDataRead(byte[] data) - { - if (data != null) - { - for (ChannelListener subscriber : this.notifier.getSubscribers()) - { - subscriber.onDataRead(this.getName(), data); - } - } - } - - protected void notifyOnDataWritten(byte[] data) - { - if (data != null) - { - for (ChannelListener subscriber : this.notifier.getSubscribers()) - { - subscriber.onDataWritten(this.getName(), data); - } - } - } - - protected void notifyOnStatusChanged() - { - for (ChannelListener subscriber : this.notifier.getSubscribers()) - { - subscriber.onStatusChanged(this.getName(), this.status); - } - } - - protected void notifyOnErrorDetected(int errorCode, String errorMessage) - { - for (ChannelListener subscriber : this.notifier.getSubscribers()) - { - subscriber.onErrorDetected(this.getName(), errorCode, errorMessage); - } - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private void init() - { - this.status = ChannelStatus.STOPPED; - this.notifier = new NotifierBase(); - } -} diff --git a/src/main/java/enedis/lab/io/channels/ChannelProtocol.java b/src/main/java/enedis/lab/io/channels/ChannelProtocol.java deleted file mode 100644 index 82206e5..0000000 --- a/src/main/java/enedis/lab/io/channels/ChannelProtocol.java +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.io.channels; - -/** - * Enumeration of channel protocol - * - */ -public enum ChannelProtocol -{ - /** File */ - FILE, - /** Serial port */ - SERIAL_PORT, - /** RTU modbus */ - MODBUS_RTU, - /** TCP modbus */ - MODBUS_TCP, - /** modbus stub */ - MODBUS_STUB, - /** TCP */ - TCP, - /** UDP */ - UDP, -} diff --git a/src/main/java/enedis/lab/io/channels/serialport/ChannelSerialPortConfiguration.java b/src/main/java/enedis/lab/io/channels/serialport/ChannelSerialPortConfiguration.java deleted file mode 100644 index de7e171..0000000 --- a/src/main/java/enedis/lab/io/channels/serialport/ChannelSerialPortConfiguration.java +++ /dev/null @@ -1,432 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.io.channels.serialport; - -import java.io.File; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import enedis.lab.io.channels.ChannelConfiguration; -import enedis.lab.io.channels.ChannelDirection; -import enedis.lab.io.channels.ChannelProtocol; -import enedis.lab.types.DataDictionary; -import enedis.lab.types.DataDictionaryException; -import enedis.lab.types.datadictionary.KeyDescriptor; -import enedis.lab.types.datadictionary.KeyDescriptorEnum; -import enedis.lab.types.datadictionary.KeyDescriptorNumber; -import enedis.lab.types.datadictionary.KeyDescriptorString; - -/** - * ChannelSerialPortConfiguration class - * - * Generated - */ -public class ChannelSerialPortConfiguration extends ChannelConfiguration -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected static final String KEY_PORT_ID = "portId"; - protected static final String KEY_PORT_NAME = "portName"; - protected static final String KEY_BAUDRATE = "baudrate"; - protected static final String KEY_PARITY = "parity"; - protected static final String KEY_DATA_BITS = "dataBits"; - protected static final String KEY_STOP_BITS = "stopBits"; - protected static final String KEY_SYNC_READ_TIMEOUT = "syncReadTimeout"; - - private static final ChannelProtocol PROTOCOL_ACCEPTED_VALUE = ChannelProtocol.SERIAL_PORT; - private static final ChannelDirection DIRECTION_ACCEPTED_VALUE = ChannelDirection.RXTX; - private static final Number[] BAUDRATE_ACCEPTED_VALUES = { 110, 300, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600, 1843200, - 3686400 }; - private static final Number[] DATA_BITS_ACCEPTED_VALUES = { 5, 6, 7, 8 }; - private static final Number[] STOP_BITS_ACCEPTED_VALUES = { 1.0d, 1.5d, 2.0d }; - private static final Number SYNC_READ_TIMEOUT_DEFAULT_VALUE = 10000; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private List> keys = new ArrayList>(); - - protected KeyDescriptorString kPortId; - protected KeyDescriptorString kPortName; - protected KeyDescriptorNumber kBaudrate; - protected KeyDescriptorEnum kParity; - protected KeyDescriptorNumber kDataBits; - protected KeyDescriptorNumber kStopBits; - protected KeyDescriptorNumber kSyncReadTimeout; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected ChannelSerialPortConfiguration() - { - super(); - this.loadKeyDescriptors(); - - this.kProtocol.setAcceptedValues(PROTOCOL_ACCEPTED_VALUE); - this.kDirection.setAcceptedValues(DIRECTION_ACCEPTED_VALUE); - } - - /** - * Constructor using map - * - * @param map - * @throws DataDictionaryException - */ - public ChannelSerialPortConfiguration(Map map) throws DataDictionaryException - { - this(); - this.copy(fromMap(map)); - } - - /** - * Constructor using datadictionary - * - * @param other - * @throws DataDictionaryException - */ - public ChannelSerialPortConfiguration(DataDictionary other) throws DataDictionaryException - { - this(); - this.copy(other); - } - - /** - * - * Constructor setting configuration name/file and parameters to default values - * - * @param name - * the configuration name - * @param file - * the configuration file - */ - public ChannelSerialPortConfiguration(String name, File file) - { - this(); - this.init(name, file); - } - - /** - * Constructor setting parameters to specific values - * - * @param name - * @param alias - * @param portId - * @param portName - * @param baudrate - * @param parity - * @param dataBits - * @param stopBits - * @param syncReadTimeout - * @throws DataDictionaryException - */ - public ChannelSerialPortConfiguration(String name, String alias, String portId, String portName, Number baudrate, Parity parity, Number dataBits, Number stopBits, - Number syncReadTimeout) throws DataDictionaryException - { - this(); - - this.setName(name); - this.setAlias(alias); - this.setPortId(portId); - this.setPortName(portName); - this.setBaudrate(baudrate); - this.setParity(parity); - this.setDataBits(dataBits); - this.setStopBits(stopBits); - this.setSyncReadTimeout(syncReadTimeout); - - this.checkAndUpdate(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// ChannelConfiguration - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - protected void updateOptionalParameters() throws DataDictionaryException - { - if (!this.exists(KEY_PORT_ID) && !this.exists(KEY_PORT_NAME)) - { - throw new DataDictionaryException("Neither " + KEY_PORT_ID + " nor " + KEY_PORT_NAME + " is defined"); - } - if (!this.exists(KEY_PROTOCOL)) - { - this.setProtocol(PROTOCOL_ACCEPTED_VALUE); - } - if (!this.exists(KEY_DIRECTION)) - { - this.setDirection(DIRECTION_ACCEPTED_VALUE); - } - if (!this.exists(KEY_SYNC_READ_TIMEOUT)) - { - this.setSyncReadTimeout(SYNC_READ_TIMEOUT_DEFAULT_VALUE); - } - super.updateOptionalParameters(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Get port id - * - * @return the port id - */ - public String getPortId() - { - return (String) this.data.get(KEY_PORT_ID); - } - - /** - * Get port name - * - * @return the port name - */ - public String getPortName() - { - return (String) this.data.get(KEY_PORT_NAME); - } - - /** - * Get baudrate - * - * @return the baudrate - */ - public Number getBaudrate() - { - return (Number) this.data.get(KEY_BAUDRATE); - } - - /** - * Get parity - * - * @return the parity - */ - public Parity getParity() - { - return (Parity) this.data.get(KEY_PARITY); - } - - /** - * Get data bits - * - * @return the data bits - */ - public Number getDataBits() - { - return (Number) this.data.get(KEY_DATA_BITS); - } - - /** - * Get stop bits - * - * @return the stop bits - */ - public Number getStopBits() - { - return (Number) this.data.get(KEY_STOP_BITS); - } - - /** - * Get sync read timeout - * - * @return the sync read timeout - */ - public Number getSyncReadTimeout() - { - return (Number) this.data.get(KEY_SYNC_READ_TIMEOUT); - } - - /** - * Set port id - * - * @param portId - * @throws DataDictionaryException - */ - public void setPortId(String portId) throws DataDictionaryException - { - this.setPortId((Object) portId); - } - - /** - * Set port name - * - * @param portName - * @throws DataDictionaryException - */ - public void setPortName(String portName) throws DataDictionaryException - { - this.setPortName((Object) portName); - } - - /** - * Set baudrate - * - * @param baudrate - * @throws DataDictionaryException - */ - public void setBaudrate(Number baudrate) throws DataDictionaryException - { - this.setBaudrate((Object) baudrate); - } - - /** - * Set parity - * - * @param parity - * @throws DataDictionaryException - */ - public void setParity(Parity parity) throws DataDictionaryException - { - this.setParity((Object) parity); - } - - /** - * Set data bits - * - * @param dataBits - * @throws DataDictionaryException - */ - public void setDataBits(Number dataBits) throws DataDictionaryException - { - this.setDataBits((Object) dataBits); - } - - /** - * Set stop bits - * - * @param stopBits - * @throws DataDictionaryException - */ - public void setStopBits(Number stopBits) throws DataDictionaryException - { - this.setStopBits((Object) stopBits); - } - - /** - * Set sync read timeout - * - * @param syncReadTimeout - * @throws DataDictionaryException - */ - public void setSyncReadTimeout(Number syncReadTimeout) throws DataDictionaryException - { - this.setSyncReadTimeout((Object) syncReadTimeout); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected void setPortId(Object portId) throws DataDictionaryException - { - this.data.put(KEY_PORT_ID, this.kPortId.convert(portId)); - } - - protected void setPortName(Object portName) throws DataDictionaryException - { - this.data.put(KEY_PORT_NAME, this.kPortName.convert(portName)); - } - - protected void setBaudrate(Object baudrate) throws DataDictionaryException - { - this.data.put(KEY_BAUDRATE, this.kBaudrate.convert(baudrate)); - } - - protected void setParity(Object parity) throws DataDictionaryException - { - this.data.put(KEY_PARITY, this.kParity.convert(parity)); - } - - protected void setDataBits(Object dataBits) throws DataDictionaryException - { - this.data.put(KEY_DATA_BITS, this.kDataBits.convert(dataBits)); - } - - protected void setStopBits(Object stopBits) throws DataDictionaryException - { - this.data.put(KEY_STOP_BITS, this.kStopBits.convert(stopBits)); - } - - protected void setSyncReadTimeout(Object syncReadTimeout) throws DataDictionaryException - { - this.data.put(KEY_SYNC_READ_TIMEOUT, this.kSyncReadTimeout.convert(syncReadTimeout)); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private void loadKeyDescriptors() - { - try - { - this.kPortId = new KeyDescriptorString(KEY_PORT_ID, false, false); - this.keys.add(this.kPortId); - - this.kPortName = new KeyDescriptorString(KEY_PORT_NAME, false, false); - this.keys.add(this.kPortName); - - this.kBaudrate = new KeyDescriptorNumber(KEY_BAUDRATE, true); - this.kBaudrate.setAcceptedValues(BAUDRATE_ACCEPTED_VALUES); - this.keys.add(this.kBaudrate); - - this.kParity = new KeyDescriptorEnum(KEY_PARITY, true, Parity.class); - this.keys.add(this.kParity); - - this.kDataBits = new KeyDescriptorNumber(KEY_DATA_BITS, true); - this.kDataBits.setAcceptedValues(DATA_BITS_ACCEPTED_VALUES); - this.keys.add(this.kDataBits); - - this.kStopBits = new KeyDescriptorNumber(KEY_STOP_BITS, true); - this.kStopBits.setAcceptedValues(STOP_BITS_ACCEPTED_VALUES); - this.keys.add(this.kStopBits); - - this.kSyncReadTimeout = new KeyDescriptorNumber(KEY_SYNC_READ_TIMEOUT, false); - this.keys.add(this.kSyncReadTimeout); - - this.addAllKeyDescriptor(this.keys); - } - catch (DataDictionaryException e) - { - throw new RuntimeException(e.getMessage(), e); - } - } -} diff --git a/src/main/java/enedis/lab/io/channels/serialport/Parity.java b/src/main/java/enedis/lab/io/channels/serialport/Parity.java deleted file mode 100644 index b5caaf4..0000000 --- a/src/main/java/enedis/lab/io/channels/serialport/Parity.java +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.io.channels.serialport; - -/** - * Parity enum - */ -public enum Parity -{ - /** None */ - NONE, - /** Even */ - EVEN, - /** Odd */ - ODD, - /** Mark */ - MARK, - /** Space */ - SPACE -} \ No newline at end of file diff --git a/src/main/java/enedis/lab/io/datastreams/DataInputStream.java b/src/main/java/enedis/lab/io/datastreams/DataInputStream.java deleted file mode 100644 index 430d8bd..0000000 --- a/src/main/java/enedis/lab/io/datastreams/DataInputStream.java +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.io.datastreams; - -import enedis.lab.types.DataDictionary; - -/** - * Data input stream - */ -public abstract class DataInputStream extends DataStreamBase -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Constructor using configuration - * - * @param configuration - * @throws DataStreamException - */ - public DataInputStream(DataStreamConfiguration configuration) throws DataStreamException - { - super(configuration); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// DataStream - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public final void write(DataDictionary data) throws DataStreamException - { - DataStreamException.raiseOperationDenied("write"); - } - - @Override - public void setup(DataStreamConfiguration configuration) throws DataStreamException - { - super.setup(configuration); - - if (DataStreamDirection.INPUT != configuration.getDirection()) - { - DataStreamException.raiseInvalidConfiguration(DataStreamConfiguration.KEY_DIRECTION + "=" + configuration.getDirection().name() + "(expected " + DataStreamDirection.INPUT.name() + ")"); - } - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -} diff --git a/src/main/java/enedis/lab/io/datastreams/DataStream.java b/src/main/java/enedis/lab/io/datastreams/DataStream.java deleted file mode 100644 index fb89041..0000000 --- a/src/main/java/enedis/lab/io/datastreams/DataStream.java +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.io.datastreams; - -/** - * DataStream interface - */ -public interface DataStream extends DataStreamUser -{ - /** - * Open the stream - * - * @throws DataStreamException - */ - public void open() throws DataStreamException; - - /** - * Close the stream - * - * @throws DataStreamException - */ - public void close() throws DataStreamException; - - /** - * Setup the stream from a configuration - * - * @param configuration - * configuration given for the stream - * @throws DataStreamException - * if an error occurs - */ - public void setup(DataStreamConfiguration configuration) throws DataStreamException; -} diff --git a/src/main/java/enedis/lab/io/datastreams/DataStreamBase.java b/src/main/java/enedis/lab/io/datastreams/DataStreamBase.java deleted file mode 100644 index 578325f..0000000 --- a/src/main/java/enedis/lab/io/datastreams/DataStreamBase.java +++ /dev/null @@ -1,373 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.io.datastreams; - -import java.util.Collection; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import enedis.lab.io.channels.Channel; -import enedis.lab.io.channels.ChannelListener; -import enedis.lab.io.channels.ChannelStatus; -import enedis.lab.types.DataDictionary; -import enedis.lab.util.task.NotifierBase; - -/** - * DataStream Base - */ -public abstract class DataStreamBase implements DataStream, ChannelListener -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected NotifierBase notifier; - protected DataStreamConfiguration configuration; - private DataStreamStatus status; - protected Channel channel; - protected Logger logger; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Constructor - * - * @param configuration - * configuration used to set the stream - * @throws DataStreamException - */ - public DataStreamBase(DataStreamConfiguration configuration) throws DataStreamException - { - this.init(configuration); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// ChannelListener - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public void onStatusChanged(String channelName, ChannelStatus channelStatus) - { - DataStreamStatus status_cpy = this.status; - - switch (channelStatus) - { - case STOPPED: - { - if (DataStreamStatus.CLOSED != this.status) - { - this.setStatus(DataStreamStatus.ERROR); - } - break; - } - case STARTED: - { - if (DataStreamStatus.ERROR == this.status) - { - this.setStatus(DataStreamStatus.OPENED); - } - break; - } - case ERROR: - { - this.setStatus(DataStreamStatus.ERROR); - break; - } - - default: - { - - } - } - - if (!this.notifier.getSubscribers().isEmpty() && (status_cpy != this.status)) - { - this.notifyOnStatusChanged(this.status); - } - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// DataStream - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public void open() throws DataStreamException - { - String channelName = this.configuration.getChannelName(); - - if (null != channelName) - { - if (null != this.channel) - { - this.channel.subscribe(this); - this.setStatus(DataStreamStatus.OPENED); - this.logger.info("Stream " + this.getName() + " start"); - } - else - { - this.setStatus(DataStreamStatus.ERROR); - DataStreamException.raiseChannelError(channelName, "channel does not exist"); - } - } - } - - @Override - public void close() throws DataStreamException - { - String channelName = this.configuration.getChannelName(); - - if (null != channelName) - { - if (null != this.channel) - { - this.channel.unsubscribe(this); - this.setStatus(DataStreamStatus.CLOSED); - this.logger.info("Service " + this.getName() + " stop"); - } - else - { - this.setStatus(DataStreamStatus.ERROR); - DataStreamException.raiseChannelError(channelName, "channel does not exist"); - } - } - } - - @Override - public void setup(DataStreamConfiguration configuration) throws DataStreamException - { - if (this.status == DataStreamStatus.OPENED) - { - DataStreamException.raiseInternalError("Cannot setup stream " + this.getName() + " (already open)"); - } - this.configuration = configuration; - } - - @Override - public void subscribe(DataStreamListener listener) - { - this.notifier.subscribe(listener); - } - - @Override - public void unsubscribe(DataStreamListener listener) - { - this.notifier.unsubscribe(listener); - } - - @Override - public boolean hasSubscriber(DataStreamListener subscriber) - { - return this.notifier.hasSubscriber(subscriber); - } - - @Override - public Collection getSubscribers() - { - return this.notifier.getSubscribers(); - } - - @Override - public String getName() - { - return this.configuration.getName(); - } - - @Override - public DataStreamConfiguration getConfiguration() - { - return (DataStreamConfiguration) this.configuration.clone(); - } - - @Override - public DataStreamDirection getDirection() - { - return this.configuration.getDirection(); - } - - @Override - public DataStreamType getType() - { - return this.configuration.getType(); - } - - @Override - public DataStreamStatus getStatus() - { - return this.status; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Set the channel reference - * - * @param channel - */ - public void setChannel(Channel channel) - { - this.channel = channel; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Notify onDataReceived listeners - * - * @param data - * new data received - */ - protected void notifyOnDataReceived(DataDictionary data) - { - if (data != null) - { - for (DataStreamListener listener : this.notifier.getSubscribers()) - { - listener.onDataReceived(this.getName(), data); - } - } - } - - /** - * Notify onDataSent listeners - * - * @param data - * new data sent - */ - protected void notifyOnDataSent(DataDictionary data) - { - if (data != null) - { - for (DataStreamListener listener : this.notifier.getSubscribers()) - { - listener.onDataSent(this.getName(), data); - } - } - } - - /** - * Notify onStatusChanged listeners - * - * @param newStatus - * new status - */ - protected void notifyOnStatusChanged(DataStreamStatus newStatus) - { - if (newStatus != null) - { - for (DataStreamListener listener : this.notifier.getSubscribers()) - { - listener.onStatusChanged(this.getName(), newStatus); - } - } - } - - /** - * Notify onErrorDetected listeners - * - * @param errorCode - * the error code - * @param errorMessage - * the error message - * @param data - * the data associated with the error - */ - protected void notifyOnErrorDetected(int errorCode, String errorMessage, DataDictionary data) - { - for (DataStreamListener listener : this.notifier.getSubscribers()) - { - listener.onErrorDetected(this.getName(), errorCode, errorMessage, data); - } - } - - /** - * Set the channel status - * - * @param status - * channel status - */ - protected void setStatus(DataStreamStatus status) - { - this.setStatus(status, true); - } - - /** - * Set the channel status. If 'notify' argument is false, no channel listener will be notified about a new status, - * otherwise, the will - * - * @param status - * channel status - * @param notify - * if 'true', the channel's listener will be notified, else it will not - */ - protected void setStatus(DataStreamStatus status, boolean notify) - { - if (status != this.status) - { - this.status = status; - - if (true == notify) - { - this.notifyOnStatusChanged(this.status); - } - } - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private void init(DataStreamConfiguration configuration) throws DataStreamException - { - this.notifier = new NotifierBase(); - this.status = DataStreamStatus.UNKNOWN; - this.configuration = configuration; - this.logger = LogManager.getLogger(this.getClass()); - this.setup(configuration); - } -} diff --git a/src/main/java/enedis/lab/io/datastreams/DataStreamConfiguration.java b/src/main/java/enedis/lab/io/datastreams/DataStreamConfiguration.java deleted file mode 100644 index ddd6069..0000000 --- a/src/main/java/enedis/lab/io/datastreams/DataStreamConfiguration.java +++ /dev/null @@ -1,296 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.io.datastreams; - -import java.io.File; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import enedis.lab.types.DataDictionary; -import enedis.lab.types.DataDictionaryException; -import enedis.lab.types.configuration.ConfigurationBase; -import enedis.lab.types.datadictionary.KeyDescriptor; -import enedis.lab.types.datadictionary.KeyDescriptorEnum; -import enedis.lab.types.datadictionary.KeyDescriptorString; - -/** - * DataStreamConfiguration class - * - * Generated - */ -public class DataStreamConfiguration extends ConfigurationBase -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected static final String KEY_NAME = "name"; - protected static final String KEY_TYPE = "type"; - protected static final String KEY_DIRECTION = "direction"; - protected static final String KEY_CHANNEL_NAME = "channelName"; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private List> keys = new ArrayList>(); - - protected KeyDescriptorString kName; - protected KeyDescriptorEnum kType; - protected KeyDescriptorEnum kDirection; - protected KeyDescriptorString kChannelName; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected DataStreamConfiguration() - { - super(); - this.loadKeyDescriptors(); - - } - - /** - * Constructor using map - * - * @param map - * @throws DataDictionaryException - */ - public DataStreamConfiguration(Map map) throws DataDictionaryException - { - this(); - this.copy(fromMap(map)); - } - - /** - * Constructor using datadictionary - * - * @param other - * @throws DataDictionaryException - */ - public DataStreamConfiguration(DataDictionary other) throws DataDictionaryException - { - this(); - this.copy(other); - } - - /** - * - * Constructor setting configuration name/file and parameters to default values - * - * @param name - * the configuration name - * @param file - * the configuration file - */ - public DataStreamConfiguration(String name, File file) - { - this(); - this.init(name, file); - } - - /** - * Constructor setting parameters to specific values - * - * @param name - * @param type - * @param direction - * @param channelName - * @throws DataDictionaryException - */ - public DataStreamConfiguration(String name, DataStreamType type, DataStreamDirection direction, String channelName) throws DataDictionaryException - { - this(); - - this.setName(name); - this.setType(type); - this.setDirection(direction); - this.setChannelName(channelName); - - this.checkAndUpdate(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// ConfigurationBase - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - protected void updateOptionalParameters() throws DataDictionaryException - { - super.updateOptionalParameters(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Get name - * - * @return the name - */ - public String getName() - { - return (String) this.data.get(KEY_NAME); - } - - /** - * Get type - * - * @return the type - */ - public DataStreamType getType() - { - return (DataStreamType) this.data.get(KEY_TYPE); - } - - /** - * Get direction - * - * @return the direction - */ - public DataStreamDirection getDirection() - { - return (DataStreamDirection) this.data.get(KEY_DIRECTION); - } - - /** - * Get channel name - * - * @return the channel name - */ - public String getChannelName() - { - return (String) this.data.get(KEY_CHANNEL_NAME); - } - - /** - * Set name - * - * @param name - * @throws DataDictionaryException - */ - public void setName(String name) throws DataDictionaryException - { - this.setName((Object) name); - } - - /** - * Set type - * - * @param type - * @throws DataDictionaryException - */ - public void setType(DataStreamType type) throws DataDictionaryException - { - this.setType((Object) type); - } - - /** - * Set direction - * - * @param direction - * @throws DataDictionaryException - */ - public void setDirection(DataStreamDirection direction) throws DataDictionaryException - { - this.setDirection((Object) direction); - } - - /** - * Set channel name - * - * @param channelName - * @throws DataDictionaryException - */ - public void setChannelName(String channelName) throws DataDictionaryException - { - this.setChannelName((Object) channelName); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected void setName(Object name) throws DataDictionaryException - { - this.data.put(KEY_NAME, this.kName.convert(name)); - } - - protected void setType(Object type) throws DataDictionaryException - { - this.data.put(KEY_TYPE, this.kType.convert(type)); - } - - protected void setDirection(Object direction) throws DataDictionaryException - { - this.data.put(KEY_DIRECTION, this.kDirection.convert(direction)); - } - - protected void setChannelName(Object channelName) throws DataDictionaryException - { - this.data.put(KEY_CHANNEL_NAME, this.kChannelName.convert(channelName)); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private void loadKeyDescriptors() - { - try - { - this.kName = new KeyDescriptorString(KEY_NAME, true, false); - this.keys.add(this.kName); - - this.kType = new KeyDescriptorEnum(KEY_TYPE, true, DataStreamType.class); - this.keys.add(this.kType); - - this.kDirection = new KeyDescriptorEnum(KEY_DIRECTION, true, DataStreamDirection.class); - this.keys.add(this.kDirection); - - this.kChannelName = new KeyDescriptorString(KEY_CHANNEL_NAME, false, false); - this.keys.add(this.kChannelName); - - this.addAllKeyDescriptor(this.keys); - } - catch (DataDictionaryException e) - { - throw new RuntimeException(e.getMessage(), e); - } - } -} diff --git a/src/main/java/enedis/lab/io/datastreams/DataStreamDirection.java b/src/main/java/enedis/lab/io/datastreams/DataStreamDirection.java deleted file mode 100644 index 66e83e7..0000000 --- a/src/main/java/enedis/lab/io/datastreams/DataStreamDirection.java +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.io.datastreams; - -/** - * DataStream direction - */ -public enum DataStreamDirection -{ - /** Input dataStream */ - INPUT, - /** Output dataStream */ - OUTPUT, - /** Inoutput dataStream */ - INOUTPUT; -} diff --git a/src/main/java/enedis/lab/io/datastreams/DataStreamException.java b/src/main/java/enedis/lab/io/datastreams/DataStreamException.java deleted file mode 100644 index 1410e0f..0000000 --- a/src/main/java/enedis/lab/io/datastreams/DataStreamException.java +++ /dev/null @@ -1,205 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.io.datastreams; - -/** - * Specific exception for data stream - */ -public class DataStreamException extends Exception -{ - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private static final long serialVersionUID = 4079445021346677107L; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Raise channel error exception - * - * @param channelName - * @param info - * @throws DataStreamException - */ - public static void raiseChannelError(String channelName, String info) throws DataStreamException - { - throw new DataStreamException("Error occurs on channel " + channelName + " (" + info + ")"); - } - - /** - * Raise unhandle type exception - * - * @param type - * @throws DataStreamException - */ - public static void raiseUnhandledType(String type) throws DataStreamException - { - throw new DataStreamException(type + " datastream is not handled"); - } - - /** - * Raise internal error exception - * - * @param info - * @throws DataStreamException - */ - public static void raiseInternalError(String info) throws DataStreamException - { - throw new DataStreamException(info); - } - - /** - * Raise invalid configuration exception - * - * @param configuration - * @param expected_configuration_name - * @throws DataStreamException - */ - public static void raiseInvalidConfiguration(DataStreamConfiguration configuration, String expected_configuration_name) throws DataStreamException - { - throw new DataStreamException("Configuration " + configuration.getClass().getSimpleName() + " is not valid (" + expected_configuration_name + " expected)"); - } - - /** - * Raise invalid configuration exceotion - * - * @param info - * @throws DataStreamException - */ - public static void raiseInvalidConfiguration(String info) throws DataStreamException - { - throw new DataStreamException(info); - } - - /** - * Raise operation denied excpetion - * - * @param operation - * @throws DataStreamException - */ - public static void raiseOperationDenied(String operation) throws DataStreamException - { - throw new DataStreamException("Operation \'" + operation + "\' is not allowed"); - } - - /** - * Raise unexpected error exception - * - * @param info - * @throws DataStreamException - */ - public static void raiseUnexpectedError(String info) throws DataStreamException - { - throw new DataStreamException("Unexpected error occurs : " + info); - } - - /** - * Raise already exists exception - * - * @param dataStream - * @throws DataStreamException - */ - public static void raiseAlreadyExists(String dataStream) throws DataStreamException - { - throw new DataStreamException("DataStream " + dataStream + " already exists"); - } - - /** - * Raise creation failed exception - * - * @param dataStream - * @param info - * @throws DataStreamException - */ - public static void raiseCreationFailed(String dataStream, String info) throws DataStreamException - { - throw new DataStreamException("Creation of dataStream " + dataStream + " creation failed : " + info); - } - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Super class constructor - * - * @param message - * @param cause - */ - public DataStreamException(String message, Throwable cause) - { - super(message, cause); - } - - /** - * Super class constructor - * - * @param message - */ - public DataStreamException(String message) - { - super(message); - } - - /** - * Super class constructor - * - * @param cause - */ - public DataStreamException(Throwable cause) - { - super(cause); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// interfaceName - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -} diff --git a/src/main/java/enedis/lab/io/datastreams/DataStreamListener.java b/src/main/java/enedis/lab/io/datastreams/DataStreamListener.java deleted file mode 100644 index f9094ef..0000000 --- a/src/main/java/enedis/lab/io/datastreams/DataStreamListener.java +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.io.datastreams; - -import enedis.lab.types.DataDictionary; -import enedis.lab.util.task.Subscriber; - -/** - * Data stream listener - */ -public interface DataStreamListener extends Subscriber -{ - /** - * Function call when data has been received - * - * @param dataStreamName - * the stream name - * @param data - * the data received - */ - public void onDataReceived(String dataStreamName, DataDictionary data); - - /** - * Function call when data has been sent - * - * @param dataStreamName - * the stream name - * @param data - * the data sent - */ - public void onDataSent(String dataStreamName, DataDictionary data); - - /** - * Function call when data stream status changed - * - * @param dataStreamName - * the stream name - * @param status - * the new status - */ - public void onStatusChanged(String dataStreamName, DataStreamStatus status); - - /** - * On error detected - * - * @param dataStreamName - * the stream name - * @param errorCode - * the error code - * @param errorMessage - * the error message - * @param data - * the data associated with error - */ - public void onErrorDetected(String dataStreamName, int errorCode, String errorMessage, DataDictionary data); -} diff --git a/src/main/java/enedis/lab/io/datastreams/DataStreamStatus.java b/src/main/java/enedis/lab/io/datastreams/DataStreamStatus.java deleted file mode 100644 index 282be74..0000000 --- a/src/main/java/enedis/lab/io/datastreams/DataStreamStatus.java +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.io.datastreams; - -/** - * DataStream status - */ -public enum DataStreamStatus -{ - /** Unknown, default status */ - UNKNOWN, - /** Closed */ - CLOSED, - /** Opened */ - OPENED, - /** Error */ - ERROR -} diff --git a/src/main/java/enedis/lab/io/datastreams/DataStreamType.java b/src/main/java/enedis/lab/io/datastreams/DataStreamType.java deleted file mode 100644 index 9d778d7..0000000 --- a/src/main/java/enedis/lab/io/datastreams/DataStreamType.java +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.io.datastreams; - -/** - * DataStream type - */ -public enum DataStreamType -{ - /** raw stream */ - RAW, - /** TIC stream */ - TIC, - /** IEC61850 stream */ - IEC61850, - /** Slave modbus stream */ - MODBUS_SLAVE, - /** Master modbus stream */ - MODBUS_MASTER, - /** LEM DC product */ - LEM_DC; -} diff --git a/src/main/java/enedis/lab/io/datastreams/DataStreamUser.java b/src/main/java/enedis/lab/io/datastreams/DataStreamUser.java deleted file mode 100644 index 6e0e865..0000000 --- a/src/main/java/enedis/lab/io/datastreams/DataStreamUser.java +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.io.datastreams; - -import enedis.lab.types.DataDictionary; -import enedis.lab.util.task.Notifier; - -/** - * DataStream interface - */ -public interface DataStreamUser extends Notifier -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// interfaceName - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * read data on the stream - * - * @return data read - * @throws DataStreamException - */ - public DataDictionary read() throws DataStreamException; - - /** - * write data on the stream - * - * @param data - * @throws DataStreamException - */ - public void write(DataDictionary data) throws DataStreamException; - - /** - * Get data stream name - * - * @return the stream name - */ - public String getName(); - - /** - * Get stream configuration - * - * @return stream configuration - */ - public DataStreamConfiguration getConfiguration(); - - /** - * Get stream direction - * - * @return stream direction - */ - public DataStreamDirection getDirection(); - - /** - * Get stream type - * - * @return stream type - */ - public DataStreamType getType(); - - /** - * Get stream status - * - * @return stream status - */ - public DataStreamStatus getStatus(); - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -} diff --git a/src/main/java/enedis/lab/io/serialport/SerialPortDescriptor.java b/src/main/java/enedis/lab/io/serialport/SerialPortDescriptor.java deleted file mode 100644 index 3c30eee..0000000 --- a/src/main/java/enedis/lab/io/serialport/SerialPortDescriptor.java +++ /dev/null @@ -1,455 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.io.serialport; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import enedis.lab.types.DataDictionary; -import enedis.lab.types.DataDictionaryException; -import enedis.lab.types.datadictionary.DataDictionaryBase; -import enedis.lab.types.datadictionary.KeyDescriptor; -import enedis.lab.types.datadictionary.KeyDescriptorNumberMinMax; -import enedis.lab.types.datadictionary.KeyDescriptorString; - -/** - * Class used to get the following serial port informations:
- * - port unique identifier
- * - port name used to open serial port
- * - port description
- * - USB device product identifier
- * - USB device vendor identifier
- * - USB device product name
- * - USB device manufacturer
- * - USB device serial number - */ -public class SerialPortDescriptor extends DataDictionaryBase -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected static final String KEY_PORT_ID = "portId"; - protected static final String KEY_PORT_NAME = "portName"; - protected static final String KEY_DESCRIPTION = "description"; - protected static final String KEY_PRODUCT_ID = "productId"; - protected static final String KEY_VENDOR_ID = "vendorId"; - protected static final String KEY_PRODUCT_NAME = "productName"; - protected static final String KEY_MANUFACTURER = "manufacturer"; - protected static final String KEY_SERIAL_NUMBER = "serialNumber"; - - private static final Number PRODUCT_ID_MIN = 0; - private static final Number PRODUCT_ID_MAX = 65535; - private static final Number VENDOR_ID_MIN = 0; - private static final Number VENDOR_ID_MAX = 65535; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private List> keys = new ArrayList>(); - - protected KeyDescriptorString kPortId; - protected KeyDescriptorString kPortName; - protected KeyDescriptorString kDescription; - protected KeyDescriptorNumberMinMax kProductId; - protected KeyDescriptorNumberMinMax kVendorId; - protected KeyDescriptorString kProductName; - protected KeyDescriptorString kManufacturer; - protected KeyDescriptorString kSerialNumber; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Empty constructor - */ - public SerialPortDescriptor() - { - super(); - this.loadKeyDescriptors(); - } - - /** - * Constructor using map - * - * @param map - * @throws DataDictionaryException - */ - public SerialPortDescriptor(Map map) throws DataDictionaryException - { - this(); - this.copy(fromMap(map)); - } - - /** - * Constructor using data dictionary - * - * @param other - * @throws DataDictionaryException - */ - public SerialPortDescriptor(DataDictionary other) throws DataDictionaryException - { - this(); - this.copy(other); - } - - /** - * Constructor setting parameters to specific values - * - * @param portId - * the port unique identifier - * @param portName - * the port name used to open serial port - * @param description - * the port description - * @param productId - * the USB device product identifier - * @param vendorId - * the USB device vendor identifier - * @param productName - * the USB device product name - * @param manufacturer - * the USB device manufacturer - * @param serialNumber - * the USB device serial number - * @throws DataDictionaryException - * if any parameters is invalid - */ - public SerialPortDescriptor(String portId, String portName, String description, Number productId, Number vendorId, String productName, String manufacturer, String serialNumber) - throws DataDictionaryException - { - this(); - - this.setPortId(portId); - this.setPortName(portName); - this.setDescription(description); - this.setProductId(productId); - this.setVendorId(vendorId); - this.setProductName(productName); - this.setManufacturer(manufacturer); - this.setSerialNumber(serialNumber); - - this.checkAndUpdate(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// DataDictionaryBase - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Get port id - * - * @return the port unique identifier - */ - public String getPortId() - { - return (String) this.data.get(KEY_PORT_ID); - } - - /** - * Get port name - * - * @return the port name used to open serial port - */ - public String getPortName() - { - return (String) this.data.get(KEY_PORT_NAME); - } - - /** - * Get description - * - * @return the port description - */ - public String getDescription() - { - return (String) this.data.get(KEY_DESCRIPTION); - } - - /** - * Get product id - * - * @return the USB device product identifier - */ - public Number getProductId() - { - return (Number) this.data.get(KEY_PRODUCT_ID); - } - - /** - * Get vendor id - * - * @return the USB device vendor identifier - */ - public Number getVendorId() - { - return (Number) this.data.get(KEY_VENDOR_ID); - } - - /** - * Get product name - * - * @return the USB device product name - */ - public String getProductName() - { - return (String) this.data.get(KEY_PRODUCT_NAME); - } - - /** - * Get manufacturer - * - * @return the USB device manufacturer - */ - public String getManufacturer() - { - return (String) this.data.get(KEY_MANUFACTURER); - } - - /** - * Get serial number - * - * @return the USB device serial number - */ - public String getSerialNumber() - { - return (String) this.data.get(KEY_SERIAL_NUMBER); - } - - /** - * Set port id - * - * @param portId - * the port unique identifier - * @throws DataDictionaryException - * if portId is empty - */ - public void setPortId(String portId) throws DataDictionaryException - { - this.setPortId((Object) portId); - } - - /** - * Set port name - * - * @param portName - * the port name used to open serial port - * @throws DataDictionaryException - * if portName is empty - */ - public void setPortName(String portName) throws DataDictionaryException - { - this.setPortName((Object) portName); - } - - /** - * Set description - * - * @param description - * the port description - * @throws DataDictionaryException - * if description is empty - */ - public void setDescription(String description) throws DataDictionaryException - { - this.setDescription((Object) description); - } - - /** - * Set product id - * - * @param productId - * the USB device product identifier - * @throws DataDictionaryException - * if productId is out of range [0-65535] - */ - public void setProductId(Number productId) throws DataDictionaryException - { - this.setProductId((Object) productId); - } - - /** - * Set vendor id - * - * @param vendorId - * the USB device vendor identifier - * @throws DataDictionaryException - * if vendorId is out of range [0-65535] - */ - public void setVendorId(Number vendorId) throws DataDictionaryException - { - this.setVendorId((Object) vendorId); - } - - /** - * Set product name - * - * @param productName - * the USB device product name - * @throws DataDictionaryException - * if productName is empty - */ - public void setProductName(String productName) throws DataDictionaryException - { - this.setProductName((Object) productName); - } - - /** - * Set manufacturer - * - * @param manufacturer - * the USB device manufacturer - * @throws DataDictionaryException - * if manufacturer is empty - */ - public void setManufacturer(String manufacturer) throws DataDictionaryException - { - this.setManufacturer((Object) manufacturer); - } - - /** - * Set serial number - * - * @param serialNumber - * the USB device serial number - * @throws DataDictionaryException - * if serialNumber is empty - */ - public void setSerialNumber(String serialNumber) throws DataDictionaryException - { - this.setSerialNumber((Object) serialNumber); - } - - /** - * Check if serial port is native (not USB) - * - * @return true if native port, false otherwise - */ - public boolean isNative() - { - return this.getPortName() != null && !this.getPortName().isEmpty() && this.getPortId() == null; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected void setPortId(Object portId) throws DataDictionaryException - { - this.data.put(KEY_PORT_ID, this.kPortId.convert(portId)); - } - - protected void setPortName(Object portName) throws DataDictionaryException - { - this.data.put(KEY_PORT_NAME, this.kPortName.convert(portName)); - } - - protected void setDescription(Object description) throws DataDictionaryException - { - this.data.put(KEY_DESCRIPTION, this.kDescription.convert(description)); - } - - protected void setProductId(Object productId) throws DataDictionaryException - { - this.data.put(KEY_PRODUCT_ID, this.kProductId.convert(productId)); - } - - protected void setVendorId(Object vendorId) throws DataDictionaryException - { - this.data.put(KEY_VENDOR_ID, this.kVendorId.convert(vendorId)); - } - - protected void setProductName(Object productName) throws DataDictionaryException - { - this.data.put(KEY_PRODUCT_NAME, this.kProductName.convert(productName)); - } - - protected void setManufacturer(Object manufacturer) throws DataDictionaryException - { - this.data.put(KEY_MANUFACTURER, this.kManufacturer.convert(manufacturer)); - } - - protected void setSerialNumber(Object serialNumber) throws DataDictionaryException - { - this.data.put(KEY_SERIAL_NUMBER, this.kSerialNumber.convert(serialNumber)); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private void loadKeyDescriptors() - { - try - { - this.kPortId = new KeyDescriptorString(KEY_PORT_ID, false, false); - this.keys.add(this.kPortId); - - this.kPortName = new KeyDescriptorString(KEY_PORT_NAME, false, false); - this.keys.add(this.kPortName); - - this.kDescription = new KeyDescriptorString(KEY_DESCRIPTION, false, false); - this.keys.add(this.kDescription); - - this.kProductId = new KeyDescriptorNumberMinMax(KEY_PRODUCT_ID, false, PRODUCT_ID_MIN, PRODUCT_ID_MAX); - this.keys.add(this.kProductId); - - this.kVendorId = new KeyDescriptorNumberMinMax(KEY_VENDOR_ID, false, VENDOR_ID_MIN, VENDOR_ID_MAX); - this.keys.add(this.kVendorId); - - this.kProductName = new KeyDescriptorString(KEY_PRODUCT_NAME, false, false); - this.keys.add(this.kProductName); - - this.kManufacturer = new KeyDescriptorString(KEY_MANUFACTURER, false, false); - this.keys.add(this.kManufacturer); - - this.kSerialNumber = new KeyDescriptorString(KEY_SERIAL_NUMBER, false, false); - this.keys.add(this.kSerialNumber); - - this.addAllKeyDescriptor(this.keys); - } - catch (DataDictionaryException e) - { - throw new RuntimeException(e.getMessage(), e); - } - } -} diff --git a/src/main/java/enedis/lab/io/serialport/SerialPortFinder.java b/src/main/java/enedis/lab/io/serialport/SerialPortFinder.java deleted file mode 100644 index 4090a4b..0000000 --- a/src/main/java/enedis/lab/io/serialport/SerialPortFinder.java +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.io.serialport; - -import enedis.lab.io.PortFinder; -import enedis.lab.types.DataArrayList; -import enedis.lab.types.DataList; - -/** - * Interface used to find all serial port descriptor - */ -public interface SerialPortFinder extends PortFinder -{ - /** - * Find serial port descriptor matching with port id - * - * @param portId - * the unique port identifier desired - * - * @return Serial port descriptor found, or null if nothing matches with portId - */ - public default SerialPortDescriptor findByPortId(String portId) - { - return this.findAll().stream().filter(k -> (k.getPortId() != null) ? k.getPortId().equals(portId) : portId == null).findFirst().orElse(null); - } - - /** - * Find serial port descriptor matching with port name - * - * @param portName - * the port name desired - * - * @return Serial port descriptor found, or null if nothing matches with portName - */ - public default SerialPortDescriptor findByPortName(String portName) - { - return this.findAll().stream().filter(k -> (k.getPortName() != null) ? k.getPortName().equals(portName) : portName == null).findFirst().orElse(null); - } - - /** - * Find native serial port (not USB) descriptor matching with port name - * - * @param portName - * the port name desired - * - * @return Serial port descriptor found, or null if nothing matches with portName - */ - public default SerialPortDescriptor findNative(String portName) - { - return this.findAll().stream().filter(k -> k.isNative() && k.getPortName().equals(portName)).findFirst().orElse(null); - } - - /** - * Find serial port descriptor matching with port id (having priority) or port name - * - * @param portId - * the unique port identifier desired - * @param portName - * the port name desired - * - * @return Serial port descriptor found, or null if nothing matches with portName - */ - public default SerialPortDescriptor findByPortIdOrPortName(String portId, String portName) - { - SerialPortDescriptor descriptor; - - if (portId != null) - { - descriptor = this.findByPortId(portId); - } - else if (portName != null) - { - descriptor = this.findByPortName(portName); - } - else - { - descriptor = null; - } - - return descriptor; - } - - /** - * Find serial port descriptor matching with pid/vid - * - * @param productId - * the USB device product identifier - * @param vendorId - * the USB device vendor identifier - * - * @return Serial port descriptor list found - */ - public default DataList findByProductIdAndVendorId(Number productId, Number vendorId) - { - DataList descriptorList = new DataArrayList(); - - for (SerialPortDescriptor descriptor : this.findAll()) - { - if (descriptor.getProductId() == null && productId != null) - { - continue; - } - if (descriptor.getVendorId() == null && vendorId != null) - { - continue; - } - if (descriptor.getProductId().equals(productId) && descriptor.getVendorId().equals(vendorId)) - { - descriptorList.add(descriptor); - } - } - - return descriptorList; - } -} diff --git a/src/main/java/enedis/lab/io/serialport/SerialPortFinderBase.java b/src/main/java/enedis/lab/io/serialport/SerialPortFinderBase.java deleted file mode 100644 index 9b9ba0f..0000000 --- a/src/main/java/enedis/lab/io/serialport/SerialPortFinderBase.java +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.io.serialport; - -import org.apache.commons.lang3.SystemUtils; - -import enedis.lab.types.DataList; - -/** - * Class used to find all serial port descriptor for any operating system - */ -public class SerialPortFinderBase implements SerialPortFinder -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Program writing the serial port descriptor list (JSON format) on the output stream - * - * @param args - * not used - */ - public static void main(String[] args) - { - DataList descriptors = getInstance().findAll(); - - System.out.println(descriptors.toString(2)); - } - - /** - * Get instance - * - * @return Unique instance - */ - public static SerialPortFinder getInstance() - { - if (instance == null) - { - if (SystemUtils.IS_OS_WINDOWS) - { - instance = SerialPortFinderForWindows.getInstance(); - } - else if (SystemUtils.IS_OS_LINUX) - { - instance = SerialPortFinderForLinux.getInstance(); - } - else - { - throw new RuntimeException("Operating system " + SystemUtils.OS_NAME + " is not handled by " + SerialPortFinderBase.class.getName()); - } - } - - return instance; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private static SerialPortFinder instance; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private SerialPortFinderBase() - { - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// SerialPortFinder - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public DataList findAll() - { - return instance.findAll(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -} diff --git a/src/main/java/enedis/lab/io/serialport/SerialPortFinderForLinux.java b/src/main/java/enedis/lab/io/serialport/SerialPortFinderForLinux.java deleted file mode 100644 index f8c774a..0000000 --- a/src/main/java/enedis/lab/io/serialport/SerialPortFinderForLinux.java +++ /dev/null @@ -1,703 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.io.serialport; - -import java.io.File; -import java.io.FileFilter; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import com.sun.jna.platform.linux.Udev; -import com.sun.jna.platform.linux.Udev.UdevContext; -import com.sun.jna.platform.linux.Udev.UdevDevice; -import com.sun.jna.platform.linux.Udev.UdevEnumerate; -import com.sun.jna.platform.linux.Udev.UdevListEntry; - -import enedis.lab.types.DataArrayList; -import enedis.lab.types.DataDictionaryException; -import enedis.lab.types.DataList; - -/** - * Class used to find all serial port descriptor for Linux - */ -public class SerialPortFinderForLinux implements SerialPortFinder -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private static String MOXA_IDENTIFIER = "ttyr"; - private static Pattern MOXA_PATTERN = Pattern.compile("(.*)" + MOXA_IDENTIFIER + "(\\d+)"); - private static String MOXA_FORMAT = MOXA_IDENTIFIER + "%02d"; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Get instance - * - * @return Unique instance - */ - public static SerialPortFinderForLinux getInstance() - { - if (instance == null) - { - instance = new SerialPortFinderForLinux(); - } - - return instance; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private static SerialPortFinderForLinux instance; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private SerialPortFinderForLinux() - { - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// SerialPortFinder - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public DataList findAll() - { - DataList serialPortDescriptorList = new DataArrayList(); - - serialPortDescriptorList = availablePortsByUdev(); - if (serialPortDescriptorList.isEmpty()) - { - serialPortDescriptorList = availablePortsBySysfs(); - } - if (serialPortDescriptorList.isEmpty()) - { - serialPortDescriptorList = availablePortsByFiltersOfDevices(); - } - - return serialPortDescriptorList; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private static DataList availablePortsByUdev() - { - UdevContext udev = Udev.INSTANCE.udev_new(); - UdevEnumerate enumerate = Udev.INSTANCE.udev_enumerate_new(udev); - Udev.INSTANCE.udev_enumerate_add_match_subsystem(enumerate, "tty"); - Udev.INSTANCE.udev_enumerate_scan_devices(enumerate); - - DataList serialPortDescriptorList = new DataArrayList(); - - for (UdevListEntry dev_list_entry = Udev.INSTANCE.udev_enumerate_get_list_entry(enumerate); dev_list_entry != null; dev_list_entry = dev_list_entry.getNext()) - { - UdevDevice device = Udev.INSTANCE.udev_device_new_from_syspath(udev, Udev.INSTANCE.udev_list_entry_get_name(dev_list_entry)); - if (device == null) - { - break; - } - SerialPortDescriptor serialPortDescriptor; - - String location = deviceLocation(device); - String portName = deviceName(device); - - UdevDevice parentdev = Udev.INSTANCE.udev_device_get_parent(device); - - if (parentdev != null) - { - String driverName = deviceDriver(parentdev); - if (isSerial8250Driver(driverName) && !isValidSerial8250(location)) - { - Udev.INSTANCE.udev_device_unref(device); - continue; - } - String description = deviceDescription(device); - String portId = devicePortId(device); - String manufacturer = deviceManufacturer(device); - String serialNumber = deviceSerialNumber(device); - Number vendorIdentifier = deviceVendorIdentifier(device); - Number productIdentifier = deviceProductIdentifier(device); - String productName = deviceProductName(device); - try - { - serialPortDescriptor = new SerialPortDescriptor(portId, location, description, productIdentifier, vendorIdentifier, productName, manufacturer, serialNumber); - } - catch (DataDictionaryException e) - { - e.printStackTrace(); - Udev.INSTANCE.udev_device_unref(device); - continue; - } - } - else - { - if (!isRfcommDevice(portName) && !isVirtualNullModemDevice(portName) && !isGadgetDevice(portName) && !isMoxaDevice(portName)) - { - Udev.INSTANCE.udev_device_unref(device); - continue; - } - try - { - serialPortDescriptor = new SerialPortDescriptor(null, location, null, null, null, null, null, null); - } - catch (DataDictionaryException e) - { - e.printStackTrace(); - Udev.INSTANCE.udev_device_unref(device); - continue; - } - } - serialPortDescriptorList.add(serialPortDescriptor); - Udev.INSTANCE.udev_device_unref(device); - } - Udev.INSTANCE.udev_enumerate_unref(enumerate); - Udev.INSTANCE.udev_unref(udev); - - return serialPortDescriptorList; - } - - private static DataList availablePortsBySysfs() - { - DataList serialPortDescriptorList = new DataArrayList(); - File ttySysClassDir = new File("/sys/class/tty"); - - if (!(ttySysClassDir.exists() && ttySysClassDir.canRead())) - { - return serialPortDescriptorList; - } - FileFilter filter = new FileFilter() - { - @Override - public boolean accept(File pathname) - { - - return pathname.isDirectory() && !pathname.getName().equals(".") && !pathname.getName().equals(".."); - } - }; - File[] fileInfos = ttySysClassDir.listFiles(filter); - for (File fileInfo : fileInfos) - { - if (!Files.isSymbolicLink(fileInfo.toPath())) - { - continue; - } - File targetDir = fileInfo.getAbsoluteFile(); - SerialPortDescriptor serialPortDescriptor; - - String portName = deviceName(targetDir); - if (portName == null) - { - continue; - } - String driverName = deviceDriver(targetDir); - if (driverName == null) - { - if (!isRfcommDevice(portName) && !isVirtualNullModemDevice(portName) && !isGadgetDevice(portName) && !isMoxaDevice(portName)) - { - continue; - } - } - - String device = portNameToSystemLocation(portName); - if (isSerial8250Driver(driverName) && !isValidSerial8250(device)) - { - continue; - } - String description = null; - String manufacturer = null; - String serialNumber = null; - Number vendorIdentifier = null; - Number productIdentifier = null; - String productName = null; - do - { - if (description == null) - { - description = deviceDescription(targetDir); - } - if (manufacturer == null) - { - manufacturer = deviceManufacturer(targetDir); - } - if (serialNumber == null) - { - serialNumber = deviceSerialNumber(targetDir); - } - if (vendorIdentifier == null) - { - vendorIdentifier = deviceVendorIdentifier(targetDir); - } - if (productIdentifier == null) - { - productIdentifier = deviceProductIdentifier(targetDir); - } - if (productName == null) - { - productName = deviceProductName(targetDir); - } - if (description != null || manufacturer != null || serialNumber != null || vendorIdentifier != null || productIdentifier != null || productName != null) - { - break; - } - targetDir = targetDir.getParentFile(); - } while (targetDir != null); - try - { - serialPortDescriptor = new SerialPortDescriptor(null, portName, description, productIdentifier, vendorIdentifier, productName, manufacturer, serialNumber); - } - catch (DataDictionaryException e) - { - e.printStackTrace(); - continue; - } - serialPortDescriptorList.add(serialPortDescriptor); - } - - return serialPortDescriptorList; - } - - private static DataList availablePortsByFiltersOfDevices() - { - DataList serialPortDescriptorList = new DataArrayList(); - - List deviceFilePaths = filteredDeviceFilePaths(); - for (String deviceFilePath : deviceFilePaths) - { - SerialPortDescriptor serialPortDescriptor; - String portName = portNameFromSystemLocation(deviceFilePath); - try - { - serialPortDescriptor = new SerialPortDescriptor(null, portName, null, null, null, null, null, null); - } - catch (DataDictionaryException e) - { - e.printStackTrace(); - continue; - } - serialPortDescriptorList.add(serialPortDescriptor); - } - - return serialPortDescriptorList; - } - - private static List filteredDeviceFilePaths() - { - List deviceFileNameFilterList = new ArrayList(); - - // Linux - deviceFileNameFilterList.add("ttyS*"); // Standard UART 8250 and etc. - deviceFileNameFilterList.add("ttyO*"); // OMAP UART 8250 and etc. - deviceFileNameFilterList.add("ttyUSB*"); // Usb/serial converters PL2303 and etc. - deviceFileNameFilterList.add("ttyACM*"); // CDC_ACM converters (i.e. Mobile Phones). - deviceFileNameFilterList.add("ttyGS*"); // Gadget serial device (i.e. Mobile Phones with gadget serial driver). - deviceFileNameFilterList.add("ttyMI*"); // MOXA pci/serial converters. - deviceFileNameFilterList.add("ttymxc*"); // Motorola IMX serial ports (i.e. Freescale i.MX). - deviceFileNameFilterList.add("ttyAMA*"); // AMBA serial device for embedded platform on ARM (i.e. Raspberry Pi). - deviceFileNameFilterList.add("ttyTHS*"); // Serial device for embedded platform on ARM (i.e. Tegra Jetson TK1). - deviceFileNameFilterList.add("rfcomm*"); // Bluetooth serial device. - deviceFileNameFilterList.add("ircomm*"); // IrDA serial device. - deviceFileNameFilterList.add("tnt*"); // Virtual tty0tty serial device. - deviceFileNameFilterList.add(MOXA_IDENTIFIER + "*"); // MOXA ethernet device. - // FreeBSD - deviceFileNameFilterList.add("cu*"); - // QNX - deviceFileNameFilterList.add("ser*"); - - List result = new ArrayList(); - - File deviceDir = new File("/dev"); - if (deviceDir.exists()) - { - FileFilter deviceFileNameFilter = new FileFilter() - { - @Override - public boolean accept(File pathname) - { - Path path = pathname.toPath(); - - return deviceFileNameFilterList.contains(pathname.getName()) && pathname.isFile() && !Files.isSymbolicLink(path); - } - }; - File[] deviceFileInfos = deviceDir.listFiles(deviceFileNameFilter); - for (File deviceFileInfo : deviceFileInfos) - { - String deviceAbsoluteFilePath = deviceFileInfo.getAbsolutePath(); - // it is a quick workaround to skip the non-serial devices (FreeBSD) - if (deviceAbsoluteFilePath.endsWith(".init") || deviceAbsoluteFilePath.endsWith(".lock")) - { - continue; - } - if (!result.contains(deviceAbsoluteFilePath)) - { - result.add(deviceAbsoluteFilePath); - } - } - } - - return result; - } - - private static boolean isSerial8250Driver(String driverName) - { - return (driverName == "serial8250"); - } - - private static boolean isValidSerial8250(String systemLocation) - { - return false; - } - - private static boolean isRfcommDevice(String portName) - { - if (!portName.startsWith("rfcomm")) - { - return false; - } - try - { - String number = portName.substring(6); - int portNumber = Integer.parseInt(number); - if (portNumber < 0 || portNumber > 255) - { - return false; - } - } - catch (Exception e) - { - return false; - } - return true; - } - - // provided by the tty0tty driver - private static boolean isVirtualNullModemDevice(String portName) - { - return portName.startsWith("tnt"); - } - - // provided by the g_serial driver - private static boolean isGadgetDevice(String portName) - { - return portName.startsWith("ttyGS"); - } - - // provided by the MOXA driver - private static boolean isMoxaDevice(String portName) - { - return portName.startsWith(MOXA_IDENTIFIER); - } - - private static String devicePortId(UdevDevice dev) - { - return deviceProperty(dev, "ID_PATH"); - } - - private static String deviceDescription(UdevDevice dev) - { - String description = deviceProperty(dev, "ID_MODEL_FROM_DATABASE"); - - return (description != null) ? description.replace('_', ' ') : null; - } - - private static String deviceDescription(File targetDir) - { - return deviceProperty(new File(targetDir, "product").getAbsolutePath()); - } - - private static String deviceManufacturer(UdevDevice dev) - { - String manufacturer = deviceProperty(dev, "ID_VENDOR"); - - return (manufacturer != null) ? manufacturer.replace('_', ' ') : null; - } - - private static String deviceManufacturer(File targetDir) - { - return deviceProperty(new File(targetDir, "manufacturer").getAbsolutePath()); - } - - private static Number deviceProductIdentifier(UdevDevice dev) - { - Number identifierValue; - try - { - String indentifierText = deviceProperty(dev, "ID_MODEL_ID"); - identifierValue = (indentifierText != null) ? Integer.parseInt(indentifierText, 16) : null; - } - catch (Exception e) - { - identifierValue = null; - } - return identifierValue; - } - - private static String deviceProductName(UdevDevice dev) - { - return deviceProperty(dev, "ID_MODEL"); - } - - private static String deviceProductName(File targetDir) - { - return deviceProperty(new File(targetDir, "product").getAbsolutePath()); - } - - private static Number deviceProductIdentifier(File targetDir) - { - String indentifierText = deviceProperty(new File(targetDir, "idProduct").getAbsolutePath()); - - if (indentifierText == null) - { - indentifierText = deviceProperty(new File(targetDir, "device").getAbsolutePath()); - } - Number identifierValue; - try - { - identifierValue = (indentifierText != null) ? Integer.parseInt(indentifierText, 16) : null; - } - catch (Exception e) - { - identifierValue = null; - } - return identifierValue; - } - - private static Number deviceVendorIdentifier(File targetDir) - { - String indentifierText = deviceProperty(new File(targetDir, "idVendor").getAbsolutePath()); - - if (indentifierText == null) - { - indentifierText = deviceProperty(new File(targetDir, "vendor").getAbsolutePath()); - } - Number identifierValue; - try - { - identifierValue = (indentifierText != null) ? Integer.parseInt(indentifierText, 16) : null; - } - catch (Exception e) - { - identifierValue = null; - } - return identifierValue; - } - - private static String deviceSerialNumber(File targetDir) - { - return deviceProperty(new File(targetDir, "serial").getAbsolutePath()); - } - - private static Number deviceVendorIdentifier(UdevDevice dev) - { - Number identifierValue; - try - { - String indentifierText = deviceProperty(dev, "ID_VENDOR_ID"); - identifierValue = (indentifierText != null) ? Integer.parseInt(indentifierText, 16) : null; - } - catch (Exception e) - { - identifierValue = null; - } - return identifierValue; - } - - private static String deviceSerialNumber(UdevDevice dev) - { - return deviceProperty(dev, "ID_SERIAL_SHORT"); - } - - private static String deviceProperty(UdevDevice dev, String name) - { - return Udev.INSTANCE.udev_device_get_property_value(dev, name); - } - - private static String deviceProperty(String targetFilePath) - { - FileInputStream f; - - try - { - f = new FileInputStream(targetFilePath); - } - catch (FileNotFoundException e) - { - e.printStackTrace(); - return null; - } - String text; - try - { - int available = f.available(); - byte[] buffer = new byte[available]; - f.read(buffer); - text = new String(buffer); - } - catch (IOException e) - { - e.printStackTrace(); - return null; - } - finally - { - try - { - f.close(); - } - catch (IOException e) - { - e.printStackTrace(); - } - } - - return text.trim(); - } - - private static String deviceDriver(UdevDevice dev) - { - return null; - } - - private static String deviceDriver(File targetDir) - { - File deviceDir = new File(targetDir, "device"); - - return ueventProperty(deviceDir, "DRIVER="); - } - - private static String deviceName(UdevDevice dev) - { - return Udev.INSTANCE.udev_device_get_sysname(dev); - } - - static String deviceName(File targetDir) - { - return ueventProperty(targetDir, "DEVNAME="); - } - - private static String deviceLocation(UdevDevice dev) - { - String location = Udev.INSTANCE.udev_device_get_devnode(dev); - // Patch for MOXA device - // Udev prints location as /dev/ttyrN but only /dev/ttyr0N exists (with N belongs to [1-4]) - // So we are renaming location from /dev/ttyrN to /dev/ttyr0N - Matcher matcher = MOXA_PATTERN.matcher(location); - - if (matcher.matches()) - { - String prefix = ""; - String indexValue; - if (matcher.groupCount() == 2) - { - prefix = matcher.group(1); - indexValue = matcher.group(2); - } - else - { - indexValue = matcher.group(2); - } - int index = Integer.parseUnsignedInt(indexValue); - location = String.format("%s" + MOXA_FORMAT, prefix, index); - } - - return location; - } - - private static String portNameToSystemLocation(String source) - { - return (source.startsWith("/") || source.startsWith("./") || source.startsWith("../")) ? source : (("/dev/") + source); - } - - private static String portNameFromSystemLocation(String source) - { - return source.startsWith("/dev/") ? source.substring(5) : source; - } - - @SuppressWarnings("resource") - private static String ueventProperty(File targetDir, String pattern) - { - FileInputStream f; - - try - { - f = new FileInputStream(new File(targetDir, "uevent")); - } - catch (FileNotFoundException e) - { - e.printStackTrace(); - return null; - } - String content; - try - { - int available = f.available(); - byte[] buffer = new byte[available]; - f.read(buffer); - content = new String(buffer); - } - catch (IOException e) - { - e.printStackTrace(); - return null; - } - int firstbound = content.indexOf(pattern); - if (firstbound == -1) - { - return null; - } - int lastbound = content.indexOf('\n', firstbound); - - return content.substring(firstbound, lastbound); - } -} diff --git a/src/main/java/enedis/lab/io/serialport/SerialPortFinderForWindows.java b/src/main/java/enedis/lab/io/serialport/SerialPortFinderForWindows.java deleted file mode 100644 index 6f66a58..0000000 --- a/src/main/java/enedis/lab/io/serialport/SerialPortFinderForWindows.java +++ /dev/null @@ -1,455 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.io.serialport; - -import static com.sun.jna.platform.win32.SetupApi.DICS_FLAG_GLOBAL; -import static com.sun.jna.platform.win32.SetupApi.DIGCF_DEVICEINTERFACE; -import static com.sun.jna.platform.win32.SetupApi.DIGCF_PRESENT; -import static com.sun.jna.platform.win32.SetupApi.DIREG_DEV; -import static com.sun.jna.platform.win32.SetupApi.GUID_DEVINTERFACE_COMPORT; -import static com.sun.jna.platform.win32.SetupApi.SPDRP_DEVICEDESC; -import static com.sun.jna.platform.win32.WinBase.INVALID_HANDLE_VALUE; -import static com.sun.jna.platform.win32.WinDef.MAX_PATH; -import static com.sun.jna.platform.win32.WinError.ERROR_SUCCESS; -import static com.sun.jna.platform.win32.WinNT.KEY_QUERY_VALUE; -import static com.sun.jna.platform.win32.WinNT.KEY_READ; -import static com.sun.jna.platform.win32.WinNT.REG_DWORD; -import static com.sun.jna.platform.win32.WinNT.REG_SZ; -import static com.sun.jna.platform.win32.WinReg.HKEY_LOCAL_MACHINE; - -import java.util.ArrayList; -import java.util.List; - -import com.sun.jna.Memory; -import com.sun.jna.Pointer; -import com.sun.jna.platform.win32.Advapi32; -import com.sun.jna.platform.win32.Advapi32Util; -import com.sun.jna.platform.win32.Cfgmgr32; -import com.sun.jna.platform.win32.Cfgmgr32Util; -import com.sun.jna.platform.win32.Guid.GUID; -import com.sun.jna.platform.win32.SetupApi; -import com.sun.jna.platform.win32.SetupApi.SP_DEVINFO_DATA; -import com.sun.jna.platform.win32.Win32Exception; -import com.sun.jna.platform.win32.WinNT.HANDLE; -import com.sun.jna.platform.win32.WinReg.HKEY; -import com.sun.jna.ptr.IntByReference; - -import enedis.lab.types.DataArrayList; -import enedis.lab.types.DataDictionaryException; -import enedis.lab.types.DataList; - -/** - * Class used to find all serial port descriptor for Windows - */ -public class SerialPortFinderForWindows implements SerialPortFinder -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private static final int SPDRP_MFG = 0x0000000B; - private static final int SPDRP_ADDRESS = 0x0000001C; - private static final int PROPERTY_MAX_SIZE = 1024; - - private static final GUID GUID_DEVCLASS_PORTS = new GUID("{4d36e978-e325-11ce-bfc1-08002be10318}"); - private static final GUID GUID_DEVCLASS_MODEM = new GUID("{4d36e96d-e325-11ce-bfc1-08002be10318}"); - private static final GUID GUID_DEVINTERFACE_MODEM = new GUID("{2c7089aa-2e0e-11d1-b114-00c04fc2aae4}"); - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Get instance - * - * @return Unique instance - */ - public static SerialPortFinderForWindows getInstance() - { - if(instance == null) - { - instance = new SerialPortFinderForWindows(); - } - - return instance; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private static SerialPortFinderForWindows instance; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private SerialPortFinderForWindows() - { - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// SerialPortFinder - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public DataList findAll() - { - final class SetupToken - { - public GUID guid; - public int flags; - - public SetupToken(GUID guid, int flags) - { - super(); - this.guid = guid; - this.flags = flags; - } - } - - SetupToken[] setupTokens = new SetupToken[] { new SetupToken(GUID_DEVCLASS_PORTS, DIGCF_PRESENT), new SetupToken(GUID_DEVCLASS_MODEM, DIGCF_PRESENT), - new SetupToken(GUID_DEVINTERFACE_COMPORT, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE), new SetupToken(GUID_DEVINTERFACE_MODEM, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE) }; - - DataList serialPortDescriptorList = new DataArrayList(); - - for (int i = 0; i < setupTokens.length; ++i) - { - HANDLE deviceInfoSet = SetupApi.INSTANCE.SetupDiGetClassDevs(setupTokens[i].guid, null, null, setupTokens[i].flags); - if (deviceInfoSet == INVALID_HANDLE_VALUE) - { - return serialPortDescriptorList; - } - SP_DEVINFO_DATA deviceInfoData = new SP_DEVINFO_DATA(); - int index = 0; - while (SetupApi.INSTANCE.SetupDiEnumDeviceInfo(deviceInfoSet, index++, deviceInfoData)) - { - SerialPortDescriptor serialPortDescriptor; - - String portName = devicePortName(deviceInfoSet, deviceInfoData); - if (portName == null || portName.isEmpty() || portName.contains("LPT")) - { - continue; - } - if (anyOfPorts(serialPortDescriptorList, portName)) - { - continue; - } - String description = deviceDescription(deviceInfoSet, deviceInfoData); - String address = deviceAddress(deviceInfoSet, deviceInfoData); - String manufacturer = deviceManufacturer(deviceInfoSet, deviceInfoData); - String instanceIdentifier = deviceInstanceIdentifier(deviceInfoData.DevInst); - String serialNumber = deviceSerialNumber(instanceIdentifier, deviceInfoData.DevInst); - Number vendorIdentifier = deviceVendorIdentifier(instanceIdentifier); - Number productIdentifier = deviceProductIdentifier(instanceIdentifier); - try - { - serialPortDescriptor = new SerialPortDescriptor(address, portName, description, productIdentifier, vendorIdentifier, null, manufacturer, serialNumber); - } - catch (DataDictionaryException e) - { - e.printStackTrace(System.err); - continue; - } - serialPortDescriptorList.add(serialPortDescriptor); - - } - SetupApi.INSTANCE.SetupDiDestroyDeviceInfoList(deviceInfoSet); - } - - List portNames = portNamesFromHardwareDeviceMap(); - for (String portName : portNames) - { - if (!anyOfPorts(serialPortDescriptorList, portName)) - { - try - { - SerialPortDescriptor serialPortDescriptor = new SerialPortDescriptor(null, portName, null, null, null, null, null, null); - serialPortDescriptorList.add(serialPortDescriptor); - } - catch (DataDictionaryException e) - { - e.printStackTrace(System.err); - } - } - } - - return serialPortDescriptorList; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private static boolean anyOfPorts(DataList descriptors, String portName) - { - if (descriptors == null) - { - return false; - } - for (SerialPortDescriptor descriptor : descriptors) - { - if (descriptor.getPortName() == null) - { - if (portName != null) - { - continue; - } - else - { - return true; - } - } - if (descriptor.getPortName().equals(portName)) - { - return true; - } - } - - return false; - } - - private static String devicePortName(HANDLE deviceInfoSet, SP_DEVINFO_DATA deviceInfoData) - { - HKEY key = SetupApi.INSTANCE.SetupDiOpenDevRegKey(deviceInfoSet, deviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ); - - if (key == INVALID_HANDLE_VALUE) - { - return null; - } - String[] keyTokens = { "PortName", "PortNumber" }; - String portName = null; - for (int i = 0; i < keyTokens.length && portName == null; i++) - { - portName = Advapi32Util.registryGetStringValue(key, keyTokens[i]); - } - - return portName; - } - - private static String deviceDescription(HANDLE deviceInfoSet, SP_DEVINFO_DATA deviceInfoData) - { - return (String) deviceRegistryProperty(deviceInfoSet, deviceInfoData, SPDRP_DEVICEDESC); - } - - private static String deviceManufacturer(HANDLE deviceInfoSet, SP_DEVINFO_DATA deviceInfoData) - { - return (String) deviceRegistryProperty(deviceInfoSet, deviceInfoData, SPDRP_MFG); - } - - private static String deviceAddress(HANDLE deviceInfoSet, SP_DEVINFO_DATA deviceInfoData) - { - Integer address = (Integer) deviceRegistryProperty(deviceInfoSet, deviceInfoData, SPDRP_ADDRESS); - return (address != null) ? address.toString() : null; - } - - private static Number deviceVendorIdentifier(String instanceIdentifier) - { - final int vendorIdentifierSize = 4; - - Number result = parseDeviceIdentifier(instanceIdentifier, "VID_", vendorIdentifierSize); - if (result == null) - { - result = parseDeviceIdentifier(instanceIdentifier, "VEN_", vendorIdentifierSize); - } - - return result; - } - - private static Number deviceProductIdentifier(String instanceIdentifier) - { - final int productIdentifierSize = 4; - - Number result = parseDeviceIdentifier(instanceIdentifier, "PID_", productIdentifierSize); - if (result == null) - { - result = parseDeviceIdentifier(instanceIdentifier, "DEV_", productIdentifierSize); - } - - return result; - } - - private static String deviceInstanceIdentifier(int deviceInstanceNumber) - { - return Cfgmgr32Util.CM_Get_Device_ID(deviceInstanceNumber); - } - - private static String deviceSerialNumber(String instanceIdentifier, int deviceInstanceNumber) - { - for (;;) - { - String serialNumber = parseDeviceSerialNumber(instanceIdentifier); - if (serialNumber != null) - { - return serialNumber; - } - deviceInstanceNumber = parentDeviceInstanceNumber(deviceInstanceNumber); - if (deviceInstanceNumber == 0) - { - break; - } - instanceIdentifier = deviceInstanceIdentifier(deviceInstanceNumber); - if (instanceIdentifier.isEmpty()) - { - break; - } - } - - return null; - } - - private static Object deviceRegistryProperty(HANDLE deviceInfoSet, SP_DEVINFO_DATA deviceInfoData, int property) - { - Object propertyValue = null; - IntByReference dataType = new IntByReference(0); - Pointer outputBuffer = new Memory(PROPERTY_MAX_SIZE); - IntByReference bytesRequired = new IntByReference(PROPERTY_MAX_SIZE); - - if (SetupApi.INSTANCE.SetupDiGetDeviceRegistryProperty(deviceInfoSet, deviceInfoData, property, dataType, outputBuffer, bytesRequired.getValue(), bytesRequired)) - { - switch (dataType.getValue()) - { - case REG_DWORD: - propertyValue = outputBuffer.getInt(0); - break; - case REG_SZ: - propertyValue = outputBuffer.getWideString(0); - break; - } - } - - return propertyValue; - } - - private static int parentDeviceInstanceNumber(int childDeviceInstanceNumber) - { - IntByReference parentInstanceNumber = new IntByReference(0); - if (Cfgmgr32.INSTANCE.CM_Get_Parent(parentInstanceNumber, childDeviceInstanceNumber, 0) != Cfgmgr32.CR_SUCCESS) - { - return 0; - } - return parentInstanceNumber.getValue(); - } - - private static String parseDeviceSerialNumber(String instanceIdentifier) - { - int firstbound = instanceIdentifier.lastIndexOf('\\'); - int lastbound = instanceIdentifier.indexOf('_', firstbound); - if (instanceIdentifier.startsWith("USB\\")) - { - if (lastbound != instanceIdentifier.length() - 3) - lastbound = instanceIdentifier.length(); - int ampersand = instanceIdentifier.indexOf('&', firstbound); - if (ampersand != -1 && ampersand < lastbound) - return null; - } - else if (instanceIdentifier.startsWith("FTDIBUS\\")) - { - firstbound = instanceIdentifier.lastIndexOf('+'); - lastbound = instanceIdentifier.indexOf('\\', firstbound); - if (lastbound == -1) - return null; - } - else - { - return null; - } - - return instanceIdentifier.substring(firstbound + 1, lastbound); - } - - private static Number parseDeviceIdentifier(String instanceIdentifier, String identifierPrefix, int identifierSize) - { - int index = instanceIdentifier.indexOf(identifierPrefix); - - if (index == -1) - { - return null; - } - String indentifierText = instanceIdentifier.substring(index + identifierPrefix.length(), index + identifierPrefix.length() + identifierSize); - Number identifierValue; - try - { - identifierValue = Integer.parseInt(indentifierText, 16); - } - catch (Exception e) - { - identifierValue = null; - } - - return identifierValue; - } - - private static List portNamesFromHardwareDeviceMap() - { - List result = new ArrayList(); - HKEY hKey = null; - try - { - hKey = Advapi32Util.registryGetKey(HKEY_LOCAL_MACHINE, "HARDWARE\\DEVICEMAP\\SERIALCOMM", KEY_QUERY_VALUE).getValue(); - } - catch(Win32Exception exception) - { - return result; - } - int index = 0; - for (;;) - { - // This is a maximum length of value name, see: - // https://msdn.microsoft.com/en-us/library/windows/desktop/ms724872%28v=vs.85%29.aspx - IntByReference requiredValueNameChars = new IntByReference(16383); - char[] outputValueName = new char[requiredValueNameChars.getValue()]; - Pointer outputBuffer = new Memory(MAX_PATH); - IntByReference bytesRequired = new IntByReference(MAX_PATH); - int ret = Advapi32.INSTANCE.RegEnumValue(hKey, index, outputValueName, requiredValueNameChars, null, null, outputBuffer, bytesRequired); - if (ret == ERROR_SUCCESS) - { - result.add(outputBuffer.getWideString(0)); - ++index; - } - else - { - break; - } - } - Advapi32.INSTANCE.RegCloseKey(hKey); - - return result; - } -} diff --git a/src/main/java/enedis/lab/io/tic/TICModemType.java b/src/main/java/enedis/lab/io/tic/TICModemType.java deleted file mode 100644 index b1f3688..0000000 --- a/src/main/java/enedis/lab/io/tic/TICModemType.java +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.io.tic; - -/** - * TIC Modem type - */ -public enum TICModemType -{ - /** Modem michaud */ - MICHAUD(0x6001, 0x0403), - /** Télé info */ - TELEINFO(0x6015, 0x0403); - - private int productId; - private int vendorId; - - TICModemType(int productId, int vendorId) - { - this.productId = productId; - this.vendorId = vendorId; - } - - /** - * Get product id - * - * @return product id - */ - public int getProductId() - { - return this.productId; - } - - /** - * Get vendor id - * - * @return vendor id - */ - public int getVendorId() - { - return this.vendorId; - } -} diff --git a/src/main/java/enedis/lab/io/tic/TICPortDescriptor.java b/src/main/java/enedis/lab/io/tic/TICPortDescriptor.java deleted file mode 100644 index 675a073..0000000 --- a/src/main/java/enedis/lab/io/tic/TICPortDescriptor.java +++ /dev/null @@ -1,291 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.io.tic; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import enedis.lab.io.serialport.SerialPortDescriptor; -import enedis.lab.io.usb.USBPortDescriptor; -import enedis.lab.types.DataDictionary; -import enedis.lab.types.DataDictionaryException; -import enedis.lab.types.datadictionary.KeyDescriptor; -import enedis.lab.types.datadictionary.KeyDescriptorEnum; - -/** - * TICPortDescriptor class - * - * Generated - */ -public class TICPortDescriptor extends SerialPortDescriptor -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected static final String KEY_MODEM_TYPE = "modemType"; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private List> keys = new ArrayList>(); - - protected KeyDescriptorEnum kModemType; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected TICPortDescriptor() - { - super(); - this.loadKeyDescriptors(); - - } - - /** - * Constructor using map - * - * @param map - * @throws DataDictionaryException - */ - public TICPortDescriptor(Map map) throws DataDictionaryException - { - this(); - this.copy(fromMap(map)); - } - - /** - * Constructor using datadictionary - * - * @param other - * @throws DataDictionaryException - */ - public TICPortDescriptor(DataDictionary other) throws DataDictionaryException - { - this(); - this.copy(other); - } - - /** - * Constructor setting parameters to specific values - * - * @param portId - * @param portName - * @param description - * @param productName - * @param manufacturer - * @param serialNumber - * @param modemType - * @throws DataDictionaryException - */ - public TICPortDescriptor(String portId, String portName, String description, String productName, String manufacturer, String serialNumber, TICModemType modemType) - throws DataDictionaryException - { - this(); - - this.setPortId(portId); - this.setPortName(portName); - this.setDescription(description); - this.setProductName(productName); - this.setManufacturer(manufacturer); - this.setSerialNumber(serialNumber); - this.setModemType(modemType); - - this.checkAndUpdate(); - } - - /** - * Constructor setting parameters to specific values - * - * @param serialPortDescriptor - * @param modemType - * @throws DataDictionaryException - */ - public TICPortDescriptor(SerialPortDescriptor serialPortDescriptor, TICModemType modemType) throws DataDictionaryException - { - this(); - - this.checkProductId(serialPortDescriptor.getProductId(), modemType); - this.checkVendorId(serialPortDescriptor.getVendorId(), modemType); - - this.setPortId(serialPortDescriptor.getPortId()); - this.setPortName(serialPortDescriptor.getPortName()); - this.setDescription(serialPortDescriptor.getDescription()); - this.setProductId(serialPortDescriptor.getProductId()); - this.setVendorId(serialPortDescriptor.getVendorId()); - this.setProductName(serialPortDescriptor.getProductName()); - this.setManufacturer(serialPortDescriptor.getManufacturer()); - this.setSerialNumber(serialPortDescriptor.getSerialNumber()); - this.setModemType(modemType); - - this.checkAndUpdate(); - } - - /** - * Constructor setting parameters to specific values - * - * @param usbPortDescriptor - * @param modemType - * @throws DataDictionaryException - */ - public TICPortDescriptor(USBPortDescriptor usbPortDescriptor, TICModemType modemType) throws DataDictionaryException - { - this(); - - this.checkProductId(usbPortDescriptor.getIdProduct(), modemType); - this.checkVendorId(usbPortDescriptor.getIdVendor(), modemType); - - this.setProductId(usbPortDescriptor.getIdProduct()); - this.setVendorId(usbPortDescriptor.getIdVendor()); - this.setProductName(usbPortDescriptor.getProduct()); - this.setManufacturer(usbPortDescriptor.getManufacturer()); - this.setSerialNumber(usbPortDescriptor.getSerialNumber()); - this.setModemType(modemType); - - this.checkAndUpdate(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// SerialPortDescriptor - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - protected void updateOptionalParameters() throws DataDictionaryException - { - if (this.exists(KEY_MODEM_TYPE)) - { - if (this.getModemType() != null) - { - this.setProductId(this.getModemType().getProductId()); - this.setVendorId(this.getModemType().getVendorId()); - } - else - { - this.setProductId(null); - this.setVendorId(null); - } - } - super.updateOptionalParameters(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Get modem type - * - * @return the modem type - */ - public TICModemType getModemType() - { - return (TICModemType) this.data.get(KEY_MODEM_TYPE); - } - - /** - * Set modem type - * - * @param modemType - * @throws DataDictionaryException - */ - public void setModemType(TICModemType modemType) throws DataDictionaryException - { - this.setModemType((Object) modemType); - if (modemType != null) - { - this.setProductId(modemType.getProductId()); - this.setVendorId(modemType.getVendorId()); - } - else - { - this.setProductId(null); - this.setVendorId(null); - } - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected void setModemType(Object modemType) throws DataDictionaryException - { - if (modemType == null) - { - this.data.put(KEY_MODEM_TYPE, null); - } - else - { - this.data.put(KEY_MODEM_TYPE, this.kModemType.convert(modemType)); - } - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private void checkProductId(Number productId, TICModemType modemType) throws DataDictionaryException - { - if (modemType != null && productId != null && productId.intValue() != modemType.getProductId()) - { - throw new DataDictionaryException("TIC modem productId is inconsistent with the given one"); - } - } - - private void checkVendorId(Number vendorId, TICModemType modemType) throws DataDictionaryException - { - if (modemType != null && vendorId != null && vendorId.intValue() != modemType.getVendorId()) - { - throw new DataDictionaryException("TIC modem vendorId is inconsistent with the given one"); - } - } - - private void loadKeyDescriptors() - { - try - { - this.kModemType = new KeyDescriptorEnum(KEY_MODEM_TYPE, false, TICModemType.class); - this.keys.add(this.kModemType); - - this.addAllKeyDescriptor(this.keys); - } - catch (DataDictionaryException e) - { - throw new RuntimeException(e.getMessage(), e); - } - } -} diff --git a/src/main/java/enedis/lab/io/tic/TICPortFinder.java b/src/main/java/enedis/lab/io/tic/TICPortFinder.java deleted file mode 100644 index 370121b..0000000 --- a/src/main/java/enedis/lab/io/tic/TICPortFinder.java +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.io.tic; - -import enedis.lab.io.PortFinder; - -/** - * Interface used to find all TIC port descriptor - */ -public interface TICPortFinder extends PortFinder -{ - /** - * Find TIC port descriptor matching with port id - * - * @param portId - * the unique port identifier desired - * - * @return TIC port descriptor found, or null if nothing matches with portId - */ - public default TICPortDescriptor findByPortId(String portId) - { - return this.findAll().stream().filter(p -> (p.getPortId() != null) ? p.getPortId().equals(portId) : portId == null).findFirst().orElse(null); - } - - /** - * Find TIC port descriptor matching with port name - * - * @param portName - * the port name desired - * - * @return TIC port descriptor found, or null if nothing matches with portName - */ - public default TICPortDescriptor findByPortName(String portName) - { - return this.findAll().stream().filter(p -> (p.getPortName() != null) ? p.getPortName().equals(portName) : portName == null).findFirst().orElse(null); - } - - /** - * Find native TIC port (not USB) descriptor matching with port name - * - * @param portName - * the port name desired - * - * @return TIC port descriptor found, or null if nothing matches with portName - */ - public TICPortDescriptor findNative(String portName); - - /** - * Find TIC port descriptor matching with port id or port name - * - * @param portId - * the unique port identifier desired - * @param portName - * the port name desired - * - * @return TIC port descriptor found, or null if nothing matches with portName - */ - public default TICPortDescriptor findByPortIdOrPortName(String portId, String portName) - { - TICPortDescriptor descriptor = this.findByPortId(portId); - - if (descriptor == null) - { - descriptor = this.findByPortName(portId); - } - - return descriptor; - } -} diff --git a/src/main/java/enedis/lab/io/tic/TICPortFinderBase.java b/src/main/java/enedis/lab/io/tic/TICPortFinderBase.java deleted file mode 100644 index d4777c1..0000000 --- a/src/main/java/enedis/lab/io/tic/TICPortFinderBase.java +++ /dev/null @@ -1,206 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.io.tic; - -import java.util.List; - -import enedis.lab.io.serialport.SerialPortDescriptor; -import enedis.lab.io.serialport.SerialPortFinder; -import enedis.lab.io.serialport.SerialPortFinderBase; -import enedis.lab.io.usb.USBPortDescriptor; -import enedis.lab.io.usb.USBPortFinder; -import enedis.lab.io.usb.USBPortFinderBase; -import enedis.lab.types.DataArrayList; -import enedis.lab.types.DataDictionaryException; -import enedis.lab.types.DataList; - -/** - * Class used to find all TIC port descriptor - */ -public class TICPortFinderBase implements TICPortFinder -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Program writing the TIC port descriptor list (JSON format) on the output stream - * - * @param args - * not used - */ - public static void main(String[] args) - { - DataList descriptors = getInstance().findAll(); - - System.out.println(descriptors.toString(2)); - } - - /** - * Get instance - * - * @return Unique instance - */ - public static TICPortFinderBase getInstance() - { - if (instance == null) - { - instance = new TICPortFinderBase(); - } - - return instance; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private static TICPortFinderBase instance; - - private SerialPortFinder serialPortFinder; - private USBPortFinder usbPortFinder; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private TICPortFinderBase() - { - this(SerialPortFinderBase.getInstance(), USBPortFinderBase.getInstance()); - } - - /** - * Constructor with finder parameters - * - * @param serialPortFinder - * the serial port finder interface - * @param usbPortFinder - * the USB port finder interface - */ - public TICPortFinderBase(SerialPortFinder serialPortFinder, USBPortFinder usbPortFinder) - { - if (serialPortFinder == null) - { - throw new IllegalArgumentException("Cannot set null serial port finder"); - } - this.serialPortFinder = serialPortFinder; - if (usbPortFinder == null) - { - throw new IllegalArgumentException("Cannot set null USB port finder"); - } - this.usbPortFinder = usbPortFinder; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// TICPortFinder - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public DataList findAll() - { - DataList ticSerialPort = new DataArrayList(); - - for (TICModemType modemType : TICModemType.values()) - { - List tmpSerialPort = this.serialPortFinder.findByProductIdAndVendorId(modemType.getProductId(), modemType.getVendorId()); - - if (tmpSerialPort.isEmpty()) - { - List tmpUSBPort = this.usbPortFinder.findByProductIdAndVendorId(modemType.getProductId(), modemType.getVendorId()); - - for (USBPortDescriptor upd : tmpUSBPort) - { - try - { - TICPortDescriptor tic = new TICPortDescriptor(upd, modemType); - ticSerialPort.add(tic); - } - catch (DataDictionaryException e) - { - } - } - } - else - { - for (SerialPortDescriptor spd : tmpSerialPort) - { - try - { - TICPortDescriptor tic = new TICPortDescriptor(spd, modemType); - ticSerialPort.add(tic); - } - catch (DataDictionaryException e) - { - } - } - } - } - - return ticSerialPort; - } - - @Override - public TICPortDescriptor findNative(String portName) - { - TICPortDescriptor ticPortDescriptor = null; - SerialPortDescriptor serialPortDescriptor = this.serialPortFinder.findNative(portName); - - if (serialPortDescriptor != null) - { - try - { - ticPortDescriptor = new TICPortDescriptor(serialPortDescriptor, null); - } - catch (DataDictionaryException e) - { - } - } - - return ticPortDescriptor; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -} diff --git a/src/main/java/enedis/lab/io/tic/TICPortPlugNotifier.java b/src/main/java/enedis/lab/io/tic/TICPortPlugNotifier.java deleted file mode 100644 index d16edc8..0000000 --- a/src/main/java/enedis/lab/io/tic/TICPortPlugNotifier.java +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.io.tic; - -import org.json.JSONObject; - -import enedis.lab.io.PlugSubscriber; -import enedis.lab.io.PortPlugNotifier; - -/** - * Class used to notify when a TIC port has been plugged or unplugged - */ -public class TICPortPlugNotifier extends PortPlugNotifier -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private static final int DEFAULT_JSON_INDENTATION = 2; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Program writing on the output stream when an TIC port has been plugged or unplugged - * - * @param args - * not used - */ - public static void main(String[] args) - { - /* 1. Create notification service */ - TICPortPlugNotifier notifier = new TICPortPlugNotifier(); - /* 2. Create subscriber to print when an TIC port has been plugged or unplugged */ - PlugSubscriber subscriber = new PlugSubscriber() - { - @Override - public void onPlugged(TICPortDescriptor descriptor) - { - JSONObject jsonObject = new JSONObject(); - jsonObject.put(notifier.getClass().getSimpleName() + ".onPlugged", descriptor.toJSON()); - System.out.println(jsonObject.toString(DEFAULT_JSON_INDENTATION) + "\n"); - - } - @Override - public void onUnplugged(TICPortDescriptor descriptor) - { - JSONObject jsonObject = new JSONObject(); - jsonObject.put(notifier.getClass().getSimpleName() + ".onUnplugged", descriptor.toJSON()); - System.out.println(jsonObject.toString(DEFAULT_JSON_INDENTATION) + "\n"); - } - }; - /* 3. Run program printing when an TIC port has been plugged or unplugged until CTRL+C is pressed */ - PortPlugNotifier.main(notifier, subscriber); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Constructor with default parameter - * - * @see #DEFAULT_PERIOD - * @see TICPortFinderBase - */ - public TICPortPlugNotifier() - { - this(DEFAULT_PERIOD,TICPortFinderBase.getInstance()); - } - - /** - * Constructor with all parameters - * - * @param period the period (in milliseconds) used to look for plugged or unplugged TIC port - * @param finder the TIC port finder interface used to find all TIC port descriptors - */ - public TICPortPlugNotifier(long period,TICPortFinder finder) - { - super(period,finder); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// Runnable - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -} diff --git a/src/main/java/enedis/lab/io/usb/USBPortDescriptor.java b/src/main/java/enedis/lab/io/usb/USBPortDescriptor.java deleted file mode 100644 index b3f71fb..0000000 --- a/src/main/java/enedis/lab/io/usb/USBPortDescriptor.java +++ /dev/null @@ -1,711 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.io.usb; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import enedis.lab.types.DataDictionary; -import enedis.lab.types.DataDictionaryException; -import enedis.lab.types.datadictionary.DataDictionaryBase; -import enedis.lab.types.datadictionary.KeyDescriptor; -import enedis.lab.types.datadictionary.KeyDescriptorNumber; -import enedis.lab.types.datadictionary.KeyDescriptorString; - -/** - * USBPortDescriptor class - * - * Generated - */ -public class USBPortDescriptor extends DataDictionaryBase -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected static final String KEY_BCD_DEVICE = "bcdDevice"; - protected static final String KEY_BCD_USB = "bcdUSB"; - protected static final String KEY_B_DESCRIPTOR_TYPE = "bDescriptorType"; - protected static final String KEY_B_DEVICE_CLASS = "bDeviceClass"; - protected static final String KEY_B_DEVICE_PROTOCOL = "bDeviceProtocol"; - protected static final String KEY_B_DEVICE_SUB_CLASS = "bDeviceSubClass"; - protected static final String KEY_B_LENGTH = "bLength"; - protected static final String KEY_B_MAX_PACKET_SIZE0 = "bMaxPacketSize0"; - protected static final String KEY_B_NUM_CONFIGURATIONS = "bNumConfigurations"; - protected static final String KEY_ID_PRODUCT = "idProduct"; - protected static final String KEY_ID_VENDOR = "idVendor"; - protected static final String KEY_I_MANUFACTURER = "iManufacturer"; - protected static final String KEY_I_PRODUCT = "iProduct"; - protected static final String KEY_I_SERIAL_NUMBER = "iSerialNumber"; - protected static final String KEY_MANUFACTURER = "manufacturer"; - protected static final String KEY_PRODUCT = "product"; - protected static final String KEY_SERIAL_NUMBER = "serialNumber"; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private List> keys = new ArrayList>(); - - protected KeyDescriptorNumber kBcdDevice; - protected KeyDescriptorNumber kBcdUSB; - protected KeyDescriptorNumber kBDescriptorType; - protected KeyDescriptorNumber kBDeviceClass; - protected KeyDescriptorNumber kBDeviceProtocol; - protected KeyDescriptorNumber kBDeviceSubClass; - protected KeyDescriptorNumber kBLength; - protected KeyDescriptorNumber kBMaxPacketSize0; - protected KeyDescriptorNumber kBNumConfigurations; - protected KeyDescriptorNumber kIdProduct; - protected KeyDescriptorNumber kIdVendor; - protected KeyDescriptorNumber kIManufacturer; - protected KeyDescriptorNumber kIProduct; - protected KeyDescriptorNumber kISerialNumber; - protected KeyDescriptorString kManufacturer; - protected KeyDescriptorString kProduct; - protected KeyDescriptorString kSerialNumber; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected USBPortDescriptor() - { - super(); - this.loadKeyDescriptors(); - - } - - /** - * Constructor using map - * - * @param map - * @throws DataDictionaryException - */ - public USBPortDescriptor(Map map) throws DataDictionaryException - { - this(); - this.copy(fromMap(map)); - } - - /** - * Constructor using datadictionary - * - * @param other - * @throws DataDictionaryException - */ - public USBPortDescriptor(DataDictionary other) throws DataDictionaryException - { - this(); - this.copy(other); - } - - /** - * Constructor setting parameters to specific values - * - * @param bcdDevice - * @param bcdUSB - * @param bDescriptorType - * @param bDeviceClass - * @param bDeviceProtocol - * @param bDeviceSubClass - * @param bLength - * @param bMaxPacketSize0 - * @param bNumConfigurations - * @param idProduct - * @param idVendor - * @param iManufacturer - * @param iProduct - * @param iSerialNumber - * @param manufacturer - * @param product - * @param serialNumber - * @throws DataDictionaryException - */ - public USBPortDescriptor(Number bcdDevice, Number bcdUSB, Number bDescriptorType, Number bDeviceClass, Number bDeviceProtocol, Number bDeviceSubClass, Number bLength, - Number bMaxPacketSize0, Number bNumConfigurations, Number idProduct, Number idVendor, Number iManufacturer, Number iProduct, Number iSerialNumber, String manufacturer, - String product, String serialNumber) throws DataDictionaryException - { - this(); - - this.setBcdDevice(bcdDevice); - this.setBcdUSB(bcdUSB); - this.setBDescriptorType(bDescriptorType); - this.setBDeviceClass(bDeviceClass); - this.setBDeviceProtocol(bDeviceProtocol); - this.setBDeviceSubClass(bDeviceSubClass); - this.setBLength(bLength); - this.setBMaxPacketSize0(bMaxPacketSize0); - this.setBNumConfigurations(bNumConfigurations); - this.setIdProduct(idProduct); - this.setIdVendor(idVendor); - this.setIManufacturer(iManufacturer); - this.setIProduct(iProduct); - this.setISerialNumber(iSerialNumber); - this.setManufacturer(manufacturer); - this.setProduct(product); - this.setSerialNumber(serialNumber); - - this.checkAndUpdate(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// DataDictionaryBase - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - protected void updateOptionalParameters() throws DataDictionaryException - { - super.updateOptionalParameters(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Get bcd device - * - * @return the bcd device - */ - public Number getBcdDevice() - { - return (Number) this.data.get(KEY_BCD_DEVICE); - } - - /** - * Get bcd u s b - * - * @return the bcd u s b - */ - public Number getBcdUSB() - { - return (Number) this.data.get(KEY_BCD_USB); - } - - /** - * Get b descriptor type - * - * @return the b descriptor type - */ - public Number getBDescriptorType() - { - return (Number) this.data.get(KEY_B_DESCRIPTOR_TYPE); - } - - /** - * Get b device class - * - * @return the b device class - */ - public Number getBDeviceClass() - { - return (Number) this.data.get(KEY_B_DEVICE_CLASS); - } - - /** - * Get b device protocol - * - * @return the b device protocol - */ - public Number getBDeviceProtocol() - { - return (Number) this.data.get(KEY_B_DEVICE_PROTOCOL); - } - - /** - * Get b device sub class - * - * @return the b device sub class - */ - public Number getBDeviceSubClass() - { - return (Number) this.data.get(KEY_B_DEVICE_SUB_CLASS); - } - - /** - * Get b length - * - * @return the b length - */ - public Number getBLength() - { - return (Number) this.data.get(KEY_B_LENGTH); - } - - /** - * Get b max packet size0 - * - * @return the b max packet size0 - */ - public Number getBMaxPacketSize0() - { - return (Number) this.data.get(KEY_B_MAX_PACKET_SIZE0); - } - - /** - * Get b num configurations - * - * @return the b num configurations - */ - public Number getBNumConfigurations() - { - return (Number) this.data.get(KEY_B_NUM_CONFIGURATIONS); - } - - /** - * Get id product - * - * @return the id product - */ - public Number getIdProduct() - { - return (Number) this.data.get(KEY_ID_PRODUCT); - } - - /** - * Get id vendor - * - * @return the id vendor - */ - public Number getIdVendor() - { - return (Number) this.data.get(KEY_ID_VENDOR); - } - - /** - * Get i manufacturer - * - * @return the i manufacturer - */ - public Number getIManufacturer() - { - return (Number) this.data.get(KEY_I_MANUFACTURER); - } - - /** - * Get i product - * - * @return the i product - */ - public Number getIProduct() - { - return (Number) this.data.get(KEY_I_PRODUCT); - } - - /** - * Get i serial number - * - * @return the i serial number - */ - public Number getISerialNumber() - { - return (Number) this.data.get(KEY_I_SERIAL_NUMBER); - } - - /** - * Get manufacturer - * - * @return the manufacturer - */ - public String getManufacturer() - { - return (String) this.data.get(KEY_MANUFACTURER); - } - - /** - * Get product - * - * @return the product - */ - public String getProduct() - { - return (String) this.data.get(KEY_PRODUCT); - } - - /** - * Get serial number - * - * @return the serial number - */ - public String getSerialNumber() - { - return (String) this.data.get(KEY_SERIAL_NUMBER); - } - - /** - * Set bcd device - * - * @param bcdDevice - * @throws DataDictionaryException - */ - public void setBcdDevice(Number bcdDevice) throws DataDictionaryException - { - this.setBcdDevice((Object) bcdDevice); - } - - /** - * Set bcd u s b - * - * @param bcdUSB - * @throws DataDictionaryException - */ - public void setBcdUSB(Number bcdUSB) throws DataDictionaryException - { - this.setBcdUSB((Object) bcdUSB); - } - - /** - * Set b descriptor type - * - * @param bDescriptorType - * @throws DataDictionaryException - */ - public void setBDescriptorType(Number bDescriptorType) throws DataDictionaryException - { - this.setBDescriptorType((Object) bDescriptorType); - } - - /** - * Set b device class - * - * @param bDeviceClass - * @throws DataDictionaryException - */ - public void setBDeviceClass(Number bDeviceClass) throws DataDictionaryException - { - this.setBDeviceClass((Object) bDeviceClass); - } - - /** - * Set b device protocol - * - * @param bDeviceProtocol - * @throws DataDictionaryException - */ - public void setBDeviceProtocol(Number bDeviceProtocol) throws DataDictionaryException - { - this.setBDeviceProtocol((Object) bDeviceProtocol); - } - - /** - * Set b device sub class - * - * @param bDeviceSubClass - * @throws DataDictionaryException - */ - public void setBDeviceSubClass(Number bDeviceSubClass) throws DataDictionaryException - { - this.setBDeviceSubClass((Object) bDeviceSubClass); - } - - /** - * Set b length - * - * @param bLength - * @throws DataDictionaryException - */ - public void setBLength(Number bLength) throws DataDictionaryException - { - this.setBLength((Object) bLength); - } - - /** - * Set b max packet size0 - * - * @param bMaxPacketSize0 - * @throws DataDictionaryException - */ - public void setBMaxPacketSize0(Number bMaxPacketSize0) throws DataDictionaryException - { - this.setBMaxPacketSize0((Object) bMaxPacketSize0); - } - - /** - * Set b num configurations - * - * @param bNumConfigurations - * @throws DataDictionaryException - */ - public void setBNumConfigurations(Number bNumConfigurations) throws DataDictionaryException - { - this.setBNumConfigurations((Object) bNumConfigurations); - } - - /** - * Set id product - * - * @param idProduct - * @throws DataDictionaryException - */ - public void setIdProduct(Number idProduct) throws DataDictionaryException - { - this.setIdProduct((Object) idProduct); - } - - /** - * Set id vendor - * - * @param idVendor - * @throws DataDictionaryException - */ - public void setIdVendor(Number idVendor) throws DataDictionaryException - { - this.setIdVendor((Object) idVendor); - } - - /** - * Set i manufacturer - * - * @param iManufacturer - * @throws DataDictionaryException - */ - public void setIManufacturer(Number iManufacturer) throws DataDictionaryException - { - this.setIManufacturer((Object) iManufacturer); - } - - /** - * Set i product - * - * @param iProduct - * @throws DataDictionaryException - */ - public void setIProduct(Number iProduct) throws DataDictionaryException - { - this.setIProduct((Object) iProduct); - } - - /** - * Set i serial number - * - * @param iSerialNumber - * @throws DataDictionaryException - */ - public void setISerialNumber(Number iSerialNumber) throws DataDictionaryException - { - this.setISerialNumber((Object) iSerialNumber); - } - - /** - * Set manufacturer - * - * @param manufacturer - * @throws DataDictionaryException - */ - public void setManufacturer(String manufacturer) throws DataDictionaryException - { - this.setManufacturer((Object) manufacturer); - } - - /** - * Set product - * - * @param product - * @throws DataDictionaryException - */ - public void setProduct(String product) throws DataDictionaryException - { - this.setProduct((Object) product); - } - - /** - * Set serial number - * - * @param serialNumber - * @throws DataDictionaryException - */ - public void setSerialNumber(String serialNumber) throws DataDictionaryException - { - this.setSerialNumber((Object) serialNumber); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected void setBcdDevice(Object bcdDevice) throws DataDictionaryException - { - this.data.put(KEY_BCD_DEVICE, this.kBcdDevice.convert(bcdDevice)); - } - - protected void setBcdUSB(Object bcdUSB) throws DataDictionaryException - { - this.data.put(KEY_BCD_USB, this.kBcdUSB.convert(bcdUSB)); - } - - protected void setBDescriptorType(Object bDescriptorType) throws DataDictionaryException - { - this.data.put(KEY_B_DESCRIPTOR_TYPE, this.kBDescriptorType.convert(bDescriptorType)); - } - - protected void setBDeviceClass(Object bDeviceClass) throws DataDictionaryException - { - this.data.put(KEY_B_DEVICE_CLASS, this.kBDeviceClass.convert(bDeviceClass)); - } - - protected void setBDeviceProtocol(Object bDeviceProtocol) throws DataDictionaryException - { - this.data.put(KEY_B_DEVICE_PROTOCOL, this.kBDeviceProtocol.convert(bDeviceProtocol)); - } - - protected void setBDeviceSubClass(Object bDeviceSubClass) throws DataDictionaryException - { - this.data.put(KEY_B_DEVICE_SUB_CLASS, this.kBDeviceSubClass.convert(bDeviceSubClass)); - } - - protected void setBLength(Object bLength) throws DataDictionaryException - { - this.data.put(KEY_B_LENGTH, this.kBLength.convert(bLength)); - } - - protected void setBMaxPacketSize0(Object bMaxPacketSize0) throws DataDictionaryException - { - this.data.put(KEY_B_MAX_PACKET_SIZE0, this.kBMaxPacketSize0.convert(bMaxPacketSize0)); - } - - protected void setBNumConfigurations(Object bNumConfigurations) throws DataDictionaryException - { - this.data.put(KEY_B_NUM_CONFIGURATIONS, this.kBNumConfigurations.convert(bNumConfigurations)); - } - - protected void setIdProduct(Object idProduct) throws DataDictionaryException - { - this.data.put(KEY_ID_PRODUCT, this.kIdProduct.convert(idProduct)); - } - - protected void setIdVendor(Object idVendor) throws DataDictionaryException - { - this.data.put(KEY_ID_VENDOR, this.kIdVendor.convert(idVendor)); - } - - protected void setIManufacturer(Object iManufacturer) throws DataDictionaryException - { - this.data.put(KEY_I_MANUFACTURER, this.kIManufacturer.convert(iManufacturer)); - } - - protected void setIProduct(Object iProduct) throws DataDictionaryException - { - this.data.put(KEY_I_PRODUCT, this.kIProduct.convert(iProduct)); - } - - protected void setISerialNumber(Object iSerialNumber) throws DataDictionaryException - { - this.data.put(KEY_I_SERIAL_NUMBER, this.kISerialNumber.convert(iSerialNumber)); - } - - protected void setManufacturer(Object manufacturer) throws DataDictionaryException - { - this.data.put(KEY_MANUFACTURER, this.kManufacturer.convert(manufacturer)); - } - - protected void setProduct(Object product) throws DataDictionaryException - { - this.data.put(KEY_PRODUCT, this.kProduct.convert(product)); - } - - protected void setSerialNumber(Object serialNumber) throws DataDictionaryException - { - this.data.put(KEY_SERIAL_NUMBER, this.kSerialNumber.convert(serialNumber)); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private void loadKeyDescriptors() - { - try - { - this.kBcdDevice = new KeyDescriptorNumber(KEY_BCD_DEVICE, true); - this.keys.add(this.kBcdDevice); - - this.kBcdUSB = new KeyDescriptorNumber(KEY_BCD_USB, true); - this.keys.add(this.kBcdUSB); - - this.kBDescriptorType = new KeyDescriptorNumber(KEY_B_DESCRIPTOR_TYPE, true); - this.keys.add(this.kBDescriptorType); - - this.kBDeviceClass = new KeyDescriptorNumber(KEY_B_DEVICE_CLASS, true); - this.keys.add(this.kBDeviceClass); - - this.kBDeviceProtocol = new KeyDescriptorNumber(KEY_B_DEVICE_PROTOCOL, true); - this.keys.add(this.kBDeviceProtocol); - - this.kBDeviceSubClass = new KeyDescriptorNumber(KEY_B_DEVICE_SUB_CLASS, true); - this.keys.add(this.kBDeviceSubClass); - - this.kBLength = new KeyDescriptorNumber(KEY_B_LENGTH, true); - this.keys.add(this.kBLength); - - this.kBMaxPacketSize0 = new KeyDescriptorNumber(KEY_B_MAX_PACKET_SIZE0, true); - this.keys.add(this.kBMaxPacketSize0); - - this.kBNumConfigurations = new KeyDescriptorNumber(KEY_B_NUM_CONFIGURATIONS, true); - this.keys.add(this.kBNumConfigurations); - - this.kIdProduct = new KeyDescriptorNumber(KEY_ID_PRODUCT, true); - this.keys.add(this.kIdProduct); - - this.kIdVendor = new KeyDescriptorNumber(KEY_ID_VENDOR, true); - this.keys.add(this.kIdVendor); - - this.kIManufacturer = new KeyDescriptorNumber(KEY_I_MANUFACTURER, true); - this.keys.add(this.kIManufacturer); - - this.kIProduct = new KeyDescriptorNumber(KEY_I_PRODUCT, true); - this.keys.add(this.kIProduct); - - this.kISerialNumber = new KeyDescriptorNumber(KEY_I_SERIAL_NUMBER, true); - this.keys.add(this.kISerialNumber); - - this.kManufacturer = new KeyDescriptorString(KEY_MANUFACTURER, false, true); - this.keys.add(this.kManufacturer); - - this.kProduct = new KeyDescriptorString(KEY_PRODUCT, false, true); - this.keys.add(this.kProduct); - - this.kSerialNumber = new KeyDescriptorString(KEY_SERIAL_NUMBER, false, true); - this.keys.add(this.kSerialNumber); - - this.addAllKeyDescriptor(this.keys); - } - catch (DataDictionaryException e) - { - throw new RuntimeException(e.getMessage(), e); - } - } -} diff --git a/src/main/java/enedis/lab/io/usb/USBPortFinder.java b/src/main/java/enedis/lab/io/usb/USBPortFinder.java deleted file mode 100644 index 391e3e2..0000000 --- a/src/main/java/enedis/lab/io/usb/USBPortFinder.java +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.io.usb; - -import java.util.stream.Collectors; - -import enedis.lab.io.PortFinder; -import enedis.lab.types.DataArrayList; -import enedis.lab.types.DataList; - -/** - * Interface used to find all USB port descriptor - */ -public interface USBPortFinder extends PortFinder -{ - /** - * Find USB device with the given product id - * - * @param idProduct the USB product identifier - * @return the USB descriptor data list of all USB device connected with the given product id - */ - public default DataList findByProductId(int idProduct) - { - DataList descriptors = new DataArrayList(); - // @formatter:off - descriptors.addAll(this.findAll().stream() - .filter(d -> d.getIdProduct().intValue() == idProduct) - .collect(Collectors.toList())); - // @formatter:on - return descriptors; - } - - /** - * Find USB device with the given vendor id - * - * @param idVendor the USB vendor identifier - * @return the USB descriptor data list of all USB device connected with the given vendor id - */ - public default DataList findByVendorId(int idVendor) - { - DataList descriptors = new DataArrayList(); - // @formatter:off - descriptors.addAll(this.findAll().stream() - .filter(d -> d.getIdVendor().intValue() == idVendor) - .collect(Collectors.toList())); - // @formatter:on - return descriptors; - } - - /** - * Find USB device with the given product id and vendor id - * - * @param idProduct the USB product identifier - * @param idVendor the USB vendor identifier - * @return the USB descriptor data list of all USB device connected with the given product id and vendor id - */ - public default DataList findByProductIdAndVendorId(int idProduct, int idVendor) - { - DataList descriptors = new DataArrayList(); - // @formatter:off - descriptors.addAll(this.findAll().stream() - .filter(d -> d.getIdProduct().intValue() == idProduct) - .filter(d -> d.getIdVendor().intValue() == idVendor) - .collect(Collectors.toList())); - // @formatter:on - return descriptors; - } -} diff --git a/src/main/java/enedis/lab/io/usb/USBPortFinderBase.java b/src/main/java/enedis/lab/io/usb/USBPortFinderBase.java deleted file mode 100644 index 712626c..0000000 --- a/src/main/java/enedis/lab/io/usb/USBPortFinderBase.java +++ /dev/null @@ -1,201 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.io.usb; - -import org.usb4java.Context; -import org.usb4java.Device; -import org.usb4java.DeviceDescriptor; -import org.usb4java.DeviceHandle; -import org.usb4java.DeviceList; -import org.usb4java.LibUsb; - -import enedis.lab.types.DataArrayList; -import enedis.lab.types.DataDictionaryException; -import enedis.lab.types.DataList; - -/** - * Class used to find all USB port descriptor - */ -public class USBPortFinderBase implements USBPortFinder -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Program writing the USB port descriptor list (JSON format) on the output stream - * - * @param args - * not used - */ - public static void main(String[] args) - { - DataList descriptors = getInstance().findAll(); - - System.out.println(descriptors.toString(2)); - } - - /** - * Get instance - * - * @return Unique instance - */ - public static USBPortFinderBase getInstance() - { - if (instance == null) - { - instance = new USBPortFinderBase(); - } - - return instance; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private static USBPortFinderBase instance; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private USBPortFinderBase() - { - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// USBPortFinder - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public DataList findAll() - { - DataList usbPortList = new DataArrayList(); - - Context context = new Context(); - DeviceList deviceList = new DeviceList(); - - // Initialize USB library access - int result = LibUsb.init(context); - if (result != LibUsb.SUCCESS) - { - return usbPortList; - } - - // Get available USB device list - result = LibUsb.getDeviceList(context, deviceList); - if (result < 0) - { - return usbPortList; - } - - // For each USB device - for (Device device : deviceList) - { - DeviceDescriptor descriptor = new DeviceDescriptor(); - - // Get USB device descriptor - result = LibUsb.getDeviceDescriptor(device, descriptor); - if (result != LibUsb.SUCCESS) - { - continue; - } - String productName = null; - String manufacturer = null; - String serialNumber = null; - // If USB device has string descriptors - if (descriptor.idProduct() != 0) - { - // Get string descriptors for USB device - DeviceHandle handle = new DeviceHandle(); - result = LibUsb.open(device, handle); - if (result == LibUsb.SUCCESS) - { - productName = LibUsb.getStringDescriptor(handle, descriptor.iProduct()); - manufacturer = LibUsb.getStringDescriptor(handle, descriptor.iManufacturer()); - serialNumber = LibUsb.getStringDescriptor(handle, descriptor.iSerialNumber()); - LibUsb.close(handle); - } - } - - try - { - // @formatter:off - USBPortDescriptor usbPort = new USBPortDescriptor( - descriptor.bcdDevice() & 0xFFFF, - descriptor.bcdUSB() & 0xFFFF, - descriptor.bDescriptorType() & 0xFF, - descriptor.bDeviceClass() & 0xFF, - descriptor.bDeviceProtocol() & 0xFF, - descriptor.bDeviceSubClass() & 0xFF, - descriptor.bLength() & 0xFF, - descriptor.bMaxPacketSize0() & 0xFF, - descriptor.bNumConfigurations() & 0xFF, - descriptor.idProduct() & 0xFFFF, - descriptor.idVendor() & 0xFFFF, - descriptor.iManufacturer() & 0xFF, - descriptor.iProduct() & 0xFF, - descriptor.iSerialNumber() & 0xFF, - manufacturer, - productName, - serialNumber); - // @formatter:on - usbPortList.add(usbPort); - } - catch (DataDictionaryException e) - { - } - } - - // Finalize USB library access - LibUsb.freeDeviceList(deviceList, true); - LibUsb.exit(context); - return usbPortList; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -} diff --git a/src/main/java/enedis/lab/protocol/tic/TICMode.java b/src/main/java/enedis/lab/protocol/tic/TICMode.java deleted file mode 100644 index 5bbc299..0000000 --- a/src/main/java/enedis/lab/protocol/tic/TICMode.java +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.protocol.tic; - -import java.util.Arrays; - -/** - * TIC mode used available - */ - -import enedis.lab.protocol.tic.frame.TICError; -import enedis.lab.protocol.tic.frame.standard.TICException; - -/** - * TIC Mode - * - */ -public enum TICMode -{ - /** Unknown mode */ - UNKNOWN, - /** Standard mode */ - STANDARD, - /** Historic mode */ - HISTORIC, - /** Auto mode */ - AUTO; - - /** Historic separator */ - public static final char HISTORIC_SEPARATOR = ' '; - /** Standard separator */ - public static final char STANDARD_SEPARATOR = '\t'; - /** Historic buffer start */ - public static final byte[] HISTORIC_BUFFER_START = { 2, 10, 65, 68, 67, 79 }; - /** Standard buffer start */ - public static final byte[] STANDARD_BUFFER_START = { 2, 10, 65, 68, 83, 67 }; - - /** - * Find mode from Frame Buffer - * - * @param frameBuffer - * @return TICMode - * @throws TICException - */ - public static TICMode findModeFromFrameBuffer(byte[] frameBuffer) throws TICException - { - byte[] frameBufferStart = new byte[HISTORIC_BUFFER_START.length]; - if (frameBuffer.length < frameBufferStart.length) - { - throw new TICException("Tic frame read 0x" + bytesToHex(frameBuffer) + " too short to determine TIC Mode !", - TICError.TIC_READER_FRAME_DECODE_FAILED); - } - System.arraycopy(frameBuffer, 0, frameBufferStart, 0, frameBufferStart.length); - if (Arrays.equals(frameBufferStart, HISTORIC_BUFFER_START)) - { - return HISTORIC; - } - else - { - if (STANDARD_BUFFER_START.length != HISTORIC_BUFFER_START.length) - { - frameBufferStart = new byte[STANDARD_BUFFER_START.length]; - System.arraycopy(frameBuffer, 0, frameBufferStart, 0, frameBufferStart.length); - } - if (Arrays.equals(frameBufferStart, STANDARD_BUFFER_START)) - { - return STANDARD; - } - return null; - } - } - - /** - * Find Mode frome Group Buffer - * - * @param groupBuffer - * @return TICMode - */ - public static TICMode findModeFromGroupBuffer(byte[] groupBuffer) - { - for (int i = 0; i < groupBuffer.length; i++) - { - if (groupBuffer[i] == HISTORIC_SEPARATOR) - { - return HISTORIC; - } - else if (groupBuffer[i] == STANDARD_SEPARATOR) - { - return STANDARD; - } - } - return null; - } - - /** - * Convert byte array to hexadecimal string (replacement for - * DatatypeConverter.printHexBinary) - * - * @param bytes the byte array to convert - * @return hexadecimal string representation - */ - private static String bytesToHex(byte[] bytes) { - StringBuilder result = new StringBuilder(); - for (byte b : bytes) { - result.append(String.format("%02X", b)); - } - return result.toString(); - } - -} diff --git a/src/main/java/enedis/lab/protocol/tic/channels/ChannelTICSerialPort.java b/src/main/java/enedis/lab/protocol/tic/channels/ChannelTICSerialPort.java deleted file mode 100644 index 468c112..0000000 --- a/src/main/java/enedis/lab/protocol/tic/channels/ChannelTICSerialPort.java +++ /dev/null @@ -1,326 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.protocol.tic.channels; - -import java.util.Arrays; - -import enedis.lab.io.channels.ChannelConfiguration; -import enedis.lab.io.channels.ChannelException; -import enedis.lab.io.channels.serialport.ChannelSerialPort; -import enedis.lab.io.channels.serialport.ChannelSerialPortErrorCode; -import enedis.lab.protocol.tic.TICMode; -import enedis.lab.types.BytesArray; -import enedis.lab.types.DataDictionaryException; -import enedis.lab.util.time.Time; - -/** - * Channel TIC SerialPort - */ -public class ChannelTICSerialPort extends ChannelSerialPort -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private static final byte START_PATTERN = (byte) 0x02; - private static final byte END_PATTERN = (byte) 0x03; - private static final int RECEIVE_DATA_POLLING_PERIOD = 100; - private static final byte[] HISTORIC_BUFFER_START = { 2, 10, 65, 68, 67, 79 }; - private static final byte[] STANDARD_BUFFER_START = { 2, 10, 65, 68, 83, 67 }; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private TICMode currentMode; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Constructor: create an instance from a SerialPortConfiguration - * - * @param configuration - * @throws ChannelException - */ - public ChannelTICSerialPort(ChannelTICSerialPortConfiguration configuration) throws ChannelException - { - super(configuration); - this.currentMode = null; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// Channel - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public void setup(ChannelConfiguration configuration) throws ChannelException - { - if (configuration == null) - { - ChannelException.raiseInvalidConfiguration("null"); - } - if (!(configuration instanceof ChannelTICSerialPortConfiguration)) - { - ChannelException.raiseInvalidConfigurationType(configuration, ChannelTICSerialPortConfiguration.class.getSimpleName()); - } - super.setup(configuration); - } - - @Override - public ChannelTICSerialPortConfiguration getConfiguration() - { - return (ChannelTICSerialPortConfiguration) this.configuration; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Get mode - * - * @return TIC Mode - */ - public TICMode getMode() - { - return (this.getCurrentMode() != null) ? this.getCurrentMode() : this.getSelectedMode(); - } - - /** - * Get selected mode - * - * @return selected Mode - */ - public TICMode getSelectedMode() - { - return this.getConfiguration().getTicMode(); - } - - /** - * Get current mode - * - * @return current Mode - */ - public TICMode getCurrentMode() - { - return this.currentMode; - } - - @Override - public byte[] read() throws ChannelException - { - long beginTime = System.currentTimeMillis(); - long elapsedTime = 0; - long timeout = this.getSyncReadTimeout(); - BytesArray buffer = new BytesArray(); - byte[] ticFrame = null; - int startOfFrame = -1, endOfFrame = -1; - - while (elapsedTime < timeout || timeout == 0) - { - if (this.available() > 0) - { - buffer.addAll(super.read(1)); - if (startOfFrame == -1) - { - startOfFrame = buffer.indexOf(START_PATTERN); - if (startOfFrame != -1) - { - endOfFrame = buffer.indexOf(END_PATTERN, startOfFrame + 1); - if (endOfFrame != -1) - { - ticFrame = buffer.subList(startOfFrame, endOfFrame).getBytes(); - break; - } - } - } - else - { - endOfFrame = buffer.indexOf(END_PATTERN, startOfFrame + 1); - if (endOfFrame != -1) - { - ticFrame = buffer.subList(startOfFrame, endOfFrame).getBytes(); - break; - } - } - } - else - { - Time.sleep(RECEIVE_DATA_POLLING_PERIOD); - elapsedTime = (System.currentTimeMillis() - beginTime); - } - } - - return ticFrame; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - protected void receiveData() - { - if (this.currentMode == null) - { - if (this.autoDetectMode() == null) - { - this.onReadTimeout(); - return; - } - } - try - { - byte[] ticFrame = this.read(); - - if (ticFrame == null) - { - this.onReadTimeout(); - } - else - { - this.notifyOnDataRead(ticFrame); - } - } - catch (ChannelException e) - { - this.notifyOnErrorDetected(ChannelSerialPortErrorCode.READ_FAILED.getCode(ERROR_CODE_OFFSET), "TIC read failed: " + e.getErrorInfo()); - } - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private void onReadTimeout() - { - this.notifyOnErrorDetected(ChannelSerialPortErrorCode.READ_TIMEOUT.getCode(ERROR_CODE_OFFSET), "TIC read timeout"); - this.configurePort(); - this.currentMode = null; - } - - private void configurePort() - { - this.closePort(); - this.openPort(); - try - { - this.flush(); - } - catch (ChannelException e) - { - } - } - - private void setSelectedMode(TICMode ticMode) - { - try - { - this.getConfiguration().setTicMode(ticMode); - } - catch (DataDictionaryException e) - { - this.logger.error("Cannot set TIC mode " + ticMode, e); - } - } - - private boolean checkAndUpdateMode(TICMode ticMode) - { - boolean result = false; - this.setSelectedMode(ticMode); - this.configurePort(); - try - { - byte[] ticFrame = this.read(); - if (ticFrame != null && ticFrame.length > HISTORIC_BUFFER_START.length) - { - byte[] ticFrameStart = new byte[HISTORIC_BUFFER_START.length]; - System.arraycopy(ticFrame, 0, ticFrameStart, 0, ticFrameStart.length); - if (ticMode == TICMode.HISTORIC) - { - if (Arrays.equals(ticFrameStart, HISTORIC_BUFFER_START)) - { - result = true; - } - } - else if (ticMode == TICMode.STANDARD) - { - if (Arrays.equals(ticFrameStart, STANDARD_BUFFER_START)) - { - result = true; - } - } - } - } - catch (ChannelException e) - { - this.notifyOnErrorDetected(ChannelSerialPortErrorCode.READ_FAILED.getCode(ERROR_CODE_OFFSET), "TIC read failed: " + e.getErrorInfo()); - } - if (result) - { - this.currentMode = ticMode; - } - this.setSelectedMode(TICMode.AUTO); - - return result; - } - - private TICMode autoDetectMode() - { - if (this.getSelectedMode() != TICMode.AUTO) - { - this.currentMode = this.getSelectedMode(); - return this.getSelectedMode(); - } - this.logger.debug("Auto detecting TIC Mode"); - if (!this.checkAndUpdateMode(TICMode.HISTORIC)) - { - if (!this.checkAndUpdateMode(TICMode.STANDARD)) - { - this.logger.debug("TIC Mode not detected"); - - return null; - } - this.logger.debug("TIC Mode STANDARD detected"); - - return TICMode.STANDARD; - } - this.logger.debug("TIC Mode HISTORIC detected"); - - return TICMode.HISTORIC; - } -} diff --git a/src/main/java/enedis/lab/protocol/tic/channels/ChannelTICSerialPortConfiguration.java b/src/main/java/enedis/lab/protocol/tic/channels/ChannelTICSerialPortConfiguration.java deleted file mode 100644 index ecfeff6..0000000 --- a/src/main/java/enedis/lab/protocol/tic/channels/ChannelTICSerialPortConfiguration.java +++ /dev/null @@ -1,250 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.protocol.tic.channels; - -import java.io.File; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import enedis.lab.io.channels.serialport.ChannelSerialPortConfiguration; -import enedis.lab.io.channels.serialport.Parity; -import enedis.lab.protocol.tic.TICMode; -import enedis.lab.types.DataDictionary; -import enedis.lab.types.DataDictionaryException; -import enedis.lab.types.datadictionary.KeyDescriptor; -import enedis.lab.types.datadictionary.KeyDescriptorEnum; - -/** - * ChannelTICSerialPortConfiguration class - * - * Generated - */ -public class ChannelTICSerialPortConfiguration extends ChannelSerialPortConfiguration -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected static final String KEY_TIC_MODE = "ticMode"; - - protected static final Number BAUDRATE_HISTORIC = 1200; - protected static final Number BAUDRATE_STANDARD = 9600; - protected static final Number[] BAUDRATE_ACCEPTED_VALUES = { BAUDRATE_HISTORIC, BAUDRATE_STANDARD }; - protected static final Parity PARITY_ACCEPTED_VALUE = Parity.EVEN; - protected static final Number DATA_BITS_ACCEPTED_VALUE = 7; - protected static final Number STOP_BITS_ACCEPTED_VALUE = 1.0d; - protected static final TICMode TIC_MODE_DEFAULT_VALUE = TICMode.AUTO; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private List> keys = new ArrayList>(); - - protected KeyDescriptorEnum kTicMode; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected ChannelTICSerialPortConfiguration() - { - super(); - this.loadKeyDescriptors(); - - this.kBaudrate.setAcceptedValues(BAUDRATE_ACCEPTED_VALUES); - this.kParity.setAcceptedValues(PARITY_ACCEPTED_VALUE); - this.kDataBits.setAcceptedValues(DATA_BITS_ACCEPTED_VALUE); - this.kStopBits.setAcceptedValues(STOP_BITS_ACCEPTED_VALUE); - } - - /** - * Constructor using map - * - * @param map - * @throws DataDictionaryException - */ - public ChannelTICSerialPortConfiguration(Map map) throws DataDictionaryException - { - this(); - this.copy(fromMap(map)); - } - - /** - * Constructor using datadictionary - * - * @param other - * @throws DataDictionaryException - */ - public ChannelTICSerialPortConfiguration(DataDictionary other) throws DataDictionaryException - { - this(); - this.copy(other); - } - - /** - * - * Constructor setting configuration name/file and parameters to default values - * - * @param name - * the configuration name - * @param file - * the configuration file - */ - public ChannelTICSerialPortConfiguration(String name, File file) - { - this(); - this.init(name, file); - } - - /** - * Constructor setting parameters to specific values - * - * @param name - * @param portName - * @param ticMode - * @throws DataDictionaryException - */ - public ChannelTICSerialPortConfiguration(String name, String portName, TICMode ticMode) throws DataDictionaryException - { - this(); - - this.setName(name); - this.setPortName(portName); - this.setTicMode(ticMode); - - this.checkAndUpdate(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// ChannelSerialPortConfiguration - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - protected void updateOptionalParameters() throws DataDictionaryException - { - if (!this.exists(KEY_TIC_MODE)) - { - this.setTicMode(TIC_MODE_DEFAULT_VALUE); - } - switch (this.getTicMode()) - { - case HISTORIC: - { - this.setBaudrate(BAUDRATE_HISTORIC); - this.setParity(PARITY_ACCEPTED_VALUE); - this.setDataBits(DATA_BITS_ACCEPTED_VALUE); - this.setStopBits(STOP_BITS_ACCEPTED_VALUE); - break; - } - case STANDARD: - case AUTO: - default: - { - this.setBaudrate(BAUDRATE_STANDARD); - this.setParity(PARITY_ACCEPTED_VALUE); - this.setDataBits(DATA_BITS_ACCEPTED_VALUE); - this.setStopBits(STOP_BITS_ACCEPTED_VALUE); - } - } - super.updateOptionalParameters(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Get tic mode - * - * @return the tic mode - */ - public TICMode getTicMode() - { - return (TICMode) this.data.get(KEY_TIC_MODE); - } - - /** - * Set tic mode - * - * @param ticMode - * @throws DataDictionaryException - */ - public void setTicMode(TICMode ticMode) throws DataDictionaryException - { - this.setTicMode((Object) ticMode); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected void setTicMode(Object ticMode) throws DataDictionaryException - { - this.data.put(KEY_TIC_MODE, this.kTicMode.convert(ticMode)); - switch (this.getTicMode()) - { - case HISTORIC: - this.setBaudrate(BAUDRATE_HISTORIC); - break; - case STANDARD: - case AUTO: - this.setBaudrate(BAUDRATE_STANDARD); - break; - default: - break; - } - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private void loadKeyDescriptors() - { - try - { - this.kTicMode = new KeyDescriptorEnum(KEY_TIC_MODE, true, TICMode.class); - this.keys.add(this.kTicMode); - - this.addAllKeyDescriptor(this.keys); - } - catch (DataDictionaryException e) - { - throw new RuntimeException(e.getMessage(), e); - } - } -} diff --git a/src/main/java/enedis/lab/protocol/tic/channels/serialport/ChannelSerialPort.java b/src/main/java/enedis/lab/protocol/tic/channels/serialport/ChannelSerialPort.java deleted file mode 100644 index 5a47500..0000000 --- a/src/main/java/enedis/lab/protocol/tic/channels/serialport/ChannelSerialPort.java +++ /dev/null @@ -1,823 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.io.channels.serialport; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; - -import org.apache.commons.lang3.SystemUtils; - -import enedis.lab.io.channels.ChannelConfiguration; -import enedis.lab.io.channels.ChannelException; -import enedis.lab.io.channels.ChannelPhysical; -import enedis.lab.io.channels.ChannelStatus; -import enedis.lab.io.serialport.SerialPortDescriptor; -import enedis.lab.io.serialport.SerialPortFinderBase; -import enedis.lab.types.DataDictionaryException; -import enedis.lab.util.SystemError; -import jssc.SerialPort; -import jssc.SerialPortEvent; -import jssc.SerialPortEventListener; -import jssc.SerialPortException; -import jssc.SerialPortTimeoutException; - -/** - * Channel serial port - */ -public class ChannelSerialPort extends ChannelPhysical implements SerialPortEventListener -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected static final int ERROR_CODE_OFFSET = 1000; - private static final int DEFAULT_DELAY = 500; - private static final int DELAY_REOPEN = DEFAULT_DELAY * 10; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Check if the port is found - * - * @param portId - * @param portName - * @return true if the specified port is found - */ - public static boolean isPortFound(String portId, String portName) - { - return SerialPortFinderBase.getInstance().findByPortIdOrPortName(portId, portName) != null; - } - - /** - * Find the port name corresponding to the given portId or portName. portId has a higher priority - * - * @param portId - * @param portName - * @return port name - */ - public static String findPortName(String portId, String portName) - { - SerialPortDescriptor descriptor = null; - if (portId != null) - { - descriptor = SerialPortFinderBase.getInstance().findByPortId(portId); - } - else - { - descriptor = SerialPortFinderBase.getInstance().findByPortName(portName); - } - - return (descriptor != null) ? descriptor.getPortName() : null; - } - - /** - * Convert the parity provided by the SerialPortConfiguration to a value usable by the channel - * - * @param parity - * @return parity - */ - public static int parityFromConfiguration(Parity parity) - { - int retVal = -1; - - switch (parity) - { - case EVEN: - retVal = SerialPort.PARITY_EVEN; - break; - case MARK: - retVal = SerialPort.PARITY_MARK; - break; - case NONE: - retVal = SerialPort.PARITY_NONE; - break; - case ODD: - retVal = SerialPort.PARITY_ODD; - break; - case SPACE: - retVal = SerialPort.PARITY_SPACE; - break; - default: /* Cas non atteignable */ - } - - return retVal; - } - - /** - * Convert the stopBits parameter provided by the SerialPortConfiguration to a value usable by the channel - * - * @param stop_bits - * @return stopBits - */ - public static int stopBitsFromConfiguration(float stop_bits) - { - int retVal = -1; - - if (1 == stop_bits) - { - retVal = SerialPort.STOPBITS_1; - } - - else if (1.5 == stop_bits) - { - retVal = SerialPort.STOPBITS_1_5; - } - - else if (2 == stop_bits) - { - retVal = SerialPort.STOPBITS_2; - } - - return retVal; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private SerialPort portHandler = null; - - private String previousPortName; - private String currentPortName; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Constructor: create an instance from a ChannelConfiguration - * - * @param configuration - * @throws ChannelException - */ - public ChannelSerialPort(ChannelConfiguration configuration) throws ChannelException - { - super(configuration); - this.setPeriod(DEFAULT_DELAY); - - this.currentPortName = this.findPortName(); - this.previousPortName = this.currentPortName; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// Channel - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public void start() - { - this.logger.info("Channel " + this.getName() + " start (" + this.findPortName() + ")"); - this.openPort(); - super.start(); - } - - @Override - public void stop() - { - this.logger.info("Channel " + this.getName() + " stop (" + this.findPortName() + ")"); - super.stop(); - this.closePort(); - } - - @Override - public void setup(ChannelConfiguration configuration) throws ChannelException - { - if (configuration == null) - { - ChannelException.raiseInvalidConfiguration("null"); - } - if (!(configuration instanceof ChannelSerialPortConfiguration)) - { - ChannelException.raiseInvalidConfigurationType(configuration, ChannelSerialPortConfiguration.class.getSimpleName()); - } - super.setup(configuration); - } - - @Override - public byte[] read() throws ChannelException - { - byte[] buffer = null; - - if (this.portHandler == null || !this.portHandler.isOpened()) - { - ChannelException.raiseChannelNotReady(this.getPortName()); - } - try - { - buffer = this.portHandler.readBytes(); - } - catch (SerialPortException exception) - { - this.setStatus(ChannelStatus.ERROR); - this.logger.error("Cannot read bytes", exception); - ChannelException.raiseInternalError(exception.getMessage()); - } - - return buffer; - } - - @Override - public void write(byte[] data) throws ChannelException - { - if (this.portHandler == null || !this.portHandler.isOpened()) - { - ChannelException.raiseChannelNotReady(this.getPortName()); - } - try - { - this.portHandler.writeBytes(data); - } - catch (SerialPortException exception) - { - this.setStatus(ChannelStatus.ERROR); - this.logger.error("Cannot write bytes", exception); - ChannelException.raiseInternalError(exception.getMessage()); - } - } - - @Override - public ChannelSerialPortConfiguration getConfiguration() - { - return (ChannelSerialPortConfiguration) this.configuration.clone(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// ChannelBase - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - protected void setup() throws ChannelException - { - /* 1. Save current state */ - ChannelStatus currentStatus = this.status; - /* 2. Stop serial port */ - this.stop(); - /* 3. update path if symbolic link */ - this.updateRealPath(); - /* 4. Create serial port handler */ - if ((null == this.portHandler) || (false == this.getPortName().equals(this.portHandler.getPortName()))) - { - this.portHandler = new SerialPort(this.getPortName()); - } - /* 5. Restore current state */ - if (ChannelStatus.STARTED == currentStatus) - { - this.start(); - } - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// SerialPortEventListener - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public void serialEvent(SerialPortEvent event) - { - switch (event.getEventType()) - { - case SerialPortEvent.RXCHAR: - this.receiveData(); - break; - default: /* Aucune action */ - } - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// Runnable - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - protected void process() - { - int delay = DEFAULT_DELAY; - - if (this.status == ChannelStatus.STARTED) - { - if (!this.isPortFound()) - { - this.onPortNotFound(); - } - else if (this.hasPortChanged()) - { - this.onPortNameChanged(); - } - else if (!this.hasEventListener()) - { - this.receiveData(); - } - } - else - { - if (this.isPortFound()) - { - this.openPort(); - if (this.status == ChannelStatus.ERROR) - { - delay = DELAY_REOPEN; - } - } - } - this.setPeriod(delay); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Blocking Read - * - * @param bytesCount - * @return read bytes - * @throws ChannelException - */ - public byte[] read(int bytesCount) throws ChannelException - { - byte[] buffer = null; - - if (this.portHandler == null || !this.portHandler.isOpened()) - { - ChannelException.raiseChannelNotReady(this.getPortName()); - } - try - { - buffer = this.portHandler.readBytes(bytesCount); - } - catch (SerialPortException exception) - { - this.setStatus(ChannelStatus.ERROR); - this.logger.error("Cannot read bytes", exception); - ChannelException.raiseInternalError(exception.getMessage()); - } - - return buffer; - } - - /** - * Blocking read with timeout - * - * @param bytesCount - * @param timeout - * @return read bytes - * @throws ChannelException - */ - public byte[] read(int bytesCount, int timeout) throws ChannelException - { - byte[] buffer = null; - - if (this.portHandler == null || !this.portHandler.isOpened()) - { - ChannelException.raiseChannelNotReady(this.getPortName()); - } - try - { - buffer = this.portHandler.readBytes(bytesCount, timeout); - } - catch (SerialPortException exception) - { - this.logger.error("Cannot read bytes", exception); - ChannelException.raiseInternalError(exception.getMessage()); - } - catch (SerialPortTimeoutException exception) - { - ChannelException.raiseInternalError(exception.getMessage()); - } - - return buffer; - } - - /** - * Get available bytes count - * - * @return Available bytes count - * @throws ChannelException - * if serial port not open or internal error occurs - */ - public int available() throws ChannelException - { - if (this.portHandler == null || !this.portHandler.isOpened()) - { - ChannelException.raiseChannelNotReady(this.getPortName()); - } - try - { - return this.portHandler.getInputBufferBytesCount(); - } - catch (SerialPortException exception) - { - this.logger.error("Cannot get bytes available", exception); - ChannelException.raiseInternalError(exception.getMessage()); - } - - return 0; - } - - /** - * Flush port - * - * @throws ChannelException - */ - public void flush() throws ChannelException - { - if (this.portHandler == null || !this.portHandler.isOpened()) - { - ChannelException.raiseChannelNotReady(this.getPortName()); - } - try - { - int mask = SerialPort.PURGE_RXCLEAR | SerialPort.PURGE_RXABORT | SerialPort.PURGE_TXCLEAR | SerialPort.PURGE_TXABORT; - if (!this.portHandler.purgePort(mask)) - { - this.logger.error("Channel " + this.getName() + " failed to purge port " + this.getPortName() + " (" + SystemError.getMessage() + ") "); - } - } - catch (SerialPortException exception) - { - this.logger.error("Cannot purge port", exception); - ChannelException.raiseInternalError(exception.getMessage()); - } - } - - /** - * - * @return the identifier of the port. If the parameter has not been set, 'null' is returned. - */ - public String getPortId() - { - return this.getChannelConfiguration().getPortId(); - } - - /** - * - * @return the name of the port. If the parameter has not been set, 'null' is returned. - */ - public String getPortName() - { - return this.getChannelConfiguration().getPortName(); - } - - /** - * - * @return the name of the port opened. If the port has not been opened, 'null' is returned. - */ - public String getPortNameOpened() - { - return (this.portHandler != null) ? this.portHandler.getPortName() : null; - } - - /** - * Find the port name associated with configuration - * - * @return Port name found or null if nothing found - */ - public String findPortName() - { - return findPortName(this.getPortId(), this.getPortName()); - } - - /** - * @return the current baudrate value. If the Baudrate has not been set (port has not been used), -1 is returned - */ - public int getBaudrate() - { - return this.getChannelConfiguration().getBaudrate().intValue(); - } - - /** - * @return the number of bits used for data (5, 6, 7, 8). If the parameter does not exist in channel configuration - * or is not consistent, the value '-1' is returned. - */ - public int getDataBits() - { - return this.getChannelConfiguration().getDataBits().intValue(); - } - - /** - * @return the current number of bits used for stop (1.0 , 1.5 , 2.0). - * - * NB : If the port has been used, the method returns -1. - */ - public float getStopBits() - { - return this.getChannelConfiguration().getStopBits().floatValue(); - } - - /** - * @return the current parity used by the port - * - * NB : If the port has been used, the method returns null. - */ - public Parity getParity() - { - return this.getChannelConfiguration().getParity(); - } - - /** - * @return the timeout used for a synchronous read operation - */ - public int getSyncReadTimeout() - { - return this.getChannelConfiguration().getSyncReadTimeout().intValue(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected boolean hasEventListener() - { - return false; - } - - protected boolean addEventListener() - { - if (this.portHandler == null) - { - return false; - } - int mask = SerialPort.MASK_RXCHAR + SerialPort.MASK_CTS + SerialPort.MASK_DSR; - try - { - if (!this.portHandler.setEventsMask(mask)) - { - this.logger.error("Channel " + this.getName() + " failed to set event mask on port " + this.getPortName() + " (" + SystemError.getMessage() + ") "); - return false; - } - } - catch (SerialPortException exception) - { - this.logger.error("Channel " + this.getName() + " failed to set event mask on port " + this.getPortName() + " : " + exception.getMessage()); - return false; - } - try - { - this.portHandler.addEventListener(this); - } - catch (SerialPortException e) - { - this.logger.error("Channel " + this.getName() + " failed to add listener :" + e.getMessage(), e); - return false; - } - - return true; - } - - protected boolean removeEventListener() - { - if (this.portHandler == null) - { - return false; - } - try - { - if (!this.portHandler.removeEventListener()) - { - this.logger.error("Channel " + this.getName() + " failed to remove listener"); - return false; - } - } - catch (SerialPortException e) - { - this.logger.error("Channel " + this.getName() + " failed to remove listener :" + e.getMessage(), e); - return false; - } - - return true; - } - - protected void receiveData() - { - try - { - if (this.available() > 0) - { - byte[] buffer = this.read(); - this.notifyOnDataRead(buffer); - } - } - catch (ChannelException exception) - { - this.notifyOnErrorDetected(ChannelSerialPortErrorCode.READ_FAILED.getCode(ERROR_CODE_OFFSET), exception.getMessage()); - } - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private boolean hasPortChanged() - { - boolean portChanged = false; - - this.currentPortName = this.findPortName(); - - if (this.currentPortName != null && !this.currentPortName.equalsIgnoreCase(this.previousPortName)) - { - portChanged = true; - } - - return portChanged; - } - - private void onPortNameChanged() - { - String errorMessage = "Port name has changed ( " + this.previousPortName + " --> " + this.currentPortName + " )"; - this.logger.error(errorMessage); - this.setStatus(ChannelStatus.ERROR); - this.closePortForced(); - this.notifyOnErrorDetected(ChannelSerialPortErrorCode.PORT_NAME_HAS_CHANGED.getCode(ERROR_CODE_OFFSET), errorMessage); - this.previousPortName = this.currentPortName; - } - - private void updateRealPath() throws ChannelException - { - if (SystemUtils.IS_OS_LINUX) - { - String realPortName; - try - { - Process p = Runtime.getRuntime().exec("realpath " + this.getPortName()); - BufferedReader stdInput = new BufferedReader(new InputStreamReader(p.getInputStream())); - realPortName = stdInput.readLine(); - this.getChannelConfiguration().setPortName(realPortName); - } - catch (IOException | DataDictionaryException e) - { - throw new ChannelException(ChannelException.ERRCODE_INVALID_CONFIGURATION, "Cannot resolve realpath (" + e.getMessage() + ")"); - } - } - } - - private ChannelSerialPortConfiguration getChannelConfiguration() - { - return (ChannelSerialPortConfiguration) this.configuration; - } - - protected void openPort() - { - /* 1. Check if serial port is already opened */ - if (this.portHandler != null && this.portHandler.isOpened()) - { - return; - } - /* 2. Open serial port */ - String portNameFound = this.findPortName(); - try - { - this.logger.info("Channel " + this.getName() + " opening port " + portNameFound); - if (this.portHandler == null) - { - this.portHandler = new SerialPort(portNameFound); - } - if (!this.portHandler.openPort()) - { - this.logger.error("Channel " + this.getName() + " failed to open port " + this.getPortNameOpened() + " (" + SystemError.getMessage() + ") "); - return; - } - this.logger.info("Channel " + this.getName() + " configuring port " + portNameFound); - if (!this.portHandler.setParams(this.getBaudrate(), this.getDataBits(), stopBitsFromConfiguration(this.getStopBits()), parityFromConfiguration(this.getParity()))) - { - this.logger.error("Channel " + this.getName() + " failed to configure port " + this.getPortNameOpened() + " (" + SystemError.getMessage() + ") "); - return; - } - } - catch (SerialPortException exception) - { - String errorMessage = "Channel " + this.getName() + " failed to open port " + this.getPortNameOpened() + " : " + exception.getMessage(); - this.logger.error(errorMessage); - if (exception.getExceptionType().equals(SerialPortException.TYPE_PORT_BUSY)) - { - this.notifyOnErrorDetected(ChannelSerialPortErrorCode.PORT_BUSY.getCode(ERROR_CODE_OFFSET), errorMessage); - } - this.closePortForced(); - return; - } - /* 3. Add serial event listener */ - if (this.hasEventListener()) - { - if (!this.addEventListener()) - { - return; - } - } - this.setStatus(ChannelStatus.STARTED); - } - - protected void closePort() - { - /* 1. Check if serial port is already closed */ - if (this.portHandler == null || !this.portHandler.isOpened()) - { - return; - } - /* 2. Remove serial event listener */ - if (this.hasEventListener()) - { - this.removeEventListener(); - } - /* 3. Close serial port */ - try - { - this.logger.info("Channel " + this.getName() + " closing port " + this.getPortNameOpened()); - if (!this.portHandler.closePort()) - { - this.logger.error("Channel " + this.getName() + " failed to close port " + this.getPortNameOpened() + " (" + SystemError.getMessage() + ") "); - return; - } - } - catch (SerialPortException exception) - { - this.logger.error("Channel " + this.getName() + " failed to close port " + this.getPortNameOpened() + " : " + exception.getMessage()); - return; - } - this.setStatus(ChannelStatus.STOPPED); - } - - protected void closePortForced() - { - try - { - this.portHandler.closePort(); - } - catch (SerialPortException exception) - { - this.logger.error("Channel " + this.getName() + " fail on close : close " + this.getPortNameOpened() + " failed due to " + exception.getMessage()); - } - this.portHandler = new SerialPort(this.findPortName()); - } - - protected boolean isPortFound() - { - return isPortFound(this.getPortId(), this.getPortName()); - } - - protected boolean isPortOpenedFound() - { - String portNameOpened = this.getPortNameOpened(); - if (portNameOpened == null) - { - return false; - } - String portNameFound = this.findPortName(); - - return portNameOpened.equals(portNameFound); - } - - protected void onPortNotFound() - { - String errorMessage = "Channel " + this.getName() + " : serial port " + this.findPortName() + " not found"; - this.logger.error(errorMessage); - this.setStatus(ChannelStatus.ERROR); - this.closePortForced(); - this.notifyOnErrorDetected(ChannelSerialPortErrorCode.PORT_NOT_FOUND.getCode(ERROR_CODE_OFFSET), errorMessage); - } - - protected void onPortOpenedNotFound() - { - String errorMessage = "Channel " + this.getName() + " : serial port " + this.getPortNameOpened() + " opened not found"; - this.logger.error(errorMessage); - this.setStatus(ChannelStatus.ERROR); - this.closePortForced(); - this.notifyOnErrorDetected(ChannelSerialPortErrorCode.PORT_OPENED_NOT_FOUND.getCode(ERROR_CODE_OFFSET), errorMessage); - } -} diff --git a/src/main/java/enedis/lab/protocol/tic/channels/serialport/ChannelSerialPortErrorCode.java b/src/main/java/enedis/lab/protocol/tic/channels/serialport/ChannelSerialPortErrorCode.java deleted file mode 100644 index 29647b4..0000000 --- a/src/main/java/enedis/lab/protocol/tic/channels/serialport/ChannelSerialPortErrorCode.java +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.io.channels.serialport; - -/** - * Channel serial port error code - */ -public enum ChannelSerialPortErrorCode -{ - /** Port not found */ - PORT_NOT_FOUND(1), - - /** Port opened not found */ - PORT_OPENED_NOT_FOUND(2), - - /** Port name has changed */ - PORT_NAME_HAS_CHANGED(3), - - /** Port busy */ - PORT_BUSY(4), - - /** Read operation failed */ - READ_FAILED(5), - - /** Read operation timed out */ - READ_TIMEOUT(6); - - private int code; - - private ChannelSerialPortErrorCode(int code) - { - this.code = code; - } - - /** - * Get error code without offset - * - * @return error code - */ - public int getCode() - { - return this.code; - } - - /** - * Get error code with offset - * - * @param offset - * - * @return error code - */ - public int getCode(int offset) - { - return offset + this.code; - } -} diff --git a/src/main/java/enedis/lab/protocol/tic/codec/CodecTICFrameHistoric.java b/src/main/java/enedis/lab/protocol/tic/codec/CodecTICFrameHistoric.java deleted file mode 100644 index 726f099..0000000 --- a/src/main/java/enedis/lab/protocol/tic/codec/CodecTICFrameHistoric.java +++ /dev/null @@ -1,172 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.protocol.tic.codec; - -import java.util.List; - -import enedis.lab.codec.Codec; -import enedis.lab.codec.CodecException; -import enedis.lab.protocol.tic.frame.TICFrame; -import enedis.lab.protocol.tic.frame.TICFrameDataSet; -import enedis.lab.protocol.tic.frame.historic.TICFrameHistoric; -import enedis.lab.protocol.tic.frame.historic.TICFrameHistoricDataSet; -import enedis.lab.types.BytesArray; - -/** - * Codec TIC Frame Historic - * - */ -public class CodecTICFrameHistoric implements Codec -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** Separator */ - public static final byte SEPARATOR = 0x20; // SP - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// Codec - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public TICFrameHistoric decode(byte[] bytesBuffer) throws CodecException - { - String errorMessage = ""; - BytesArray rawDataSet = null; - TICFrameHistoric ticFrame = null; - CodecTICFrameHistoricDataSet codecTICFrameHistoricDataSet = new CodecTICFrameHistoricDataSet(); - - BytesArray bytesArray = new BytesArray(bytesBuffer); - - if ((true == bytesArray.startsWith(TICFrame.BEGINNING_PATTERN)) && (true == bytesArray.endsWith(TICFrame.END_PATTERN)) && (bytesArray.contains(TICFrame.EOT) == false)) - { - bytesArray.remove(0); - bytesArray.remove(bytesArray.size() - 1); - - ticFrame = new TICFrameHistoric(); - - List datasetList = bytesArray.slice(TICFrameDataSet.BEGINNING_PATTERN, TICFrameDataSet.END_PATTERN, BytesArray.CONTIGUOUS); - - if (datasetList.isEmpty() == false) - { - for (int i = 0; i < datasetList.size(); i++) - { - TICFrameHistoricDataSet dataSet = null; - rawDataSet = datasetList.get(i); - byte[] rawDataSetByte = rawDataSet.getBytes(); - - try - { - dataSet = codecTICFrameHistoricDataSet.decode(rawDataSetByte); - ticFrame.addDataSet(dataSet); - } - catch (CodecException exception) - { - errorMessage += exception.getMessage() + " : " + new String(rawDataSet.getBytes()) + "\n"; - } - } - } - } - - if (errorMessage.isEmpty()) - { - return ticFrame; - } - else - { - throw new CodecException(errorMessage, ticFrame); - } - - } - - @Override - public byte[] encode(TICFrameHistoric ticFrameHistoric) throws CodecException - { - String errorMessage = ""; - CodecTICFrameHistoricDataSet codec = new CodecTICFrameHistoricDataSet(); - BytesArray dataSet = new BytesArray(); - - List ticFrameHistoricList = ticFrameHistoric.getDataSetList(); - - if (ticFrameHistoric != null && !ticFrameHistoricList.isEmpty()) - { - List groups = ticFrameHistoric.getDataSetList(); - dataSet.add(TICFrame.BEGINNING_PATTERN); - for (int i = 0; i < groups.size(); i++) - { - try - { - byte[] buff = codec.encode((TICFrameHistoricDataSet) groups.get(i)); - dataSet.addAll(buff); - } - catch (CodecException e) - { - errorMessage += e.getMessage() + " : " + new String(ticFrameHistoric.getBytes()) + "\n"; - } - } - dataSet.add(TICFrame.END_PATTERN); - } - - else - { - return null; - } - - if (errorMessage.isEmpty()) - { - return dataSet.getBytes(); - } - else - { - throw new CodecException(errorMessage, dataSet.getBytes()); - } - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -} \ No newline at end of file diff --git a/src/main/java/enedis/lab/protocol/tic/codec/CodecTICFrameHistoricDataSet.java b/src/main/java/enedis/lab/protocol/tic/codec/CodecTICFrameHistoricDataSet.java deleted file mode 100644 index c275a52..0000000 --- a/src/main/java/enedis/lab/protocol/tic/codec/CodecTICFrameHistoricDataSet.java +++ /dev/null @@ -1,198 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.protocol.tic.codec; - -import java.util.List; - -import enedis.lab.codec.Codec; -import enedis.lab.codec.CodecException; -import enedis.lab.protocol.tic.frame.TICFrameDataSet; -import enedis.lab.protocol.tic.frame.historic.TICFrameHistoricDataSet; -import enedis.lab.types.BytesArray; - -/** - * Codec TIC Frame Historic Data Set - * - */ -public class CodecTICFrameHistoricDataSet implements Codec -{ - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// Codec - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public byte[] encode(TICFrameHistoricDataSet ticFrameHistoricDataSet) throws CodecException - { - BytesArray dataSet = new BytesArray(); - - if ((ticFrameHistoricDataSet.getLabel() != null) && (ticFrameHistoricDataSet.getData() != null)) - { - dataSet.add(TICFrameDataSet.BEGINNING_PATTERN); - dataSet.addAll(ticFrameHistoricDataSet.getLabel().getBytes()); - - dataSet.add(TICFrameHistoricDataSet.SEPARATOR); - dataSet.addAll(ticFrameHistoricDataSet.getData().getBytes()); - - dataSet.add(TICFrameHistoricDataSet.SEPARATOR); - - if (!ticFrameHistoricDataSet.isValid()) - { - throw new CodecException("Invalid Checksum value"); - } - dataSet.add(ticFrameHistoricDataSet.getChecksum()); - dataSet.add(TICFrameDataSet.END_PATTERN); - } - - return dataSet.getBytes(); - } - - @Override - public TICFrameHistoricDataSet decode(byte[] bytes) throws CodecException - { - BytesArray bytesArray = new BytesArray(bytes); - TICFrameHistoricDataSet dataSet = null; - - if (this.isStartStopDelimiterPresent(bytesArray)) - { - this.removeStartStopDelimiter(bytesArray); - - } - - List parts = this.splitFrame(bytesArray); - - // Structure "LABEL/DATA/CHECKSUM" : - if (this.isStructureLabelDataChecksum(parts)) - { - - if (this.isChecksumInOneByte(parts.get(2))) - - { - dataSet = new TICFrameHistoricDataSet(); - dataSet = this.createDataSetLabelDataChecksum(parts, dataSet); - - } - else - { - throw new CodecException("Invalid Checksum value : The part to the Checksum must occupy one and only one byte\r\n" + "The Label part must not exceed 8 bytes "); - } - } - else - { - throw new CodecException("Invalid format of TICFrameHistoricDataSet"); - } - - if (dataSet.isValid() == false) - { - throw new CodecException("Invalid Checksum value - Historic"); - } - - return dataSet; - } - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private boolean isStartStopDelimiterPresent(BytesArray bytes) - { - return bytes.startsWith(TICFrameDataSet.BEGINNING_PATTERN) && bytes.endsWith(TICFrameDataSet.END_PATTERN); - } - - private void removeStartStopDelimiter(BytesArray bytes) - - { - bytes.remove(0); - bytes.remove(bytes.size() - 1); - } - - private TICFrameHistoricDataSet createDataSetLabelDataChecksum(List parts, TICFrameHistoricDataSet dataSet) - { - - dataSet.setup(parts.get(0).getBytes(), parts.get(1).getBytes()); - dataSet.setChecksum(parts.get(2).get(0)); - return dataSet; - } - - private boolean isChecksumInOneByte(BytesArray part) - { - return part.size() == 1; - } - - private boolean isStructureLabelDataChecksum(List parts) - { - return parts.size() == 3; - } - - private List splitFrame(BytesArray bytesArray) throws CodecException - { - List parts; - - if (bytesArray.size() < 5) - { - throw new CodecException("Not enough bytes in TICFrameHistoricDataSet"); - } - if (bytesArray.get(bytesArray.size() - 1) == TICFrameHistoricDataSet.SEPARATOR) - { - BytesArray subList = bytesArray.subList(0, bytesArray.size() - 2); - parts = subList.split(TICFrameHistoricDataSet.SEPARATOR); - if (parts.size() < 1) - { - throw new CodecException("Invalid format of TICFrameHistoricDataSet"); - } - BytesArray checksum = parts.get(parts.size() - 1); - checksum.addAll(new byte[] { TICFrameHistoricDataSet.SEPARATOR }); - } - else - { - parts = bytesArray.split(TICFrameHistoricDataSet.SEPARATOR); - } - - return parts; - } - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -} diff --git a/src/main/java/enedis/lab/protocol/tic/codec/CodecTICFrameStandard.java b/src/main/java/enedis/lab/protocol/tic/codec/CodecTICFrameStandard.java deleted file mode 100644 index 3e98acb..0000000 --- a/src/main/java/enedis/lab/protocol/tic/codec/CodecTICFrameStandard.java +++ /dev/null @@ -1,156 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.protocol.tic.codec; - -import java.util.List; - -import enedis.lab.codec.Codec; -import enedis.lab.codec.CodecException; -import enedis.lab.protocol.tic.frame.TICFrame; -import enedis.lab.protocol.tic.frame.TICFrameDataSet; -import enedis.lab.protocol.tic.frame.standard.TICFrameStandard; -import enedis.lab.protocol.tic.frame.standard.TICFrameStandardDataSet; -import enedis.lab.types.BytesArray; - -/** - * Codec TIC Frame Standard - * - */ -public class CodecTICFrameStandard implements Codec -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// Codec - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public TICFrameStandard decode(byte[] bytes) throws CodecException - { - String errorMessage = ""; - BytesArray rawDataSet = null; - TICFrameStandard ticFrame = null; - CodecTICFrameStandardDataSet codecTICFrameStandardDataSet = new CodecTICFrameStandardDataSet(); - - BytesArray bytesArray = new BytesArray(bytes); - - // Extract the body of the frame - // NB: the presence of an EOT character makes the content of a frame invalid - if ((bytesArray.startsWith(TICFrame.BEGINNING_PATTERN) == true) && (bytesArray.endsWith(TICFrame.END_PATTERN) == true) && (bytesArray.contains(TICFrame.EOT) == false)) - { - bytesArray.remove(0); - bytesArray.remove(bytesArray.size() - 1); - - ticFrame = new TICFrameStandard(); - - // Isolate each memory area supposed to correspond to an Information Group - // (DataSet) - List datasetList = bytesArray.slice(TICFrameDataSet.BEGINNING_PATTERN, TICFrameDataSet.END_PATTERN, BytesArray.CONTIGUOUS); - - // Analyze each memory area to extract the controls of the Group of information - // If the format of a zone is invalid, then the browse is interrupted and the whole frame is invalid - // (null) - if (datasetList.isEmpty() == false) - { - for (int i = 0; i < datasetList.size(); i++) - { - TICFrameStandardDataSet dataSet = null; - rawDataSet = datasetList.get(i); - byte[] rawDataSetByte = rawDataSet.getBytes(); - try - { - dataSet = codecTICFrameStandardDataSet.decode(rawDataSetByte); - ticFrame.addDataSet(dataSet); - } - catch (CodecException exception) - { - errorMessage += exception.getMessage() + " : " + new String(rawDataSet.getBytes()) + "\n"; - } - } - } - } - - if (errorMessage.isEmpty()) - { - return ticFrame; - } - else - { - throw new CodecException(errorMessage, ticFrame); - } - } - - @Override - public byte[] encode(TICFrameStandard ticFrameStandard) throws CodecException - { - CodecTICFrameStandardDataSet codec = new CodecTICFrameStandardDataSet(); - BytesArray dataSet = new BytesArray(); - - List ticFrameStandardList = ticFrameStandard.getDataSetList(); - - if (ticFrameStandard != null && !ticFrameStandardList.isEmpty()) - { - List groups = ticFrameStandard.getDataSetList(); - dataSet.add(TICFrame.BEGINNING_PATTERN); - for (int i = 0; i < groups.size(); i++) - { - byte[] buff = codec.encode((TICFrameStandardDataSet) groups.get(i)); - dataSet.addAll(buff); - } - dataSet.add(TICFrame.END_PATTERN); - return dataSet.getBytes(); - } - else - { - return null; - } - } - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -} diff --git a/src/main/java/enedis/lab/protocol/tic/codec/CodecTICFrameStandardDataSet.java b/src/main/java/enedis/lab/protocol/tic/codec/CodecTICFrameStandardDataSet.java deleted file mode 100644 index 9e89e85..0000000 --- a/src/main/java/enedis/lab/protocol/tic/codec/CodecTICFrameStandardDataSet.java +++ /dev/null @@ -1,197 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.protocol.tic.codec; - -import java.util.List; - -import enedis.lab.codec.Codec; -import enedis.lab.codec.CodecException; -import enedis.lab.protocol.tic.frame.TICFrameDataSet; -import enedis.lab.protocol.tic.frame.standard.TICFrameStandardDataSet; -import enedis.lab.types.BytesArray; - -/** - * Codec TIC Frame Standard Data Set - * - */ -public class CodecTICFrameStandardDataSet implements Codec -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// Codec - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public byte[] encode(TICFrameStandardDataSet ticFrameStandardDataSet) throws CodecException - { - BytesArray dataSet = new BytesArray(); - - if ((null != ticFrameStandardDataSet.getLabel()) && (null != ticFrameStandardDataSet.getData())) - { - dataSet.add(TICFrameDataSet.BEGINNING_PATTERN); - dataSet.addAll(ticFrameStandardDataSet.getLabel().getBytes()); - - if (ticFrameStandardDataSet.checkDateTime() == true) - { - dataSet.add(TICFrameStandardDataSet.SEPARATOR); - dataSet.addAll(ticFrameStandardDataSet.getDateTime().getBytes()); - } - - dataSet.add(TICFrameStandardDataSet.SEPARATOR); - dataSet.addAll(ticFrameStandardDataSet.getData().getBytes()); - - dataSet.add(TICFrameStandardDataSet.SEPARATOR); - if (!ticFrameStandardDataSet.isValid()) - { - throw new CodecException("Invalid Checksum value"); - } - - dataSet.add(ticFrameStandardDataSet.getChecksum()); - dataSet.add(TICFrameDataSet.END_PATTERN); - } - - return dataSet.getBytes(); - } - - @Override - public TICFrameStandardDataSet decode(byte[] bytes) throws CodecException - { - BytesArray bytesArray = new BytesArray(bytes); - TICFrameStandardDataSet dataSet = null; - - if (this.isStartStopDelimiterPresent(bytesArray)) - { - this.removeStartStopDelimiter(bytesArray); - } - - List parts = bytesArray.split(TICFrameStandardDataSet.SEPARATOR); - - // Structure "LABEL/DATA/CHECKSUM" : - if (this.isStructureLabelDataChecksum(parts)) - { - if (this.isChecksumInOneByte(parts.get(2))) - { - dataSet = new TICFrameStandardDataSet(); - dataSet = this.createDataSetLabelDataChecksum(parts, dataSet); - } - else - { - throw new CodecException("Invalid Checksum value : The part to the Checksum must occupy one and only one byte\r\n" + "The Label part must not exceed 8 bytes "); - } - } - // Structure "LABEL/DATETIME/DATA/CHECKSUM" : - else if (this.isStructureLabelDateTimeDataChecksum(parts)) - { - if (this.isChecksumInOneByte(parts.get(3))) - { - dataSet = new TICFrameStandardDataSet(); - dataSet = this.createDataSetLabelDatetimeDataChecksum(parts, dataSet); - } - else - { - throw new CodecException("Invalid Checksum value : The part to the Checksum must occupy one and only one byte\r\n" + "The Label part must not exceed 8 bytes "); - } - } - else - { - throw new CodecException("Invalid bytes for decode - Standard"); - } - - if (dataSet.isValid() == false) - { - throw new CodecException("Invalid Checksum value"); - } - - return dataSet; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private boolean isStructureLabelDateTimeDataChecksum(List parts) - { - return parts.size() == 4; - } - - private boolean isStructureLabelDataChecksum(List parts) - { - return parts.size() == 3; - } - - private boolean isChecksumInOneByte(BytesArray part) - { - return part.size() == 1; - } - - private void removeStartStopDelimiter(BytesArray bytes) - { - bytes.remove(0); - bytes.remove(bytes.size() - 1); - } - - private boolean isStartStopDelimiterPresent(BytesArray bytes) - { - return bytes.startsWith(TICFrameDataSet.BEGINNING_PATTERN) && bytes.endsWith(TICFrameDataSet.END_PATTERN); - } - - private TICFrameStandardDataSet createDataSetLabelDataChecksum(List parts, TICFrameStandardDataSet dataSet) - { - dataSet.setup(parts.get(0).getBytes(), parts.get(1).getBytes()); - dataSet.setChecksum(parts.get(2).get(0)); - return dataSet; - } - - private TICFrameStandardDataSet createDataSetLabelDatetimeDataChecksum(List parts, TICFrameStandardDataSet dataSet) - { - dataSet.setup(parts.get(0).getBytes(), parts.get(2).getBytes(), parts.get(1).getBytes()); - dataSet.setChecksum(parts.get(3).get(0)); - return dataSet; - } - -} \ No newline at end of file diff --git a/src/main/java/enedis/lab/protocol/tic/codec/TICCodec.java b/src/main/java/enedis/lab/protocol/tic/codec/TICCodec.java deleted file mode 100644 index 2649dfb..0000000 --- a/src/main/java/enedis/lab/protocol/tic/codec/TICCodec.java +++ /dev/null @@ -1,295 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.protocol.tic.codec; - -import enedis.lab.codec.Codec; -import enedis.lab.codec.CodecException; -import enedis.lab.protocol.tic.TICMode; -import enedis.lab.protocol.tic.frame.TICFrame; -import enedis.lab.protocol.tic.frame.historic.TICFrameHistoric; -import enedis.lab.protocol.tic.frame.standard.TICException; -import enedis.lab.protocol.tic.frame.standard.TICFrameStandard; -import enedis.lab.types.BytesArray; - -/** - * Codec TIC - */ -public class TICCodec implements Codec -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private static final TICMode DEFAULT_MODE = TICMode.STANDARD; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private BytesArray Buffer; - private TICMode mode = TICMode.UNKNOWN; - private TICMode currentMode = TICMode.UNKNOWN; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Default constructor - */ - public TICCodec() - { - this.mode = TICMode.UNKNOWN; - this.currentMode = TICMode.UNKNOWN; - this.Buffer = new BytesArray(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// Codec - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public TICFrame decode(byte[] newData) throws CodecException - { - CodecTICFrameStandard codecStandard = new CodecTICFrameStandard(); - CodecTICFrameHistoric codecHistoric = new CodecTICFrameHistoric(); - TICFrameStandard ticFrameStandard = null; - TICFrameHistoric ticFrameHistoric = null; - - TICFrame ticFrame = null; - TICMode currentTICMode = null; - - try - { - switch (this.currentMode) - { - case STANDARD: - { - ticFrameStandard = codecStandard.decode(newData); - ticFrame = ticFrameStandard; - break; - } - case HISTORIC: - { - ticFrameHistoric = codecHistoric.decode(newData); - ticFrame = ticFrameHistoric; - break; - } - - case AUTO: - { - try - { - currentTICMode = TICMode.findModeFromFrameBuffer(newData); - } - catch (TICException exception) - { - throw new CodecException("can't determinated TIC Mode"); - } - - if (currentTICMode == TICMode.STANDARD) - { - ticFrameStandard = codecStandard.decode(newData); - ticFrame = ticFrameStandard; - break; - } - else if (currentTICMode == TICMode.HISTORIC) - { - ticFrameHistoric = codecHistoric.decode(newData); - ticFrame = ticFrameHistoric; - } - else - { - throw new CodecException("can't decode TIC, unable to find TIC Modem"); - } - - } - - default: - { - /**/ - } - } - } - catch (CodecException exception) - { - throw new CodecException(exception.getMessage(), exception.getData()); - } - return ticFrame; - } - - @Override - public byte[] encode(TICFrame ticFrame) throws CodecException - { - CodecTICFrameStandard codecStandard = new CodecTICFrameStandard(); - CodecTICFrameHistoric codecHistoric = new CodecTICFrameHistoric(); - - byte[] bytesBuffer = new byte[0]; - - try - { - switch (ticFrame.getMode()) - { - case STANDARD: - { - bytesBuffer = codecStandard.encode((TICFrameStandard) ticFrame); - break; - } - case HISTORIC: - { - bytesBuffer = codecHistoric.encode((TICFrameHistoric) ticFrame); - break; - } - default: - { - bytesBuffer = codecStandard.encode((TICFrameStandard) ticFrame); - break; - } - } - } - catch (CodecException exception) - { - throw new CodecException("Can't encode TICFrame" + exception.getMessage()); - } - return bytesBuffer; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Reset buffer - */ - public void reset() - { - this.Buffer.clear(); - } - - /** - * Append data to buffer - * - * @param data - */ - public void append(byte[] data) - { - this.Buffer.addAll(data); - } - - /** - * Append data to buffer - * - * @param data - */ - public void append(byte data) - { - this.Buffer.add(data); - } - - /** - * Append data to buffer - * - * @param data - */ - public void append(BytesArray data) - { - this.Buffer.addAll(data.getBytes()); - } - - /** - * Get mode - * - * @return mode - */ - public TICMode getMode() - { - return this.mode; - } - - /** - * Set mode - * - * @param mode - */ - public void setMode(TICMode mode) - { - if (this.mode != mode) - { - this.mode = mode; - - if (TICMode.AUTO != mode) - { - this.setCurrentMode(mode); - } - - else - { - this.setCurrentMode(DEFAULT_MODE); - } - } - } - - /** - * Get current mode - * - * @return current mode - */ - public TICMode getCurrentMode() - { - return this.currentMode; - } - - /** - * Set current mode - * - * @param currentMode - */ - public void setCurrentMode(TICMode currentMode) - { - if (currentMode != this.currentMode) - { - this.currentMode = currentMode; - } - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -} diff --git a/src/main/java/enedis/lab/protocol/tic/datastreams/TICInputStream.java b/src/main/java/enedis/lab/protocol/tic/datastreams/TICInputStream.java deleted file mode 100644 index ec4ebf3..0000000 --- a/src/main/java/enedis/lab/protocol/tic/datastreams/TICInputStream.java +++ /dev/null @@ -1,241 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.protocol.tic.datastreams; - -import enedis.lab.codec.CodecException; -import enedis.lab.io.datastreams.DataInputStream; -import enedis.lab.io.datastreams.DataStreamException; -import enedis.lab.io.datastreams.DataStreamType; -import enedis.lab.protocol.tic.TICMode; -import enedis.lab.protocol.tic.channels.ChannelTICSerialPort; -import enedis.lab.protocol.tic.codec.TICCodec; -import enedis.lab.protocol.tic.frame.TICError; -import enedis.lab.protocol.tic.frame.TICFrame; -import enedis.lab.types.DataDictionary; -import enedis.lab.types.DataDictionaryException; -import enedis.lab.types.datadictionary.DataDictionaryBase; - -/** - * TIC input stream - */ -public class TICInputStream extends DataInputStream -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** Key timestamp */ - public static final String KEY_TIMESTAMP = "timestamp"; - /** Key channel */ - public static final String KEY_CHANNEL = "channel"; - /** Key data */ - public static final String KEY_DATA = "data"; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - protected TICCodec codec; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Constructor using configuration - * - * @param configuration - * @throws DataStreamException - */ - public TICInputStream(TICStreamConfiguration configuration) throws DataStreamException - { - super(configuration); - this.codec = new TICCodec(); - this.codec.setCurrentMode(configuration.getTicMode()); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// DataInputStream - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public DataDictionary read() throws DataStreamException - { - return null; - } - - @Override - public DataStreamType getType() - { - return DataStreamType.TIC; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// ChannelListener - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public void onDataRead(String channelName, byte[] data) - { - if (!this.notifier.getSubscribers().isEmpty()) - { - DataDictionary ticFrame = null; - try - { - ticFrame = this.decodeTICFrame(data); - if (ticFrame != null) - { - this.notifyOnDataReceived(ticFrame); - } - } - catch (DataDictionaryException exception) - { - this.logger.error(exception.getMessage(), exception); - } - catch (CodecException exception) - { - DataDictionaryBase errorDataDictionary = new DataDictionaryBase(); - - String KEY_PARTIAL_FRAME = "partialTICFrame"; - - errorDataDictionary.addKey(KEY_PARTIAL_FRAME); - - try - { - Object exceptionData = exception.getData(); - if (exceptionData != null && exceptionData instanceof TICFrame) - { - try - { - DataDictionary frameDataDictionary = ((TICFrame) exceptionData).getDataDictionary(); - if (frameDataDictionary != null) - { - errorDataDictionary.set(KEY_PARTIAL_FRAME, frameDataDictionary); - } - else - { - this.logger.warn("Frame data dictionary is null"); - errorDataDictionary.set(KEY_PARTIAL_FRAME, ""); - } - } - catch (DataDictionaryException frameDataDictionaryException) - { - this.logger.warn("Can't get TICFrame data dictionary: " + frameDataDictionaryException.getMessage()); - errorDataDictionary.set(KEY_PARTIAL_FRAME, ""); - } - } - else - { - this.logger.error("No frame data available"); - errorDataDictionary.set(KEY_PARTIAL_FRAME, ""); - } - } - catch (DataDictionaryException dataDictionaryException) - { - this.logger.error("Can't convert TICFrame to DataDictonary" + dataDictionaryException.getMessage()); - } - - this.logger.error(exception.getMessage() + errorDataDictionary.toString()); - this.onErrorDetected(channelName, TICError.TIC_READER_READ_FRAME_CHECKSUM_INVALID.getValue(), exception.getMessage(), errorDataDictionary); - } - } - } - - @Override - public void onDataWritten(String channelName, byte[] data) - { - // Not used - } - - @Override - public void onErrorDetected(String channelName, int errorCode, String errorMessage) - { - this.notifyOnErrorDetected(errorCode, errorMessage, null); - } - - @Override - public void onErrorDetected(String channelName, int errorCode, String errorMessage, DataDictionary errorData) - { - this.notifyOnErrorDetected(errorCode, errorMessage, errorData); - } - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Get Mode - * - * @return TIC Mode - */ - public TICMode getMode() - { - ChannelTICSerialPort channelTIC = (ChannelTICSerialPort) this.channel; - - return channelTIC.getMode(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected DataDictionary decodeTICFrame(byte[] data) throws DataDictionaryException, CodecException - { - TICFrame ticFrame; - try - { - ticFrame = this.codec.decode(data); - } - catch (CodecException exception) - { - throw new CodecException(exception.getMessage(), exception.getData()); - } - - long timestamp = System.currentTimeMillis(); - - DataDictionaryBase decodedTICFrame = new DataDictionaryBase(); - - decodedTICFrame.set(KEY_TIMESTAMP, timestamp); - decodedTICFrame.set(KEY_CHANNEL, this.getConfiguration().getChannelName()); - decodedTICFrame.set(KEY_DATA, ticFrame); - - return decodedTICFrame; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -} diff --git a/src/main/java/enedis/lab/protocol/tic/datastreams/TICStreamConfiguration.java b/src/main/java/enedis/lab/protocol/tic/datastreams/TICStreamConfiguration.java deleted file mode 100644 index 4003b4b..0000000 --- a/src/main/java/enedis/lab/protocol/tic/datastreams/TICStreamConfiguration.java +++ /dev/null @@ -1,220 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.protocol.tic.datastreams; - -import java.io.File; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import enedis.lab.io.datastreams.DataStreamConfiguration; -import enedis.lab.io.datastreams.DataStreamDirection; -import enedis.lab.io.datastreams.DataStreamType; -import enedis.lab.protocol.tic.TICMode; -import enedis.lab.types.DataDictionary; -import enedis.lab.types.DataDictionaryException; -import enedis.lab.types.datadictionary.KeyDescriptor; -import enedis.lab.types.datadictionary.KeyDescriptorEnum; - -/** - * TICStreamConfiguration class - * - * Generated - */ -public class TICStreamConfiguration extends DataStreamConfiguration -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected static final String KEY_TIC_MODE = "ticMode"; - - private static final DataStreamType TYPE_ACCEPTED_VALUE = DataStreamType.TIC; - private static final DataStreamDirection[] DIRECTION_ACCEPTED_VALUES = { DataStreamDirection.OUTPUT, DataStreamDirection.INPUT }; - private static final TICMode TIC_MODE_DEFAULT_VALUE = TICMode.AUTO; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private List> keys = new ArrayList>(); - - protected KeyDescriptorEnum kTicMode; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected TICStreamConfiguration() - { - super(); - this.loadKeyDescriptors(); - - this.kType.setAcceptedValues(TYPE_ACCEPTED_VALUE); - this.kDirection.setAcceptedValues(DIRECTION_ACCEPTED_VALUES); - this.kChannelName.setMandatory(true); - } - - /** - * Constructor using map - * - * @param map - * @throws DataDictionaryException - */ - public TICStreamConfiguration(Map map) throws DataDictionaryException - { - this(); - this.copy(fromMap(map)); - } - - /** - * Constructor using datadictionary - * - * @param other - * @throws DataDictionaryException - */ - public TICStreamConfiguration(DataDictionary other) throws DataDictionaryException - { - this(); - this.copy(other); - } - - /** - * - * Constructor setting configuration name/file and parameters to default values - * - * @param name - * the configuration name - * @param file - * the configuration file - */ - public TICStreamConfiguration(String name, File file) - { - this(); - this.init(name, file); - } - - /** - * Constructor setting parameters to specific values - * - * @param name - * @param direction - * @param channelName - * @param ticMode - * @throws DataDictionaryException - */ - public TICStreamConfiguration(String name, DataStreamDirection direction, String channelName, TICMode ticMode) throws DataDictionaryException - { - this(); - - this.setName(name); - this.setDirection(direction); - this.setChannelName(channelName); - this.setTicMode(ticMode); - - this.checkAndUpdate(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// DataStreamConfiguration - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - protected void updateOptionalParameters() throws DataDictionaryException - { - if (!this.exists(KEY_TYPE)) - { - this.setType(TYPE_ACCEPTED_VALUE); - } - if (!this.exists(KEY_TIC_MODE)) - { - this.setTicMode(TIC_MODE_DEFAULT_VALUE); - } - super.updateOptionalParameters(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Get tic mode - * - * @return the tic mode - */ - public TICMode getTicMode() - { - return (TICMode) this.data.get(KEY_TIC_MODE); - } - - /** - * Set tic mode - * - * @param ticMode - * @throws DataDictionaryException - */ - public void setTicMode(TICMode ticMode) throws DataDictionaryException - { - this.setTicMode((Object) ticMode); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected void setTicMode(Object ticMode) throws DataDictionaryException - { - this.data.put(KEY_TIC_MODE, this.kTicMode.convert(ticMode)); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private void loadKeyDescriptors() - { - try - { - this.kTicMode = new KeyDescriptorEnum(KEY_TIC_MODE, true, TICMode.class); - this.keys.add(this.kTicMode); - - this.addAllKeyDescriptor(this.keys); - } - catch (DataDictionaryException e) - { - throw new RuntimeException(e.getMessage(), e); - } - } -} diff --git a/src/main/java/enedis/lab/protocol/tic/frame/TICError.java b/src/main/java/enedis/lab/protocol/tic/frame/TICError.java deleted file mode 100644 index db44f6e..0000000 --- a/src/main/java/enedis/lab/protocol/tic/frame/TICError.java +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.protocol.tic.frame; - -import jssc.SerialPortException; - -/** - * TICClient errors definition - */ -public enum TICError -{ - /** No error */ - NO_ERROR(0), - /** Serial port not found */ - SERIAL_PORT_NOT_FOUND(17), - /** Serial port not found */ - SERIAL_PORT_INCORRECT_SERIAL_PORT(18), - /** Serial port not found */ - SERIAL_PORT_NULL_NOT_PERMITTED(19), - /** Serial port not found */ - SERIAL_PORT_ALREADY_OPENED(20), - /** Serial port not found */ - SERIAL_PORT_SERIAL_PORT_BUSY(21), - /** Serial port not found */ - SERIAL_PORT_CONFIGURATION_FAILURE(22), - /** TIC reader default error */ - TIC_READER_DEFAULT_ERROR(23), - /** TIC reader label name not found */ - TIC_READER_LABEL_NAME_NOT_FOUND(24), - /** TIC reader frame decode failed */ - TIC_READER_FRAME_DECODE_FAILED(25), - /** TIC reader read frame timeout */ - TIC_READER_READ_FRAME_TIMEOUT(26), - /** TIC reader read frame with checksum invalid */ - TIC_READER_READ_FRAME_CHECKSUM_INVALID(27),; - - private int value; - - private TICError(int value) - { - this.value = value; - } - - /** - * Get error value - * - * @return the value - */ - public int getValue() - { - return this.value; - } - - /** - * Get serial port error - * - * @param serialPortException - * @return TICError - */ - public static TICError getSerialPortError(SerialPortException serialPortException) - { - if (serialPortException.getExceptionType().equals(SerialPortException.TYPE_PORT_BUSY)) - { - return TICError.SERIAL_PORT_SERIAL_PORT_BUSY; - } - if (serialPortException.getExceptionType().equals(SerialPortException.TYPE_INCORRECT_SERIAL_PORT)) - { - return TICError.SERIAL_PORT_INCORRECT_SERIAL_PORT; - } - if (serialPortException.getExceptionType().equals(SerialPortException.TYPE_NULL_NOT_PERMITTED)) - { - return TICError.SERIAL_PORT_NULL_NOT_PERMITTED; - } - if (serialPortException.getExceptionType().equals(SerialPortException.TYPE_PORT_NOT_FOUND)) - { - return TICError.SERIAL_PORT_NOT_FOUND; - } - if (serialPortException.getExceptionType().equals(SerialPortException.TYPE_PORT_ALREADY_OPENED)) - { - return TICError.SERIAL_PORT_ALREADY_OPENED; - } - return null; - } - -} diff --git a/src/main/java/enedis/lab/protocol/tic/frame/TICFrame.java b/src/main/java/enedis/lab/protocol/tic/frame/TICFrame.java deleted file mode 100644 index cd89e18..0000000 --- a/src/main/java/enedis/lab/protocol/tic/frame/TICFrame.java +++ /dev/null @@ -1,522 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.protocol.tic.frame; - -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; - -import org.json.JSONObject; - -import enedis.lab.protocol.tic.TICMode; -import enedis.lab.types.BytesArray; -import enedis.lab.types.DataDictionary; -import enedis.lab.types.DataDictionaryException; -import enedis.lab.types.datadictionary.DataDictionaryBase; - -/** - * TICFrame - */ -public abstract class TICFrame -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** Beginning pattern */ - public static final byte BEGINNING_PATTERN = 0x02; // STX - /** End pattern */ - public static final byte END_PATTERN = 0x03; // ETX - /** End of trame pattern */ - public static final byte EOT = 0x04; // EOT - - // Options - /** No specific options */ - public static final int EXPLICIT = 0x0000; - /** No checksum options */ - public static final int NOCHECKSUM = 0x0001; - /** No date time options */ - public static final int NODATETIME = 0x0002; - /** No tic mode options */ - public static final int NOTICMODE = 0x0004; - /** No invalid options */ - public static final int NOINVALID = 0x0008; - /** Trimmed options */ - public static final int TRIMMED = NOCHECKSUM | NODATETIME | NOINVALID; - - /** Key tic frame */ - public static final String KEY_TICFRAME = "ticFrame"; - /** Key tic mode */ - public static final String KEY_TICMODE = "ticMode"; - /** Key label */ - public static final String KEY_LABEL = "label"; - /** Key data */ - public static final String KEY_DATA = "data"; - /** Key checksum */ - public static final String KEY_CHECKSUM = "checksum"; - /** Key date time */ - public static final String KEY_DATETIME = "dateTime"; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - protected List DataSetList; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Default constructor - */ - public TICFrame() - { - this.DataSetList = new ArrayList(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// Object - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public int hashCode() - { - return Objects.hash(this.DataSetList); - } - - @Override - public boolean equals(Object obj) - { - if (this == obj) - return true; - if (obj == null) - return false; - if (this.getClass() != obj.getClass()) - return false; - TICFrame other = (TICFrame) obj; - return Objects.equals(this.DataSetList, other.DataSetList); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Return the list of DataSet - * - * @return the list of DataSet - */ - public List getDataSetList() - { - return this.DataSetList; - } - - /** - * Set the list of DataSet - * - * @param dataSetList - */ - public void setDataSetList(List dataSetList) - { - this.DataSetList = dataSetList; - } - - /** - * Return the index of the given DataSet - * - * @param label - * Label of the DataSet - * @return the index of the given DataSet or '-1' if it does not exist - */ - public int indexOf(String label) - { - int index = -1; - - for (int i = 0; i < this.DataSetList.size(); i++) - { - if (this.DataSetList.get(i).getLabel().equals(label)) - { - index = i; - break; - } - } - - return index; - } - - /** - * Return the given DataSet - * - * @param label - * Label of the DataSet - * @return the given DataSet or 'null' if it does not exist - */ - public TICFrameDataSet getDataSet(String label) - { - TICFrameDataSet dataSet = null; - - for (int i = 0; i < this.DataSetList.size(); i++) - { - if (this.DataSetList.get(i).getLabel().equals(label)) - { - dataSet = this.DataSetList.get(i); - break; - } - } - - return dataSet; - } - - /** - * Return the data field of the given DataSet - * - * @param label - * Label of the DataSet - * @return the data field of the given DataSet - */ - public String getData(String label) - { - TICFrameDataSet dataSet = this.getDataSet(label); - - if (dataSet != null) - { - return dataSet.getData(); - } - - else - { - return null; - } - } - - /** - * Add the dataSet at the end of the list. If the dataSet already existed, its data and checksum are just set - * - * @param dataSet - */ - public void addDataSet(TICFrameDataSet dataSet) - { - TICFrameDataSet oldDataSet = this.getDataSet(dataSet.getLabel()); - - if (oldDataSet == null) - { - this.DataSetList.add(dataSet); - } - - else - { - oldDataSet.setData(dataSet.getData()); - oldDataSet.setChecksum(dataSet.getChecksum()); - } - } - - /** - * Add the dataSet at the given index of the list. If the dataSet already existed, its data and checksum are set and - * it is moved at the given index - * - * @param index - * @param dataSet - */ - public void addDataSet(int index, TICFrameDataSet dataSet) - { - int dataSetIndex = this.indexOf(dataSet.getLabel()); - - if (dataSetIndex < 0) - { - this.DataSetList.add(index, dataSet); - } - - else - { - if (dataSetIndex != index) - { - this.removeDataSet(dataSetIndex); - this.DataSetList.add(index, dataSet); - } - - else - { - this.DataSetList.get(index).setData(dataSet.getData()); - this.DataSetList.get(index).setChecksum(dataSet.getChecksum()); - } - } - } - - /** - * Add data set - * - * @param label - * @param data - * @return tic frame data set - */ - public abstract TICFrameDataSet addDataSet(String label, String data); - - /** - * Add data set - * - * @param index - * @param label - * @param data - * @return tic frame data set - */ - public abstract TICFrameDataSet addDataSet(int index, String label, String data); - - /** - * Move the DataSet at the given index. - * - * @param label - * @param index - * @return true if the operation has been done, else return false - */ - public boolean moveDataSet(String label, int index) - { - int previous_index = this.indexOf(label); - - // Si l'ensemble des conditions suivantes sont vérifiées : - // - le Groupe d'Information existe, - // - l'index donné est cohérent - // - l'index donné diffère de l'index actuel - if ((previous_index >= 0) && (index >= 0) && (index < this.DataSetList.size()) && (index != previous_index)) - { - // Alors déplacer le Groupe d'Information à l'index donné: - - TICFrameDataSet dataSet = this.DataSetList.remove(previous_index); - - if (index < this.DataSetList.size()) - { - this.DataSetList.add(index, dataSet); - } - - else - { - this.DataSetList.add(dataSet); - } - - return true; - } - - else - { - // Sinon, l'opération n'est pas effectuée - return false; - } - } - - /** - * Set data set - * - * @param label - * @param data - * @return true if succeed - */ - public boolean setDataSet(String label, String data) - { - TICFrameDataSet dataSet = this.getDataSet(label); - - if (dataSet != null) - { - dataSet.setData(data); - dataSet.getConsistentChecksum(); - - return true; - } - - else - { - return false; - } - } - - /** - * Set data set - * - * @param label - * @param data - * @param checksum - * @return true if succeed - */ - public boolean setDataSet(String label, String data, byte checksum) - { - TICFrameDataSet dataSet = this.getDataSet(label); - - if (dataSet != null) - { - dataSet.setData(data); - dataSet.setChecksum(checksum); - - return true; - } - - else - { - return false; - } - } - - /** - * Remove data set - * - * @param label - * @return tic frame data set - */ - public TICFrameDataSet removeDataSet(String label) - { - TICFrameDataSet dataSet = null; - - int index = this.indexOf(label); - - if (index >= 0) - { - dataSet = this.DataSetList.remove(index); - } - - return dataSet; - } - - /** - * Remove data set - * - * @param index - * @return tic frame data set - */ - public TICFrameDataSet removeDataSet(int index) - { - TICFrameDataSet dataSet = null; - - if ((index >= 0) && (index < this.DataSetList.size())) - { - dataSet = this.DataSetList.remove(index); - } - - return dataSet; - } - - /** - * Get bytes - * - * @return bytes - */ - public byte[] getBytes() - { - BytesArray bytesFrame = new BytesArray(); - - bytesFrame.add(BEGINNING_PATTERN); - - for (int i = 0; i < this.DataSetList.size(); i++) - { - bytesFrame.addAll(this.DataSetList.get(i).getBytes()); - } - - bytesFrame.add(END_PATTERN); - - return bytesFrame.getBytes(); - } - - /** - * Get data dictionary - * - * @return data dictionary - * @throws DataDictionaryException - */ - public DataDictionary getDataDictionary() throws DataDictionaryException - { - return this.getDataDictionary(0); - } - - /** - * Return a DataDictionary object corresponding to the TIC frame - * - * @param options - * options to DataDictionary render (use like bits fields) : - EXPLICIT : frame is detailed - NOCHECKSUM - * : DataSet checksum are hidden - NODATETIME : DataSet dateTime fields are hidden - NOTICMODE : Tic mode - * is hidden; - TRIMMED : NOCHECKSUM | NODATETIME - FILTER_INVALID : Invalid DataSet are filtered - * - * - * @return data dictionary - * @throws DataDictionaryException - */ - public DataDictionary getDataDictionary(int options) throws DataDictionaryException - { - DataDictionaryBase dictionary = new DataDictionaryBase(); - - JSONObject jsonObject = new JSONObject(); - - if (0 == (options & NOTICMODE)) - { - dictionary.addKey(KEY_TICMODE); - dictionary.set(KEY_TICMODE, this.getMode().name()); - } - - for (int i = 0; i < this.DataSetList.size(); i++) - { - TICFrameDataSet dataSet = this.DataSetList.get(i); - - // Si le DataSet n'est pas valid et que l'option "filtrer les - // groupes invalides" est activée, - if ((false == dataSet.isValid()) && ((options & NOINVALID) > 0)) - { - // Ignorer le DataSet - } - - // Sinon, - else - { - jsonObject.append(KEY_TICFRAME, dataSet.toJSON(options)); - } - - } - - dictionary.addKey(KEY_TICFRAME); - dictionary.set(KEY_TICFRAME, jsonObject.get(KEY_TICFRAME)); - - return dictionary; - } - - /** - * Get mode - * - * @return mode - */ - public abstract TICMode getMode(); - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -} diff --git a/src/main/java/enedis/lab/protocol/tic/frame/TICFrameDataSet.java b/src/main/java/enedis/lab/protocol/tic/frame/TICFrameDataSet.java deleted file mode 100644 index ccea017..0000000 --- a/src/main/java/enedis/lab/protocol/tic/frame/TICFrameDataSet.java +++ /dev/null @@ -1,313 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.protocol.tic.frame; - -import java.util.Objects; - -import org.json.JSONObject; - -import enedis.lab.types.BytesArray; - -/** - * TIC frame data set - */ -public abstract class TICFrameDataSet -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** Beginning pattern */ - public static final byte BEGINNING_PATTERN = 0x0A; // LF - /** End pattern */ - public static final byte END_PATTERN = 0x0D; // CR - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected BytesArray label = null; - protected BytesArray data = null; - protected byte checksum; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Default constructor - */ - public TICFrameDataSet() - { - this.init(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// Object - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public int hashCode() - { - return Objects.hash(this.checksum, this.data, this.label); - } - - @Override - public boolean equals(Object obj) - { - if (this == obj) - return true; - if (obj == null) - return false; - if (this.getClass() != obj.getClass()) - return false; - TICFrameDataSet other = (TICFrameDataSet) obj; - return this.checksum == other.checksum && Objects.equals(this.data, other.data) && Objects.equals(this.label, other.label); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Setup from string label and data - * - * @param label - * @param data - */ - public void setup(String label, String data) - { - this.setup(label.getBytes(), data.getBytes()); - } - - /** - * Setup from byte[] label and data - * - * @param label - * @param data - */ - public void setup(byte[] label, byte[] data) - { - this.label = new BytesArray(label); - this.data = new BytesArray(data); - } - - /** - * Get label - * - * @return label - */ - public String getLabel() - { - return new String(this.label.getBytes()); - } - - /** - * Set the Label - * - * @param label - */ - public void setLabel(String label) - { - this.setLabel(label.getBytes()); - } - - /** - * Set the Label - * - * @param label - */ - public void setLabel(byte[] label) - { - this.setLabel(new BytesArray(label)); - } - - /** - * Set the Label - * - * @param label - */ - public void setLabel(BytesArray label) - { - this.label = label; - this.setChecksum(); - } - - /** - * Get data - * - * @return data - */ - public String getData() - { - return new String(this.data.getBytes()); - } - - /** - * Set data - * - * @param data - */ - public void setData(String data) - { - this.setData(data.getBytes()); - } - - /** - * Set data - * - * @param data - */ - public void setData(byte[] data) - { - this.setData(new BytesArray(data)); - } - - /** - * Set data - * - * @param data - */ - public void setData(BytesArray data) - { - this.data = data; - this.setChecksum(); - } - - /** - * Get checksum - * - * @return checksum - */ - public byte getChecksum() - { - - return this.checksum; - } - - /** - * Compute and set the checksum (NB: Label and Data shall have been set) - * - * @return true if the operation succeeds, else, return false - */ - public boolean setChecksum() - { - Byte checksum = this.getConsistentChecksum(); - - if (checksum != null) - { - this.checksum = checksum; - return true; - } - - else - { - return false; - } - } - - /** - * Set the checksum at a given value - * - * @param checksum - */ - public void setChecksum(byte checksum) - { - this.checksum = checksum; - - } - - /** - * - * @return true if fields are consistent with checksum - */ - public boolean isValid() - { - Byte consistentChecksum = this.getConsistentChecksum(); - - if ((consistentChecksum != null) && (consistentChecksum.byteValue() == (this.checksum & (byte) 0xFF))) - { - return true; - } - - else - { - return false; - } - } - - /** - * Get bytes - * - * @return bytes - */ - public abstract byte[] getBytes(); - - /** - * Conver to JSON - * - * @return json object - */ - public abstract JSONObject toJSON(); - - /** - * Conver to JSON - * - * @param option - * @return json object - */ - public abstract JSONObject toJSON(int option); - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Return the consistent checksum of the DataSet - * - * @return the consistent checksum of the DataSet - */ - protected abstract Byte getConsistentChecksum(); - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - private void init() - { - this.label = null; - this.data = null; - this.checksum = -1; - } -} diff --git a/src/main/java/enedis/lab/protocol/tic/frame/historic/TICFrameHistoric.java b/src/main/java/enedis/lab/protocol/tic/frame/historic/TICFrameHistoric.java deleted file mode 100644 index 417b23b..0000000 --- a/src/main/java/enedis/lab/protocol/tic/frame/historic/TICFrameHistoric.java +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.protocol.tic.frame.historic; - -import enedis.lab.protocol.tic.TICMode; -import enedis.lab.protocol.tic.frame.TICFrame; - -/** - * TIC frame historic - */ -public class TICFrameHistoric extends TICFrame -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** Separator */ - public static final byte SEPARATOR = 0x20; // SP - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Default constructor - */ - public TICFrameHistoric() - { - super(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// TICFrame - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public TICFrameHistoricDataSet addDataSet(String label, String data) - { - return this.addDataSet(this.DataSetList.size(), label, data); - } - - @Override - public TICFrameHistoricDataSet addDataSet(int index, String label, String data) - { - TICFrameHistoricDataSet dataSet = (TICFrameHistoricDataSet) this.getDataSet(label); - - if (dataSet == null) - { - dataSet = new TICFrameHistoricDataSet(); - dataSet.setLabel(label); - dataSet.setData(data); - dataSet.getConsistentChecksum(); - - if ((index >= 0) && (index < this.DataSetList.size())) - { - this.DataSetList.add(index, dataSet); - } - - else - { - this.DataSetList.add(dataSet); - } - } - - else - { - dataSet.setData(data); - dataSet.getConsistentChecksum(); - - this.DataSetList.remove(dataSet); - - if (index >= this.DataSetList.size()) - { - this.DataSetList.add(dataSet); - } - - else - { - this.DataSetList.add(index, dataSet); - } - } - - return dataSet; - } - - @Override - public TICMode getMode() - { - return TICMode.HISTORIC; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -} diff --git a/src/main/java/enedis/lab/protocol/tic/frame/historic/TICFrameHistoricDataSet.java b/src/main/java/enedis/lab/protocol/tic/frame/historic/TICFrameHistoricDataSet.java deleted file mode 100644 index 8c4ef34..0000000 --- a/src/main/java/enedis/lab/protocol/tic/frame/historic/TICFrameHistoricDataSet.java +++ /dev/null @@ -1,190 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.protocol.tic.frame.historic; - -import org.json.JSONObject; - -import enedis.lab.protocol.tic.frame.TICFrame; -import enedis.lab.protocol.tic.frame.TICFrameDataSet; -import enedis.lab.types.BytesArray; - -/** - * TIC frame historic data set - */ -public class TICFrameHistoricDataSet extends TICFrameDataSet -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** Separator */ - public static final byte SEPARATOR = 0x20; // SP - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Constructor - */ - public TICFrameHistoricDataSet() - { - super(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// TICFrameDataSet - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public Byte getConsistentChecksum() - { - Byte crc = 0; - byte[] labelByte; - byte[] dataByte; - if ((this.label != null) && (this.data != null)) - { - labelByte = this.label.getBytes(); - for (int i = 0; i < labelByte.length; i++) - { - crc = this.computeUpdate(crc, labelByte[i]); - } - - crc = this.computeUpdate(crc, SEPARATOR); - dataByte = this.data.getBytes(); - - for (int i = 0; i < dataByte.length; i++) - { - crc = this.computeUpdate(crc, dataByte[i]); - } - - return this.computeEnd(crc); - } - else - { - return null; - } - - } - - /** - * compute Update - * - * @param crc - * @param octet - * @return Byte crc after compute update - */ - public Byte computeUpdate(Byte crc, byte octet) - { - return (byte) (crc + (octet & 0xff)); - } - - /** - * compute End - * - * @param crc - * @return Byte crc after compute end - */ - public Byte computeEnd(Byte crc) - { - return (byte) ((crc & 0x3F) + 0x20); - } - - @Override - public byte[] getBytes() - { - BytesArray dataSet = new BytesArray(); - - if ((this.label != null) && (this.data != null)) - { - dataSet.add(BEGINNING_PATTERN); - dataSet.addAll(this.label.getBytes()); - - dataSet.add(SEPARATOR); - dataSet.addAll(this.data.getBytes()); - - dataSet.add(SEPARATOR); - dataSet.add(this.checksum); - - dataSet.add(END_PATTERN); - } - - return dataSet.getBytes(); - } - - @Override - public JSONObject toJSON() - { - return this.toJSON(TICFrame.TRIMMED); - } - - @Override - public JSONObject toJSON(int option) - { - JSONObject jsonObject = new JSONObject(); - - if ((option & TICFrame.NOCHECKSUM) > 0) - { - jsonObject.put(new String(this.label.getBytes()), new String(this.data.getBytes())); - } - - else - { - JSONObject content = new JSONObject(); - content.put(TICFrame.KEY_DATA, new String(this.data.getBytes())); - content.put(TICFrame.KEY_CHECKSUM, this.checksum); - jsonObject.put(new String(this.label.getBytes()), content); - } - - return jsonObject; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -} diff --git a/src/main/java/enedis/lab/protocol/tic/frame/standard/TICException.java b/src/main/java/enedis/lab/protocol/tic/frame/standard/TICException.java deleted file mode 100644 index d50abe1..0000000 --- a/src/main/java/enedis/lab/protocol/tic/frame/standard/TICException.java +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.protocol.tic.frame.standard; - -import enedis.lab.protocol.tic.frame.TICError; - -/** - * TICException - * - */ -public class TICException extends Exception -{ - /** - * Unique identifier used for serialization - */ - private static final long serialVersionUID = -2780151361870269473L; - private TICError error; - - /** - * Constructor TICException - */ - public TICException() - { - super(); - this.reset(); - } - - /** - * Constructor TICException - * - * @param message - */ - public TICException(String message) - { - super(message); - this.error = TICError.TIC_READER_DEFAULT_ERROR; - } - - /** - * Constructor TICException - * - * @param message - * @param readerError - */ - public TICException(String message, TICError readerError) - { - super(message); - this.error = readerError; - } - - /** - * Reset TICError - */ - public void reset() - { - this.error = TICError.TIC_READER_DEFAULT_ERROR; - } - - /** - * Get error - * - * @return the readerError - */ - public TICError getError() - { - return this.error; - } -} diff --git a/src/main/java/enedis/lab/protocol/tic/frame/standard/TICFrameStandard.java b/src/main/java/enedis/lab/protocol/tic/frame/standard/TICFrameStandard.java deleted file mode 100644 index d23c26a..0000000 --- a/src/main/java/enedis/lab/protocol/tic/frame/standard/TICFrameStandard.java +++ /dev/null @@ -1,247 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.protocol.tic.frame.standard; - -import java.time.LocalDateTime; - -import enedis.lab.protocol.tic.TICMode; -import enedis.lab.protocol.tic.frame.TICFrame; - -/** - * TIC frame standard - */ -public class TICFrameStandard extends TICFrame -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** Begin info group */ - public static final byte INFOGROUP_BEGIN = 0x03; // LF - /** End info group */ - public static final byte INFOGROUP_END = 0x03; // CR - /** Sep info group */ - public static final byte INFOGROUP_SEP = 0x03; // HT - - /** Min size info group */ - public static final int INFOGROUP_MIN_SIZE = 7; // LF + Label + HT + Data + HT + - /** MIN_SIZE */ - public static final int MIN_SIZE = INFOGROUP_MIN_SIZE + 2; // ETX + INFGROUP_MIN_SIZE + STX - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Default constructor - */ - public TICFrameStandard() - { - super(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// TICFrame - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public TICFrameStandardDataSet addDataSet(String label, String data) - { - TICFrameStandardDataSet dataSet = (TICFrameStandardDataSet) this.getDataSet(label); - - if (dataSet == null) - { - dataSet = new TICFrameStandardDataSet(); - dataSet.setLabel(label); - dataSet.setData(data); - dataSet.getConsistentChecksum(); - } - - else - { - dataSet.setData(data); - dataSet.getConsistentChecksum(); - } - - this.DataSetList.add(dataSet); - - return dataSet; - } - - @Override - public TICFrameStandardDataSet addDataSet(int index, String label, String data) - { - TICFrameStandardDataSet dataSet = (TICFrameStandardDataSet) this.getDataSet(label); - - if (dataSet == null) - { - dataSet = new TICFrameStandardDataSet(); - dataSet.setLabel(label); - dataSet.setData(data); - dataSet.getConsistentChecksum(); - - if ((index >= 0) && (index < this.DataSetList.size())) - { - this.DataSetList.add(index, dataSet); - } - - else - { - this.DataSetList.add(dataSet); - } - } - - else - { - dataSet.setData(data); - dataSet.getConsistentChecksum(); - - this.DataSetList.remove(dataSet); - - if (index >= this.DataSetList.size()) - { - this.DataSetList.add(dataSet); - } - - else - { - this.DataSetList.add(index, dataSet); - } - } - - return dataSet; - } - - @Override - public TICMode getMode() - { - return TICMode.STANDARD; - } - - @Override - public String getData(String label) - { - TICFrameStandardDataSet dataSet = (TICFrameStandardDataSet) this.getDataSet(label); - - if (dataSet != null) - { - if (dataSet.getLabel().equals("DATE")) - { - return dataSet.getDateTime(); - } - else - { - return dataSet.getData(); - } - } - - else - { - return null; - } - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Add data set - * - * @param label - * @param data - * @param dateTime - * @return the added data set - */ - public TICFrameStandardDataSet addDataSet(String label, String data, String dateTime) - { - TICFrameStandardDataSet dataSet = this.addDataSet(label, data); - - dataSet.setDateTime(dateTime); - - return dataSet; - } - - /** - * Get string datetime - * - * @param label - * @return string datetime - */ - public String getDateTime(String label) - { - TICFrameStandardDataSet dataSet = (TICFrameStandardDataSet) this.getDataSet(label); - if (dataSet != null) - { - return dataSet.getDateTime(); - } - else - { - return null; - } - } - - /** - * Get date time as localDateTime - * - * @param label - * @return LocalDateTime - */ - public LocalDateTime getDateTimeAsLocalDateTime(String label) - { - TICFrameStandardDataSet dataSet = (TICFrameStandardDataSet) this.getDataSet(label); - if (dataSet != null) - { - return dataSet.getDateTimeAsLocalDateTime(); - } - else - { - return null; - } - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -} diff --git a/src/main/java/enedis/lab/protocol/tic/frame/standard/TICFrameStandardDataSet.java b/src/main/java/enedis/lab/protocol/tic/frame/standard/TICFrameStandardDataSet.java deleted file mode 100644 index 8ee0198..0000000 --- a/src/main/java/enedis/lab/protocol/tic/frame/standard/TICFrameStandardDataSet.java +++ /dev/null @@ -1,352 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.protocol.tic.frame.standard; - -import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; -import java.time.format.DateTimeParseException; - -import org.json.JSONObject; - -import enedis.lab.protocol.tic.frame.TICFrame; -import enedis.lab.protocol.tic.frame.TICFrameDataSet; -import enedis.lab.types.BytesArray; - -/** - * TIC frame standard data set - */ -public class TICFrameStandardDataSet extends TICFrameDataSet -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** Separator */ - public static final byte SEPARATOR = 0x09; // HT - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected BytesArray dateTime = null; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Constructor - */ - public TICFrameStandardDataSet() - { - super(); - this.init(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// TICFrameDataSet - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public Byte getConsistentChecksum() - { - Byte crc = 0; - byte[] labelByte; - byte[] dataByte; - byte[] dateByte; - - if ((this.label != null) && (this.data != null)) - { - labelByte = this.label.getBytes(); - for (int i = 0; i < labelByte.length; i++) - { - crc = this.computeUpdate(crc, labelByte[i]); - } - - crc = this.computeUpdate(crc, SEPARATOR); - - if (this.dateTime != null) - { - dateByte = this.dateTime.getBytes(); - for (int i = 0; i < dateByte.length; i++) - { - crc = this.computeUpdate(crc, dateByte[i]); - } - - crc = this.computeUpdate(crc, SEPARATOR); - } - - dataByte = this.data.getBytes(); - - for (int i = 0; i < dataByte.length; i++) - { - crc = this.computeUpdate(crc, dataByte[i]); - } - crc = this.computeUpdate(crc, SEPARATOR); - - return this.computeEnd(crc); - } - else - { - return null; - } - - } - - /** - * Compute update - * - * @param crc - * @param octet - * @return Byte crc compute after Update - */ - public Byte computeUpdate(Byte crc, byte octet) - { - return (byte) (crc + (octet & 0xff)); - } - - /** - * Compute end - * - * @param crc - * @return Byte crc compute after End - */ - public Byte computeEnd(Byte crc) - { - return (byte) ((crc & 0x3F) + 0x20); - } - - @Override - public byte[] getBytes() - { - BytesArray dataSet = new BytesArray(); - - if ((this.label != null) && (this.data != null)) - { - dataSet.add(BEGINNING_PATTERN); - dataSet.addAll(this.label.getBytes()); - - if (null != this.dateTime) - { - dataSet.add(SEPARATOR); - dataSet.addAll(this.dateTime.getBytes()); - } - - dataSet.add(SEPARATOR); - dataSet.addAll(this.data.getBytes()); - - dataSet.add(SEPARATOR); - dataSet.add(this.checksum); - - dataSet.add(END_PATTERN); - } - - return dataSet.getBytes(); - } - - @Override - public JSONObject toJSON() - { - return this.toJSON(TICFrame.TRIMMED); - } - - @Override - public JSONObject toJSON(int option) - { - JSONObject jsonObject = new JSONObject(); - - if ((option & TICFrame.NOCHECKSUM) > 0) - { - if ((this.dateTime == null) || ((option & TICFrame.NODATETIME) > 0)) - { - jsonObject.put(new String(this.label.getBytes()), new String(this.data.getBytes())); - } - - else - { - JSONObject content = new JSONObject(); - content.put(TICFrame.KEY_DATA, new String(this.data.getBytes())); - content.put(TICFrame.KEY_DATETIME, new String(this.dateTime.getBytes())); - jsonObject.put(new String(this.label.getBytes()), content); - } - } - - else - { - if ((this.dateTime == null) || ((option & TICFrame.NODATETIME) > 0)) - { - JSONObject content = new JSONObject(); - content.put(TICFrame.KEY_DATA, new String(this.data.getBytes())); - content.put(TICFrame.KEY_CHECKSUM, this.checksum); - jsonObject.put(new String(this.label.getBytes()), content); - } - - else - { - JSONObject content = new JSONObject(); - content.put(TICFrame.KEY_DATA, new String(this.data.getBytes())); - content.put(TICFrame.KEY_DATETIME, new String(this.dateTime.getBytes())); - content.put(TICFrame.KEY_CHECKSUM, this.checksum); - jsonObject.put(new String(this.label.getBytes()), content); - } - } - - return jsonObject; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Setup - * - * @param label - * @param data - * @param dateTime - */ - public void setup(String label, String data, String dateTime) - { - this.setup(label.getBytes(), data.getBytes(), dateTime.getBytes()); - } - - /** - * Setup - * - * @param label - * @param data - * @param dateTime - */ - public void setup(byte[] label, byte[] data, byte[] dateTime) - { - super.setup(label, data); - this.dateTime = new BytesArray(dateTime); - } - - /** - * Get datetime - * - * @return datetime - */ - public String getDateTime() - { - return new String(this.dateTime.getBytes()); - } - - /** - * Check datetime - * - * @return result - */ - public Boolean checkDateTime() - { - if (this.dateTime == null) - { - return false; - } - return true; - } - - /** - * Get datetime as local datetime - * - * @return datetime as local datetime - */ - // DATE H190730100158 yyMMddHHmmss - public LocalDateTime getDateTimeAsLocalDateTime() - { - String strDateTime = this.getDateTime(); - LocalDateTime localDateTime = null; - - if (strDateTime != null && strDateTime.length() == 13) - { - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyMMddHHmmss"); - try - { - localDateTime = LocalDateTime.parse(strDateTime.substring(1), formatter); - } - catch (DateTimeParseException e) - { - localDateTime = null; - } - } - - return localDateTime; - } - - /** - * Set date time - * - * @param dateTime - */ - public void setDateTime(String dateTime) - { - this.setDateTime(dateTime.getBytes()); - } - - /** - * Set datetime - * - * @param dateTime - */ - public void setDateTime(byte[] dateTime) - { - this.setDateTime(new BytesArray(dateTime)); - } - - /** - * Set date time - * - * @param dateTime - */ - public void setDateTime(BytesArray dateTime) - { - this.dateTime = dateTime; - this.setChecksum(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private void init() - { - this.dateTime = null; - } -} diff --git a/src/main/java/enedis/lab/types/BytesArray.java b/src/main/java/enedis/lab/types/BytesArray.java deleted file mode 100644 index fb1cd50..0000000 --- a/src/main/java/enedis/lab/types/BytesArray.java +++ /dev/null @@ -1,1280 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.types; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Iterator; -import java.util.List; -import java.util.ListIterator; - -/** - * Bytes array - */ -public class BytesArray implements List -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** Default option */ - public static final int DEFAULT_OPTIONS = 0x0000; - /** Greedy option */ - public static final int GREEDY = 0x0001; - /** Contiguous option */ - public static final int CONTIGUOUS = 0x0002; - /** Remove patterns option */ - public static final int REMOVE_PATTERNS = 0x0004; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Convert int to byte[] - * - * @param value - * @param numberOfByte - * @return byte[] - * @throws NumberFormatException - */ - public static byte[] intToArrayOfByte(int value, int numberOfByte) throws NumberFormatException - { - if (countBytes(value) > numberOfByte) - { - throw new NumberFormatException("Value " + value + " can't be converted in a byte[" + numberOfByte + "]"); - } - - byte[] byteArray = new byte[numberOfByte]; - - for (int i = 0; i < byteArray.length; i++) - { - if (i < Integer.BYTES) - { - byteArray[byteArray.length - i - 1] = (byte) (value >> (i * 8)); - } - } - - return byteArray; - } - - /** - * Conver int to BytesArray - * - * @param value - * @param numberOfByte - * @return BytesArray - * @throws Exception - */ - public static BytesArray valueOf(int value, int numberOfByte) throws Exception - { - return new BytesArray(intToArrayOfByte(value, numberOfByte)); - } - - private static int countBytes(int value) - { - int tmp = Math.abs(value); - int count = 0; - - for (int i = 0; i < Integer.BYTES; i++) - { - tmp = tmp >> 8; - count++; - if (tmp == 0) - { - break; - } - } - return count; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected byte[] buffer; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Default constructor - */ - public BytesArray() - { - this.buffer = new byte[0]; - } - - /** - * Constructor from array of byte - * - * @param bytesArray - */ - public BytesArray(byte[] bytesArray) - { - this.buffer = bytesArray.clone(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// List - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public int size() - { - return this.buffer.length; - } - - @Override - public boolean isEmpty() - { - return (0 == this.buffer.length) ? true : false; - } - - @Override - public boolean contains(Object element) - { - int index = this.indexOf(element); - return (index >= 0) ? true : false; - } - - @SuppressWarnings({ "rawtypes", "unchecked" }) - @Override - public Iterator iterator() - { - throw new UnsupportedOperationException(); - } - - @Override - public Byte[] toArray() - { - Byte[] bytesArray = new Byte[this.buffer.length]; - - for (int i = 0; i < this.buffer.length; i++) - { - bytesArray[i] = this.buffer[i]; - } - - return bytesArray; - } - - @SuppressWarnings("unchecked") - @Override - public Byte[] toArray(Object[] a) - { - throw new UnsupportedOperationException(); - } - - @Override - public boolean add(Byte element) - { - byte byte_element = element; - byte[] bytesArray = new byte[this.buffer.length + 1]; - - System.arraycopy(this.buffer, 0, bytesArray, 0, this.buffer.length); - bytesArray[bytesArray.length - 1] = byte_element; - this.buffer = bytesArray; - - return true; - } - - @Override - public void add(int index, Byte element) - { - if ((index < 0) || (index >= this.buffer.length)) - { - this.add(element); - } - - else - { - byte[] bytesArray = new byte[this.buffer.length + 1]; - - // Si l'index est le premier - if (0 == index) - { - System.arraycopy(this.buffer, 0, bytesArray, 1, this.buffer.length); - } - - // Sinon, si l'index est le dernier - else if ((this.buffer.length - 1) == index) - { - System.arraycopy(this.buffer, 0, bytesArray, 0, this.buffer.length - 1); - - bytesArray[bytesArray.length - 1] = this.buffer[this.buffer.length - 1]; - } - - // Sinon, si l'index est au milieu du tableau - else - { - System.arraycopy(this.buffer, 0, bytesArray, 0, index - 1); - - System.arraycopy(this.buffer, index, // src , src_pos - bytesArray, index + 1, // dest, dest_pos - this.buffer.length - index - 1); // size - } - - bytesArray[index] = element; - this.buffer = bytesArray; - } - } - - @Override - public boolean remove(Object element) - { - boolean success = true; - - if ((null != element) && (element instanceof Number)) - { - // Obtenir l'index de la première occurence de l'élément - int index = this.indexOf(element); - - // Si un tel élément a été trouvé, - if (index >= 0) - { - this.removeIndex(index); - } - - // Sinon, - else - { - success = false; - } - } - - else - { - success = false; - } - - return success; - } - - @Override - public Byte remove(int index) - { - Byte element = null; - - if ((index >= 0) && (index < this.buffer.length)) - { - element = new Byte(this.buffer[index]); - this.removeIndex(index); - } - - else - { - // Aucune action - } - - return element; - } - - /** - * Remove the buffer from an index to other - * - * @param fromIndex - * @param toIndex - * @return new length of buffer - */ - public int remove(int fromIndex, int toIndex) - { - int length = 0; - - if ((fromIndex >= 0) && (toIndex < this.buffer.length) && (toIndex > fromIndex)) - { - this.removeSubList(fromIndex, toIndex); - length = toIndex - fromIndex + 1; - } - - return length; - } - - @Override - public boolean containsAll(Collection c) - { - // TODO Auto-generated method stub - return false; - } - - @Override - public boolean addAll(Collection collection) - { - boolean hasChanged; - - if ((null != collection) && (collection.size() > 0)) - { - Object[] collectionArray = collection.toArray(); - byte[] bytesArray = new byte[this.buffer.length + collection.size()]; - - System.arraycopy(this.buffer, 0, bytesArray, 0, this.buffer.length); - - int j = this.buffer.length; - for (int i = 0; i < collectionArray.length; i++) - { - bytesArray[j] = ((Byte) collectionArray[i]).byteValue(); - j++; - } - - this.buffer = bytesArray; - - hasChanged = true; - } - - else - { - hasChanged = false; - } - - return hasChanged; - } - - @Override - public boolean addAll(int index, Collection collection) - { - boolean hasChanged; - - if ((null != collection) && (collection.size() > 0) && (index >= 0) && (index <= this.buffer.length)) - { - Object[] collectionArray = collection.toArray(); - byte[] bytesArray = new byte[this.buffer.length + collection.size()]; - - // Cas ou on ajoute en début: - if (0 == index) - { - for (int i = 0; i < collectionArray.length; i++) - { - bytesArray[i] = ((Byte) collectionArray[i]).byteValue(); - } - - System.arraycopy(this.buffer, 0, bytesArray, collectionArray.length, this.buffer.length); - } - - // Cas où on ajoute à la fin: - else if (this.buffer.length == index) - { - System.arraycopy(this.buffer, 0, bytesArray, 0, this.buffer.length); - - int j = index; - for (int i = 0; i < collectionArray.length; i++) - { - bytesArray[j] = ((Byte) collectionArray[i]).byteValue(); - j++; - } - } - - // Cas où on ajoute au milieu: - else - { - System.arraycopy(this.buffer, 0, bytesArray, 0, index); - - int j = index; - for (int i = 0; i < collectionArray.length; i++) - { - bytesArray[j] = ((Byte) collectionArray[i]).byteValue(); - j++; - } - - System.arraycopy(this.buffer, index, bytesArray, index + collectionArray.length, this.buffer.length - index); - } - - this.buffer = bytesArray; - - hasChanged = true; - } - - else - { - hasChanged = false; - } - - return hasChanged; - } - - @Override - public boolean removeAll(Collection c) - { - // TODO Auto-generated method stub - return false; - } - - @Override - public boolean retainAll(Collection c) - { - // TODO Auto-generated method stub - return false; - } - - @Override - public void clear() - { - this.buffer = new byte[0]; - } - - @Override - public Byte get(int index) - { - Byte element = null; - - if ((index >= 0) && (index < this.buffer.length)) - { - element = new Byte(this.buffer[index]); - } - - else - { - - } - - return element; - } - - @Override - public Byte set(int index, Byte element) - { - Byte previous_element = null; - - if ((index >= 0) && (index < this.buffer.length)) - { - previous_element = new Byte(this.buffer[index]); - this.buffer[index] = element; - } - - else - { - previous_element = new Byte(this.buffer[this.buffer.length - 1]); - this.buffer[this.buffer.length - 1] = element; - } - - return new Byte(previous_element); - } - - @Override - public int indexOf(Object element) - { - return this.indexOf(element, 0); - } - - /** - * Get the buffer element of the given index - * - * @param element - * @param offset - * @return the element - */ - public int indexOf(Object element, int offset) - { - int index = -1; - - if ((null != element) && (element instanceof Number) && offset >= 0 && offset < this.buffer.length) - { - Byte byte_element = ((Number) element).byteValue(); - - for (int i = offset; i < this.buffer.length; i++) - { - if (this.buffer[i] == byte_element) - { - index = i; - break; - } - } - } - - else - { - // Aucune action - } - - return index; - } - - @Override - public int lastIndexOf(Object element) - { - int index = -1; - - if ((null != element) && (element instanceof Number)) - { - Byte byte_element = ((Number) element).byteValue(); - - for (int i = this.buffer.length - 1; i >= 0; i--) - { - if (this.buffer[i] == byte_element) - { - index = i; - break; - } - } - } - - else - { - // Aucune action - } - - return index; - } - - @Override - public ListIterator listIterator() - { - // TODO Auto-generated method stub - return null; - } - - @Override - public ListIterator listIterator(int index) - { - // TODO Auto-generated method stub - return null; - } - - @Override - public BytesArray subList(int fromIndex, int toIndex) - { - BytesArray subBytesArray = new BytesArray(new byte[0]); - - if (fromIndex >= 0) - { - if ((toIndex > fromIndex) && (toIndex < this.buffer.length)) - { - int size = (toIndex - fromIndex) + 1; - byte[] buffer = new byte[size]; - - System.arraycopy(this.buffer, fromIndex, buffer, 0, size); - - subBytesArray = new BytesArray(buffer); - } - - else if ((toIndex < 0) || (toIndex >= this.buffer.length)) - { - int size = this.buffer.length - fromIndex; - byte[] buffer = new byte[size]; - - System.arraycopy(this.buffer, fromIndex, buffer, 0, size); - - subBytesArray = new BytesArray(buffer); - } - - else - { - - } - } - - return subBytesArray; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Get bytes - * - * @return bytes - */ - public byte[] getBytes() - { - return this.buffer; - } - - /** - * Copy - * - * @return copied BytesArray - */ - public BytesArray copy() - { - return new BytesArray(this.buffer); - } - - /** - * Get index of element - * - * @param element - * @return index of element - */ - public List indexesOf(Object element) - { - List indexesList = new ArrayList(); - - if ((null != element) && (element instanceof Number)) - { - Byte byte_element = ((Number) element).byteValue(); - - for (int i = 0; i < this.buffer.length; i++) - { - if (this.buffer[i] == byte_element) - { - indexesList.add(i); - } - } - } - - else - { - // Aucune action - } - - return indexesList; - } - - /** - * - * @param value - * @return true if the BytesArray starts with the given value, else return false - */ - public boolean startsWith(byte value) - { - boolean retVal; - - if ((this.buffer.length > 0) && (this.buffer[0] == value)) - { - retVal = true; - } - - else - { - retVal = false; - } - - return retVal; - } - - /** - * - * @param value - * @return true if the BytesArray ends with the given value, else return false - */ - public boolean endsWith(byte value) - { - boolean retVal; - - if ((this.buffer.length > 0) && (this.buffer[this.buffer.length - 1] == value)) - { - retVal = true; - } - - else - { - retVal = false; - } - - return retVal; - } - - /** - * Get element count - * - * @param element - * @return element count - */ - public int count(Object element) - { - return this.indexesOf(element).size(); - } - - /** - * Split - * - * @param pattern - * @return split BytesArray - */ - public List split(Number pattern) - { - List patternsIndexesList = this.indexesOf(pattern.byteValue()); - List bytesArraysList = new ArrayList(); - - // Si le motif de séparation existe, copier chaque segment dans l'élément associé du tableau - if (false == patternsIndexesList.isEmpty()) - { - int begin_index = 0; - int end_index; - int segment_length; - int nb_segments = patternsIndexesList.size() + 1; - - for (int i = 0; i < nb_segments; i++) - { - end_index = (i < patternsIndexesList.size()) ? patternsIndexesList.get(i) : this.buffer.length; - - segment_length = end_index - begin_index; - - // Si la taille du segment est non nulle, - if (segment_length > 0) - { - byte[] segment = new byte[segment_length]; - - System.arraycopy(this.buffer, begin_index, segment, 0, segment_length); - - bytesArraysList.add(new BytesArray(segment)); - } - - // Sinon, - else - { - bytesArraysList.add(new BytesArray()); - } - - begin_index = end_index + 1; - } - } - - // Sinon, copier dans l'unique élément du tableau l'intégralité des données - else - { - bytesArraysList.add(new BytesArray(this.buffer)); - } - - return bytesArraysList; - } - - /** - * Extract parts in the ByteArray according specific 'begin' and 'end' patterns.
- * NB : 'begin' and 'end' patterns shall be different. Use split() method if they don't.
- *
- * Example:
- *
- * BytesArray myArray(new byte[12] {42,14,20,98,34,47,14,61,17,98,110,25});
- * List mySlicedArray = myArray.slice(14,98);
- * mySlicedArray.get(0) contains {14,20,98}
- * mySlicedArray.get(1) contains {14,61,17,98}
- * - * @param beginPattern - * @param endPattern - * @return slices list - */ - public List slice(Number beginPattern, Number endPattern) - { - return this.slice(beginPattern, endPattern, -1, 0); - } - - /** - * - * @param beginPattern - * @param endPattern - * @param options - * @return slices list - */ - public List slice(Number beginPattern, Number endPattern, int options) - { - return this.slice(beginPattern, endPattern, -1, options); - } - - /** - * - * @param beginPattern - * @param endPattern - * @param occurences - * @param options - * @return slices list - */ - public List slice(Number beginPattern, Number endPattern, int occurences, int options) - { - List bytesArraysList; - - // ... Si l'appel de la fonction est "gourmand" (greedy), il n'y aura au mieux qu'un élément à retourner qui - // correspondra au plus grand segment [begin_pattern, end_pattern] du tableau - // NB le paramètre 'occurences' est alors non signifiant - if ((options & GREEDY) != 0) - { - bytesArraysList = this.sliceGreedy(beginPattern, endPattern, options); - } - - // ... Si l'appel de la fonction est "non gourmand" (not greedy), les éléments du tableau à retourner - // correspondront aux segments [begin_pattern, end_pattern] - // les plus rationnels, dans la limite des n premières occurences demandées - else - { - bytesArraysList = this.sliceNotGreedy(beginPattern, endPattern, occurences, options); - } - - return bytesArraysList; - } - - /** - * Add all byte - * - * @param bytesArray - * @return true if changed has been applied - */ - public boolean addAll(byte[] bytesArray) - { - boolean hasChanged = false; - - if (bytesArray != null && bytesArray.length > 0) - { - byte[] newBytesArray = new byte[this.buffer.length + bytesArray.length]; - - // copie des données existantes - System.arraycopy(this.buffer, 0, newBytesArray, 0, this.buffer.length); - - // copie des nouvelles données - System.arraycopy(bytesArray, 0, newBytesArray, this.buffer.length, bytesArray.length); - - this.buffer = newBytesArray; - hasChanged = true; - } - - else - { - hasChanged = false; - } - - return hasChanged; - } - - /** - * Add all byte at index - * - * @param index - * @param bytesArray - * @return true if changed has been applied - */ - public boolean addAll(int index, byte[] bytesArray) - { - boolean hasChanged = false; - - if ((index >= 0) && (index <= this.buffer.length)) - { - byte[] newBytesArray = new byte[this.buffer.length + bytesArray.length]; - - // Cas ou on ajoute au début: - if (0 == index) - { - System.arraycopy(bytesArray, 0, newBytesArray, 0, bytesArray.length); - - // copie des données existantes - System.arraycopy(this.buffer, 0, newBytesArray, bytesArray.length, this.buffer.length); - } - - // Cas où on ajoute à la fin: - else if (this.buffer.length == index) - { - // copie des données existantes - System.arraycopy(this.buffer, 0, newBytesArray, 0, this.buffer.length); - - // copie des nouvelles données - System.arraycopy(bytesArray, 0, newBytesArray, this.buffer.length, bytesArray.length); - } - - // Cas où on ajoute au milieu: - else - { - // copie des données existantes (premier segment) - System.arraycopy(this.buffer, 0, newBytesArray, 0, index); - - // copie des nouvelles données - System.arraycopy(bytesArray, 0, newBytesArray, index, bytesArray.length); - - // copie des données existantes (deuxième segment) - System.arraycopy(this.buffer, index, newBytesArray, index + bytesArray.length, this.buffer.length - index); - } - - this.buffer = newBytesArray; - hasChanged = true; - } - - else - { - hasChanged = false; - } - - return hasChanged; - } - - /** - * Compute the BytesArray checksum on 8bits (Byte) - * - * @return the computed checksum or 'null' if the BytesArray is empty - * - */ - public Byte checksum8() - { - Byte checksum = null; - - if (this.buffer.length > 0) - { - byte checksum_8 = 0; - - for (int i = 0; i < this.buffer.length; i++) - { - checksum_8 += this.buffer[i]; - } - - checksum = new Byte(checksum_8); - } - - else - { - - } - - return checksum; - } - - /** - * Compute the BytesArray checksum on 16 bits (Short) - * - * @return the computed checksum or 'null' if the BytesArray is empty - * - */ - public Short checksum16() - { - Short checksum = null; - - if (this.buffer.length > 0) - { - short checksum_16 = 0; - - for (int i = 0; i < this.buffer.length; i++) - { - checksum_16 += this.buffer[i]; - } - - checksum = new Short(checksum_16); - } - - else - { - - } - - return checksum; - } - - /** - * Compute the BytesArray checksum on 32 bits (Integer) - * - * @return the computed checksum or 'null' if the BytesArray is empty - * - */ - public Integer checksum32() - { - Integer checksum = null; - - if (this.buffer.length > 0) - { - int checksum_32 = 0; - - for (int i = 0; i < this.buffer.length; i++) - { - checksum_32 += this.buffer[i]; - } - - checksum = new Integer(checksum_32); - } - - else - { - - } - - return checksum; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * - * @param beginPattern - * @param endPattern - * @param options - * @return - */ - private List sliceGreedy(Number beginPattern, Number endPattern, int options) - { - List bytesArraysList = new ArrayList(); - - int beginIndex = this.indexOf(beginPattern.byteValue()); - - if (beginIndex >= 0) - { - int endIndex = this.lastIndexOf(endPattern.byteValue()); - - if (endIndex > 0) - { - if ((options & REMOVE_PATTERNS) != 0) - { - beginIndex++; - endIndex--; - } - - int size = endIndex - beginIndex + 1; - - if (size > 0) - { - byte[] bytesBuffer = new byte[size]; - - System.arraycopy(this.buffer, beginIndex, bytesBuffer, 0, size); - - bytesArraysList.add(new BytesArray(bytesBuffer)); - } - - else - { - bytesArraysList.add(new BytesArray(new byte[0])); - } - } - } - - else - { - - } - - return bytesArraysList; - } - - /** - * - * @param beginPattern - * @param endPattern - * @param occurences - * @param options - * @return - */ - private List sliceNotGreedy(Number beginPattern, Number endPattern, int occurences, int options) - { - List bytesArraysList = new ArrayList(); - - // Si la contiguité des segments est requise, - if ((options & CONTIGUOUS) != 0) - { - bytesArraysList = this.sliceContiguous(beginPattern, endPattern, occurences, options); - } - - else - { - bytesArraysList = this.sliceNotContiguous(beginPattern, endPattern, occurences, options); - } - - return bytesArraysList; - } - - /** - * - * @param beginPattern - * @param endPattern - * @param occurences - * @param options - * @return - */ - private List sliceContiguous(Number beginPattern, Number endPattern, int occurences, int options) - { - List bytesArraysList = new ArrayList(); - - int beginIndex = -1; - int endIndex = -1; - - for (int i = 0; i < this.buffer.length; i++) - { - // Traiter un motif DEBUT - if (this.buffer[i] == beginPattern.byteValue()) - { - if ((-1 == endIndex) || (this.buffer[i - 1] == endPattern.byteValue())) - { - beginIndex = i; - } - } - - // Traiter un motif FIN - else if (this.buffer[i] == endPattern.byteValue()) - { - // Si nous ne sommes pas au dernier élément du tableau - if (i < (this.buffer.length - 1)) - { - // Si le prochain caractère est le motif de début de trame - if (this.buffer[i + 1] == beginPattern.byteValue()) - { - endIndex = i; - - this.slicePart(bytesArraysList, beginIndex, endIndex, options); - - // Si un nombre d'occurences est spécifié et si le nombre de segments l'a déjà atteint, - // interrompre le traitement - if ((occurences > 0) && (bytesArraysList.size() >= occurences)) - { - break; - } - } - } - - // Sinon, si nous sommes au dernier élément du tableau - else - { - endIndex = i; - - this.slicePart(bytesArraysList, beginIndex, endIndex, options); - - // Si un nombre d'occurences est spécifié et si le nombre de segments l'a déjà atteint, - // interrompre le traitement - if ((occurences > 0) && (bytesArraysList.size() >= occurences)) - { - break; - } - } - } - - else - { - - } - } - - return bytesArraysList; - } - - /** - * - * @param beginPattern - * @param endPattern - * @param occurences - * @param options - * @return - */ - private List sliceNotContiguous(Number beginPattern, Number endPattern, int occurences, int options) - { - List bytesArraysList = new ArrayList(); - - int beginIndex = -1; - int endIndex = -1; - - for (int i = 0; i < this.buffer.length; i++) - { - if (this.buffer[i] == beginPattern.byteValue()) - { - beginIndex = i; - } - - else if (this.buffer[i] == endPattern.byteValue()) - { - endIndex = i; - - this.slicePart(bytesArraysList, beginIndex, endIndex, options); - - // Si un nombre d'occurences est spécifié et si le nombre de segments l'a déjà atteint, - // interrompre le traitement - if ((occurences > 0) && (bytesArraysList.size() >= occurences)) - { - break; - } - } - - else - { - - } - } - - return bytesArraysList; - } - - /** - * - * @param bytesArraysList - * @param beginIndex - * @param endIndex - * @param options - */ - private void slicePart(List bytesArraysList, int beginIndex, int endIndex, int options) - { - if (beginIndex >= 0) - { - if ((options & REMOVE_PATTERNS) != 0) - { - beginIndex++; - endIndex--; - } - - BytesArray part = this.subList(beginIndex, endIndex); - - if (null != part) - { - bytesArraysList.add(part); - } - } - } - - /** - * @param index - */ - private void removeIndex(int index) - { - byte[] bytesArray = new byte[this.buffer.length - 1]; - - // Si l'index est le premier du tableau - if (0 == index) - { - System.arraycopy(this.buffer, 1, bytesArray, 0, bytesArray.length); - } - - // Sinon, si l'index est le dernier - else if ((this.buffer.length - 1) == index) - { - System.arraycopy(this.buffer, 0, bytesArray, 0, bytesArray.length); - } - - // Sinon, si l'index est au milieu du tableau - else - { - System.arraycopy(this.buffer, 0, bytesArray, 0, index); - - System.arraycopy(this.buffer, index + 1, // src , src_pos - bytesArray, index, // dest, dest_pos - bytesArray.length - index); // size - } - - this.buffer = bytesArray; - } - - private void removeSubList(int fromIndex, int toIndex) - { - byte[] bytesArray = new byte[this.buffer.length - (toIndex - fromIndex + 1)]; - - if (fromIndex > 0) - { - System.arraycopy(this.buffer, 0, bytesArray, 0, fromIndex); - } - if (toIndex + 1 < this.buffer.length) - { - System.arraycopy(this.buffer, toIndex + 1, bytesArray, fromIndex, bytesArray.length - fromIndex); - } - - this.buffer = bytesArray; - } -} diff --git a/src/main/java/enedis/lab/types/DataArrayList.java b/src/main/java/enedis/lab/types/DataArrayList.java deleted file mode 100644 index a6b267c..0000000 --- a/src/main/java/enedis/lab/types/DataArrayList.java +++ /dev/null @@ -1,392 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.types; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.RandomAccess; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -/** - * Resizable-array implementation of the {@code DataList} interface. - * - * @param the type of elements in this data list - */ -public class DataArrayList extends ArrayList implements DataList -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private static final long serialVersionUID = 3116080161929203526L; - - private static final int JSON_INDENT_FACTOR = 0; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Returns a fixed-size data list backed by the specified array. (Changes to - * the returned data list "write through" to the array.) This method acts - * as bridge between array-based and collection-based APIs, in - * combination with {@link Collection#toArray}. The returned list is - * serializable and implements {@link RandomAccess}. - * - *

This method also provides a convenient way to create a fixed-size - * data list initialized to contain several elements: - *

-     *     DataList<String> stooges = DataArrayList.asList("Larry", "Moe", "Curly");
-     * 
- * - * @param the class of the objects in the array - * @param items the array by which the data list will be backed - * @return a data list view of the specified array - */ - @SafeVarargs - public static DataList asList(E... items) - { - DataList dataList = new DataArrayList(); - - for(E item : items) - { - dataList.add(item); - } - - return dataList; - } - - /** - * Instantiate a data list from a File - * - * @param the class of the objects in the list - * @param file - * @param clazz - * - * @return a data list - * @throws JSONException - * @throws IOException - */ - public static DataList fromFile(File file,Class clazz) throws JSONException, IOException - { - InputStream stream = new FileInputStream(file); - - return fromStream(stream,clazz); - } - - /** - * Instantiate a data list from a Stream - * - * @param the class of the objects in the list - * @param stream - * @param clazz - * - * @return a data list - * @throws JSONException - * @throws IOException - */ - public static DataList fromStream(InputStream stream,Class clazz) throws JSONException, IOException - { - byte[] buffer = new byte[stream.available()]; - stream.read(buffer); - stream.close(); - String text = new String(buffer); - - return fromString(text,clazz); - } - - /** - * Instantiate a data list from a String - * - * @param the class of the objects in the list - * @param text - * @param clazz - * - * @return a data list - * @throws JSONException - */ - public static DataList fromString(String text,Class clazz) throws JSONException - { - if (text == null) - { - return null; - } - - JSONArray jsonArray = new JSONArray(text); - - return fromJSON(jsonArray,clazz); - } - - /** - * Instantiate a data list from a JSONObject - * - * @param the class of the objects in the list - * @param jsonArray - * @param clazz - * - * @return a data list - * @throws JSONException - */ - public static DataList fromJSON(JSONArray jsonArray, Class clazz) throws JSONException - { - if(jsonArray == null) - { - return null; - } - DataList dataList = new DataArrayList(); - for(int i = 0; i < jsonArray.length(); i++) - { - Object jsonItem = jsonArray.get(i); - E dataListItem; - try - { - if(JSONObject.NULL.equals(jsonItem)) - { - dataListItem = null; - } - else if(clazz.isAssignableFrom(jsonItem.getClass())) - { - dataListItem = clazz.cast(jsonItem); - } - else if(Enum.class.isAssignableFrom(clazz)) - { - dataListItem = convertToEnum(jsonItem,clazz); - } - else if(LocalDateTime.class.isAssignableFrom(clazz)) - { - dataListItem = convertToLocalDateTime(jsonItem,clazz); - } - else if(List.class.isAssignableFrom(clazz)) - { - dataListItem = convertToDataList(jsonItem,clazz); - } - else if(DataDictionary.class.isAssignableFrom(clazz)) - { - dataListItem = convertToDataDictionary(jsonItem,clazz); - } - else - { - throw new IllegalArgumentException("Cannot convert " + jsonItem.getClass().getName() + " to " + clazz.getName()); - } - } - catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException e) - { - throw new IllegalArgumentException("Cannot convert " + jsonItem + " to " + clazz.getName() + " (" + e.getMessage() + ")",e); - } - catch (InvocationTargetException e) - { - throw new IllegalArgumentException("Cannot convert " + jsonItem + " to " + clazz.getName() + " (" + e.getTargetException().getMessage() + ")",e); - } - dataList.add(dataListItem); - } - - return dataList; - } - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Constructs an empty data list with an initial capacity of ten. - */ - public DataArrayList() - { - super(); - } - - /** - * Constructs a data list containing the elements of the specified - * collection, in the order they are returned by the collection's - * iterator. - * - * @param collection the collection whose elements are to be placed into this data list - * @throws NullPointerException if the specified collection is null - */ - public DataArrayList(Collection collection) - { - super(collection); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// interfaceName - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public JSONArray toJSON() - { - JSONArray jsonArray = new JSONArray(); - - for(E item : this) - { - Object objectItem; - if(item instanceof DataDictionary) - { - DataDictionary dictionaryItem = (DataDictionary)item; - objectItem = dictionaryItem.toJSON(); - } - else - { - objectItem = item; - } - jsonArray.put(objectItem); - } - - return jsonArray; - } - - @Override - public void toFile(File file, int indentFactor) throws IOException - { - OutputStream stream = new FileOutputStream(file); - - this.toStream(stream, indentFactor); - } - - @Override - public void toStream(OutputStream stream, int indentFactor) throws IOException - { - String text = this.toString(indentFactor); - - stream.write(text.getBytes()); - } - - @Override - public String toString() - { - return this.toString(JSON_INDENT_FACTOR); - } - - @Override - public String toString(int identFactor) - { - return this.toJSON().toString(identFactor); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @SuppressWarnings("unchecked") - private static E convertToDataDictionary(Object value,Class clazz) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException - { - E result; - - if(value instanceof JSONObject) - { - Method method = clazz.getMethod("fromJSON",JSONObject.class,Class.class); - result = (E) method.invoke(null,value,clazz); - } - else - { - throw new IllegalArgumentException("Cannot convert " + value.getClass().getName() + " to " + clazz.getName()); - } - - return result; - } - - @SuppressWarnings("unchecked") - private static E convertToDataList(Object value,Class clazz) - { - E result; - - if(value instanceof JSONArray) - { - result = (E) DataArrayList.fromJSON((JSONArray)value, Object.class); - } - else - { - throw new IllegalArgumentException("Cannot convert " + value.getClass().getName() + " to " + clazz.getName()); - } - - return result; - } - - @SuppressWarnings("unchecked") - private static E convertToEnum(Object value,Class clazz) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException - { - E result; - - if(value instanceof String) - { - Method method = clazz.getDeclaredMethod("valueOf", String.class); - result = (E) method.invoke(null, (String)value); - } - else - { - throw new IllegalArgumentException("Cannot convert " + value.getClass().getName() + " to " + clazz.getName()); - } - - return result; - } - - @SuppressWarnings("unchecked") - private static E convertToLocalDateTime(Object value,Class clazz) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException - { - E result; - - if(value instanceof String) - { - Method method = clazz.getDeclaredMethod("parse", CharSequence.class); - result = (E) method.invoke(null, (String)value); - } - else - { - throw new IllegalArgumentException("Cannot convert " + value.getClass().getName() + " to " + clazz.getName()); - } - - return result; - } -} diff --git a/src/main/java/enedis/lab/types/DataDictionary.java b/src/main/java/enedis/lab/types/DataDictionary.java deleted file mode 100644 index 56f3bfe..0000000 --- a/src/main/java/enedis/lab/types/DataDictionary.java +++ /dev/null @@ -1,146 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.types; - -import java.io.File; -import java.io.IOException; -import java.io.OutputStream; -import java.util.Map; - -import org.json.JSONObject; - -/** - * Interface used to handle data dictionaries - */ -public interface DataDictionary extends Cloneable -{ - /** - * Check key exists - * - * @param key - * Key to check - * - * @return true if key exists, false otherwise - */ - public boolean exists(String key); - - /** - * Get the datadictionary current map keys list - * - * @return the datadictionary current map keys list - */ - public String[] keys(); - - /** - * Check if the datadictionary map contains the given key - * - * @param key - * @return true if the datadictionary map contains the given key - */ - public boolean existsInKeys(String key); - - /** - * Add the given key in the datadictionary map, if the given key already exists, do nothing - * - * @param key - */ - public void addKey(String key); - - /** - * Remove the given key in the datadictionary map - * - * @param key - */ - public void removeKey(String key); - - /** - * Clear the datadictionary map - */ - public void clear(); - - /** - * Get value of the given key - * - * @param key - * @return value of the given key - */ - public Object get(String key); - - /** - * Set value of the given key - * - * @param key - * @param value - * @throws DataDictionaryException - */ - public void set(String key, Object value) throws DataDictionaryException; - - /** - * Copy an other datadictionary into this one - * - * @param other - * @throws DataDictionaryException - */ - public void copy(DataDictionary other) throws DataDictionaryException; - - /** - * Convert this dataditionary to JSON - * - * @return a JSONObject - */ - public JSONObject toJSON(); - - /** - * Convert this dataditionary to Map - * - * @return a JSONObject - */ - public Map toMap(); - - /** - * Convert the given datadictionary to a File - * - * @param file - * @param indentFactor - * @throws IOException - */ - public void toFile(File file, int indentFactor) throws IOException; - - /** - * Convert the given datadictionary to a Stream - * - * @param stream - * @param indentFactor - * @throws IOException - */ - public void toStream(OutputStream stream, int indentFactor) throws IOException; - - @Override - public String toString(); - - /** - * Convert this dataditionary to a String - * - * @param indentFactor - * @return a JSONObject - */ - public String toString(int indentFactor); - - /** - * Convert this dataditionary to Map - * - * @return a JSONObject - * @throws CloneNotSupportedException - */ - public Object clone() throws CloneNotSupportedException; - - /** - * Print this datactionary in the console - */ - public void print(); -} diff --git a/src/main/java/enedis/lab/types/DataDictionaryException.java b/src/main/java/enedis/lab/types/DataDictionaryException.java deleted file mode 100644 index 0d2f088..0000000 --- a/src/main/java/enedis/lab/types/DataDictionaryException.java +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.types; - -/** - * Data dictionary exception - */ -public class DataDictionaryException extends Exception -{ - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private static final long serialVersionUID = -7967428428453584771L; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Default constructor - */ - public DataDictionaryException() - { - super(); - } - - /** - * Constructor using message, cause, enable suppression flag and writable stack trace flag - * - * @param message - * @param cause - * @param enableSuppression - * @param writableStackTrace - */ - public DataDictionaryException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) - { - super(message, cause, enableSuppression, writableStackTrace); - } - - /** - * Constructor using message and cause - * - * @param message - * @param cause - */ - public DataDictionaryException(String message, Throwable cause) - { - super(message, cause); - } - - /** - * Constructor using message - * - * @param message - */ - public DataDictionaryException(String message) - { - super(message); - } - - /** - * Constructor using cause - * - * @param cause - */ - public DataDictionaryException(Throwable cause) - { - super(cause); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// interfaceName - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -} diff --git a/src/main/java/enedis/lab/types/DataList.java b/src/main/java/enedis/lab/types/DataList.java deleted file mode 100644 index 12eed5f..0000000 --- a/src/main/java/enedis/lab/types/DataList.java +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.types; - -import java.io.File; -import java.io.IOException; -import java.io.OutputStream; -import java.util.List; - -import org.json.JSONArray; -/** - * Interface extending Java standard List to provide JSON serialization mechanism - * - * @param the type of elements in this list - */ -public interface DataList extends List -{ - /** - * Write this data list to a File - * - * @param file the output file - * @param indentFactor JSON indentation factor - * @throws IOException if writing file fails - */ - public void toFile(File file, int indentFactor) throws IOException; - - /** - * Write this data list to a Stream - * - * @param stream the output stream - * @param indentFactor JSON indentation factor - * @throws IOException if writing stream fails - */ - public void toStream(OutputStream stream, int indentFactor) throws IOException; - - @Override - public String toString(); - /** - * Convert this data list to a String - * - * @param indentFactor JSON indentation factor - * @return JSON string representation - */ - public String toString(int indentFactor); - - /** - * Convert this data list to JSON array - * - * @return JSON array - */ - public JSONArray toJSON(); -} diff --git a/src/main/java/enedis/lab/types/ExceptionBase.java b/src/main/java/enedis/lab/types/ExceptionBase.java deleted file mode 100644 index 99e3e7f..0000000 --- a/src/main/java/enedis/lab/types/ExceptionBase.java +++ /dev/null @@ -1,132 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.types; - -/** - * Exception base - */ -@SuppressWarnings("serial") -public class ExceptionBase extends Exception -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected int code; - protected String info; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Constructor - * - * @param code - * @param info - */ - public ExceptionBase(int code, String info) - { - this.setErrorCode(code); - this.setErrorInfo(info); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// Exception - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public String getMessage() - { - return this.info + " (" + this.code + ")"; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Get error code - * - * @return error code - */ - public int getErrorCode() - { - return this.code; - } - - /** - * Set error code - * - * @param errorCode - */ - public void setErrorCode(int errorCode) - { - this.code = errorCode; - } - - /** - * Get error info - * - * @return error info - */ - public String getErrorInfo() - { - return this.info; - } - - /** - * Set error info - * - * @param errorInfo - */ - public void setErrorInfo(String errorInfo) - { - this.info = errorInfo; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -} diff --git a/src/main/java/enedis/lab/types/configuration/Configuration.java b/src/main/java/enedis/lab/types/configuration/Configuration.java deleted file mode 100644 index 46939e9..0000000 --- a/src/main/java/enedis/lab/types/configuration/Configuration.java +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.types.configuration; - -import java.io.File; - -import enedis.lab.types.DataDictionary; - -/** - * Interface used to handle any configuration - */ -public interface Configuration extends DataDictionary -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// interfaceName - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Load configuration from file - * - * @throws ConfigurationException - * load file failed - */ - public void load() throws ConfigurationException; - - /** - * Save configuration to file - * - * @throws ConfigurationException - * save file failed - */ - public void save() throws ConfigurationException; - - /** - * Get config name - * - * @return configuration name - */ - public String getConfigName(); - - /** - * Get config file - * - * @return configuration file reference - */ - public File getConfigFile(); - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -} diff --git a/src/main/java/enedis/lab/types/configuration/ConfigurationBase.java b/src/main/java/enedis/lab/types/configuration/ConfigurationBase.java deleted file mode 100644 index be58331..0000000 --- a/src/main/java/enedis/lab/types/configuration/ConfigurationBase.java +++ /dev/null @@ -1,186 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.types.configuration; - -import java.io.File; -import java.util.Map; - -import enedis.lab.types.DataDictionary; -import enedis.lab.types.DataDictionaryException; -import enedis.lab.types.datadictionary.DataDictionaryBase; - -/** - * Basic implementation of Configuration - */ -public class ConfigurationBase extends DataDictionaryBase implements Configuration -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private String name = null; - private File file = null; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected ConfigurationBase() - { - super(); - } - - /** - * Constructor using datadictionary - * - * @param other - * @throws DataDictionaryException - */ - public ConfigurationBase(DataDictionary other) throws DataDictionaryException - { - super(other); - } - - /** - * Constructor using Map - * - * @param map - * @throws DataDictionaryException - */ - public ConfigurationBase(Map map) throws DataDictionaryException - { - super(map); - } - - /** - * Constructor using name and file - * - * @param name - * @param file - */ - public ConfigurationBase(String name, File file) - { - super(); - this.init(name, file); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// Configuration - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public void load() throws ConfigurationException - { - DataDictionary configuration; - - try - { - configuration = DataDictionaryBase.fromFile(this.file, this.getClass()); - } - catch (Exception exception) - { - throw new ConfigurationException("Cannot load configuration '" + ((this.name == null) ? "" : this.name) + "' from file '" + ((this.file == null) ? "" : this.file) - + "' (" + exception.getMessage() + ") " + exception.getClass().getSimpleName()); - } - try - { - this.copy(configuration); - } - catch (Exception exception) - { - throw new ConfigurationException("Cannot copy configuration '" + ((this.name == null) ? "" : this.name) + "' from file '" + ((this.file == null) ? "" : this.file) - + "' (" + exception.getMessage() + ")"); - } - } - - @Override - public void save() throws ConfigurationException - { - try - { - this.toFile(this.file, 2); - } - catch (Exception exception) - { - throw new ConfigurationException("Cannot save configuration '" + ((this.name == null) ? "" : this.name) + "' to file '" + ((this.file == null) ? "" : this.file) + "' (" - + exception.getMessage() + ")"); - } - } - - @Override - public String getConfigName() - { - return this.name; - } - - @Override - public File getConfigFile() - { - return this.file; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Set config name - * - * @param configName - */ - public void setConfigName(String configName) - { - this.name = configName; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected void init(String name, File file) - { - this.name = name; - this.file = file; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -} diff --git a/src/main/java/enedis/lab/types/configuration/ConfigurationException.java b/src/main/java/enedis/lab/types/configuration/ConfigurationException.java deleted file mode 100644 index 3e435e2..0000000 --- a/src/main/java/enedis/lab/types/configuration/ConfigurationException.java +++ /dev/null @@ -1,172 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.types.configuration; - -import enedis.lab.types.DataDictionaryException; - -/** - * Configuration exception - */ -public class ConfigurationException extends DataDictionaryException -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private static final long serialVersionUID = 8090072693974075297L; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Create missing parameter exception - * - * @param parameter - * @return configurationException - */ - public static ConfigurationException createMissingParameterException(String parameter) - { - return new ConfigurationException("Parameter \'" + parameter + "\' is missing"); - } - - /** - * Create unknown parameter exception - * - * @param parameter - * @return configurationException - */ - public static ConfigurationException createUnknownParameterException(String parameter) - { - return new ConfigurationException("Parameter \'" + parameter + "\' is unknown"); - } - - /** - * Create invalid parameter value exception - * - * @param parameter - * @param info - * @return configurationException - */ - public static ConfigurationException createInvalidParameterValueException(String parameter, String info) - { - return new ConfigurationException("Parameter \'" + parameter + "\' has an invalid value : " + info); - } - - /** - * Create invalid paramter type exception - * - * @param parameter - * @param type - * @return configurationException - */ - public static ConfigurationException createInvalidParameterTypeException(String parameter, Class type) - { - return new ConfigurationException("Parameter \'" + parameter + "\' has an invalid type : " + type.getName()); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Default constructor - */ - public ConfigurationException() - { - super(); - } - - /** - * Constructor using message, cause, enable suppression flag and writable stack trace flag - * - * @param message - * @param cause - * @param enableSuppression - * @param writableStackTrace - */ - public ConfigurationException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) - { - super(message, cause, enableSuppression, writableStackTrace); - } - - /** - * Constructor using message and cause - * - * @param message - * @param cause - */ - public ConfigurationException(String message, Throwable cause) - { - super(message, cause); - } - - /** - * Constructor using message - * - * @param message - */ - public ConfigurationException(String message) - { - super(message); - } - - /** - * Constructor using cause - * - * @param cause - */ - public ConfigurationException(Throwable cause) - { - super(cause); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// interfaceName - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -} diff --git a/src/main/java/enedis/lab/types/datadictionary/DataDictionaryBase.java b/src/main/java/enedis/lab/types/datadictionary/DataDictionaryBase.java deleted file mode 100644 index 02ca337..0000000 --- a/src/main/java/enedis/lab/types/datadictionary/DataDictionaryBase.java +++ /dev/null @@ -1,723 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.types.datadictionary; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -import enedis.lab.types.DataArrayList; -import enedis.lab.types.DataDictionary; -import enedis.lab.types.DataDictionaryException; -import enedis.lab.types.DataList; - -/** - * DataDictionary basic implementation - */ -public class DataDictionaryBase implements DataDictionary -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private static final int JSON_INDENT_FACTOR = 0; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Instantiate a datadictionary from a File - * - * @param file - * @param clazz - * - * @return a datadictionary - * @throws JSONException - * @throws DataDictionaryException - * @throws IOException - */ - public static DataDictionary fromFile(File file, Class clazz) throws JSONException, DataDictionaryException, IOException - { - if (file == null) - { - throw new DataDictionaryException("Can't load file from null"); - } - - InputStream stream = new FileInputStream(file); - - return DataDictionaryBase.fromStream(stream, clazz); - } - - /** - * Instantiate a datadictionary from a Stream - * - * @param stream - * @param clazz - * - * @return a datadictionary - * @throws JSONException - * @throws DataDictionaryException - * @throws IOException - */ - public static DataDictionary fromStream(InputStream stream, Class clazz) throws JSONException, DataDictionaryException, IOException - { - if (stream == null) - { - return null; - } - - byte[] buffer = new byte[stream.available()]; - stream.read(buffer); - stream.close(); - String text = new String(buffer); - - return DataDictionaryBase.fromString(text, clazz); - } - - /** - * Instantiate a datadictionary from a String - * - * @param text - * @param clazz - * - * @return a datadictionary - * @throws JSONException - * @throws DataDictionaryException - */ - public static DataDictionary fromString(String text, Class clazz) throws JSONException, DataDictionaryException - { - if (text == null) - { - return null; - } - - JSONObject jsonObject = new JSONObject(text); - - return DataDictionaryBase.fromJSON(jsonObject, clazz); - } - - /** - * Instantiate a datadictionary from a JSONObject - * - * @param jsonObject - * @param clazz - * - * @return a datadictionary - * @throws JSONException - * @throws DataDictionaryException - */ - public static DataDictionary fromJSON(JSONObject jsonObject, Class clazz) throws JSONException, DataDictionaryException - { - if (jsonObject == null) - { - return null; - } - - return fromMap(jsonObject.toMap(), clazz); - } - - /** - * Instantiate a datadictionary from a Map - * - * @param map - * @param clazz - * - * @return a datadictionary - * @throws JSONException - * @throws DataDictionaryException - */ - public static DataDictionary fromMap(Map map, Class clazz) throws DataDictionaryException - { - if (map == null) - { - return null; - } - if (clazz == null) - { - return fromMap(map); - } - DataDictionary dataDictionnary; - try - { - Constructor constructor = clazz.getConstructor(Map.class); - dataDictionnary = constructor.newInstance(map); - } - catch (InvocationTargetException exception) - { - throw new DataDictionaryException("Cannot create instance of " + clazz.getName() + " : " + exception.getTargetException().getMessage()); - } - catch (Exception exception) - { - throw new DataDictionaryException("Cannot create instance of " + clazz.getName() + " : " + exception.getMessage()); - } - - return dataDictionnary; - } - - /** - * Instantiate a datadictionary from a Map - * - * @param map - * - * @return a datadictionary - * @throws JSONException - * @throws DataDictionaryException - */ - public static DataDictionary fromMap(Map map) throws DataDictionaryException - { - if (map == null) - { - return null; - } - DataDictionaryBase dataDictionnary = new DataDictionaryBase(); - for (String key : map.keySet()) - { - Object value = map.get(key); - if (value instanceof JSONObject) - { - JSONObject jsonObjectValue = (JSONObject) value; - DataDictionary dataDictionaryValue = fromMap(jsonObjectValue.toMap()); - dataDictionnary.set(key, dataDictionaryValue); - } - else if (value instanceof JSONArray) - { - JSONArray jsonArrayValue = (JSONArray) value; - DataList listValue = new DataArrayList(jsonArrayValue.toList()); - dataDictionnary.set(key, listValue); - } - else - { - dataDictionnary.set(key, value); - } - } - - return dataDictionnary; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private List> keyDescriptors; - protected HashMap data; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Default constructor - */ - public DataDictionaryBase() - { - this.init(); - } - - /** - * Constructor using map and setting key not defined allowed flag - * - * @param map - * @throws DataDictionaryException - */ - public DataDictionaryBase(Map map) throws DataDictionaryException - { - this(); - this.copy(fromMap(map)); - } - - /** - * Constructor using dataDictionary and setting key not defined allowed flag - * - * @param other - * @throws DataDictionaryException - */ - public DataDictionaryBase(DataDictionary other) throws DataDictionaryException - { - this(); - this.copy(other); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// DataDictionnary - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public final boolean exists(String key) - { - return this.data.containsKey(key); - } - - @Override - public final boolean existsInKeys(String key) - { - // @formatter:off - return this.keyDescriptors.stream() - .filter(k -> k.getName().equals(key)) - .findAny() - .isPresent(); - // @formatter:on - } - - @Override - public final String[] keys() - { - Set setKeys = this.data.keySet(); - String[] keys = new String[setKeys.size()]; - - setKeys.toArray(keys); - - return keys; - } - - @Override - public final void addKey(String key) - { - if (key != null) - { - this.data.putIfAbsent(key, null); - } - } - - @Override - public final void removeKey(String key) - { - if (key != null) - { - this.data.remove(key); - } - } - - @Override - public final Object get(String key) - { - return this.data.get(key); - } - - @Override - public final void set(String key, Object value) throws DataDictionaryException - { - if (key == null) - { - throw new DataDictionaryException("Key null not allowed"); - } - - if (this.keyDescriptors.isEmpty()) - { - this.data.put(key, value); - } - else - { - Optional> keyDescriptor = this.getKeyDescriptor(key); - if (keyDescriptor.isPresent()) - { - try - { - String setterName = this.getSetterName(key); - // @formatter:off - List methodNameList = Arrays.asList(this.getClass().getDeclaredMethods()) - .stream() - .map(m -> m.getName()) - .collect(Collectors.toList()); - // @formatter:on - if (methodNameList.contains(setterName)) - { - Method method = this.getClass().getDeclaredMethod(setterName, Object.class); - method.setAccessible(true); - method.invoke(this, value); - } - else - { - this.data.put(key, keyDescriptor.get().convert(value)); - } - } - catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException e) - { - throw new DataDictionaryException("Set key " + key + " failed : " + e.getClass().getSimpleName() + " -> " + e.getMessage()); - } - catch (InvocationTargetException e) - { - throw new DataDictionaryException( - "Set key " + key + " failed : " + e.getTargetException().getClass().getSimpleName() + " -> " + e.getTargetException().getMessage()); - } - - } - else - { - throw new DataDictionaryException("Key " + key + " not allowed"); - } - } - } - - @Override - public void copy(DataDictionary other) throws DataDictionaryException - { - String[] otherKeys = other.keys(); - - this.clear(); - for (int i = 0; i < otherKeys.length; i++) - { - this.set(otherKeys[i], other.get(otherKeys[i])); - } - - this.checkAndUpdate(); - } - - @Override - public final void clear() - { - this.data.clear(); - } - - @Override - public final int hashCode() - { - final int prime = 31; - int result = 1; - result = prime * result + ((this.data == null) ? 0 : this.data.hashCode()); - return result; - } - - @Override - public final boolean equals(Object object) - { - if (object == null) - { - return false; - } - if (this == object) - { - return true; - } - if (!(object instanceof DataDictionary)) - { - return false; - } - DataDictionaryBase other = (DataDictionaryBase) object; - - if (this.data == null) - { - if (other.data != null) - { - return false; - } - } - else - { - if (!this.data.keySet().equals(other.data.keySet())) - { - return false; - } - for (String key : this.data.keySet()) - { - Object thisValue = this.data.get(key); - Object otherValue = other.data.get(key); - - if (thisValue == null) - { - if (otherValue != null) - { - return false; - } - else - { - continue; - } - } - else if (otherValue == null) - { - return false; - } - if (!thisValue.getClass().equals(otherValue.getClass())) - { - if ((thisValue instanceof Number) && (otherValue instanceof Number)) - { - double thisDoubleValue = ((Number) thisValue).doubleValue(); - double otherDoubleValue = ((Number) otherValue).doubleValue(); - return thisDoubleValue == otherDoubleValue; - } - else - { - return false; - } - } - if (thisValue.getClass().isArray()) - { - if (thisValue instanceof boolean[]) - { - if (!Arrays.equals((boolean[]) thisValue, (boolean[]) otherValue)) - { - return false; - } - } - else if (thisValue instanceof byte[]) - { - if (!Arrays.equals((byte[]) thisValue, (byte[]) otherValue)) - { - return false; - } - } - else if (thisValue instanceof char[]) - { - if (!Arrays.equals((char[]) thisValue, (char[]) otherValue)) - { - return false; - } - } - else if (thisValue instanceof short[]) - { - if (!Arrays.equals((short[]) thisValue, (short[]) otherValue)) - { - return false; - } - } - else if (thisValue instanceof int[]) - { - if (!Arrays.equals((int[]) thisValue, (int[]) otherValue)) - { - return false; - } - } - else if (thisValue instanceof long[]) - { - if (!Arrays.equals((long[]) thisValue, (long[]) otherValue)) - { - return false; - } - } - else if (thisValue instanceof float[]) - { - if (!Arrays.equals((float[]) thisValue, (float[]) otherValue)) - { - return false; - } - } - else if (thisValue instanceof double[]) - { - if (!Arrays.equals((double[]) thisValue, (double[]) otherValue)) - { - return false; - } - } - else if (thisValue instanceof Object[]) - { - if (!Arrays.equals((Object[]) thisValue, (Object[]) otherValue)) - { - return false; - } - } - } - else - { - if (!thisValue.equals(otherValue)) - { - return false; - } - } - } - } - - return true; - } - - @Override - public final void toFile(File file, int indentFactor) throws IOException - { - OutputStream stream = new FileOutputStream(file); - - this.toStream(stream, indentFactor); - } - - @Override - public final void toStream(OutputStream stream, int indentFactor) throws IOException - { - String text = this.toString(indentFactor); - - stream.write(text.getBytes()); - } - - @Override - public JSONObject toJSON() - { - JSONObject jsonObject = new JSONObject(); - String[] keys = this.keys(); - - for (int i = 0; i < keys.length; i++) - { - Object value = this.get(keys[i]); - if (value instanceof DataDictionaryBase) - { - DataDictionaryBase dataDictionary = (DataDictionaryBase) value; - jsonObject.put(keys[i], dataDictionary.toJSON()); - } - else if (value instanceof LocalDateTime) - { - String textValue = ((LocalDateTime) value).format(KeyDescriptorLocalDateTime.DEFAULT_FORMATTER); - jsonObject.put(keys[i], textValue); - } - else - { - jsonObject.put(keys[i], value); - } - } - - return jsonObject; - } - - @SuppressWarnings("unchecked") - @Override - public final Map toMap() - { - return (Map) this.data.clone(); - } - - @Override - public String toString() - { - return this.toString(DataDictionaryBase.JSON_INDENT_FACTOR); - } - - @Override - public String toString(int identFactor) - { - return this.toJSON().toString(identFactor); - } - - @Override - public DataDictionaryBase clone() - { - try - { - Constructor constructor = this.getClass().getConstructor(DataDictionary.class); - return this.getClass().cast(constructor.newInstance(this)); - } - catch (Exception e) - { - throw new RuntimeException(e.getMessage(), e); - } - } - - @Override - public void print() - { - System.out.println(this.toString(2)); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected final void checkAndUpdate() throws DataDictionaryException - { - this.updateOptionalParameters(); - this.checkMandatoryParameters(); - } - - protected void checkMandatoryParameters() throws DataDictionaryException - { - for (KeyDescriptor key : this.keyDescriptors) - { - if (key.isMandatory() && !this.exists(key.getName())) - { - throw new DataDictionaryException("Mandatory key " + key.getName() + " not defined"); - } - } - } - - protected void updateOptionalParameters() throws DataDictionaryException - { - } - - protected void addKeyDescriptor(KeyDescriptor keyDescriptor) throws DataDictionaryException - { - if (this.existsInKeys(keyDescriptor.getName())) - { - throw new DataDictionaryException("Key " + keyDescriptor.getName() + "already exists"); - } - this.keyDescriptors.add(keyDescriptor); - } - - protected void addAllKeyDescriptor(List> keyDescriptor) throws DataDictionaryException - { - for (KeyDescriptor key : keyDescriptor) - { - this.addKeyDescriptor(key); - } - } - - protected Optional> getKeyDescriptor(String name) - { - // @formatter:off - return this.keyDescriptors.stream() - .filter(k -> k.getName().equals(name)) - .findFirst(); - // @formatter:on - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private String getSetterName(String key) - { - return "set" + key.substring(0, 1).toUpperCase() + key.substring(1); - } - - private void init() - { - this.keyDescriptors = new ArrayList>(); - this.data = new HashMap(); - } - -} diff --git a/src/main/java/enedis/lab/types/datadictionary/KeyDescriptor.java b/src/main/java/enedis/lab/types/datadictionary/KeyDescriptor.java deleted file mode 100644 index 1596b47..0000000 --- a/src/main/java/enedis/lab/types/datadictionary/KeyDescriptor.java +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.types.datadictionary; - -import enedis.lab.types.DataDictionaryException; - -/** - * DataDictionary key descriptor interface - * - * @param - */ -public interface KeyDescriptor -{ - /** - * Get key name - * - * @return key name - */ - public String getName(); - - /** - * Get mandatory flag - * - * @return mandatory flag - */ - public boolean isMandatory(); - - /** - * Set mandatory flag - * - * @param mandatory - */ - public void setMandatory(boolean mandatory); - - /** - * Set a list of accepted values - * - * @param acceptedValues - */ - @SuppressWarnings("unchecked") - public void setAcceptedValues(T... acceptedValues); - - /** - * Convert a Object value to a T value - * - * @param value - * object to convert - * @return value converted to T type - * @throws DataDictionaryException - */ - public T convert(Object value) throws DataDictionaryException; - - /** - * Convert a T value to String - * - * @param value - * value to convert to String - * @return String representation of the value - */ - public String toString(T value); -} diff --git a/src/main/java/enedis/lab/types/datadictionary/KeyDescriptorBase.java b/src/main/java/enedis/lab/types/datadictionary/KeyDescriptorBase.java deleted file mode 100644 index cac21c7..0000000 --- a/src/main/java/enedis/lab/types/datadictionary/KeyDescriptorBase.java +++ /dev/null @@ -1,210 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.types.datadictionary; - -import java.util.Arrays; -import java.util.List; - -import enedis.lab.types.DataDictionaryException; - -/** - * DataDictionary key descriptor base - * - * @param - */ -public abstract class KeyDescriptorBase implements KeyDescriptor -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private String name; - private boolean mandatory; - protected List acceptedValues; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Constructor setting all attributes - * - * @param name - * @param mandatory - */ - public KeyDescriptorBase(String name, boolean mandatory) - { - super(); - this.name = name; - this.mandatory = mandatory; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// KeyDescriptor - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public final T convert(Object value) throws DataDictionaryException - { - T convertedValue = null; - - if (value == null) - { - this.handleNullValue(); - return null; - } - - convertedValue = this.convertValue(value); - - this.checkAcceptedValues(convertedValue); - - return convertedValue; - } - - @Override - public String toString(T value) - { - if (value == null) - { - return null; - } - - return value.toString(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Get key name - * - * @return key name - */ - @Override - public String getName() - { - return this.name; - } - - /** - * Set key name - * - * @param name - */ - public void setName(String name) - { - this.name = name; - } - - /** - * Get mandatory flag - * - * @return mandatory flag - */ - @Override - public boolean isMandatory() - { - return this.mandatory; - } - - /** - * Set mandatory flag - * - * @param mandatory - */ - @Override - public void setMandatory(boolean mandatory) - { - this.mandatory = mandatory; - } - - /** - * Set mandatory value - * - * @param acceptedValues - */ - @SuppressWarnings("unchecked") - @Override - public void setAcceptedValues(T... acceptedValues) - { - this.acceptedValues = Arrays.asList(acceptedValues); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected abstract T convertValue(Object value) throws DataDictionaryException; - - protected final void handleNullValue() throws DataDictionaryException - { - if (this.isMandatory()) - { - throw new DataDictionaryException("Cannot set null " + this.getName()); - } - } - - protected void checkAcceptedValues(T value) throws DataDictionaryException - { - if (this.acceptedValues != null) - { - boolean accepted = false; - - for (T v : this.acceptedValues) - { - if (v.equals(value)) - { - accepted = true; - break; - } - } - - if (!accepted) - { - throw new DataDictionaryException("Key " + this.getName() + " doesn't respect mandatory value"); - } - } - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -} diff --git a/src/main/java/enedis/lab/types/datadictionary/KeyDescriptorDataDictionary.java b/src/main/java/enedis/lab/types/datadictionary/KeyDescriptorDataDictionary.java deleted file mode 100644 index 397464d..0000000 --- a/src/main/java/enedis/lab/types/datadictionary/KeyDescriptorDataDictionary.java +++ /dev/null @@ -1,152 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.types.datadictionary; - -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.util.Map; - -import enedis.lab.types.DataDictionary; -import enedis.lab.types.DataDictionaryException; - -/** - * DataDictionary key descriptor DataDictionary - * - * @param - */ -public class KeyDescriptorDataDictionary extends KeyDescriptorBase -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private Class dataDictionaryClass; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Default constructor - * - * @param name - * @param mandatory - * @param dataDictionaryClass - */ - public KeyDescriptorDataDictionary(String name, boolean mandatory, Class dataDictionaryClass) - { - super(name, mandatory); - this.dataDictionaryClass = dataDictionaryClass; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// DataDictionaryKeyDescriptor - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @SuppressWarnings("unchecked") - @Override - public T convertValue(Object value) throws DataDictionaryException - { - T convertedValue = null; - - if (this.dataDictionaryClass.isAssignableFrom(value.getClass())) - { - convertedValue = this.dataDictionaryClass.cast(value); - } - else if (value instanceof String) - { - convertedValue = (T) DataDictionaryBase.fromString((String) value, this.dataDictionaryClass); - } - else if (value instanceof DataDictionary) - { - try - { - Constructor constructor = this.dataDictionaryClass.getConstructor(DataDictionary.class); - convertedValue = constructor.newInstance((DataDictionary) value); - } - catch (InvocationTargetException e) - { - throw new DataDictionaryException("Key " + this.getName() + ": Cannot convert type " + value.getClass().getSimpleName() + " to " - + this.dataDictionaryClass.getSimpleName() + " : " + e.getTargetException().getMessage()); - } - catch (NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException | IllegalArgumentException e) - { - throw new DataDictionaryException("Key " + this.getName() + ": Cannot convert type " + value.getClass().getSimpleName() + " to " - + this.dataDictionaryClass.getSimpleName() + " : " + e.getMessage()); - } - } - else if (value instanceof Map) - { - try - { - Constructor constructor = this.dataDictionaryClass.getConstructor(Map.class); - convertedValue = constructor.newInstance((Map) value); - } - catch (InvocationTargetException e) - { - throw new DataDictionaryException("Key " + this.getName() + ": Cannot convert type " + value.getClass().getSimpleName() + " to " - + this.dataDictionaryClass.getSimpleName() + " : " + e.getTargetException().getMessage()); - } - catch (NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException | IllegalArgumentException e) - { - throw new DataDictionaryException("Key " + this.getName() + ": Cannot convert type " + value.getClass().getSimpleName() + " to " - + this.dataDictionaryClass.getSimpleName() + " : " + e.getMessage()); - } - } - else - { - throw new DataDictionaryException( - "Key " + this.getName() + ": Cannot convert type " + value.getClass().getSimpleName() + " to " + this.dataDictionaryClass.getSimpleName()); - } - - return convertedValue; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -} diff --git a/src/main/java/enedis/lab/types/datadictionary/KeyDescriptorEnum.java b/src/main/java/enedis/lab/types/datadictionary/KeyDescriptorEnum.java deleted file mode 100644 index aeffc8f..0000000 --- a/src/main/java/enedis/lab/types/datadictionary/KeyDescriptorEnum.java +++ /dev/null @@ -1,142 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.types.datadictionary; - -import enedis.lab.types.DataDictionaryException; - -/** - * DataDictionary key descriptor Enum - * - * @param - */ -@SuppressWarnings("rawtypes") -public class KeyDescriptorEnum extends KeyDescriptorBase -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private Class enumClass; - private String prefix; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Default constructor - * - * @param name - * @param mandatory - * @param enumClass - */ - public KeyDescriptorEnum(String name, boolean mandatory, Class enumClass) - { - this(name, mandatory, enumClass, ""); - } - - /** - * Constructor setting all parameters - * - * @param name - * @param mandatory - * @param enumClass - * @param prefix - */ - public KeyDescriptorEnum(String name, boolean mandatory, Class enumClass, String prefix) - { - super(name, mandatory); - this.enumClass = enumClass; - this.prefix = prefix; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// DataDictionaryKeyDescriptor - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public T convertValue(Object value) throws DataDictionaryException - { - T convertedValue = null; - - if (this.enumClass.isAssignableFrom(value.getClass())) - { - convertedValue = this.enumClass.cast(value); - } - else if (value instanceof String) - { - convertedValue = this.toEnum((String) value); - } - else - { - throw new DataDictionaryException("Key " + this.getName() + ": Cannot convert type " + value.getClass().getSimpleName() + " to " + this.enumClass.getSimpleName()); - } - - return convertedValue; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @SuppressWarnings("unchecked") - protected T toEnum(String value) throws DataDictionaryException - { - T convertedValue = null; - try - { - String preparedValue = this.prefix + value.toUpperCase().replace(".", "_").replace("-", "_"); - convertedValue = (T) Enum.valueOf(this.enumClass, preparedValue); - } - catch (IllegalArgumentException e) - { - throw new DataDictionaryException("Key " + this.getName() + ": " + this.enumClass.getSimpleName() + " doesn't contain " + value); - } - return convertedValue; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -} diff --git a/src/main/java/enedis/lab/types/datadictionary/KeyDescriptorList.java b/src/main/java/enedis/lab/types/datadictionary/KeyDescriptorList.java deleted file mode 100644 index 464997d..0000000 --- a/src/main/java/enedis/lab/types/datadictionary/KeyDescriptorList.java +++ /dev/null @@ -1,233 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.types.datadictionary; - -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.json.JSONObject; - -import enedis.lab.types.DataDictionary; -import enedis.lab.types.DataDictionaryException; - -/** - * DataDictionary key descriptor List - * - * @param - */ -public class KeyDescriptorList extends KeyDescriptorBase> -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private Class itemClass; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Default constructor - * - * @param name - * @param mandatory - * @param itemClass - */ - public KeyDescriptorList(String name, boolean mandatory, Class itemClass) - { - super(name, mandatory); - this.itemClass = itemClass; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// KeyDescriptor> - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public List convertValue(Object value) throws DataDictionaryException - { - List convertedValue = new ArrayList(); - - if (this.itemClass.isAssignableFrom(value.getClass())) - { - T convertedItem = this.convertItem(value); - convertedValue.add(convertedItem); - } - else if (value instanceof HashMap) - { - T convertedItem = this.convertItem(value); - convertedValue.add(convertedItem); - } - else if (value instanceof List) - { - for (Object item : (List) value) - { - T convertedItem = this.convertItem(item); - convertedValue.add(convertedItem); - } - } - else if (value instanceof Object[]) - { - for (Object item : (Object[]) value) - { - T convertedItem = this.convertItem(item); - convertedValue.add(convertedItem); - } - } - else - { - throw new DataDictionaryException( - "Key " + this.getName() + ": Cannot convert type " + value.getClass().getSimpleName() + " to List<" + this.itemClass.getSimpleName() + ">"); - } - return convertedValue; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private T convertItem(Object item) throws DataDictionaryException - { - T convertedItem = null; - if (this.itemClass.isAssignableFrom(item.getClass())) - { - convertedItem = this.itemClass.cast(item); - } - else if (DataDictionary.class.isAssignableFrom(this.itemClass)) - { - convertedItem = this.convertDataDictionaryItem(item); - } - else if (Enum.class.isAssignableFrom(this.itemClass)) - { - convertedItem = this.convertEnumItem(item); - } - else - { - throw new DataDictionaryException( - "Key " + this.getName() + ": at least on item isn't a " + this.itemClass.getSimpleName() + ", type received :" + item.getClass().getSimpleName()); - } - return convertedItem; - } - - private T convertDataDictionaryItem(Object item) throws DataDictionaryException - { - T convertedItem = null; - if (item instanceof JSONObject) - { - JSONObject itemJsonObject = (JSONObject) item; - try - { - Constructor constructor = this.itemClass.getConstructor(Map.class); - convertedItem = (T) constructor.newInstance(itemJsonObject.toMap()); - } - catch (SecurityException | InstantiationException | IllegalAccessException | IllegalArgumentException | NoSuchMethodException e) - { - e.printStackTrace(); - } - catch (InvocationTargetException e) - { - e.printStackTrace(); - } - } - else if (item instanceof Map) - { - try - { - Constructor constructor = this.itemClass.getConstructor(Map.class); - convertedItem = (T) constructor.newInstance((Map) item); - } - catch (SecurityException | InstantiationException | IllegalAccessException | IllegalArgumentException | NoSuchMethodException e) - { - e.printStackTrace(); - } - catch (InvocationTargetException e) - { - e.printStackTrace(); - } - } - else - { - throw new DataDictionaryException("Key " + this.getName() + ": at least on item isn't a JSONObject, type received :" + item.getClass().getSimpleName()); - } - return convertedItem; - } - - @SuppressWarnings("unchecked") - private T convertEnumItem(Object item) throws DataDictionaryException - { - T convertedItem = null; - if (item instanceof String) - { - String itemString = (String) item; - try - { - Method valueOf = this.itemClass.getMethod("valueOf", String.class); - convertedItem = (T) valueOf.invoke(null, itemString.toUpperCase()); - } - catch (SecurityException | IllegalAccessException | IllegalArgumentException | NoSuchMethodException e) - { - e.printStackTrace(); - } - catch (InvocationTargetException e) - { - e.printStackTrace(); - } - - } - else - { - throw new DataDictionaryException("Key " + this.getName() + ": at least on item isn't a JSONObject, type received :" + item.getClass().getSimpleName()); - } - return convertedItem; - } -} diff --git a/src/main/java/enedis/lab/types/datadictionary/KeyDescriptorListMinMaxSize.java b/src/main/java/enedis/lab/types/datadictionary/KeyDescriptorListMinMaxSize.java deleted file mode 100644 index 92b47e7..0000000 --- a/src/main/java/enedis/lab/types/datadictionary/KeyDescriptorListMinMaxSize.java +++ /dev/null @@ -1,170 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.types.datadictionary; - -import java.util.List; - -import enedis.lab.types.DataDictionaryException; -import enedis.lab.util.MinMaxChecker; - -/** - * DataDictionary key descriptor Number min max - * - * @param - */ -public class KeyDescriptorListMinMaxSize extends KeyDescriptorList -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private MinMaxChecker minMaxChecker; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Default constructor - * - * @param name - * @param mandatory - * @param itemClass - */ - public KeyDescriptorListMinMaxSize(String name, boolean mandatory, Class itemClass) - { - this(name, mandatory, itemClass, null, null); - } - - /** - * Constructor setting all attributes - * - * @param name - * @param mandatory - * @param itemClass - * @param min - * @param max - */ - public KeyDescriptorListMinMaxSize(String name, boolean mandatory, Class itemClass, Integer min, Integer max) - { - super(name, mandatory, itemClass); - this.minMaxChecker = new MinMaxChecker(min, max); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// DataDictionaryKeyDescriptor - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public List convertValue(Object value) throws DataDictionaryException - { - List convertedValue = super.convertValue(value); - - this.check(convertedValue); - - return convertedValue; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Get min - * - * @return min - */ - public Integer getMin() - { - return this.minMaxChecker.getMin().intValue(); - } - - /** - * Set min - * - * @param min - * @throws IllegalArgumentException - * if min is greater than max - */ - public void setMin(Integer min) - { - this.minMaxChecker.setMin(min); - } - - /** - * Get max - * - * @return max - */ - public Integer getMax() - { - return this.minMaxChecker.getMax().intValue(); - } - - /** - * Set max - * - * @param max - * @throws IllegalArgumentException - * if max is smaller than min - */ - public void setMax(Integer max) - { - this.minMaxChecker.setMax(max); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private void check(List list) throws DataDictionaryException - { - if (list != null) - { - if (!this.minMaxChecker.check(list.size())) - { - throw new DataDictionaryException("Key " + this.getName() + ": value size (" + list.size() + ") out of bound"); - } - } - } -} diff --git a/src/main/java/enedis/lab/types/datadictionary/KeyDescriptorLocalDateTime.java b/src/main/java/enedis/lab/types/datadictionary/KeyDescriptorLocalDateTime.java deleted file mode 100644 index 7f868dd..0000000 --- a/src/main/java/enedis/lab/types/datadictionary/KeyDescriptorLocalDateTime.java +++ /dev/null @@ -1,160 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.types.datadictionary; - -import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; -import java.time.format.DateTimeParseException; - -import enedis.lab.types.DataDictionaryException; - -/** - * DataDictionary key descriptor LocalDateTime - */ -public class KeyDescriptorLocalDateTime extends KeyDescriptorBase -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** Default pattern used */ - public static final String DEFAULT_PATTERN = "dd/MM/yyyy HH:mm:ss"; - /** Default formatter used */ - public static final DateTimeFormatter DEFAULT_FORMATTER = DateTimeFormatter.ofPattern(DEFAULT_PATTERN); - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private DateTimeFormatter formatter; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Default constructor - * - * @param name - * @param mandatory - */ - public KeyDescriptorLocalDateTime(String name, boolean mandatory) - { - this(name, mandatory, DEFAULT_PATTERN); - } - - /** - * Default constructor - * - * @param name - * @param mandatory - * @param formatterPattern - */ - public KeyDescriptorLocalDateTime(String name, boolean mandatory, String formatterPattern) - { - super(name, mandatory); - this.formatter = DateTimeFormatter.ofPattern(formatterPattern); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// KeyDescriptor - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public String toString(LocalDateTime value) - { - if (value == null) - { - return null; - } - - return this.formatter.format(value); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// KeyDescriptorBase - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public LocalDateTime convertValue(Object value) throws DataDictionaryException - { - LocalDateTime convertedValue = null; - - if (value instanceof LocalDateTime) - { - convertedValue = (LocalDateTime) value; - } - else if (value instanceof String) - { - convertedValue = this.toLocalDateTime((String) value); - } - else - { - throw new DataDictionaryException("Key " + this.getName() + ": Cannot convert type " + value.getClass().getSimpleName() + " to LocalDateTime"); - } - - return convertedValue; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private LocalDateTime toLocalDateTime(String value) throws DataDictionaryException - { - LocalDateTime convertedValue = null; - try - { - convertedValue = LocalDateTime.parse(value, this.formatter); - } - catch (DateTimeParseException e) - { - throw new DataDictionaryException("Key " + this.getName() + ": string " + value + " cannot be converted to LocalDateTime"); - } - return convertedValue; - } - -} diff --git a/src/main/java/enedis/lab/types/datadictionary/KeyDescriptorNumber.java b/src/main/java/enedis/lab/types/datadictionary/KeyDescriptorNumber.java deleted file mode 100644 index c455a86..0000000 --- a/src/main/java/enedis/lab/types/datadictionary/KeyDescriptorNumber.java +++ /dev/null @@ -1,139 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.types.datadictionary; - -import enedis.lab.types.DataDictionaryException; - -/** - * DataDictionary key descriptor Number - */ -public class KeyDescriptorNumber extends KeyDescriptorBase -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Default constructor - * - * @param name - * @param mandatory - */ - public KeyDescriptorNumber(String name, boolean mandatory) - { - super(name, mandatory); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// DataDictionaryKeyDescriptor - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public Number convertValue(Object value) throws DataDictionaryException - { - Number convertedValue = null; - - if (value instanceof Number) - { - convertedValue = (Number) value; - } - else if (value instanceof String) - { - convertedValue = this.toNumber((String) value); - } - else - { - throw new DataDictionaryException("Key " + this.getName() + ": Cannot convert type " + value.getClass().getSimpleName() + " to Number"); - } - - return convertedValue; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected void checkAcceptedValues(Number value) throws DataDictionaryException - { - if (this.acceptedValues != null) - { - boolean accepted = false; - - for(Number v : this.acceptedValues) - { - if(v.doubleValue() == value.doubleValue()) - { - accepted = true; - break; - } - } - - if(!accepted) - { - throw new DataDictionaryException("Key " + this.getName() + " doesn't respect mandatory value"); - } - } - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private Number toNumber(String value) throws DataDictionaryException - { - Number out = null; - try - { - out = Double.valueOf((String) value); - } - catch (NumberFormatException e) - { - throw new DataDictionaryException("Key " + this.getName() + ": Cannot convert type " + value.getClass().getSimpleName() + " to Number"); - } - return out; - } -} diff --git a/src/main/java/enedis/lab/types/datadictionary/KeyDescriptorNumberMinMax.java b/src/main/java/enedis/lab/types/datadictionary/KeyDescriptorNumberMinMax.java deleted file mode 100644 index ce295f3..0000000 --- a/src/main/java/enedis/lab/types/datadictionary/KeyDescriptorNumberMinMax.java +++ /dev/null @@ -1,164 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.types.datadictionary; - -import enedis.lab.types.DataDictionaryException; -import enedis.lab.util.MinMaxChecker; - -/** - * DataDictionary key descriptor Number min max - */ -public class KeyDescriptorNumberMinMax extends KeyDescriptorNumber -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private MinMaxChecker minMaxChecker; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Default constructor - * - * @param name - * @param mandatory - */ - public KeyDescriptorNumberMinMax(String name, boolean mandatory) - { - this(name, mandatory, null, null); - } - - /** - * Constructor setting all attributes - * - * @param name - * @param mandatory - * @param min - * @param max - */ - public KeyDescriptorNumberMinMax(String name, boolean mandatory, Number min, Number max) - { - super(name, mandatory); - this.minMaxChecker = new MinMaxChecker(min, max); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// DataDictionaryKeyDescriptor - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public Number convertValue(Object value) throws DataDictionaryException - { - Number convertedValue = super.convertValue(value); - - this.check(convertedValue); - - return convertedValue; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Get min - * - * @return min - */ - public Number getMin() - { - return this.minMaxChecker.getMin(); - } - - /** - * Set min - * - * @param min - * @throws IllegalArgumentException - * if min is greater than max - */ - public void setMin(Number min) - { - this.minMaxChecker.setMin(min); - } - - /** - * Get max - * - * @return max - */ - public Number getMax() - { - return this.minMaxChecker.getMax(); - } - - /** - * Set max - * - * @param max - * @throws IllegalArgumentException - * if max is smaller than min - */ - public void setMax(Number max) - { - this.minMaxChecker.setMax(max); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private void check(Number convertedValue) throws DataDictionaryException - { - if (convertedValue != null) - { - if (!this.minMaxChecker.check(convertedValue)) - { - throw new DataDictionaryException("Key " + this.getName() + ": value (" + convertedValue + ") out of bound"); - } - } - } -} diff --git a/src/main/java/enedis/lab/types/datadictionary/KeyDescriptorString.java b/src/main/java/enedis/lab/types/datadictionary/KeyDescriptorString.java deleted file mode 100644 index a7ca434..0000000 --- a/src/main/java/enedis/lab/types/datadictionary/KeyDescriptorString.java +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.types.datadictionary; - -import enedis.lab.types.DataDictionaryException; - -/** - * DataDictionary key descriptor String - */ -public class KeyDescriptorString extends KeyDescriptorBase -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private static final boolean DEFAULT_EMPTY_ALLOW_FLAG = true; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private boolean emptyAllow; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Default constructor - * - * @param name - * @param mandatory - */ - public KeyDescriptorString(String name, boolean mandatory) - { - this(name, mandatory, DEFAULT_EMPTY_ALLOW_FLAG); - } - - /** - * Default constructor - * - * @param name - * @param mandatory - * @param emptyAllow - */ - public KeyDescriptorString(String name, boolean mandatory, boolean emptyAllow) - { - super(name, mandatory); - this.emptyAllow = emptyAllow; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// DataDictionaryKeyDescriptor - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public String convertValue(Object value) throws DataDictionaryException - { - String convertedValue = null; - - convertedValue = value.toString(); - - this.check(convertedValue); - - return convertedValue; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Get empty allow flag - * - * @return empty allow flag - */ - public boolean isEmptyAllow() - { - return this.emptyAllow; - } - - /** - * Set empty allow flag - * - * @param emptyAllow - */ - public void setEmptyAllow(boolean emptyAllow) - { - this.emptyAllow = emptyAllow; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private void check(String value) throws DataDictionaryException - { - if (!this.emptyAllow && value.trim().isEmpty()) - { - throw new DataDictionaryException("Key " + this.getName() + ": value can't be empty"); - } - } - -} diff --git a/src/main/java/enedis/lab/util/MinMaxChecker.java b/src/main/java/enedis/lab/util/MinMaxChecker.java deleted file mode 100644 index 12ad83c..0000000 --- a/src/main/java/enedis/lab/util/MinMaxChecker.java +++ /dev/null @@ -1,185 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.util; - -/** - * Min max class - */ -public class MinMaxChecker -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private Number min; - private Number max; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Default constructor - */ - public MinMaxChecker() - { - super(); - } - - /** - * Constructor setting parameters - * - * @param min - * @param max - */ - public MinMaxChecker(Number min, Number max) - { - this(); - this.setMin(min); - this.setMax(max); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// interfaceName - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Get min - * - * @return min - */ - public Number getMin() - { - return this.min; - } - - /** - * Set min - * - * @param min - * @throws IllegalArgumentException - * if min is greater than max - */ - public void setMin(Number min) - { - if (min != null) - { - if (this.max != null && min.doubleValue() > this.max.doubleValue()) - { - throw new IllegalArgumentException("min can't be greater than max"); - } - } - this.min = min; - } - - /** - * Get max - * - * @return max - */ - public Number getMax() - { - return this.max; - } - - /** - * Set max - * - * @param max - * @throws IllegalArgumentException - * if max is smaller than min - */ - public void setMax(Number max) - { - if (max != null) - { - if (this.min != null && max.doubleValue() < this.min.doubleValue()) - { - throw new IllegalArgumentException("max can't be smaller than min"); - } - } - this.max = max; - } - - /** - * Check the given value - * - * @param value - * @return true if the value is in [min, max] - */ - public boolean check(Number value) - { - if (value != null) - { - if (this.min != null) - { - if (value.doubleValue() < this.min.doubleValue()) - { - return false; - } - } - if (this.max != null) - { - if (value.doubleValue() > this.max.doubleValue()) - { - return false; - } - } - return true; - } - else - { - return false; - } - - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -} diff --git a/src/main/java/enedis/lab/util/SystemError.java b/src/main/java/enedis/lab/util/SystemError.java deleted file mode 100644 index 90b48c1..0000000 --- a/src/main/java/enedis/lab/util/SystemError.java +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.util; - -import org.apache.commons.lang3.SystemUtils; - -import com.sun.jna.Native; -import com.sun.jna.platform.win32.Kernel32Util; - -/** - * Class for system error - * - */ -public class SystemError -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Get system last error code - * - * @return System last error code - */ - static public int getCode() - { - return Native.getLastError(); - } - - /** - * Get system last error message - * - * @return System last error message - */ - static public String getMessage() - { - return getMessage(getCode()); - } - - /** - * Get system error message associated with code - * - * @param code - * the system error code - * - * @return System error message - */ - static public String getMessage(int code) - { - String message = null; - - if (SystemUtils.IS_OS_WINDOWS) - { - message = Kernel32Util.formatMessage(code); - } - else if (SystemUtils.IS_OS_LINUX || SystemUtils.IS_OS_UNIX || SystemUtils.IS_OS_MAC_OSX) - { - message = SystemLibC.INSTANCE.strerror(code); - } - - return message; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// interfaceName - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -} diff --git a/src/main/java/enedis/lab/util/SystemLibC.java b/src/main/java/enedis/lab/util/SystemLibC.java deleted file mode 100644 index 49592d5..0000000 --- a/src/main/java/enedis/lab/util/SystemLibC.java +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.util; - -import com.sun.jna.Library; -import com.sun.jna.Native; - -/** - * Interface for system of C library - * - */ -public interface SystemLibC extends Library -{ - /** - * Instance - */ - SystemLibC INSTANCE = Native.load("c", SystemLibC.class); - - /** - * Get string error from code - * - * @param code - * @return string error - */ - public String strerror(int code); -} diff --git a/src/main/java/enedis/lab/util/message/Event.java b/src/main/java/enedis/lab/util/message/Event.java deleted file mode 100644 index 1b23b0a..0000000 --- a/src/main/java/enedis/lab/util/message/Event.java +++ /dev/null @@ -1,189 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.util.message; - -import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import enedis.lab.types.DataDictionary; -import enedis.lab.types.DataDictionaryException; -import enedis.lab.types.datadictionary.KeyDescriptor; -import enedis.lab.types.datadictionary.KeyDescriptorLocalDateTime; - -/** - * Event class - * - * Generated - */ -public abstract class Event extends Message -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected static final String KEY_DATE_TIME = "dateTime"; - - private static final MessageType TYPE_ACCEPTED_VALUE = MessageType.EVENT; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private List> keys = new ArrayList>(); - - protected KeyDescriptorLocalDateTime kDateTime; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected Event() - { - super(); - this.loadKeyDescriptors(); - - this.kType.setAcceptedValues(TYPE_ACCEPTED_VALUE); - } - - /** - * Constructor using map - * - * @param map - * @throws DataDictionaryException - */ - public Event(Map map) throws DataDictionaryException - { - this(); - this.copy(fromMap(map)); - } - - /** - * Constructor using datadictionary - * - * @param other - * @throws DataDictionaryException - */ - public Event(DataDictionary other) throws DataDictionaryException - { - this(); - this.copy(other); - } - - /** - * Constructor setting parameters to specific values - * - * @param name - * @param dateTime - * @throws DataDictionaryException - */ - public Event(String name, LocalDateTime dateTime) throws DataDictionaryException - { - this(); - - this.setName(name); - this.setDateTime(dateTime); - - this.checkAndUpdate(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// Message - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - protected void updateOptionalParameters() throws DataDictionaryException - { - if (!this.exists(KEY_TYPE)) - { - this.setType(TYPE_ACCEPTED_VALUE); - } - super.updateOptionalParameters(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Get date time - * - * @return the date time - */ - public LocalDateTime getDateTime() - { - return (LocalDateTime) this.data.get(KEY_DATE_TIME); - } - - /** - * Set date time - * - * @param dateTime - * @throws DataDictionaryException - */ - public void setDateTime(LocalDateTime dateTime) throws DataDictionaryException - { - this.setDateTime((Object) dateTime); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected void setDateTime(Object dateTime) throws DataDictionaryException - { - this.data.put(KEY_DATE_TIME, this.kDateTime.convert(dateTime)); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private void loadKeyDescriptors() - { - try - { - this.kDateTime = new KeyDescriptorLocalDateTime(KEY_DATE_TIME, true); - this.keys.add(this.kDateTime); - - this.addAllKeyDescriptor(this.keys); - } - catch (DataDictionaryException e) - { - throw new RuntimeException(e.getMessage(), e); - } - } -} diff --git a/src/main/java/enedis/lab/util/message/Message.java b/src/main/java/enedis/lab/util/message/Message.java deleted file mode 100644 index efec77a..0000000 --- a/src/main/java/enedis/lab/util/message/Message.java +++ /dev/null @@ -1,216 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.util.message; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import enedis.lab.types.DataDictionary; -import enedis.lab.types.DataDictionaryException; -import enedis.lab.types.datadictionary.DataDictionaryBase; -import enedis.lab.types.datadictionary.KeyDescriptor; -import enedis.lab.types.datadictionary.KeyDescriptorEnum; -import enedis.lab.types.datadictionary.KeyDescriptorString; - -/** - * Message class - * - * Generated - */ -public class Message extends DataDictionaryBase -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** Key type */ - public static final String KEY_TYPE = "type"; - /** Key name */ - public static final String KEY_NAME = "name"; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private List> keys = new ArrayList>(); - - protected KeyDescriptorEnum kType; - protected KeyDescriptorString kName; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected Message() - { - super(); - this.loadKeyDescriptors(); - - } - - /** - * Constructor using map - * - * @param map - * @throws DataDictionaryException - */ - public Message(Map map) throws DataDictionaryException - { - this(); - this.copy(fromMap(map)); - } - - /** - * Constructor using datadictionary - * - * @param other - * @throws DataDictionaryException - */ - public Message(DataDictionary other) throws DataDictionaryException - { - this(); - this.copy(other); - } - - /** - * Constructor setting parameters to specific values - * - * @param type - * @param name - * @throws DataDictionaryException - */ - public Message(MessageType type, String name) throws DataDictionaryException - { - this(); - - this.setType(type); - this.setName(name); - - this.checkAndUpdate(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// DataDictionaryBase - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - protected void updateOptionalParameters() throws DataDictionaryException - { - super.updateOptionalParameters(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Get type - * - * @return the type - */ - public MessageType getType() - { - return (MessageType) this.data.get(KEY_TYPE); - } - - /** - * Get name - * - * @return the name - */ - public String getName() - { - return (String) this.data.get(KEY_NAME); - } - - /** - * Set type - * - * @param type - * @throws DataDictionaryException - */ - public void setType(MessageType type) throws DataDictionaryException - { - this.setType((Object) type); - } - - /** - * Set name - * - * @param name - * @throws DataDictionaryException - */ - public void setName(String name) throws DataDictionaryException - { - this.setName((Object) name); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected void setType(Object type) throws DataDictionaryException - { - this.data.put(KEY_TYPE, this.kType.convert(type)); - } - - protected void setName(Object name) throws DataDictionaryException - { - this.data.put(KEY_NAME, this.kName.convert(name)); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private void loadKeyDescriptors() - { - try - { - this.kType = new KeyDescriptorEnum(KEY_TYPE, true, MessageType.class); - this.keys.add(this.kType); - - this.kName = new KeyDescriptorString(KEY_NAME, true, false); - this.keys.add(this.kName); - - this.addAllKeyDescriptor(this.keys); - } - catch (DataDictionaryException e) - { - throw new RuntimeException(e.getMessage(), e); - } - } -} diff --git a/src/main/java/enedis/lab/util/message/Request.java b/src/main/java/enedis/lab/util/message/Request.java deleted file mode 100644 index 7ad542b..0000000 --- a/src/main/java/enedis/lab/util/message/Request.java +++ /dev/null @@ -1,155 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.util.message; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import enedis.lab.types.DataDictionary; -import enedis.lab.types.DataDictionaryException; -import enedis.lab.types.datadictionary.KeyDescriptor; - -/** - * Request class - * - * Generated - */ -public abstract class Request extends Message -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private static final MessageType TYPE_ACCEPTED_VALUE = MessageType.REQUEST; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private List> keys = new ArrayList>(); - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected Request() - { - super(); - this.loadKeyDescriptors(); - - this.kType.setAcceptedValues(TYPE_ACCEPTED_VALUE); - } - - /** - * Constructor using map - * - * @param map - * @throws DataDictionaryException - */ - public Request(Map map) throws DataDictionaryException - { - this(); - this.copy(fromMap(map)); - } - - /** - * Constructor using datadictionary - * - * @param other - * @throws DataDictionaryException - */ - public Request(DataDictionary other) throws DataDictionaryException - { - this(); - this.copy(other); - } - - /** - * Constructor setting parameters to specific values - * - * @param type - * @param name - * @throws DataDictionaryException - */ - public Request(MessageType type, String name) throws DataDictionaryException - { - this(); - - this.setType(type); - this.setName(name); - - this.checkAndUpdate(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// Message - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - protected void updateOptionalParameters() throws DataDictionaryException - { - if (!this.exists(KEY_TYPE)) - { - this.setType(TYPE_ACCEPTED_VALUE); - } - super.updateOptionalParameters(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private void loadKeyDescriptors() - { - try - { - - this.addAllKeyDescriptor(this.keys); - } - catch (DataDictionaryException e) - { - throw new RuntimeException(e.getMessage(), e); - } - } -} diff --git a/src/main/java/enedis/lab/util/message/Response.java b/src/main/java/enedis/lab/util/message/Response.java deleted file mode 100644 index 772c4b0..0000000 --- a/src/main/java/enedis/lab/util/message/Response.java +++ /dev/null @@ -1,259 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.util.message; - -import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import enedis.lab.types.DataDictionary; -import enedis.lab.types.DataDictionaryException; -import enedis.lab.types.datadictionary.KeyDescriptor; -import enedis.lab.types.datadictionary.KeyDescriptorLocalDateTime; -import enedis.lab.types.datadictionary.KeyDescriptorNumber; -import enedis.lab.types.datadictionary.KeyDescriptorString; - -/** - * Response class - * - * Generated - */ -public abstract class Response extends Message -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected static final String KEY_DATE_TIME = "dateTime"; - protected static final String KEY_ERROR_CODE = "errorCode"; - protected static final String KEY_ERROR_MESSAGE = "errorMessage"; - - private static final MessageType TYPE_ACCEPTED_VALUE = MessageType.RESPONSE; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private List> keys = new ArrayList>(); - - protected KeyDescriptorLocalDateTime kDateTime; - protected KeyDescriptorNumber kErrorCode; - protected KeyDescriptorString kErrorMessage; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected Response() - { - super(); - this.loadKeyDescriptors(); - - this.kType.setAcceptedValues(TYPE_ACCEPTED_VALUE); - } - - /** - * Constructor using map - * - * @param map - * @throws DataDictionaryException - */ - public Response(Map map) throws DataDictionaryException - { - this(); - this.copy(fromMap(map)); - } - - /** - * Constructor using datadictionary - * - * @param other - * @throws DataDictionaryException - */ - public Response(DataDictionary other) throws DataDictionaryException - { - this(); - this.copy(other); - } - - /** - * Constructor setting parameters to specific values - * - * @param type - * @param name - * @param dateTime - * @param errorCode - * @param errorMessage - * @throws DataDictionaryException - */ - public Response(MessageType type, String name, LocalDateTime dateTime, Number errorCode, String errorMessage) throws DataDictionaryException - { - this(); - - this.setType(type); - this.setName(name); - this.setDateTime(dateTime); - this.setErrorCode(errorCode); - this.setErrorMessage(errorMessage); - - this.checkAndUpdate(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// Message - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - protected void updateOptionalParameters() throws DataDictionaryException - { - if (!this.exists(KEY_TYPE)) - { - this.setType(TYPE_ACCEPTED_VALUE); - } - super.updateOptionalParameters(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Get date time - * - * @return the date time - */ - public LocalDateTime getDateTime() - { - return (LocalDateTime) this.data.get(KEY_DATE_TIME); - } - - /** - * Get error code - * - * @return the error code - */ - public Number getErrorCode() - { - return (Number) this.data.get(KEY_ERROR_CODE); - } - - /** - * Get error message - * - * @return the error message - */ - public String getErrorMessage() - { - return (String) this.data.get(KEY_ERROR_MESSAGE); - } - - /** - * Set date time - * - * @param dateTime - * @throws DataDictionaryException - */ - public void setDateTime(LocalDateTime dateTime) throws DataDictionaryException - { - this.setDateTime((Object) dateTime); - } - - /** - * Set error code - * - * @param errorCode - * @throws DataDictionaryException - */ - public void setErrorCode(Number errorCode) throws DataDictionaryException - { - this.setErrorCode((Object) errorCode); - } - - /** - * Set error message - * - * @param errorMessage - * @throws DataDictionaryException - */ - public void setErrorMessage(String errorMessage) throws DataDictionaryException - { - this.setErrorMessage((Object) errorMessage); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected void setDateTime(Object dateTime) throws DataDictionaryException - { - this.data.put(KEY_DATE_TIME, this.kDateTime.convert(dateTime)); - } - - protected void setErrorCode(Object errorCode) throws DataDictionaryException - { - this.data.put(KEY_ERROR_CODE, this.kErrorCode.convert(errorCode)); - } - - protected void setErrorMessage(Object errorMessage) throws DataDictionaryException - { - this.data.put(KEY_ERROR_MESSAGE, this.kErrorMessage.convert(errorMessage)); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private void loadKeyDescriptors() - { - try - { - this.kDateTime = new KeyDescriptorLocalDateTime(KEY_DATE_TIME, true); - this.keys.add(this.kDateTime); - - this.kErrorCode = new KeyDescriptorNumber(KEY_ERROR_CODE, true); - this.keys.add(this.kErrorCode); - - this.kErrorMessage = new KeyDescriptorString(KEY_ERROR_MESSAGE, false, true); - this.keys.add(this.kErrorMessage); - - this.addAllKeyDescriptor(this.keys); - } - catch (DataDictionaryException e) - { - throw new RuntimeException(e.getMessage(), e); - } - } -} diff --git a/src/main/java/enedis/lab/util/message/ResponseBase.java b/src/main/java/enedis/lab/util/message/ResponseBase.java deleted file mode 100644 index bd44949..0000000 --- a/src/main/java/enedis/lab/util/message/ResponseBase.java +++ /dev/null @@ -1,189 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.util.message; - -import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import enedis.lab.types.DataDictionary; -import enedis.lab.types.DataDictionaryException; -import enedis.lab.types.datadictionary.DataDictionaryBase; -import enedis.lab.types.datadictionary.KeyDescriptor; -import enedis.lab.types.datadictionary.KeyDescriptorDataDictionary; - -/** - * ResponseBase class - * - * Generated - */ -public class ResponseBase extends Response -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected static final String KEY_DATA = "data"; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private List> keys = new ArrayList>(); - - protected KeyDescriptorDataDictionary kData; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected ResponseBase() - { - super(); - this.loadKeyDescriptors(); - - } - - /** - * Constructor using map - * - * @param map - * @throws DataDictionaryException - */ - public ResponseBase(Map map) throws DataDictionaryException - { - this(); - this.copy(fromMap(map)); - } - - /** - * Constructor using datadictionary - * - * @param other - * @throws DataDictionaryException - */ - public ResponseBase(DataDictionary other) throws DataDictionaryException - { - this(); - this.copy(other); - } - - /** - * Constructor setting parameters to specific values - * - * @param name - * @param dateTime - * @param errorCode - * @param errorMessage - * @param data - * @throws DataDictionaryException - */ - public ResponseBase(String name, LocalDateTime dateTime, Number errorCode, String errorMessage, DataDictionaryBase data) throws DataDictionaryException - { - this(); - - this.setName(name); - this.setDateTime(dateTime); - this.setErrorCode(errorCode); - this.setErrorMessage(errorMessage); - this.setData(data); - - this.checkAndUpdate(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// Response - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - protected void updateOptionalParameters() throws DataDictionaryException - { - super.updateOptionalParameters(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Get data - * - * @return the data - */ - public DataDictionaryBase getData() - { - return (DataDictionaryBase) this.data.get(KEY_DATA); - } - - /** - * Set data - * - * @param data - * @throws DataDictionaryException - */ - public void setData(DataDictionaryBase data) throws DataDictionaryException - { - this.setData((Object) data); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected void setData(Object data) throws DataDictionaryException - { - this.data.put(KEY_DATA, this.kData.convert(data)); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private void loadKeyDescriptors() - { - try - { - this.kData = new KeyDescriptorDataDictionary(KEY_DATA, false, DataDictionaryBase.class); - this.keys.add(this.kData); - - this.addAllKeyDescriptor(this.keys); - } - catch (DataDictionaryException e) - { - throw new RuntimeException(e.getMessage(), e); - } - } -} diff --git a/src/main/java/enedis/lab/util/message/exception/MessageException.java b/src/main/java/enedis/lab/util/message/exception/MessageException.java deleted file mode 100644 index 217fe8e..0000000 --- a/src/main/java/enedis/lab/util/message/exception/MessageException.java +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.util.message.exception; - -/** - * Message exception - */ -public class MessageException extends Exception -{ - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private static final long serialVersionUID = -2263755971102386572L; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Default constructor - */ - public MessageException() - { - super(); - } - - /** - * Constructor using message and cause - * - * @param message - * @param cause - */ - public MessageException(String message, Throwable cause) - { - super(message, cause); - } - - /** - * Constructor using message - * - * @param message - */ - public MessageException(String message) - { - super(message); - } - - /** - * Constructor using cause - * - * @param cause - */ - public MessageException(Throwable cause) - { - super(cause); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// interfaceName - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -} diff --git a/src/main/java/enedis/lab/util/message/exception/MessageInvalidContentException.java b/src/main/java/enedis/lab/util/message/exception/MessageInvalidContentException.java deleted file mode 100644 index 27847b0..0000000 --- a/src/main/java/enedis/lab/util/message/exception/MessageInvalidContentException.java +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.util.message.exception; - -/** - * Unvalid message format exception - */ -public class MessageInvalidContentException extends MessageException -{ - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private static final long serialVersionUID = -2263755971102386572L; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Default constructor - */ - public MessageInvalidContentException() - { - super(); - } - - /** - * Constructor using message and cause - * - * @param message - * @param cause - */ - public MessageInvalidContentException(String message, Throwable cause) - { - super(message, cause); - } - - /** - * Constructor using message - * - * @param message - */ - public MessageInvalidContentException(String message) - { - super(message); - } - - /** - * Constructor using cause - * - * @param cause - */ - public MessageInvalidContentException(Throwable cause) - { - super(cause); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// interfaceName - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -} diff --git a/src/main/java/enedis/lab/util/message/exception/MessageInvalidFormatException.java b/src/main/java/enedis/lab/util/message/exception/MessageInvalidFormatException.java deleted file mode 100644 index c1e04fb..0000000 --- a/src/main/java/enedis/lab/util/message/exception/MessageInvalidFormatException.java +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.util.message.exception; - -/** - * Unvalid message format exception - */ -public class MessageInvalidFormatException extends MessageException -{ - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private static final long serialVersionUID = -2263755971102386572L; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Default constructor - */ - public MessageInvalidFormatException() - { - super(); - } - - /** - * Constructor using message and cause - * - * @param message - * @param cause - */ - public MessageInvalidFormatException(String message, Throwable cause) - { - super(message, cause); - } - - /** - * Constructor using message - * - * @param message - */ - public MessageInvalidFormatException(String message) - { - super(message); - } - - /** - * Constructor using cause - * - * @param cause - */ - public MessageInvalidFormatException(Throwable cause) - { - super(cause); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// interfaceName - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -} diff --git a/src/main/java/enedis/lab/util/message/exception/MessageInvalidTypeException.java b/src/main/java/enedis/lab/util/message/exception/MessageInvalidTypeException.java deleted file mode 100644 index 0eee2df..0000000 --- a/src/main/java/enedis/lab/util/message/exception/MessageInvalidTypeException.java +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.util.message.exception; - -/** - * Unvalid message format exception - */ -public class MessageInvalidTypeException extends MessageException -{ - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private static final long serialVersionUID = -2263755971102386572L; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Default constructor - */ - public MessageInvalidTypeException() - { - super(); - } - - /** - * Constructor using message and cause - * - * @param message - * @param cause - */ - public MessageInvalidTypeException(String message, Throwable cause) - { - super(message, cause); - } - - /** - * Constructor using message - * - * @param message - */ - public MessageInvalidTypeException(String message) - { - super(message); - } - - /** - * Constructor using cause - * - * @param cause - */ - public MessageInvalidTypeException(Throwable cause) - { - super(cause); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// interfaceName - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -} diff --git a/src/main/java/enedis/lab/util/message/exception/MessageKeyNameDoesntExistException.java b/src/main/java/enedis/lab/util/message/exception/MessageKeyNameDoesntExistException.java deleted file mode 100644 index 326eb13..0000000 --- a/src/main/java/enedis/lab/util/message/exception/MessageKeyNameDoesntExistException.java +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.util.message.exception; - -/** - * Unvalid message format exception - */ -public class MessageKeyNameDoesntExistException extends MessageException -{ - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private static final long serialVersionUID = -2263755971102386572L; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Default constructor - */ - public MessageKeyNameDoesntExistException() - { - super(); - } - - /** - * Constructor using message and cause - * - * @param message - * @param cause - */ - public MessageKeyNameDoesntExistException(String message, Throwable cause) - { - super(message, cause); - } - - /** - * Constructor using message - * - * @param message - */ - public MessageKeyNameDoesntExistException(String message) - { - super(message); - } - - /** - * Constructor using cause - * - * @param cause - */ - public MessageKeyNameDoesntExistException(Throwable cause) - { - super(cause); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// interfaceName - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -} diff --git a/src/main/java/enedis/lab/util/message/exception/MessageKeyTypeDoesntExistException.java b/src/main/java/enedis/lab/util/message/exception/MessageKeyTypeDoesntExistException.java deleted file mode 100644 index 747843b..0000000 --- a/src/main/java/enedis/lab/util/message/exception/MessageKeyTypeDoesntExistException.java +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.util.message.exception; - -/** - * Unvalid message format exception - */ -public class MessageKeyTypeDoesntExistException extends MessageException -{ - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private static final long serialVersionUID = -2263755971102386572L; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Default constructor - */ - public MessageKeyTypeDoesntExistException() - { - super(); - } - - /** - * Constructor using message and cause - * - * @param message - * @param cause - */ - public MessageKeyTypeDoesntExistException(String message, Throwable cause) - { - super(message, cause); - } - - /** - * Constructor using message - * - * @param message - */ - public MessageKeyTypeDoesntExistException(String message) - { - super(message); - } - - /** - * Constructor using cause - * - * @param cause - */ - public MessageKeyTypeDoesntExistException(Throwable cause) - { - super(cause); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// interfaceName - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -} diff --git a/src/main/java/enedis/lab/util/message/exception/UnsupportedMessageException.java b/src/main/java/enedis/lab/util/message/exception/UnsupportedMessageException.java deleted file mode 100644 index e1f0277..0000000 --- a/src/main/java/enedis/lab/util/message/exception/UnsupportedMessageException.java +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.util.message.exception; - -/** - * Unvalid message format exception - */ -public class UnsupportedMessageException extends MessageException -{ - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private static final long serialVersionUID = -2263755971102386572L; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Default constructor - */ - public UnsupportedMessageException() - { - super(); - } - - /** - * Constructor using message and cause - * - * @param message - * @param cause - */ - public UnsupportedMessageException(String message, Throwable cause) - { - super(message, cause); - } - - /** - * Constructor using message - * - * @param message - */ - public UnsupportedMessageException(String message) - { - super(message); - } - - /** - * Constructor using cause - * - * @param cause - */ - public UnsupportedMessageException(Throwable cause) - { - super(cause); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// interfaceName - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -} diff --git a/src/main/java/enedis/lab/util/message/factory/AbstractMessageFactory.java b/src/main/java/enedis/lab/util/message/factory/AbstractMessageFactory.java deleted file mode 100644 index 9ecbf5b..0000000 --- a/src/main/java/enedis/lab/util/message/factory/AbstractMessageFactory.java +++ /dev/null @@ -1,153 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.util.message.factory; - -import java.util.HashMap; -import java.util.Map; - -import org.json.JSONException; - -import enedis.lab.types.DataDictionaryException; -import enedis.lab.types.datadictionary.DataDictionaryBase; -import enedis.lab.util.message.Message; -import enedis.lab.util.message.exception.MessageInvalidContentException; -import enedis.lab.util.message.exception.MessageInvalidFormatException; -import enedis.lab.util.message.exception.UnsupportedMessageException; - -/** - * Message factory - * - * @param - */ -public class AbstractMessageFactory -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private Class clazz; - private Map> messageClasses; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Default constructor - * - * @param clazz - */ - public AbstractMessageFactory(Class clazz) - { - this.clazz = clazz; - this.messageClasses = new HashMap>(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// Response - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Get message from text - * - * @param text - * @param name - * @return message - * @throws UnsupportedMessageException - * @throws MessageInvalidFormatException - * @throws MessageInvalidContentException - */ - public final T getMessage(String text, String name) throws UnsupportedMessageException, MessageInvalidFormatException, MessageInvalidContentException - { - T message = null; - - try - { - Class messageClazz = this.messageClasses.get(name); - - if (messageClazz != null) - { - message = messageClazz.cast(DataDictionaryBase.fromString(text, messageClazz)); - } - else - { - throw new UnsupportedMessageException("Unsupported " + this.clazz.getSimpleName() + " : " + name); - } - } - catch (JSONException e) - { - throw new MessageInvalidFormatException("Invalid " + this.clazz.getSimpleName() + " " + name + " format, it should be JSON : " + e.getMessage(), e); - } - catch (DataDictionaryException e) - { - throw new MessageInvalidContentException("Invalid " + this.clazz.getSimpleName() + " " + name + " content : " + e.getMessage(), e); - } - - return message; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Add a Message class to decode message with the given name - * - * @param name - * @param messageClazz - */ - public final void addMessageClass(String name, Class messageClazz) - { - if (name == null || messageClazz == null) - { - throw new IllegalArgumentException("Name and " + this.clazz.getSimpleName() + " class can't be null"); - } - - this.messageClasses.put(name, messageClazz); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -} \ No newline at end of file diff --git a/src/main/java/enedis/lab/util/message/factory/BasicMessageFactory.java b/src/main/java/enedis/lab/util/message/factory/BasicMessageFactory.java deleted file mode 100644 index 84a8e75..0000000 --- a/src/main/java/enedis/lab/util/message/factory/BasicMessageFactory.java +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.util.message.factory; - -import org.json.JSONException; -import org.json.JSONObject; - -import enedis.lab.types.DataDictionaryException; -import enedis.lab.util.message.Message; -import enedis.lab.util.message.MessageType; -import enedis.lab.util.message.exception.MessageInvalidFormatException; -import enedis.lab.util.message.exception.MessageInvalidTypeException; -import enedis.lab.util.message.exception.MessageKeyNameDoesntExistException; -import enedis.lab.util.message.exception.MessageKeyTypeDoesntExistException; - -/** - * Message factory - */ -public abstract class BasicMessageFactory -{ - /** - * Get message from text - * - * @param text - * @return message - * @throws MessageInvalidFormatException - * @throws MessageKeyTypeDoesntExistException - * @throws MessageKeyNameDoesntExistException - * @throws MessageInvalidTypeException - */ - public static Message getMessage(String text) - throws MessageInvalidFormatException, MessageKeyTypeDoesntExistException, MessageKeyNameDoesntExistException, MessageInvalidTypeException - { - JSONObject messageJson = convertTextToJson(text); - - MessageType type = extractType(messageJson); - String name = extractName(messageJson); - - return createMessage(type, name); - } - - private static JSONObject convertTextToJson(String text) throws MessageInvalidFormatException - { - try - { - return new JSONObject(text); - } - catch (JSONException e) - { - throw new MessageInvalidFormatException("Invalid format, it should be JSON : " + e.getMessage()); - } - } - - private static MessageType extractType(JSONObject jsonObj) throws MessageKeyTypeDoesntExistException, MessageInvalidFormatException, MessageInvalidTypeException - { - try - { - checkKeyTypeExists(jsonObj); - String typeStr = jsonObj.getString(Message.KEY_TYPE); - MessageType type = MessageType.valueOf(typeStr); - return type; - } - catch (JSONException e) - { - throw new MessageInvalidFormatException("Invalid format : " + e.getMessage()); - } - catch (IllegalArgumentException e) - { - throw new MessageInvalidTypeException("Invalid format : " + e.getMessage()); - } - } - - private static void checkKeyTypeExists(JSONObject jsonObj) throws MessageKeyTypeDoesntExistException - { - if (!jsonObj.has(Message.KEY_TYPE)) - { - throw new MessageKeyTypeDoesntExistException("Key type missing"); - } - } - - private static String extractName(JSONObject jsonObj) throws MessageInvalidFormatException, MessageKeyNameDoesntExistException - { - try - { - checkKeyNameExists(jsonObj); - return jsonObj.getString(Message.KEY_NAME); - } - catch (JSONException e) - { - throw new MessageInvalidFormatException("Invalid format : " + e.getMessage()); - } - } - - private static void checkKeyNameExists(JSONObject jsonObj) throws MessageKeyNameDoesntExistException - { - if (!jsonObj.has(Message.KEY_NAME)) - { - throw new MessageKeyNameDoesntExistException("Key name missing"); - } - } - - private static Message createMessage(MessageType type, String name) - { - try - { - return new Message(type, name); - } - catch (DataDictionaryException e) - { - return null; - } - } -} diff --git a/src/main/java/enedis/lab/util/message/factory/EventFactory.java b/src/main/java/enedis/lab/util/message/factory/EventFactory.java deleted file mode 100644 index f349021..0000000 --- a/src/main/java/enedis/lab/util/message/factory/EventFactory.java +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.util.message.factory; - -import enedis.lab.util.message.Event; - -/** - * Request factory - */ -public class EventFactory extends AbstractMessageFactory -{ - /** - * Default constructor - */ - public EventFactory() - { - super(Event.class); - } -} diff --git a/src/main/java/enedis/lab/util/message/factory/MessageFactory.java b/src/main/java/enedis/lab/util/message/factory/MessageFactory.java deleted file mode 100644 index daa4df0..0000000 --- a/src/main/java/enedis/lab/util/message/factory/MessageFactory.java +++ /dev/null @@ -1,177 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.util.message.factory; - -import enedis.lab.util.message.Message; -import enedis.lab.util.message.exception.MessageInvalidContentException; -import enedis.lab.util.message.exception.MessageInvalidFormatException; -import enedis.lab.util.message.exception.MessageInvalidTypeException; -import enedis.lab.util.message.exception.MessageKeyNameDoesntExistException; -import enedis.lab.util.message.exception.MessageKeyTypeDoesntExistException; -import enedis.lab.util.message.exception.UnsupportedMessageException; - -/** - * Message factory - */ -public class MessageFactory -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private RequestFactory requestFactory; - private ResponseFactory responseFactory; - private EventFactory eventFactory; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Default constructor - */ - public MessageFactory() - { - super(); - } - - /** - * Constructor using field - * - * @param requestFactory - * @param responseFactory - * @param eventFactory - */ - public MessageFactory(RequestFactory requestFactory, ResponseFactory responseFactory, EventFactory eventFactory) - { - super(); - this.requestFactory = requestFactory; - this.responseFactory = responseFactory; - this.eventFactory = eventFactory; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// interfaceName - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Get message from String - * - * @param text - * @return message - * @throws MessageInvalidTypeException - * @throws MessageKeyNameDoesntExistException - * @throws MessageKeyTypeDoesntExistException - * @throws MessageInvalidFormatException - * @throws MessageInvalidContentException - * @throws UnsupportedMessageException - */ - public Message getMessage(String text) throws MessageInvalidFormatException, MessageKeyTypeDoesntExistException, MessageKeyNameDoesntExistException, - MessageInvalidTypeException, UnsupportedMessageException, MessageInvalidContentException - { - this.checkSubFactoryReferences(); - - Message genericMessage = BasicMessageFactory.getMessage(text); - Message message = null; - - // @formatter:off - switch (genericMessage.getType()) - { - case REQUEST: message = this.requestFactory.getMessage(text, genericMessage.getName()); break; - case RESPONSE: message = this.responseFactory.getMessage(text, genericMessage.getName()); break; - case EVENT: message = this.eventFactory.getMessage(text, genericMessage.getName()); break; - default: - break; - } - // @formatter:on - - return message; - } - - /** - * Set request factory - * - * @param requestFactory - */ - public void setRequestFactory(RequestFactory requestFactory) - { - this.requestFactory = requestFactory; - } - - /** - * Set response factory - * - * @param responseFactory - */ - public void setResponseFactory(ResponseFactory responseFactory) - { - this.responseFactory = responseFactory; - } - - /** - * Set event factory - * - * @param eventFactory - */ - public void setEventFactory(EventFactory eventFactory) - { - this.eventFactory = eventFactory; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private void checkSubFactoryReferences() - { - if (this.requestFactory == null || this.responseFactory == null || this.eventFactory == null) - { - throw new IllegalStateException("requestFactory, responseFactory and eventFactory have to be set"); - } - } - -} diff --git a/src/main/java/enedis/lab/util/message/factory/RequestFactory.java b/src/main/java/enedis/lab/util/message/factory/RequestFactory.java deleted file mode 100644 index 4df5690..0000000 --- a/src/main/java/enedis/lab/util/message/factory/RequestFactory.java +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.util.message.factory; - -import enedis.lab.util.message.Request; - -/** - * Request factory - */ -public class RequestFactory extends AbstractMessageFactory -{ - /** - * Default constructor - */ - public RequestFactory() - { - super(Request.class); - } -} diff --git a/src/main/java/enedis/lab/util/message/factory/ResponseFactory.java b/src/main/java/enedis/lab/util/message/factory/ResponseFactory.java deleted file mode 100644 index eda280e..0000000 --- a/src/main/java/enedis/lab/util/message/factory/ResponseFactory.java +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.util.message.factory; - -import enedis.lab.util.message.Response; - -/** - * Request factory - */ -public class ResponseFactory extends AbstractMessageFactory -{ - /** - * Default constructor - */ - public ResponseFactory() - { - super(Response.class); - } -} diff --git a/src/main/java/enedis/lab/util/task/FilteredNotifier.java b/src/main/java/enedis/lab/util/task/FilteredNotifier.java deleted file mode 100644 index bf86a63..0000000 --- a/src/main/java/enedis/lab/util/task/FilteredNotifier.java +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.util.task; - -import java.util.Collection; -import java.util.function.Predicate; - -/** - * Notifier interface with filter - * - * @param - * the filter - * @param - * the subscriber - */ -public interface FilteredNotifier extends Notifier -{ - /** - * Add a subscriber with filter - * - * @param filter - * the filter used for subscription - * @param listener - * the subscriber reference - * @throws Exception - * on subscription failure - */ - public void subscribe(F filter, T listener) throws Exception; - - /** - * Remove a subscriber with filter - * - * @param filter - * the filter used for subscription - * @param listener - * the subscriber reference - * @throws Exception - * if filter or listener not found - */ - public void unsubscribe(F filter, T listener) throws Exception; - - /** - * Check if the given filter has a given subscriber - * - * @param filter - * the filter used for subscription - * @param listener - * the subscriber reference - * @return true if the given subscriber exists - */ - public boolean hasSubscriber(F filter, T listener); - - /** - * Get subscribers associated with filter - * - * @param filter - * the filter used for subscription - * @return The subscribers collection - */ - public Collection getSubscribers(F filter); - - /** - * Get subscribers including global and/or filters - * - * @param includeGlobal - * indicates if includes global subscribers - * @param includeFilter - * indicates if includes filters subscribers - * @return The subscribers collection - */ - public Collection getSubscribers(boolean includeGlobal, boolean includeFilter); - - /** - * Get subscribers associated with predicate filter - * - * @param predicate - * the predicate used to test with filters used for subscription - * @param includeGlobal - * indicates if includes global subscribers - * @return The subscribers collection - */ - public Collection getSubscribers(Predicate predicate, boolean includeGlobal); - - /** - * Check if the given filter has been set - * - * @param filter - * the filter used for subscription - * @return true if the given filter exists - */ - public boolean hasFilter(F filter); - - /** - * Get filters - * - * @return The filters collection - */ - public Collection getFilters(); - - /** - * Get filters associated with listener - * - * @param listener - * the subscriber reference - * @return The filters collection - */ - public Collection getFilters(T listener); -} diff --git a/src/main/java/enedis/lab/util/task/FilteredNotifierBase.java b/src/main/java/enedis/lab/util/task/FilteredNotifierBase.java deleted file mode 100644 index 5b772d7..0000000 --- a/src/main/java/enedis/lab/util/task/FilteredNotifierBase.java +++ /dev/null @@ -1,302 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.util.task; - -import java.util.Collection; -import java.util.HashSet; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.CopyOnWriteArraySet; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; -import java.util.function.Predicate; - -/** - * Filtered notifier with subscribers basic implementation - * - * @param - * the filter type - * @param - * the subscriber type - */ -public class FilteredNotifierBase implements FilteredNotifier -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected Map> subscribersFiltered; - private Lock subscribersFilteredLock = new ReentrantLock(); - protected Collection subscribersUnfiltered; - private Lock subscribersUnfilteredLock = new ReentrantLock(); - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Default constructor - */ - public FilteredNotifierBase() - { - super(); - this.subscribersFiltered = new ConcurrentHashMap>(); - this.subscribersUnfiltered = new CopyOnWriteArraySet(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// Listenable - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public void subscribe(T listener) - { - if (listener == null) - { - return; - } - this.subscribersUnfilteredLock.lock(); - this.subscribersUnfiltered.add(listener); - this.subscribersUnfilteredLock.unlock(); - } - - @Override - public void unsubscribe(T listener) - { - if (listener == null) - { - return; - } - for (F filter : this.getFilters()) - { - this.unsubscribe(filter, listener); - } - this.subscribersUnfilteredLock.lock(); - this.subscribersUnfiltered.remove(listener); - this.subscribersUnfilteredLock.unlock(); - } - - @Override - public boolean hasSubscriber(T listener) - { - for (F filter : this.getFilters()) - { - if (this.hasSubscriber(filter, listener)) - { - return true; - } - } - - this.subscribersUnfilteredLock.lock(); - boolean hasSubscriber = this.subscribersUnfiltered.contains(listener); - this.subscribersUnfilteredLock.unlock(); - - return hasSubscriber; - } - - @Override - public Collection getSubscribers() - { - return this.getSubscribers(true, true); - } - - @Override - public void subscribe(F filter, T listener) - { - if (filter == null || listener == null) - { - return; - } - Collection subscribers; - if (this.hasFilter(filter)) - { - subscribers = this.getSubscribers(filter); - if (!subscribers.contains(listener)) - { - subscribers.add(listener); - } - } - else - { - subscribers = new HashSet(); - subscribers.add(listener); - } - this.subscribersFilteredLock.lock(); - this.subscribersFiltered.put(filter, subscribers); - this.subscribersFilteredLock.unlock(); - } - - @Override - public void unsubscribe(F filter, T listener) - { - if (filter == null || listener == null) - { - return; - } - Collection subscribers = this.getSubscribers(filter); - if (subscribers.contains(listener)) - { - subscribers.remove(listener); - if (subscribers.size() == 0) - { - this.subscribersFilteredLock.lock(); - this.subscribersFiltered.remove(filter); - this.subscribersFilteredLock.unlock(); - } - } - } - - @Override - public boolean hasSubscriber(F filter, T listener) - { - Collection subscribers = this.getSubscribers(filter); - - return subscribers.contains(listener); - } - - @Override - public Collection getSubscribers(F filter) - { - this.subscribersFilteredLock.lock(); - Collection subscribersFiltered = (this.hasFilter(filter)) ? this.subscribersFiltered.get(filter) : new HashSet(); - this.subscribersFilteredLock.unlock(); - - return subscribersFiltered; - } - - @Override - public Collection getSubscribers(boolean includeGlobal, boolean includeFilter) - { - Collection subscribers = new HashSet(); - - if (includeFilter) - { - for (F filter : this.getFilters()) - { - Collection filterSubscribers = this.getSubscribers(filter); - subscribers.addAll(filterSubscribers); - } - } - if (includeGlobal) - { - this.subscribersUnfilteredLock.lock(); - subscribers.addAll(this.subscribersUnfiltered); - this.subscribersUnfilteredLock.unlock(); - } - - return subscribers; - } - - @Override - public Collection getSubscribers(Predicate predicate, boolean includeGlobal) - { - Collection subscribers = new HashSet(); - - if (predicate != null) - { - this.subscribersFilteredLock.lock(); - for (F filter : this.subscribersFiltered.keySet()) - { - if (predicate.test(filter)) - { - subscribers.addAll(this.subscribersFiltered.get(filter)); - } - } - this.subscribersFilteredLock.unlock(); - } - if (includeGlobal) - { - this.subscribersUnfilteredLock.lock(); - subscribers.addAll(this.subscribersUnfiltered); - this.subscribersUnfilteredLock.unlock(); - } - - return subscribers; - } - - @Override - public boolean hasFilter(F filter) - { - this.subscribersFilteredLock.lock(); - boolean hasFilter = (filter != null) ? this.subscribersFiltered.containsKey(filter) : false; - this.subscribersFilteredLock.unlock(); - - return hasFilter; - } - - @Override - public Collection getFilters() - { - this.subscribersFilteredLock.lock(); - Collection subscribersFiltered = this.subscribersFiltered.keySet(); - this.subscribersFilteredLock.unlock(); - - return subscribersFiltered; - } - - @Override - public Collection getFilters(T listener) - { - Collection filters = new HashSet(); - - for (F filter : this.getFilters()) - { - Collection subscribers = this.getSubscribers(filter); - if (subscribers.contains(listener)) - { - filters.add(filter); - } - } - - return filters; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -} \ No newline at end of file diff --git a/src/main/java/enedis/lab/util/task/Notifier.java b/src/main/java/enedis/lab/util/task/Notifier.java deleted file mode 100644 index e8ec73e..0000000 --- a/src/main/java/enedis/lab/util/task/Notifier.java +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.util.task; - -import java.util.Collection; - -/** - * Notifier interface - * - * @param - */ -public interface Notifier -{ - /** - * Add a subscriber - * - * @param subscriber - */ - public void subscribe(T subscriber); - - /** - * Remove a subscriber - * - * @param subscriber - */ - public void unsubscribe(T subscriber); - - /** - * Check if the given subscriber has been added - * - * @param subscriber - * @return true if the given subscriber has been added - */ - public boolean hasSubscriber(T subscriber); - - /** - * Get subscribers - * - * @return The subscribers collection - */ - public Collection getSubscribers(); -} diff --git a/src/main/java/enedis/lab/util/task/NotifierBase.java b/src/main/java/enedis/lab/util/task/NotifierBase.java deleted file mode 100644 index d0a9979..0000000 --- a/src/main/java/enedis/lab/util/task/NotifierBase.java +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.util.task; - -import java.util.Collection; -import java.util.Set; -import java.util.concurrent.CopyOnWriteArraySet; - -/** - * Notifier with subscribers basic implementation - * - * @param - * the subscriber type - */ -public class NotifierBase implements Notifier -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected Set subscribers; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Default constructor - */ - public NotifierBase() - { - super(); - this.subscribers = new CopyOnWriteArraySet(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// Listenable - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public void subscribe(T listener) - { - if (listener != null && !this.subscribers.contains(listener)) - { - this.subscribers.add(listener); - } - } - - @Override - public void unsubscribe(T listener) - { - if (listener != null && this.subscribers.contains(listener)) - { - this.subscribers.remove(listener); - } - } - - @Override - public boolean hasSubscriber(T listener) - { - return this.subscribers.contains(listener); - } - - @Override - public Collection getSubscribers() - { - return this.subscribers; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -} \ No newline at end of file diff --git a/src/main/java/enedis/lab/util/task/Task.java b/src/main/java/enedis/lab/util/task/Task.java deleted file mode 100644 index d3ead6f..0000000 --- a/src/main/java/enedis/lab/util/task/Task.java +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.util.task; - -/** - * Task interface - */ -public interface Task -{ - /** - * Start task - */ - public void start(); - - /** - * Stop task - */ - public void stop(); - - /** - * Get the task running state - * - * @return true if the task running - */ - public boolean isRunning(); -} diff --git a/src/main/java/enedis/lab/util/task/TaskBase.java b/src/main/java/enedis/lab/util/task/TaskBase.java deleted file mode 100644 index 15b94d8..0000000 --- a/src/main/java/enedis/lab/util/task/TaskBase.java +++ /dev/null @@ -1,205 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.util.task; - -import java.util.concurrent.atomic.AtomicBoolean; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -/** - * Task basic implementation - */ -public abstract class TaskBase implements Task, Runnable -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private AtomicBoolean stopRequired; - private Thread task; - protected static Logger logger = LogManager.getLogger(); - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Default constructor - */ - public TaskBase() - { - super(); - this.stopRequired = new AtomicBoolean(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// Task - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public void start() - { - if (this.task == null || !this.task.isAlive()) - { - this.stopRequired.set(false); - this.task = new Thread(this); - this.task.start(); - } - } - - @Override - public void stop() - { - try - { - if (this.task != null && this.task.isAlive()) - { - this.stopRequired.set(true); - if (this.task != Thread.currentThread()) - { - this.task.join(); - } - } - } - catch (InterruptedException exception) - { - logger.error("Stop task interrupted", exception); - } - } - - @Override - public final boolean isRunning() - { - return this.task == null ? false : this.task.isAlive(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public void run() - { - this.runOnStart(); - this.runProcess(); - this.runOnTerminate(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected final boolean isStopRequired() - { - return this.stopRequired.get(); - } - - protected final void runOnStart() - { - try - { - this.onStart(); - } - catch (Exception exception) - { - logger.error("Task on start aborted", exception); - this.runOnError(exception); - } - } - - protected final void runProcess() - { - try - { - this.process(); - } - catch (Exception exception) - { - logger.error("Task process aborted", exception); - this.runOnError(exception); - } - } - - protected final void runOnTerminate() - { - try - { - this.onTerminate(); - } - catch (Exception exception) - { - logger.error("Task on terminate aborted", exception); - this.runOnError(exception); - } - } - - protected final void runOnError(Exception exception) - { - try - { - this.onError(exception); - } - catch (Exception onErrorException) - { - logger.error("Task on error aborted", exception); - } - } - - /** - * Task core process method - */ - protected abstract void process(); - - protected void onStart() - { - } - - protected void onTerminate() - { - } - - protected void onError(Exception exception) - { - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -} diff --git a/src/main/java/enedis/lab/util/task/TaskPeriodic.java b/src/main/java/enedis/lab/util/task/TaskPeriodic.java deleted file mode 100644 index 84f279d..0000000 --- a/src/main/java/enedis/lab/util/task/TaskPeriodic.java +++ /dev/null @@ -1,151 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.util.task; - -import java.util.concurrent.atomic.AtomicLong; - -import enedis.lab.util.time.Time; - -/** - * Periodic task with configurable period - */ -public abstract class TaskPeriodic extends TaskBase -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Default period (in milliseconds) used to execute process - */ - public static final long DEFAULT_PERIOD = 1000; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private AtomicLong period = new AtomicLong(); - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Constructor with default parameter - * - * @see #DEFAULT_PERIOD - */ - public TaskPeriodic() - { - super(); - this.setPeriod(DEFAULT_PERIOD); - } - - /** - * Constructor with polling period - * - * @param period - * the period (in milliseconds) used to execute process - */ - public TaskPeriodic(long period) - { - super(); - this.setPeriod(period); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// Runnable - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public void run() - { - this.runOnStart(); - while (!this.isStopRequired()) - { - this.runProcess(); - if (this.isStopRequired()) - { - break; - } - this.waitPeriod(); - } - this.runOnTerminate(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Get polling period - * - * @return The period (in milliseconds) used to execute process - */ - public long getPeriod() - { - return this.period.get(); - } - - /** - * Set the polling period - * - * @param period - * the period (in milliseconds) used to execute process - * @throws IllegalArgumentException - * if period <= 0 - */ - public void setPeriod(long period) - { - if (period <= 0) - { - throw new IllegalArgumentException("Cannot set period " + period + " : must be > 0"); - } - this.period.set(period); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private void waitPeriod() - { - Time.sleep(this.getPeriod()); - } -} diff --git a/src/main/java/enedis/lab/util/task/TaskPeriodicWithSubscribers.java b/src/main/java/enedis/lab/util/task/TaskPeriodicWithSubscribers.java deleted file mode 100644 index bf34fb8..0000000 --- a/src/main/java/enedis/lab/util/task/TaskPeriodicWithSubscribers.java +++ /dev/null @@ -1,122 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.util.task; - -import java.util.Collection; - -/** - * Periodic task with subscribers basic implementation - * - * @param - * the subscriber type - */ -public abstract class TaskPeriodicWithSubscribers extends TaskPeriodic implements Notifier -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected Notifier notifier; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Default constructor - */ - public TaskPeriodicWithSubscribers() - { - super(); - this.notifier = new NotifierBase(); - } - - /** - * Constructor setting period - * - * @param period - * the period in milliseconds - */ - public TaskPeriodicWithSubscribers(long period) - { - super(period); - this.notifier = new NotifierBase(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// interfaceName - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public void subscribe(T listener) - { - this.notifier.subscribe(listener); - } - - @Override - public void unsubscribe(T listener) - { - this.notifier.unsubscribe(listener); - } - - @Override - public boolean hasSubscriber(T listener) - { - return this.notifier.hasSubscriber(listener); - } - - @Override - public Collection getSubscribers() - { - return this.notifier.getSubscribers(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -} diff --git a/src/main/java/enedis/lab/util/time/Time.java b/src/main/java/enedis/lab/util/time/Time.java deleted file mode 100644 index 25999f0..0000000 --- a/src/main/java/enedis/lab/util/time/Time.java +++ /dev/null @@ -1,163 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.util.time; - -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.Date; - -/** - * Time implementation - */ -public abstract class Time -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** Millisecond */ - public final static int MILLISECOND = 1; - /** Second */ - public final static int SECOND = 1000 * MILLISECOND; - /** Minute */ - public final static int MINUTE = 60 * SECOND; - /** Hour */ - public final static int HOUR = 60 * MINUTE; - /** Day */ - public final static int DAY = 24 * HOUR; - - /* Default format for displaying the date/time */ - private static final String DFLT_DATETIME_FORMAT = "yyyy/MM/dd HH:mm:ss.SSS"; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Wait the given duration in millisecond - * - * @param duration - */ - public static void sleep(long duration) - { - if (duration <= 0L) - { - return; - } - try - { - Thread.sleep(duration); - } - catch (InterruptedException e) - { - e.printStackTrace(); - } - } - - /** - * Convert date/time from long number (since an origin) to a string in the default format - * - * @param timestamp - * a long number (of milliseconds since January 1, 1970, 00:00:00 GMT) - * @return the time/date string in the default format - */ - public static String timestampToDateTimeStr(long timestamp) - { - return timestampToDateTimeStr(timestamp, DFLT_DATETIME_FORMAT); - } - - /** - * Convert date/time from long number to a string in the specified format - * - * @param timestamp - * a long number (of milliseconds since January 1, 1970, 00:00:00 GMT) - * @param dateTimeFormatStr - * the format specified - * @return the time/date string in the specified format - */ - public static String timestampToDateTimeStr(long timestamp, String dateTimeFormatStr) - { - DateFormat dateFormat = new SimpleDateFormat(dateTimeFormatStr); - Date date = new Date(timestamp); - return dateFormat.format(date); - } - - /** - * Timestamp a message with the current DateTime - * - * @param msg - * @return the message decorated with current DateTime - */ - public static String timestamp(String msg) - { - return timestamp(msg, DFLT_DATETIME_FORMAT); - } - - /** - * Timestamp a message with the current DateTime - * - * @param msg - * @param dateTimeFormat - * @return the message decorated with current DateTime - */ - public static String timestamp(String msg, String dateTimeFormat) - { - DateFormat dateFormat = new SimpleDateFormat(dateTimeFormat); - Date date = new Date(); - String text = dateFormat.format(date) + " : " + msg; - return text; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// interfaceName - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -} diff --git a/src/main/java/enedis/tic/core/ReadNextFrameSubscriber.java b/src/main/java/enedis/tic/core/ReadNextFrameSubscriber.java deleted file mode 100644 index 1cbce3d..0000000 --- a/src/main/java/enedis/tic/core/ReadNextFrameSubscriber.java +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.tic.core; - -public class ReadNextFrameSubscriber implements TICCoreSubscriber -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private TICCoreFrame frame; - private TICCoreError error; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - public ReadNextFrameSubscriber() - { - super(); - this.clear(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// interfaceName - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public void onData(TICCoreFrame frame) - { - this.frame = frame; - } - - @Override - public void onError(TICCoreError error) - { - this.error = error; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - public TICCoreFrame getData() - { - return this.frame; - } - - public TICCoreError getError() - { - return this.error; - } - - public void clear() - { - this.frame = null; - this.error = null; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -} diff --git a/src/main/java/enedis/tic/core/TICCore.java b/src/main/java/enedis/tic/core/TICCore.java deleted file mode 100644 index b04d740..0000000 --- a/src/main/java/enedis/tic/core/TICCore.java +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.tic.core; - -import java.util.List; - -import enedis.lab.io.tic.TICPortDescriptor; -import enedis.lab.util.task.Task; - -/** - * TICCore interface - */ -public interface TICCore extends Task -{ - /** - * Get available TICs - * - * @return The collection of TIC identifiers - */ - public List getAvailableTICs(); - - /** - * Get modems informations - * - * @return The collection of TIC port descriptors - */ - public List getModemsInfo(); - - /** - * Read next frame - * - * @param identifier - * the TIC identifier - * - * @return Frame read or null if timed out - * @throws TICCoreException - * if identifier not found or if any error occurs - */ - public TICCoreFrame readNextFrame(TICIdentifier identifier) throws TICCoreException; - - /** - * Read next frame - * - * @param identifier - * the TIC identifier - * @param timeout - * the read timeout in milliseconds - * - * @return Frame read or null if timed out - * @throws TICCoreException - * if identifier not found or if any error occurs - */ - public TICCoreFrame readNextFrame(TICIdentifier identifier, int timeout) throws TICCoreException; - - /** - * Add a subscriber - * - * @param subscriber - */ - public void subscribe(TICCoreSubscriber subscriber); - - /** - * Remove a subscriber - * - * @param subscriber - */ - public void unsubscribe(TICCoreSubscriber subscriber); - - /** - * Add a subscriber with identifier - * - * @param identifier - * the identifier used for subscription - * @param listener - * the subscriber reference - * @throws Exception - * on subscription failure - */ - public void subscribe(TICIdentifier identifier, TICCoreSubscriber listener) throws TICCoreException; - - /** - * Remove a subscriber with identifier - * - * @param identifier - * the identifier used for subscription - * @param listener - * the subscriber reference - * @throws Exception - * if filter or listener not found - */ - public void unsubscribe(TICIdentifier identifier, TICCoreSubscriber listener) throws TICCoreException; - - /** - * Get TICs identifier associated with a subscriber - * - * @param listener - * the subscriber reference - * - * @return The collection of TIC identifiers for the subscriber - */ - public List getIndentifiers(TICCoreSubscriber listener); -} diff --git a/src/main/java/enedis/tic/core/TICCoreBase.java b/src/main/java/enedis/tic/core/TICCoreBase.java deleted file mode 100644 index 206c705..0000000 --- a/src/main/java/enedis/tic/core/TICCoreBase.java +++ /dev/null @@ -1,581 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.tic.core; - -import java.lang.reflect.Constructor; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.function.Predicate; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import enedis.lab.io.PlugSubscriber; -import enedis.lab.io.tic.TICPortDescriptor; -import enedis.lab.io.tic.TICPortFinder; -import enedis.lab.io.tic.TICPortFinderBase; -import enedis.lab.io.tic.TICPortPlugNotifier; -import enedis.lab.protocol.tic.TICMode; -import enedis.lab.types.DataArrayList; -import enedis.lab.types.DataDictionaryException; -import enedis.lab.util.time.Time; -import enedis.lab.util.task.FilteredNotifier; -import enedis.lab.util.task.FilteredNotifierBase; -import enedis.lab.util.task.Task; -import enedis.lab.util.task.TaskBase; - -/** - * TICCore implementation - */ -public class TICCoreBase implements TICCore, Task, TICCoreSubscriber, PlugSubscriber -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private static final int PLUG_NOTIFIER_POLLING_PERIOD = 100; - private static final int READ_NEXT_FRAME_TIMEOUT = 30000; - private static final int READ_NEXT_FRAME_POLLING_PERIOD = 100; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private TICPortFinder portFinder; - private TICPortPlugNotifier plugNotifier; - private long plugNotifierPeriod; - private Constructor streamConstructor; - private TICMode streamMode; - private List nativePortNamesOnStart; - private Collection streamList; - private FilteredNotifier eventNotifier; - private static Logger logger = LogManager.getLogger(); - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - public TICCoreBase() - { - this(TICMode.AUTO, null); - } - - public TICCoreBase(TICMode streamMode, List nativePortNamesStart) - { - this(TICPortFinderBase.getInstance(), PLUG_NOTIFIER_POLLING_PERIOD, TICCoreStreamBase.class, streamMode, nativePortNamesStart); - } - - public TICCoreBase(TICPortFinder ticPortFinder, long plugNotifierPeriod, Class streamClass, TICMode streamMode, List nativePortNamesOnStart) - { - super(); - this.portFinder = ticPortFinder; - this.plugNotifierPeriod = plugNotifierPeriod; - try - { - this.streamConstructor = streamClass.getConstructor(String.class, String.class, TICMode.class); - } - catch (NoSuchMethodException e) - { - throw new IllegalArgumentException("Class " + streamClass.getName() + " has no valid constructor : " + e.getMessage()); - } - if (streamMode == null) - { - throw new IllegalArgumentException("TICMode should be defined"); - } - this.streamMode = streamMode; - this.nativePortNamesOnStart = nativePortNamesOnStart; - this.streamList = Collections.synchronizedSet(new HashSet()); - this.eventNotifier = new FilteredNotifierBase(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// TICCore - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public List getAvailableTICs() - { - List identifiers = new DataArrayList(); - - for (TICCoreStream stream : this.streamList) - { - identifiers.add(stream.getIdentifier()); - } - - return identifiers; - } - - @Override - public List getModemsInfo() - { - List descriptors = new DataArrayList(); - - for (TICCoreStream stream : this.streamList) - { - TICPortDescriptor descriptor = this.portFinder.findByPortName(stream.getIdentifier().getPortName()); - descriptors.add(descriptor); - } - - return descriptors; - } - - @Override - public TICCoreFrame readNextFrame(TICIdentifier identifier) throws TICCoreException - { - return this.readNextFrame(identifier, READ_NEXT_FRAME_TIMEOUT); - } - - @Override - public TICCoreFrame readNextFrame(TICIdentifier identifier, int timeout) throws TICCoreException - { - TICCoreFrame frame = null; - TICPortDescriptor descriptor = null; - TICCoreStream stream = this.findStream(identifier); - - if (stream == null) - { - descriptor = this.portFinder.findNative(identifier.getPortName()); - if (descriptor == null) - { - TICCoreException exception = new TICCoreException(TICCoreErrorCode.STREAM_IDENTIFIER_NOT_FOUND.getCode(), "Stream " + identifier + " not found!"); - logger.error(exception.getMessage(), exception); - throw exception; - } - stream = this.startNewStream(descriptor); - } - ReadNextFrameSubscriber subscriber = new ReadNextFrameSubscriber(); - stream.subscribe(subscriber); - - long begin = System.nanoTime(); - long elapsed = 0; - while (elapsed < timeout) - { - if (subscriber.getError() != null) - { - TICCoreException exception = new TICCoreException(subscriber.getError().getErrorCode().intValue(), subscriber.getError().getErrorMessage()); - logger.error(exception.getMessage(), exception); - stream.unsubscribe(subscriber); - this.closeNativeStream(identifier, stream, subscriber); - throw exception; - } - if (subscriber.getData() != null) - { - frame = subscriber.getData(); - break; - } - Time.sleep(READ_NEXT_FRAME_POLLING_PERIOD); - elapsed = (System.nanoTime() - begin) / 1000000; - } - stream.unsubscribe(subscriber); - this.closeNativeStream(identifier, stream, subscriber); - if (elapsed >= timeout) - { - TICCoreException exception = new TICCoreException(TICCoreErrorCode.DATA_READ_TIMEOUT.getCode(), "Stream " + identifier + " data read timeout !"); - logger.error(exception.getMessage(), exception); - throw exception; - } - return frame; - } - - @Override - public void subscribe(TICIdentifier identifier, TICCoreSubscriber subscriber) throws TICCoreException - { - TICCoreStream stream = this.findStream(identifier); - - if (stream == null) - { - TICPortDescriptor descriptor = this.portFinder.findNative(identifier.getPortName()); - if (descriptor == null) - { - TICCoreException exception = new TICCoreException(TICCoreErrorCode.STREAM_IDENTIFIER_NOT_FOUND.getCode(), "Stream " + identifier + " not found!"); - logger.error(exception.getMessage(), exception); - throw exception; - } - this.startNewStream(descriptor); - } - try - { - this.eventNotifier.subscribe(identifier, subscriber); - } - catch (Exception e) - { - logger.error(e.getMessage(), e); - } - } - - @Override - public void unsubscribe(TICIdentifier identifier, TICCoreSubscriber subscriber) throws TICCoreException - { - TICPortDescriptor descriptor = this.portFinder.findNative(identifier.getPortName()); - if (descriptor != null) - { - if (this.nativePortNamesOnStart == null || !this.nativePortNamesOnStart.contains(identifier.getPortName())) - { - Collection subscribers = this.findSubscribers(identifier, false); - if (subscribers.contains(subscriber) && subscribers.size() == 1) - { - this.stopStream(descriptor); - } - } - } - try - { - this.eventNotifier.unsubscribe(identifier, subscriber); - } - catch (Exception e) - { - logger.error(e.getMessage(), e); - } - } - - @Override - public void subscribe(TICCoreSubscriber subscriber) - { - this.eventNotifier.subscribe(subscriber); - } - - @Override - public void unsubscribe(TICCoreSubscriber subscriber) - { - this.eventNotifier.unsubscribe(subscriber); - } - - @Override - public List getIndentifiers(TICCoreSubscriber listener) - { - List identifiers = new ArrayList(); - - if (this.eventNotifier.getSubscribers(true, false).contains(listener)) - { - identifiers.addAll(this.getAvailableTICs()); - } - else if (this.eventNotifier.getSubscribers(false, true).contains(listener)) - { - identifiers.addAll(this.eventNotifier.getFilters(listener)); - } - - return identifiers; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// TICCoreSubscriber - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public void onData(TICCoreFrame frame) - { - logger.trace("TICCore frame:\n" + frame.toString(2)); - Collection subscriberList = this.findSubscribers(frame.getIdentifier(), true); - Task task = new TaskBase() - { - @Override - public void process() - { - TICCoreBase.this.notifyOnData(frame, subscriberList); - } - }; - task.start(); - } - - @Override - public void onError(TICCoreError error) - { - logger.error("TICCore error:\n" + error.toString(2)); - Collection subscriberList = this.findSubscribers(error.getIdentifier(), true); - Task task = new TaskBase() - { - @Override - public void process() - { - TICCoreBase.this.notifyOnError(error, subscriberList); - } - }; - task.start(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// PortPlugSubscriber - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public void onPlugged(TICPortDescriptor descriptor) - { - logger.info("TICCore modem plugged:\n" + descriptor.toString(2)); - this.startNewStream(descriptor); - } - - @Override - public void onUnplugged(TICPortDescriptor descriptor) - { - logger.info("TICCore modem unplugged:\n" + descriptor.toString(2)); - TICIdentifier identifier = this.stopStream(descriptor); - Task task = new TaskBase() - { - @Override - public void process() - { - TICCoreBase.this.notifyOnUnpluggedAndUnsubscribe(identifier); - } - }; - task.start(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// Task - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public void start() - { - if (!this.isRunning()) - { - logger.info("Starting TICCore"); - logger.debug("Starting TIC port plug notifier"); - this.plugNotifier = new TICPortPlugNotifier(this.plugNotifierPeriod, this.portFinder); - this.plugNotifier.subscribe(this); - this.plugNotifier.start(); - logger.debug("TIC port plug notifier started"); - if (this.nativePortNamesOnStart != null && this.nativePortNamesOnStart.size() > 0) - { - logger.debug("Starting natives TIC port: " + Arrays.toString(this.nativePortNamesOnStart.toArray())); - for (String portName : this.nativePortNamesOnStart) - { - TICPortDescriptor descriptor = this.portFinder.findNative(portName); - logger.debug("Starting native TIC port " + portName + " : " + descriptor); - if (descriptor != null && this.findStream(descriptor) == null) - { - this.startNewStream(descriptor); - } - } - } - } - } - - @Override - public void stop() - { - logger.info("Stopping TICCore"); - logger.debug("Stopping TIC port plug notifier"); - this.plugNotifier.unsubscribe(this); - this.plugNotifier.stop(); - logger.debug("Stopping all streams"); - for (TICCoreStream stream : this.streamList) - { - stream.unsubscribe(this); - stream.stop(); - } - this.streamList.clear(); - logger.debug("Removing all subscribers"); - this.unsubscribe(this.eventNotifier.getSubscribers()); - } - - @Override - public boolean isRunning() - { - return (this.plugNotifier != null) ? this.plugNotifier.isRunning() : false; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private TICCoreStream findStream(TICIdentifier identifier) - { - for (TICCoreStream stream : this.streamList) - { - if (stream.getIdentifier().matches(identifier)) - { - return stream; - } - } - - return null; - } - - private TICCoreStream findStream(TICPortDescriptor descriptor) - { - for (TICCoreStream stream : this.streamList) - { - TICIdentifier identifier = stream.getIdentifier(); - if (descriptor.getPortId() != null && identifier.getPortId() != null) - { - if (descriptor.getPortId().equals(identifier.getPortId())) - { - return stream; - } - } - if (descriptor.getPortName() != null && identifier.getPortName() != null) - { - if (descriptor.getPortName().equals(identifier.getPortName())) - { - return stream; - } - } - } - - return null; - } - - private TICCoreStream startNewStream(TICPortDescriptor descriptor) - { - TICCoreStream stream = null; - logger.debug("TICCore starting new stream : " + descriptor.toString()); - try - { - stream = this.streamConstructor.newInstance(descriptor.getPortId(), descriptor.getPortName(), this.streamMode); - - stream.subscribe(this); - - stream.start(); - this.streamList.add(stream); - logger.debug("TICCore started new stream : " + descriptor.toString()); - } - catch (Exception e) - { - logger.error(e.getMessage(), e); - } - return stream; - } - - private TICIdentifier stopStream(TICPortDescriptor descriptor) - { - TICIdentifier identifier = null; - TICCoreStream stream = this.findStream(descriptor); - logger.debug("TICCore stopping new stream : " + descriptor.toString()); - if (stream != null) - { - identifier = stream.getIdentifier(); - stream.unsubscribe(this); - stream.stop(); - this.streamList.remove(stream); - logger.debug("TICCore stopped new stream : " + descriptor.toString()); - } - - return identifier; - } - - private void closeNativeStream(TICIdentifier identifier, TICCoreStream stream, ReadNextFrameSubscriber subscriber) - { - TICPortDescriptor nativeDescriptor = this.portFinder.findNative(identifier.getPortName()); - if (nativeDescriptor != null) - { - if (this.nativePortNamesOnStart == null || !this.nativePortNamesOnStart.contains(identifier.getPortName())) - { - Collection streamSubscribers = stream.getSubscribers(); - Collection ticCoreSubscribers = this.findSubscribers(identifier, false); - if (!streamSubscribers.contains(subscriber) && streamSubscribers.contains(this) && streamSubscribers.size() == 1 && ticCoreSubscribers.size() == 0) - { - this.stopStream(nativeDescriptor); - } - } - } - } - - private Collection findSubscribers(TICIdentifier sourceIdentifier, boolean globalSubscribers) - { - Predicate predicate = new Predicate() - { - @Override - public boolean test(TICIdentifier identifier) - { - return sourceIdentifier.matches(identifier); - } - }; - - return this.eventNotifier.getSubscribers(predicate, globalSubscribers); - } - - private void notifyOnUnpluggedAndUnsubscribe(TICIdentifier identifier) - { - try - { - TICCoreError error = new TICCoreError(identifier, TICCoreErrorCode.STREAM_UNPLUGGED.getCode(), - "TICCore stream " + identifier + " has been unplugged (unsubscribe has been forced)"); - Collection subscriberList = this.findSubscribers(identifier, true); - this.notifyOnError(error, subscriberList); - subscriberList = this.findSubscribers(identifier, false); - this.unsubscribe(subscriberList); - } - catch (DataDictionaryException e) - { - logger.error(e.getMessage(), e); - } - } - - private void notifyOnData(TICCoreFrame frame, Collection subscriberList) - { - for (TICCoreSubscriber subscriber : subscriberList) - { - subscriber.onData(frame); - } - } - - private void notifyOnError(TICCoreError error, Collection subscriberList) - { - for (TICCoreSubscriber subscriber : subscriberList) - { - subscriber.onError(error); - } - } - - private void unsubscribe(Collection subscriberList) - { - for (TICCoreSubscriber subscriber : subscriberList) - { - this.unsubscribe(subscriber); - } - } -} diff --git a/src/main/java/enedis/tic/core/TICCoreError.java b/src/main/java/enedis/tic/core/TICCoreError.java deleted file mode 100644 index 2e9ad38..0000000 --- a/src/main/java/enedis/tic/core/TICCoreError.java +++ /dev/null @@ -1,288 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.tic.core; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import enedis.lab.types.DataDictionary; -import enedis.lab.types.DataDictionaryException; -import enedis.lab.types.datadictionary.DataDictionaryBase; -import enedis.lab.types.datadictionary.KeyDescriptor; -import enedis.lab.types.datadictionary.KeyDescriptorDataDictionary; -import enedis.lab.types.datadictionary.KeyDescriptorNumber; -import enedis.lab.types.datadictionary.KeyDescriptorString; - -/** - * TICCoreError class - * - * Generated - */ -public class TICCoreError extends DataDictionaryBase -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected static final String KEY_IDENTIFIER = "identifier"; - protected static final String KEY_ERROR_CODE = "errorCode"; - protected static final String KEY_ERROR_MESSAGE = "errorMessage"; - protected static final String KEY_DATA = "data"; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private List> keys = new ArrayList>(); - - protected KeyDescriptorDataDictionary kIdentifier; - protected KeyDescriptorNumber kErrorCode; - protected KeyDescriptorString kErrorMessage; - protected KeyDescriptorDataDictionary kData; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected TICCoreError() - { - super(); - this.loadKeyDescriptors(); - - } - - /** - * Constructor using map - * - * @param map - * @throws DataDictionaryException - */ - public TICCoreError(Map map) throws DataDictionaryException - { - this(); - this.copy(fromMap(map)); - } - - /** - * Constructor using datadictionary - * - * @param other - * @throws DataDictionaryException - */ - public TICCoreError(DataDictionary other) throws DataDictionaryException - { - this(); - this.copy(other); - } - - /** - * Constructor setting parameters to specific values - * - * @param identifier - * @param errorCode - * @param errorMessage - * @throws DataDictionaryException - */ - public TICCoreError(TICIdentifier identifier, Number errorCode, String errorMessage) throws DataDictionaryException - { - this(identifier, errorCode, errorMessage, null); - } - - /** - * Constructor setting parameters to specific values - * - * @param identifier - * @param errorCode - * @param errorMessage - * @param data - * @throws DataDictionaryException - */ - public TICCoreError(TICIdentifier identifier, Number errorCode, String errorMessage, DataDictionary data) throws DataDictionaryException - { - this(); - - this.setIdentifier(identifier); - this.setErrorCode(errorCode); - this.setErrorMessage(errorMessage); - this.setData(data); - - this.checkAndUpdate(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// DataDictionaryBase - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Get identifier - * - * @return the identifier - */ - public TICIdentifier getIdentifier() - { - return (TICIdentifier) this.data.get(KEY_IDENTIFIER); - } - - /** - * Get error code - * - * @return the error code - */ - public Number getErrorCode() - { - return (Number) this.data.get(KEY_ERROR_CODE); - } - - /** - * Get error message - * - * @return the error message - */ - public String getErrorMessage() - { - return (String) this.data.get(KEY_ERROR_MESSAGE); - } - - /** - * Get data - * - * @return the data - */ - public DataDictionaryBase getData() - { - return (DataDictionaryBase) this.data.get(KEY_DATA); - } - - /** - * Set identifier - * - * @param identifier - * @throws DataDictionaryException - */ - public void setIdentifier(TICIdentifier identifier) throws DataDictionaryException - { - this.setIdentifier((Object) identifier); - } - - /** - * Set error code - * - * @param errorCode - * @throws DataDictionaryException - */ - public void setErrorCode(Number errorCode) throws DataDictionaryException - { - this.setErrorCode((Object) errorCode); - } - - /** - * Set error message - * - * @param errorMessage - * @throws DataDictionaryException - */ - public void setErrorMessage(String errorMessage) throws DataDictionaryException - { - this.setErrorMessage((Object) errorMessage); - } - - /** - * Set data - * - * @param data - * @throws DataDictionaryException - */ - public void setData(DataDictionary data) throws DataDictionaryException - { - this.setData((Object) data); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected void setIdentifier(Object identifier) throws DataDictionaryException - { - this.data.put(KEY_IDENTIFIER, this.kIdentifier.convert(identifier)); - } - - protected void setErrorCode(Object errorCode) throws DataDictionaryException - { - this.data.put(KEY_ERROR_CODE, this.kErrorCode.convert(errorCode)); - } - - protected void setErrorMessage(Object errorMessage) throws DataDictionaryException - { - this.data.put(KEY_ERROR_MESSAGE, this.kErrorMessage.convert(errorMessage)); - } - - protected void setData(Object data) throws DataDictionaryException - { - this.data.put(KEY_DATA, this.kData.convert(data)); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private void loadKeyDescriptors() - { - try - { - this.kIdentifier = new KeyDescriptorDataDictionary(KEY_IDENTIFIER, true, TICIdentifier.class); - this.keys.add(this.kIdentifier); - - this.kErrorCode = new KeyDescriptorNumber(KEY_ERROR_CODE, true); - this.keys.add(this.kErrorCode); - - this.kErrorMessage = new KeyDescriptorString(KEY_ERROR_MESSAGE, true, false); - this.keys.add(this.kErrorMessage); - - this.kData = new KeyDescriptorDataDictionary(KEY_DATA, false, DataDictionaryBase.class); - this.keys.add(this.kData); - - this.addAllKeyDescriptor(this.keys); - } - catch (DataDictionaryException e) - { - throw new RuntimeException(e.getMessage(), e); - } - } -} diff --git a/src/main/java/enedis/tic/core/TICCoreErrorCode.java b/src/main/java/enedis/tic/core/TICCoreErrorCode.java deleted file mode 100644 index 548a78f..0000000 --- a/src/main/java/enedis/tic/core/TICCoreErrorCode.java +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.tic.core; - -public enum TICCoreErrorCode -{ - NO_ERROR(0), - STREAM_PORT_ID_NOT_FOUND(1), - STREAM_PORT_NAME_NOT_FOUND(2), - STREAM_PORT_DESCRIPTOR_EMPTY(3), - STREAM_MODE_NOT_DEFINED(4), - STREAM_IDENTIFIER_NOT_FOUND(5), - STREAM_UNPLUGGED(6), - DATA_READ_TIMEOUT(7), - OTHER_REASON(99); - - private int code; - - private TICCoreErrorCode(int code) - { - this.code = code; - } - - public int getCode() - { - return this.code; - } -} diff --git a/src/main/java/enedis/tic/core/TICCoreException.java b/src/main/java/enedis/tic/core/TICCoreException.java deleted file mode 100644 index aa0fa67..0000000 --- a/src/main/java/enedis/tic/core/TICCoreException.java +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.tic.core; - -import enedis.lab.types.ExceptionBase; - -public class TICCoreException extends ExceptionBase -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private static final long serialVersionUID = -3285641164559292710L; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - public TICCoreException(int code, String info) - { - super(code, info); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// interfaceName - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -} diff --git a/src/main/java/enedis/tic/core/TICCoreFrame.java b/src/main/java/enedis/tic/core/TICCoreFrame.java deleted file mode 100644 index eb6c7f2..0000000 --- a/src/main/java/enedis/tic/core/TICCoreFrame.java +++ /dev/null @@ -1,283 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.tic.core; - -import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import enedis.lab.protocol.tic.TICMode; -import enedis.lab.types.DataDictionary; -import enedis.lab.types.DataDictionaryException; -import enedis.lab.types.datadictionary.DataDictionaryBase; -import enedis.lab.types.datadictionary.KeyDescriptor; -import enedis.lab.types.datadictionary.KeyDescriptorDataDictionary; -import enedis.lab.types.datadictionary.KeyDescriptorEnum; -import enedis.lab.types.datadictionary.KeyDescriptorLocalDateTime; - -/** - * TICCoreFrame class - * - * Generated - */ -public class TICCoreFrame extends DataDictionaryBase -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected static final String KEY_IDENTIFIER = "identifier"; - protected static final String KEY_MODE = "mode"; - protected static final String KEY_CAPTURE_DATE_TIME = "captureDateTime"; - protected static final String KEY_CONTENT = "content"; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private List> keys = new ArrayList>(); - - protected KeyDescriptorDataDictionary kIdentifier; - protected KeyDescriptorEnum kMode; - protected KeyDescriptorLocalDateTime kCaptureDateTime; - protected KeyDescriptorDataDictionary kContent; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected TICCoreFrame() - { - super(); - this.loadKeyDescriptors(); - - } - - /** - * Constructor using map - * - * @param map - * @throws DataDictionaryException - */ - public TICCoreFrame(Map map) throws DataDictionaryException - { - this(); - this.copy(fromMap(map)); - } - - /** - * Constructor using datadictionary - * - * @param other - * @throws DataDictionaryException - */ - public TICCoreFrame(DataDictionary other) throws DataDictionaryException - { - this(); - this.copy(other); - } - - /** - * Constructor setting parameters to specific values - * - * @param identifier - * @param mode - * @param captureDateTime - * @param content - * @throws DataDictionaryException - */ - public TICCoreFrame(TICIdentifier identifier, TICMode mode, LocalDateTime captureDateTime, DataDictionaryBase content) throws DataDictionaryException - { - this(); - - this.setIdentifier(identifier); - this.setMode(mode); - this.setCaptureDateTime(captureDateTime); - this.setContent(content); - - this.checkAndUpdate(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// DataDictionaryBase - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - protected void updateOptionalParameters() throws DataDictionaryException - { - super.updateOptionalParameters(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Get identifier - * - * @return the identifier - */ - public TICIdentifier getIdentifier() - { - return (TICIdentifier) this.data.get(KEY_IDENTIFIER); - } - - /** - * Get mode - * - * @return the mode - */ - public TICMode getMode() - { - return (TICMode) this.data.get(KEY_MODE); - } - - /** - * Get capture date time - * - * @return the capture date time - */ - public LocalDateTime getCaptureDateTime() - { - return (LocalDateTime) this.data.get(KEY_CAPTURE_DATE_TIME); - } - - /** - * Get content - * - * @return the content - */ - public DataDictionaryBase getContent() - { - return (DataDictionaryBase) this.data.get(KEY_CONTENT); - } - - /** - * Set identifier - * - * @param identifier - * @throws DataDictionaryException - */ - public void setIdentifier(TICIdentifier identifier) throws DataDictionaryException - { - this.setIdentifier((Object) identifier); - } - - /** - * Set mode - * - * @param mode - * @throws DataDictionaryException - */ - public void setMode(TICMode mode) throws DataDictionaryException - { - this.setMode((Object) mode); - } - - /** - * Set capture date time - * - * @param captureDateTime - * @throws DataDictionaryException - */ - public void setCaptureDateTime(LocalDateTime captureDateTime) throws DataDictionaryException - { - this.setCaptureDateTime((Object) captureDateTime); - } - - /** - * Set content - * - * @param content - * @throws DataDictionaryException - */ - public void setContent(DataDictionaryBase content) throws DataDictionaryException - { - this.setContent((Object) content); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected void setIdentifier(Object identifier) throws DataDictionaryException - { - this.data.put(KEY_IDENTIFIER, this.kIdentifier.convert(identifier)); - } - - protected void setMode(Object mode) throws DataDictionaryException - { - this.data.put(KEY_MODE, this.kMode.convert(mode)); - } - - protected void setCaptureDateTime(Object captureDateTime) throws DataDictionaryException - { - this.data.put(KEY_CAPTURE_DATE_TIME, this.kCaptureDateTime.convert(captureDateTime)); - } - - protected void setContent(Object content) throws DataDictionaryException - { - this.data.put(KEY_CONTENT, this.kContent.convert(content)); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private void loadKeyDescriptors() - { - try - { - this.kIdentifier = new KeyDescriptorDataDictionary(KEY_IDENTIFIER, true, TICIdentifier.class); - this.keys.add(this.kIdentifier); - - this.kMode = new KeyDescriptorEnum(KEY_MODE, true, TICMode.class); - this.keys.add(this.kMode); - - this.kCaptureDateTime = new KeyDescriptorLocalDateTime(KEY_CAPTURE_DATE_TIME, true); - this.keys.add(this.kCaptureDateTime); - - this.kContent = new KeyDescriptorDataDictionary(KEY_CONTENT, true, DataDictionaryBase.class); - this.keys.add(this.kContent); - - this.addAllKeyDescriptor(this.keys); - } - catch (DataDictionaryException e) - { - throw new RuntimeException(e.getMessage(), e); - } - } -} diff --git a/src/main/java/enedis/tic/core/TICCoreStream.java b/src/main/java/enedis/tic/core/TICCoreStream.java deleted file mode 100644 index 8a72a48..0000000 --- a/src/main/java/enedis/tic/core/TICCoreStream.java +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.tic.core; - -import enedis.lab.util.task.Notifier; -import enedis.lab.util.task.Task; - -/** - * TICCore stream interface - */ -public interface TICCoreStream extends Notifier, Task -{ - /** - * Get identifier - * - * @return The TICIdentifier associated with the stream - */ - public TICIdentifier getIdentifier(); -} diff --git a/src/main/java/enedis/tic/core/TICCoreStreamBase.java b/src/main/java/enedis/tic/core/TICCoreStreamBase.java deleted file mode 100644 index 21ff386..0000000 --- a/src/main/java/enedis/tic/core/TICCoreStreamBase.java +++ /dev/null @@ -1,378 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.tic.core; - -import java.time.LocalDateTime; -import java.util.Collection; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import enedis.lab.io.channels.Channel; -import enedis.lab.io.channels.ChannelException; -import enedis.lab.io.datastreams.DataStreamBase; -import enedis.lab.io.datastreams.DataStreamDirection; -import enedis.lab.io.datastreams.DataStreamException; -import enedis.lab.io.datastreams.DataStreamListener; -import enedis.lab.io.datastreams.DataStreamStatus; -import enedis.lab.io.tic.TICPortDescriptor; -import enedis.lab.io.tic.TICPortFinderBase; -import enedis.lab.protocol.tic.TICMode; -import enedis.lab.protocol.tic.channels.ChannelTICSerialPort; -import enedis.lab.protocol.tic.channels.ChannelTICSerialPortConfiguration; -import enedis.lab.protocol.tic.datastreams.TICInputStream; -import enedis.lab.protocol.tic.datastreams.TICStreamConfiguration; -import enedis.lab.protocol.tic.frame.TICFrame; -import enedis.lab.protocol.tic.frame.TICFrameDataSet; -import enedis.lab.protocol.tic.frame.historic.TICFrameHistoric; -import enedis.lab.protocol.tic.frame.standard.TICFrameStandard; -import enedis.lab.types.DataDictionary; -import enedis.lab.types.DataDictionaryException; -import enedis.lab.types.datadictionary.DataDictionaryBase; -import enedis.lab.util.task.Notifier; -import enedis.lab.util.task.NotifierBase; -import enedis.lab.util.task.Task; - -/** - * TICCore stream implementation - */ -public class TICCoreStreamBase implements TICCoreStream, Task, DataStreamListener -{ - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private TICIdentifier identifier; - private DataStreamBase stream; - private Channel channel; - private Notifier notifier; - static private Logger logger = LogManager.getLogger(); - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - public TICCoreStreamBase(String portId, String portName, TICMode ticMode) throws TICCoreException - { - TICPortDescriptor descriptor = null; - - if (portId != null) - { - descriptor = TICPortFinderBase.getInstance().findByPortId(portId); - if (descriptor == null) - { - TICCoreException exception = new TICCoreException(TICCoreErrorCode.STREAM_PORT_ID_NOT_FOUND.getCode(), "TICCore stream port id " + portId + " not found!"); - logger.error(exception.getMessage(), exception); - throw exception; - } - } - else if (portName != null) - { - descriptor = TICPortFinderBase.getInstance().findByPortName(portName); - if (descriptor == null) - { - descriptor = TICPortFinderBase.getInstance().findNative(portName); - if (descriptor == null) - { - TICCoreException exception = new TICCoreException(TICCoreErrorCode.STREAM_PORT_NAME_NOT_FOUND.getCode(), - "TICCore stream port name " + portName + " not found!"); - logger.error(exception.getMessage(), exception); - throw exception; - } - } - } - else - { - TICCoreException exception = new TICCoreException(TICCoreErrorCode.STREAM_PORT_DESCRIPTOR_EMPTY.getCode(), "TICCore stream port descriptor empty!"); - logger.error(exception.getMessage(), exception); - throw exception; - } - if (ticMode == null) - { - TICCoreException exception = new TICCoreException(TICCoreErrorCode.STREAM_MODE_NOT_DEFINED.getCode(), "TICCore stream mode not defined!"); - logger.error(exception.getMessage(), exception); - throw exception; - } - try - { - this.identifier = new TICIdentifier(portId, portName, null); - this.channel = new ChannelTICSerialPort(new ChannelTICSerialPortConfiguration("Channel@" + descriptor.getPortName(), portName, ticMode)); - this.stream = new TICInputStream( - new TICStreamConfiguration("Stream@" + descriptor.getPortName(), DataStreamDirection.INPUT, "Channel@" + descriptor.getPortName(), ticMode)); - this.stream.setChannel(this.channel); - this.notifier = new NotifierBase(); - logger = LogManager.getLogger(); - } - catch (DataDictionaryException | ChannelException | DataStreamException e) - { - TICCoreException exception = new TICCoreException(TICCoreErrorCode.OTHER_REASON.getCode(), "TICCore stream instanciation failed : " + e.getMessage()); - logger.error(exception.getMessage(), exception); - throw exception; - } - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// TICCoreStream - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public TICIdentifier getIdentifier() - { - TICIdentifier identifier; - - synchronized (this.identifier) - { - identifier = (TICIdentifier) this.identifier.clone(); - } - - return identifier; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// Notifier - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public Collection getSubscribers() - { - return this.notifier.getSubscribers(); - } - - @Override - public boolean hasSubscriber(TICCoreSubscriber subscriber) - { - return this.notifier.hasSubscriber(subscriber); - } - - @Override - public void subscribe(TICCoreSubscriber subscriber) - { - this.notifier.subscribe(subscriber); - } - - @Override - public void unsubscribe(TICCoreSubscriber subscriber) - { - this.notifier.unsubscribe(subscriber); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// DataStreamListener - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public void onDataReceived(String dataStreamName, DataDictionary data) - { - TICCoreFrame frame = this.createFrame(data); - - if (frame != null) - { - this.notifyOnData(frame); - } - else - { - logger.debug("Frame creation skipped due to null TICFrame"); - } - } - - @Override - public void onDataSent(String dataStreamName, DataDictionary data) - { - } - - @Override - public void onStatusChanged(String dataStreamName, DataStreamStatus newStatus) - { - } - - @Override - public void onErrorDetected(String dataStreamName, int errorCode, String errorMessage, DataDictionary data) - { - TICCoreError error = this.createError(errorCode, errorMessage, data); - this.notifyOnError(error); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// Task - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public void start() - { - this.channel.start(); - try - { - this.stream.open(); - this.stream.subscribe(this); - } - catch (DataStreamException e) - { - logger.error(e.getMessage()); - } - } - - @Override - public void stop() - { - this.stream.unsubscribe(this); - try - { - this.stream.close(); - } - catch (DataStreamException e) - { - logger.error(e.getMessage()); - } - this.channel.stop(); - } - - @Override - public boolean isRunning() - { - return this.channel.isRunning(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private TICCoreFrame createFrame(DataDictionary data) - { - TICCoreFrame frame = new TICCoreFrame(); - try - { - frame.setCaptureDateTime(LocalDateTime.now()); - TICFrame ticFrame = (TICFrame) data.get(TICInputStream.KEY_DATA); - - if (ticFrame == null) - { - logger.warn("TICFrame is null. Skipping frame creation."); - return null; - } - - DataDictionaryBase content = new DataDictionaryBase(); - for (TICFrameDataSet frameDataSet : ticFrame.getDataSetList()) - { - String label = frameDataSet.getLabel(); - content.set(label, ticFrame.getData(label)); - } - frame.setContent(content); - String serialNumber = null; - if (ticFrame instanceof TICFrameStandard) - { - frame.setMode(TICMode.STANDARD); - serialNumber = (String) content.get("ADSC"); - } - else if (ticFrame instanceof TICFrameHistoric) - { - frame.setMode(TICMode.HISTORIC); - serialNumber = (String) content.get("ADCO"); - } - synchronized (this.identifier) - { - this.identifier.setSerialNumber(serialNumber); - frame.setIdentifier(this.identifier.clone()); - } - } - catch (DataDictionaryException e) - { - logger.error(e.getMessage()); - frame = null; - } - - return frame; - } - - private TICCoreError createError(int errorCode, String errorMessage, DataDictionary data) - { - TICCoreError error = null; - try - { - error = new TICCoreError(this.getIdentifier(), errorCode, errorMessage, data); - } - catch (DataDictionaryException e) - { - logger.error(e.getMessage()); - } - - return error; - } - - private void notifyOnData(TICCoreFrame frame) - { - if (frame == null) - { - return; - } - for (TICCoreSubscriber subscriber : this.notifier.getSubscribers()) - { - subscriber.onData(frame); - } - } - - private void notifyOnError(TICCoreError error) - { - if (error == null) - { - return; - } - for (TICCoreSubscriber subscriber : this.notifier.getSubscribers()) - { - subscriber.onError(error); - } - } -} diff --git a/src/main/java/enedis/tic/core/TICCoreSubscriber.java b/src/main/java/enedis/tic/core/TICCoreSubscriber.java deleted file mode 100644 index 4adc14e..0000000 --- a/src/main/java/enedis/tic/core/TICCoreSubscriber.java +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.tic.core; - -import enedis.lab.util.task.Subscriber; - -/** - * TICCore subscriber interface - */ -public interface TICCoreSubscriber extends Subscriber -{ - /** - * Notify when data - * - * @param frame - * the frame received - */ - public void onData(TICCoreFrame frame); - - /** - * Notify when error - * - * @param error - * the error detected - */ - public void onError(TICCoreError error); -} diff --git a/src/main/java/enedis/tic/core/TICIdentifier.java b/src/main/java/enedis/tic/core/TICIdentifier.java deleted file mode 100644 index 7f83c81..0000000 --- a/src/main/java/enedis/tic/core/TICIdentifier.java +++ /dev/null @@ -1,282 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.tic.core; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import enedis.lab.types.DataDictionary; -import enedis.lab.types.DataDictionaryException; -import enedis.lab.types.datadictionary.DataDictionaryBase; -import enedis.lab.types.datadictionary.KeyDescriptor; -import enedis.lab.types.datadictionary.KeyDescriptorString; - -/** - * TICIdentifier class - * - * Generated - */ -public class TICIdentifier extends DataDictionaryBase -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected static final String KEY_PORT_ID = "portId"; - protected static final String KEY_PORT_NAME = "portName"; - protected static final String KEY_SERIAL_NUMBER = "serialNumber"; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private List> keys = new ArrayList>(); - - protected KeyDescriptorString kPortId; - protected KeyDescriptorString kPortName; - protected KeyDescriptorString kSerialNumber; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected TICIdentifier() - { - super(); - this.loadKeyDescriptors(); - - } - - /** - * Constructor using map - * - * @param map - * @throws DataDictionaryException - */ - public TICIdentifier(Map map) throws DataDictionaryException - { - this(); - this.copy(fromMap(map)); - } - - /** - * Constructor using datadictionary - * - * @param other - * @throws DataDictionaryException - */ - public TICIdentifier(DataDictionary other) throws DataDictionaryException - { - this(); - this.copy(other); - } - - /** - * Constructor setting parameters to specific values - * - * @param portId - * @param portName - * @param serialNumber - * @throws DataDictionaryException - */ - public TICIdentifier(String portId, String portName, String serialNumber) throws DataDictionaryException - { - this(); - - this.setPortId((Object) portId); - this.setPortName((Object) portName); - this.setSerialNumber((Object) serialNumber); - - this.checkAndUpdate(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// DataDictionaryBase - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - protected void updateOptionalParameters() throws DataDictionaryException - { - if (this.getPortId() == null && this.getPortName() == null && this.getSerialNumber() == null) - { - throw new DataDictionaryException("Empty TICIdentifier not allowed!"); - } - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - public boolean matches(TICIdentifier identifier) - { - if (identifier != null) - { - if (this.getSerialNumber() != null && identifier.getSerialNumber() != null) - { - return this.getSerialNumber().equals(identifier.getSerialNumber()); - } - if (this.getPortId() != null && identifier.getPortId() != null) - { - return this.getPortId().equals(identifier.getPortId()); - } - if (this.getPortName() != null && identifier.getPortName() != null) - { - return this.getPortName().equals(identifier.getPortName()); - } - } - - return false; - } - - /** - * Get port id - * - * @return the port id - */ - public String getPortId() - { - return (String) this.data.get(KEY_PORT_ID); - } - - /** - * Get port name - * - * @return the port name - */ - public String getPortName() - { - return (String) this.data.get(KEY_PORT_NAME); - } - - /** - * Get serial number - * - * @return the serial number - */ - public String getSerialNumber() - { - return (String) this.data.get(KEY_SERIAL_NUMBER); - } - - /** - * Set port id - * - * @param portId - * @throws DataDictionaryException - */ - public void setPortId(String portId) throws DataDictionaryException - { - if (portId == null && this.getPortName() == null && this.getSerialNumber() == null) - { - throw new DataDictionaryException("Cannot set null portId because empty TICIdentifier not allowed!"); - } - this.setPortId((Object) portId); - } - - /** - * Set port name - * - * @param portName - * @throws DataDictionaryException - */ - public void setPortName(String portName) throws DataDictionaryException - { - if (this.getPortId() == null && portName == null && this.getSerialNumber() == null) - { - throw new DataDictionaryException("Cannot set null portName because empty TICIdentifier not allowed!"); - } - this.setPortName((Object) portName); - } - - /** - * Set serial number - * - * @param serialNumber - * @throws DataDictionaryException - */ - public void setSerialNumber(String serialNumber) throws DataDictionaryException - { - if (this.getPortId() == null && this.getPortName() == null && serialNumber == null) - { - throw new DataDictionaryException("Cannot set null serialNumber because empty TICIdentifier not allowed!"); - } - this.setSerialNumber((Object) serialNumber); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected void setPortId(Object portId) throws DataDictionaryException - { - this.data.put(KEY_PORT_ID, this.kPortId.convert(portId)); - } - - protected void setPortName(Object portName) throws DataDictionaryException - { - this.data.put(KEY_PORT_NAME, this.kPortName.convert(portName)); - } - - protected void setSerialNumber(Object serialNumber) throws DataDictionaryException - { - this.data.put(KEY_SERIAL_NUMBER, this.kSerialNumber.convert(serialNumber)); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private void loadKeyDescriptors() - { - try - { - this.kPortId = new KeyDescriptorString(KEY_PORT_ID, false, false); - this.keys.add(this.kPortId); - - this.kPortName = new KeyDescriptorString(KEY_PORT_NAME, false, false); - this.keys.add(this.kPortName); - - this.kSerialNumber = new KeyDescriptorString(KEY_SERIAL_NUMBER, false, false); - this.keys.add(this.kSerialNumber); - - this.addAllKeyDescriptor(this.keys); - } - catch (DataDictionaryException e) - { - throw new RuntimeException(e.getMessage(), e); - } - } -} diff --git a/src/main/java/enedis/tic/service/TIC2WebSocketApplication.java b/src/main/java/enedis/tic/service/TIC2WebSocketApplication.java deleted file mode 100644 index 82dcd19..0000000 --- a/src/main/java/enedis/tic/service/TIC2WebSocketApplication.java +++ /dev/null @@ -1,424 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.tic.service; - -import java.io.File; -import java.io.InputStream; -import java.util.Properties; - -import org.apache.logging.log4j.Level; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.apache.logging.log4j.core.LoggerContext; - -import enedis.lab.types.datadictionary.DataDictionaryBase; -import enedis.tic.core.TICCore; -import enedis.tic.core.TICCoreBase; -import enedis.tic.service.client.TIC2WebSocketClientPool; -import enedis.tic.service.client.TIC2WebSocketClientPoolBase; -import enedis.tic.service.config.TIC2WebSocketConfiguration; -import enedis.tic.service.netty.TIC2WebSocketServer; -import enedis.tic.service.requesthandler.TIC2WebSocketRequestHandler; -import enedis.tic.service.requesthandler.TIC2WebSocketRequestHandlerBase; -import picocli.CommandLine; -import picocli.CommandLine.IVersionProvider; -import picocli.CommandLine.ParseResult; - -/** - * Class used to handle the application - */ -public class TIC2WebSocketApplication -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Project properties (see file project.properties) - */ - public static final Properties PROJECT_PROPERTIES = new Properties(); - - static - { - try - { - InputStream stream = TIC2WebSocketApplication.class.getClassLoader().getResourceAsStream("TIC2WebSocket.properties"); - - if (stream == null) - { - System.err.println("Can't find projet property file!"); - } - else - { - TIC2WebSocketApplication.PROJECT_PROPERTIES.load(stream); - } - } - catch (Exception exception) - { - System.err.println("Can't load projet property file!"); - exception.printStackTrace(System.err); - } - } - - /** - * Project name ("project_name" from project.properties) - */ - public static final String NAME = PROJECT_PROPERTIES.getProperty("project_name", ""); - - /** - * Project version ("project_version" from project.properties) - */ - public static final String VERSION = PROJECT_PROPERTIES.getProperty("project_version", ""); - - /** - * Project description ("project_description" from project.properties) - */ - public static final String DESCRIPTION = PROJECT_PROPERTIES.getProperty("project_description", ""); - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Program entry point - * - * @param args - * Command line arguments - */ - public static void main(String[] args) - { - try - { - TIC2WebSocketApplication application = new TIC2WebSocketApplication(args); - int result = application.run(); - System.exit(result); - } - catch (Exception exception) - { - exception.printStackTrace(System.err); - System.exit(-1); - } - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private String[] commandLineArgs; - private CommandLine commandLineParser; - private TIC2WebSocketCommandLine commandLine; - private Logger logger; - private boolean started; - private TIC2WebSocketConfiguration configuration; - - private TIC2WebSocketClientPool clientPool; - private TIC2WebSocketServer server; - private TIC2WebSocketRequestHandler requestHandler; - private TICCore ticCore; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// interfaceName - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Application constructor - * - * @param args - * Command line arguments - */ - public TIC2WebSocketApplication(String[] args) - { - this.commandLineArgs = args; - this.commandLine = new TIC2WebSocketCommandLine(); - this.commandLineParser = new CommandLine(this.commandLine); - this.commandLineParser.setCommandName(TIC2WebSocketApplication.NAME); - this.commandLineParser.getCommandSpec().versionProvider(new IVersionProvider() - { - @Override - public String[] getVersion() throws Exception - { - return new String[] { TIC2WebSocketApplication.NAME + " v" + TIC2WebSocketApplication.VERSION }; - } - }); - this.commandLineParser.registerConverter(Level.class, new TIC2WebSocketCommandLine.VerboseLevelConverter()); - this.updateLoggerConfiguration(Level.ERROR); - this.started = false; - } - - /** - * Application execution - * - * @return 0 if success, else an error code - * @throws InterruptedException - * If the application thread gets interrupted - * @see TIC2WebSocketApplicationErrorCode - */ - public int run() throws InterruptedException - { - int result = this.init(); - - if (result != TIC2WebSocketApplicationErrorCode.NO_ERROR.code()) - { - return result; - } - result = this.start(); - if (result != TIC2WebSocketApplicationErrorCode.NO_ERROR.code()) - { - return result; - } - - Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() - { - @Override - public void run() - { - TIC2WebSocketApplication.this.stop(); - } - })); - - while (this.isStarted()) - { - Thread.sleep(1000); - } - - return TIC2WebSocketApplicationErrorCode.NO_ERROR.code(); - } - - /** - * Application initialization - * - * @return 0 if success, else an error code - * @see TIC2WebSocketApplicationErrorCode - */ - public int init() - { - if (this.isStarted()) - { - this.logger.error("Application already started!"); - return TIC2WebSocketApplicationErrorCode.APPLICATION_ALREADY_STARTED.code(); - } - int result = this.parseCommandLine(); - if (result != TIC2WebSocketApplicationErrorCode.NO_ERROR.code()) - { - return result; - } - result = this.updateLoggerConfiguration(this.commandLine.verboseLevel); - if (result != TIC2WebSocketApplicationErrorCode.NO_ERROR.code()) - { - return result; - } - - result = this.loadConfiguration(); - if (result != TIC2WebSocketApplicationErrorCode.NO_ERROR.code()) - { - return result; - } - - this.logger.info(TIC2WebSocketApplication.NAME + " initialized"); - - this.ticCore = new TICCoreBase(this.configuration.getTicMode(), this.configuration.getTicPortNames()); - this.clientPool = new TIC2WebSocketClientPoolBase(); - this.requestHandler = new TIC2WebSocketRequestHandlerBase(this.ticCore); - - this.server = new TIC2WebSocketServer("localhost", this.configuration.getServerPort().intValue(), - this.clientPool, this.requestHandler); - - return TIC2WebSocketApplicationErrorCode.NO_ERROR.code(); - } - - /** - * Application start-up - * - * @return 0 if success, else an error code - */ - public int start() - { - if (this.commandLineParser.isUsageHelpRequested()) - { - this.commandLineParser.usage(System.out); - } - if (this.commandLineParser.isVersionHelpRequested()) - { - this.commandLineParser.printVersionHelp(System.out); - } - this.logger.info(TIC2WebSocketApplication.NAME + " starting"); - - try - { - this.ticCore.start(); - this.server.start(); - } - catch (Exception exception) - { - this.logger.error(exception.getMessage(), exception); - return TIC2WebSocketApplicationErrorCode.LOAD_CONFIGURATION_FAILURE.code(); - } - - this.logger.info(TIC2WebSocketApplication.NAME + " started"); - this.started = true; - - return TIC2WebSocketApplicationErrorCode.NO_ERROR.code(); - } - - /** - * Application start-up indicator - * - * @return true if the application is started, false otherwise - */ - public boolean isStarted() - { - return this.started; - } - - /** - * Application stop - * - * @return 0 if success, else an error code - * @see TIC2WebSocketApplicationErrorCode - */ - public int stop() - { - if (!this.isStarted()) - { - this.logger.error("Application not started!"); - return TIC2WebSocketApplicationErrorCode.APPLICATION_NOT_STARTED.code(); - } - - try - { - this.server.stop(); - this.ticCore.stop(); - } - catch (Exception exception) - { - this.logger.error(exception.getMessage(), exception); - return TIC2WebSocketApplicationErrorCode.LOAD_CONFIGURATION_FAILURE.code(); - } - - this.logger.info(TIC2WebSocketApplication.NAME + " stopped"); - this.started = false; - - return TIC2WebSocketApplicationErrorCode.NO_ERROR.code(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private int parseCommandLine() - { - try - { - ParseResult parseResult = this.commandLineParser.parseArgs(this.commandLineArgs); - if (parseResult.errors().size() > 0) - { - this.logger.error("Invalid command line!"); - for (int i = 0; i < parseResult.errors().size(); i++) - { - this.logger.error(parseResult.errors().get(i).getMessage()); - } - return TIC2WebSocketApplicationErrorCode.COMMAND_LINE_INVALID.code(); - } - } - catch (Exception exception) - { - this.logger.error("Invalid command line!"); - this.logger.error(exception.getMessage()); - return TIC2WebSocketApplicationErrorCode.COMMAND_LINE_INVALID.code(); - } - - return TIC2WebSocketApplicationErrorCode.NO_ERROR.code(); - } - - private int updateLoggerConfiguration(Level level) - { - try - { - System.setProperty("log4j.configurationFile", "log4j2-" + level.name().toLowerCase() + ".xml"); - LoggerContext context = (LoggerContext) LogManager.getContext(false); - context.reconfigure(); - this.logger = LogManager.getLogger(); - } - catch (Exception exception) - { - System.err.println("Log configuration update failure!"); - System.err.println(exception.getMessage()); - return TIC2WebSocketApplicationErrorCode.UPDATE_LOGGER_CONFIGURATION_FAILURE.code(); - } - - return TIC2WebSocketApplicationErrorCode.NO_ERROR.code(); - } - - private int loadConfiguration() - { - String configFile = null; - - if (this.commandLine.configFile != null) - { - configFile = this.commandLine.configFile; - } - else - { - configFile = System.getProperty("configFile", NAME + "Configuration.json"); - } - File configPath = new File(configFile); - if (!configPath.exists()) - { - this.logger.error("No configuration file path '" + configPath.getAbsolutePath() + "' not found"); - return TIC2WebSocketApplicationErrorCode.LOAD_CONFIGURATION_FAILURE.code(); - } - try - { - this.logger.info("Loading configuration file " + configPath); - this.configuration = (TIC2WebSocketConfiguration) DataDictionaryBase.fromFile(configPath, TIC2WebSocketConfiguration.class); - } - catch (Exception exception) - { - this.logger.error("Loading configuration file " + configPath + " failed", exception); - return TIC2WebSocketApplicationErrorCode.LOAD_CONFIGURATION_FAILURE.code(); - } - - return TIC2WebSocketApplicationErrorCode.NO_ERROR.code(); - - } -} \ No newline at end of file diff --git a/src/main/java/enedis/tic/service/TIC2WebSocketApplicationErrorCode.java b/src/main/java/enedis/tic/service/TIC2WebSocketApplicationErrorCode.java deleted file mode 100644 index c2b970c..0000000 --- a/src/main/java/enedis/tic/service/TIC2WebSocketApplicationErrorCode.java +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.tic.service; - -/** - * Application error codes list - */ -public enum TIC2WebSocketApplicationErrorCode -{ - /** Success code */ - NO_ERROR(0), - /** Command line invalid code */ - COMMAND_LINE_INVALID(1), - /** Update logger configuration code */ - UPDATE_LOGGER_CONFIGURATION_FAILURE(2), - /** Application already started code */ - APPLICATION_ALREADY_STARTED(3), - /** Application not started code */ - APPLICATION_NOT_STARTED(4), - /** Load configuration failure code */ - LOAD_CONFIGURATION_FAILURE(5); - - private int code; - - private TIC2WebSocketApplicationErrorCode(int code) - { - this.code = code; - } - - /** - * Return error code - * - * @return code - */ - public int code() - { - return this.code; - } - -} diff --git a/src/main/java/enedis/tic/service/TIC2WebSocketCommandLine.java b/src/main/java/enedis/tic/service/TIC2WebSocketCommandLine.java deleted file mode 100644 index ac5474b..0000000 --- a/src/main/java/enedis/tic/service/TIC2WebSocketCommandLine.java +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.tic.service; - -import org.apache.logging.log4j.Level; - -import picocli.CommandLine.Command; -import picocli.CommandLine.ITypeConverter; -import picocli.CommandLine.Option; -import picocli.CommandLine.TypeConversionException; - -/** - * Class used for command line - */ -@Command() -public class TIC2WebSocketCommandLine -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - static class VerboseLevelConverter implements ITypeConverter - { - @Override - public Level convert(String value) throws Exception - { - try - { - switch (Integer.parseInt(value)) - { - case 0: - return Level.OFF; - case 1: - return Level.FATAL; - case 2: - return Level.ERROR; - case 3: - return Level.WARN; - case 4: - return Level.INFO; - case 5: - return Level.DEBUG; - case 6: - return Level.TRACE; - default: - throw new TypeConversionException(value); - } - } - catch (NumberFormatException exception) - { - Level level = Level.getLevel(value); - if (level == null) - { - throw new TypeConversionException(value); - } - return level; - } - } - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Option(names = { "-h", "--help" }, usageHelp = true, description = "Display help") - boolean helpRequested = false; - - @Option(names = { "--version" }, versionHelp = true, description = "Display version") - boolean versionRequested = false; - - //@formatter:off - @Option(names = { "-v", - "--verbose" }, defaultValue = "2", paramLabel = "LEVEL", - description = "Define verbosity level:\n" + - "0 ou OFF = muted\n" + - "1 ou FATAL = critical errors\n" + - "2 ou ERROR = error (default)\n" + - "3 ou WARN = warnings\n" + - "4 ou INFO = informations\n" + - "5 ou DEBUG = debugging\n" + - "6 ou TRACE = traces\n") - Level verboseLevel; - //@formatter:on - - @Option(names = { "--configFile" }, paramLabel = "PATH", description = "Set configuration file") - String configFile = null; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// interfaceName - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -}; diff --git a/src/main/java/enedis/tic/service/client/TIC2WebSocketClient.java b/src/main/java/enedis/tic/service/client/TIC2WebSocketClient.java deleted file mode 100644 index b45040a..0000000 --- a/src/main/java/enedis/tic/service/client/TIC2WebSocketClient.java +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.tic.service.client; - -import java.time.LocalDateTime; - -import io.netty.channel.Channel; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import enedis.lab.types.DataDictionaryException; -import enedis.lab.util.message.Event; -import enedis.tic.core.TICCoreError; -import enedis.tic.core.TICCoreFrame; -import enedis.tic.core.TICCoreSubscriber; -import enedis.tic.service.endpoint.EventSender; -import enedis.tic.service.message.EventOnError; -import enedis.tic.service.message.EventOnTICData; - -/** - * TIC2WebSocket client - */ -public class TIC2WebSocketClient implements TICCoreSubscriber -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private Logger logger; - private Channel channel; - private EventSender eventSender; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Constructor - * - * @param channel - * @param eventSender - */ - public TIC2WebSocketClient(Channel channel, EventSender eventSender) { - super(); - this.logger = LogManager.getLogger(this.getClass()); - this.channel = channel; - this.eventSender = eventSender; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// TICCoreSubscriber - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public void onData(TICCoreFrame frame) - { - try - { - Event event = new EventOnTICData(LocalDateTime.now(), frame); - this.eventSender.sendEvent(this.channel, event); - } - catch (DataDictionaryException e) - { - this.logger.error(e.getMessage(), e); - } - } - - @Override - public void onError(TICCoreError error) - { - try - { - Event event = new EventOnError(LocalDateTime.now(), error); - this.eventSender.sendEvent(this.channel, event); - } - catch (DataDictionaryException e) - { - this.logger.error(e.getMessage(), e); - } - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Get client websocket channel - * - * @return websocket channel - */ - public Channel getChannel() - { - return this.channel; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -} diff --git a/src/main/java/enedis/tic/service/client/TIC2WebSocketClientPool.java b/src/main/java/enedis/tic/service/client/TIC2WebSocketClientPool.java deleted file mode 100644 index 1518ae4..0000000 --- a/src/main/java/enedis/tic/service/client/TIC2WebSocketClientPool.java +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.tic.service.client; - -import java.util.Optional; - -import io.netty.channel.Channel; - -import enedis.tic.service.endpoint.EventSender; - -/** - * TIC2WebSocket client pool interface - */ -public interface TIC2WebSocketClientPool -{ - /** - * Get client from channel id - * - * @param channelId - * @return client - */ - public Optional getClient(String channelId); - - /** - * Check if a client with the given channel id exists - * - * @param channelId - * @return true if a client with the given channel id exists - */ - public boolean exists(String channelId); - - /** - * Create a new client - * - * @param channel - * @param sender - * @return new client - */ - public TIC2WebSocketClient createClient(Channel channel, EventSender sender); - - /** - * Remove client with the given channel id - * - * @param channelId - */ - public void remove(String channelId); -} diff --git a/src/main/java/enedis/tic/service/client/TIC2WebSocketClientPoolBase.java b/src/main/java/enedis/tic/service/client/TIC2WebSocketClientPoolBase.java deleted file mode 100644 index 7cf68db..0000000 --- a/src/main/java/enedis/tic/service/client/TIC2WebSocketClientPoolBase.java +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.tic.service.client; - -import java.util.Optional; -import java.util.Set; -import java.util.concurrent.CopyOnWriteArraySet; - -import io.netty.channel.Channel; - -import enedis.tic.service.endpoint.EventSender; - -/** - * Client pool - */ -public class TIC2WebSocketClientPoolBase implements TIC2WebSocketClientPool -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private Set clients; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Default constructor - */ - public TIC2WebSocketClientPoolBase() - { - super(); - this.clients = new CopyOnWriteArraySet(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// interfaceName - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public Optional getClient(String channelId) - { - // @formatter:off - return this.clients.stream() - .filter(c -> c.getChannel().id().asLongText().equals(channelId)) - .findAny(); - // @formatter:on - } - - @Override - public boolean exists(String channelId) - { - return this.getClient(channelId).isPresent(); - } - - @Override - public TIC2WebSocketClient createClient(Channel channel, EventSender sender) - { - this.checkArguments(channel, sender); - - String channelId = channel.id().asLongText(); - Optional client = this.getClient(channelId); - if (!client.isPresent()) - { - TIC2WebSocketClient newClient = new TIC2WebSocketClient(channel, sender); - this.clients.add(newClient); - return newClient; - } - else - { - return client.get(); - } - } - - @Override - public void remove(String channelId) - { - Optional client = this.getClient(channelId); - if (client.isPresent()) - { - this.clients.remove(client.get()); - } - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private void checkArguments(Channel channel, EventSender sender) - { - if (channel == null || sender == null) { - throw new IllegalArgumentException("Cannot create client with a null Channel or null EventSender"); - } - } -} diff --git a/src/main/java/enedis/tic/service/config/TIC2WebSocketConfiguration.java b/src/main/java/enedis/tic/service/config/TIC2WebSocketConfiguration.java deleted file mode 100644 index 6fa8e44..0000000 --- a/src/main/java/enedis/tic/service/config/TIC2WebSocketConfiguration.java +++ /dev/null @@ -1,275 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.tic.service.config; - -import java.io.File; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import enedis.lab.protocol.tic.TICMode; -import enedis.lab.types.DataDictionary; -import enedis.lab.types.DataDictionaryException; -import enedis.lab.types.configuration.ConfigurationBase; -import enedis.lab.types.datadictionary.KeyDescriptor; -import enedis.lab.types.datadictionary.KeyDescriptorEnum; -import enedis.lab.types.datadictionary.KeyDescriptorListMinMaxSize; -import enedis.lab.types.datadictionary.KeyDescriptorNumberMinMax; - -/** - * TIC2WebSocketConfiguration class - * - * Generated - */ -public class TIC2WebSocketConfiguration extends ConfigurationBase -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected static final String KEY_SERVER_PORT = "serverPort"; - protected static final String KEY_TIC_MODE = "ticMode"; - protected static final String KEY_TIC_PORT_NAMES = "ticPortNames"; - - private static final Number SERVER_PORT_MIN = 1; - private static final Number SERVER_PORT_MAX = 65535; - private static final int TIC_PORT_NAMES_MIN_SIZE = 1; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private List> keys = new ArrayList>(); - - protected KeyDescriptorNumberMinMax kServerPort; - protected KeyDescriptorEnum kTicMode; - protected KeyDescriptorListMinMaxSize kTicPortNames; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected TIC2WebSocketConfiguration() - { - super(); - this.loadKeyDescriptors(); - - } - - /** - * Constructor using map - * - * @param map - * @throws DataDictionaryException - */ - public TIC2WebSocketConfiguration(Map map) throws DataDictionaryException - { - this(); - this.copy(fromMap(map)); - } - - /** - * Constructor using datadictionary - * - * @param other - * @throws DataDictionaryException - */ - public TIC2WebSocketConfiguration(DataDictionary other) throws DataDictionaryException - { - this(); - this.copy(other); - } - - /** - * - * Constructor setting configuration name/file and parameters to default values - * - * @param name - * the configuration name - * @param file - * the configuration file - */ - public TIC2WebSocketConfiguration(String name, File file) - { - this(); - this.init(name, file); - } - - /** - * Constructor setting parameters to specific values - * - * @param serverPort - * @param ticMode - * @param ticPortNames - * @throws DataDictionaryException - */ - public TIC2WebSocketConfiguration(Number serverPort, TICMode ticMode, List ticPortNames) throws DataDictionaryException - { - this(); - - this.setServerPort(serverPort); - this.setTicMode(ticMode); - this.setTicPortNames(ticPortNames); - - this.checkAndUpdate(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Get server port - * - * @return the server port - */ - public Number getServerPort() - { - return (Number) this.data.get(KEY_SERVER_PORT); - } - - /** - * Get tic mode - * - * @return the tic mode - */ - public TICMode getTicMode() - { - return (TICMode) this.data.get(KEY_TIC_MODE); - } - - /** - * Get tic port names - * - * @return the tic port names - */ - @SuppressWarnings("unchecked") - public List getTicPortNames() - { - return (List) this.data.get(KEY_TIC_PORT_NAMES); - } - - /** - * Set server port - * - * @param serverPort - * @throws DataDictionaryException - */ - public void setServerPort(Number serverPort) throws DataDictionaryException - { - this.setServerPort((Object) serverPort); - } - - /** - * Set tic mode - * - * @param ticMode - * @throws DataDictionaryException - */ - public void setTicMode(TICMode ticMode) throws DataDictionaryException - { - this.setTicMode((Object) ticMode); - } - - /** - * Set tic port names - * - * @param ticPortNames - * @throws DataDictionaryException - */ - public void setTicPortNames(List ticPortNames) throws DataDictionaryException - { - this.setTicPortNames((Object) ticPortNames); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected void setServerPort(Object serverPort) throws DataDictionaryException - { - this.data.put(KEY_SERVER_PORT, this.kServerPort.convert(serverPort)); - } - - protected void setTicMode(Object ticMode) throws DataDictionaryException - { - this.data.put(KEY_TIC_MODE, this.kTicMode.convert(ticMode)); - } - - protected void setTicPortNames(Object ticPortNames) throws DataDictionaryException - { - List portNames = this.kTicPortNames.convert(ticPortNames); - for (int i = 0; i < portNames.size(); i++) - { - String portName = portNames.get(i); - if (portName == null) - { - throw new DataDictionaryException("Key " + KEY_TIC_PORT_NAMES + ": value at index " + i + "(" + portName + ") cannot be null"); - } - else if (portName.isEmpty()) - { - throw new DataDictionaryException("Key " + KEY_TIC_PORT_NAMES + ": value at index " + i + "(" + portName + ") cannot be empty"); - } - else if (i != portNames.lastIndexOf(portName)) - { - throw new DataDictionaryException( - "Key " + KEY_TIC_PORT_NAMES + ": value at index " + i + " and " + portNames.lastIndexOf(portName) + "(" + portName + ") are identical"); - } - } - this.data.put(KEY_TIC_PORT_NAMES, portNames); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private void loadKeyDescriptors() - { - try - { - this.kServerPort = new KeyDescriptorNumberMinMax(KEY_SERVER_PORT, true, SERVER_PORT_MIN, SERVER_PORT_MAX); - this.keys.add(this.kServerPort); - - this.kTicMode = new KeyDescriptorEnum(KEY_TIC_MODE, false, TICMode.class); - this.keys.add(this.kTicMode); - - this.kTicPortNames = new KeyDescriptorListMinMaxSize(KEY_TIC_PORT_NAMES, false, String.class, TIC_PORT_NAMES_MIN_SIZE, null); - this.keys.add(this.kTicPortNames); - - this.addAllKeyDescriptor(this.keys); - } - catch (DataDictionaryException e) - { - throw new RuntimeException(e.getMessage(), e); - } - } -} diff --git a/src/main/java/enedis/tic/service/endpoint/EventSender.java b/src/main/java/enedis/tic/service/endpoint/EventSender.java deleted file mode 100644 index 2437707..0000000 --- a/src/main/java/enedis/tic/service/endpoint/EventSender.java +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.tic.service.endpoint; - -import io.netty.channel.Channel; - -import enedis.lab.util.message.Event; - -/** - * Event sender interface - */ -public interface EventSender -{ - /** - * Send event - * - * @param channel - * @param event - */ - public void sendEvent(Channel channel, Event event); -} diff --git a/src/main/java/enedis/tic/service/endpoint/TIC2WebSocketEndPointErrorCode.java b/src/main/java/enedis/tic/service/endpoint/TIC2WebSocketEndPointErrorCode.java deleted file mode 100644 index 5eca674..0000000 --- a/src/main/java/enedis/tic/service/endpoint/TIC2WebSocketEndPointErrorCode.java +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.tic.service.endpoint; - -/** - * End point error codes list - */ -public enum TIC2WebSocketEndPointErrorCode -{ - /** Success code */ - NO_ERROR(0), - /** Unvalid message */ - INVALID_MESSAGE_FORMAT(-1), - /** Message type missing */ - MESSAGE_TYPE_MISSING(-2), - /** Message name missing */ - MESSAGE_NAME_MISSING(-3), - /** Message type invalid */ - MESSAGE_TYPE_INVALID(-4), - /** Unsupported message */ - UNSUPPORTED_MESSAGE(-5), - /** Invalid messge content */ - INVALID_MESSAGE_CONTENT(-6), - /** Internal error */ - INTERNAL_ERROR(-7), - /** Subscription fail */ - SUBSCRIPTION_FAIL(-10), - /** Unsubscription fail */ - UNSUBSCRIPTION_FAIL(-11), - /** TIC identifier not found */ - IDENTIFIER_NOT_FOUND(-12), - /** Read TIC timeout */ - READ_TIMEOUT(-13); - - private int value; - - private TIC2WebSocketEndPointErrorCode(int value) - { - this.value = value; - } - - /** - * Return error code - * - * @return code - */ - public int value() - { - return this.value; - } - -} diff --git a/src/main/java/enedis/tic/service/endpoint/TIC2WebSocketEndPointException.java b/src/main/java/enedis/tic/service/endpoint/TIC2WebSocketEndPointException.java deleted file mode 100644 index 4e7b38c..0000000 --- a/src/main/java/enedis/tic/service/endpoint/TIC2WebSocketEndPointException.java +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.tic.service.endpoint; - -/** - * @author Antoine - * - */ -/** - * TIC2WebSocket end point Exception - */ -public class TIC2WebSocketEndPointException extends Exception -{ - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private static final long serialVersionUID = -2263755971102386572L; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private TIC2WebSocketEndPointErrorCode code; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Default constructor - * - * @param code - */ - public TIC2WebSocketEndPointException(TIC2WebSocketEndPointErrorCode code) - { - super(); - this.code = code; - } - - /** - * Constructor using message and cause - * - * @param code - * - * @param message - * @param cause - */ - public TIC2WebSocketEndPointException(TIC2WebSocketEndPointErrorCode code, String message, Throwable cause) - { - super(message, cause); - this.code = code; - } - - /** - * Constructor using message - * - * @param code - * - * @param message - */ - public TIC2WebSocketEndPointException(TIC2WebSocketEndPointErrorCode code, String message) - { - super(message); - this.code = code; - } - - /** - * Constructor using cause - * - * @param code - * - * @param cause - */ - public TIC2WebSocketEndPointException(TIC2WebSocketEndPointErrorCode code, Throwable cause) - { - super(cause); - this.code = code; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// interfaceName - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Get error code - * - * @return error code - */ - public TIC2WebSocketEndPointErrorCode getCode() - { - return this.code; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -} diff --git a/src/main/java/enedis/tic/service/message/EventOnError.java b/src/main/java/enedis/tic/service/message/EventOnError.java deleted file mode 100644 index da39693..0000000 --- a/src/main/java/enedis/tic/service/message/EventOnError.java +++ /dev/null @@ -1,192 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.tic.service.message; - -import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import enedis.lab.types.DataDictionary; -import enedis.lab.types.DataDictionaryException; -import enedis.lab.types.datadictionary.KeyDescriptor; -import enedis.lab.types.datadictionary.KeyDescriptorDataDictionary; -import enedis.lab.util.message.Event; -import enedis.tic.core.TICCoreError; - -/** - * EventOnError class - * - * Generated - */ -public class EventOnError extends Event -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected static final String KEY_DATA = "data"; - - /** Message name */ - public static final String NAME = "OnError"; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private List> keys = new ArrayList>(); - - protected KeyDescriptorDataDictionary kData; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected EventOnError() - { - super(); - this.loadKeyDescriptors(); - - this.kName.setAcceptedValues(NAME); - } - - /** - * Constructor using map - * - * @param map - * @throws DataDictionaryException - */ - public EventOnError(Map map) throws DataDictionaryException - { - this(); - this.copy(fromMap(map)); - } - - /** - * Constructor using datadictionary - * - * @param other - * @throws DataDictionaryException - */ - public EventOnError(DataDictionary other) throws DataDictionaryException - { - this(); - this.copy(other); - } - - /** - * Constructor setting parameters to specific values - * - * @param dateTime - * @param data - * @throws DataDictionaryException - */ - public EventOnError(LocalDateTime dateTime, TICCoreError data) throws DataDictionaryException - { - this(); - - this.setDateTime(dateTime); - this.setData(data); - - this.checkAndUpdate(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// Event - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - protected void updateOptionalParameters() throws DataDictionaryException - { - if (!this.exists(KEY_NAME)) - { - this.setName(NAME); - } - super.updateOptionalParameters(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Get data - * - * @return the data - */ - public TICCoreError getData() - { - return (TICCoreError) this.data.get(KEY_DATA); - } - - /** - * Set data - * - * @param data - * @throws DataDictionaryException - */ - public void setData(TICCoreError data) throws DataDictionaryException - { - this.setData((Object) data); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected void setData(Object data) throws DataDictionaryException - { - this.data.put(KEY_DATA, this.kData.convert(data)); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private void loadKeyDescriptors() - { - try - { - this.kData = new KeyDescriptorDataDictionary(KEY_DATA, false, TICCoreError.class); - this.keys.add(this.kData); - - this.addAllKeyDescriptor(this.keys); - } - catch (DataDictionaryException e) - { - throw new RuntimeException(e.getMessage(), e); - } - } -} diff --git a/src/main/java/enedis/tic/service/message/EventOnTICData.java b/src/main/java/enedis/tic/service/message/EventOnTICData.java deleted file mode 100644 index c47d701..0000000 --- a/src/main/java/enedis/tic/service/message/EventOnTICData.java +++ /dev/null @@ -1,192 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.tic.service.message; - -import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import enedis.lab.types.DataDictionary; -import enedis.lab.types.DataDictionaryException; -import enedis.lab.types.datadictionary.KeyDescriptor; -import enedis.lab.types.datadictionary.KeyDescriptorDataDictionary; -import enedis.lab.util.message.Event; -import enedis.tic.core.TICCoreFrame; - -/** - * EventOnTICData class - * - * Generated - */ -public class EventOnTICData extends Event -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected static final String KEY_DATA = "data"; - - /** Message name */ - public static final String NAME = "OnTICData"; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private List> keys = new ArrayList>(); - - protected KeyDescriptorDataDictionary kData; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected EventOnTICData() - { - super(); - this.loadKeyDescriptors(); - - this.kName.setAcceptedValues(NAME); - } - - /** - * Constructor using map - * - * @param map - * @throws DataDictionaryException - */ - public EventOnTICData(Map map) throws DataDictionaryException - { - this(); - this.copy(fromMap(map)); - } - - /** - * Constructor using datadictionary - * - * @param other - * @throws DataDictionaryException - */ - public EventOnTICData(DataDictionary other) throws DataDictionaryException - { - this(); - this.copy(other); - } - - /** - * Constructor setting parameters to specific values - * - * @param dateTime - * @param data - * @throws DataDictionaryException - */ - public EventOnTICData(LocalDateTime dateTime, TICCoreFrame data) throws DataDictionaryException - { - this(); - - this.setDateTime(dateTime); - this.setData(data); - - this.checkAndUpdate(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// Event - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - protected void updateOptionalParameters() throws DataDictionaryException - { - if (!this.exists(KEY_NAME)) - { - this.setName(NAME); - } - super.updateOptionalParameters(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Get data - * - * @return the data - */ - public TICCoreFrame getData() - { - return (TICCoreFrame) this.data.get(KEY_DATA); - } - - /** - * Set data - * - * @param data - * @throws DataDictionaryException - */ - public void setData(TICCoreFrame data) throws DataDictionaryException - { - this.setData((Object) data); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected void setData(Object data) throws DataDictionaryException - { - this.data.put(KEY_DATA, this.kData.convert(data)); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private void loadKeyDescriptors() - { - try - { - this.kData = new KeyDescriptorDataDictionary(KEY_DATA, true, TICCoreFrame.class); - this.keys.add(this.kData); - - this.addAllKeyDescriptor(this.keys); - } - catch (DataDictionaryException e) - { - throw new RuntimeException(e.getMessage(), e); - } - } -} diff --git a/src/main/java/enedis/tic/service/message/RequestGetAvailableTICs.java b/src/main/java/enedis/tic/service/message/RequestGetAvailableTICs.java deleted file mode 100644 index 0fdd485..0000000 --- a/src/main/java/enedis/tic/service/message/RequestGetAvailableTICs.java +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.tic.service.message; - -import java.util.Map; - -import enedis.lab.types.DataDictionary; -import enedis.lab.types.DataDictionaryException; -import enedis.lab.util.message.Request; - -/** - * RequestGetAvailableTICs class - * - * Generated - */ -public class RequestGetAvailableTICs extends Request -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** Message name */ - public static final String NAME = "GetAvailableTICs"; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Default constructor - * - * @throws DataDictionaryException - */ - public RequestGetAvailableTICs() throws DataDictionaryException - { - super(); - - this.kName.setAcceptedValues(NAME); - - this.checkAndUpdate(); - } - - /** - * Constructor using map - * - * @param map - * @throws DataDictionaryException - */ - public RequestGetAvailableTICs(Map map) throws DataDictionaryException - { - this(); - this.copy(fromMap(map)); - } - - /** - * Constructor using datadictionary - * - * @param other - * @throws DataDictionaryException - */ - public RequestGetAvailableTICs(DataDictionary other) throws DataDictionaryException - { - this(); - this.copy(other); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// Request - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - protected void updateOptionalParameters() throws DataDictionaryException - { - if (!this.exists(KEY_NAME)) - { - this.setName(NAME); - } - super.updateOptionalParameters(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -} diff --git a/src/main/java/enedis/tic/service/message/RequestGetModemsInfo.java b/src/main/java/enedis/tic/service/message/RequestGetModemsInfo.java deleted file mode 100644 index 250981a..0000000 --- a/src/main/java/enedis/tic/service/message/RequestGetModemsInfo.java +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.tic.service.message; - -import java.util.Map; - -import enedis.lab.types.DataDictionary; -import enedis.lab.types.DataDictionaryException; -import enedis.lab.util.message.Request; - -/** - * RequestGetModemsInfo class - * - * Generated - */ -public class RequestGetModemsInfo extends Request -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** Message name */ - public static final String NAME = "GetModemsInfo"; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - public RequestGetModemsInfo() throws DataDictionaryException - { - super(); - - this.kName.setAcceptedValues(NAME); - - this.checkAndUpdate(); - } - - /** - * Constructor using map - * - * @param map - * @throws DataDictionaryException - */ - public RequestGetModemsInfo(Map map) throws DataDictionaryException - { - this(); - this.copy(fromMap(map)); - } - - /** - * Constructor using datadictionary - * - * @param other - * @throws DataDictionaryException - */ - public RequestGetModemsInfo(DataDictionary other) throws DataDictionaryException - { - this(); - this.copy(other); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// Request - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - protected void updateOptionalParameters() throws DataDictionaryException - { - if (!this.exists(KEY_NAME)) - { - this.setName(NAME); - } - super.updateOptionalParameters(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -} diff --git a/src/main/java/enedis/tic/service/message/RequestReadTIC.java b/src/main/java/enedis/tic/service/message/RequestReadTIC.java deleted file mode 100644 index 95fb548..0000000 --- a/src/main/java/enedis/tic/service/message/RequestReadTIC.java +++ /dev/null @@ -1,189 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.tic.service.message; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import enedis.lab.types.DataDictionary; -import enedis.lab.types.DataDictionaryException; -import enedis.lab.types.datadictionary.KeyDescriptor; -import enedis.lab.types.datadictionary.KeyDescriptorDataDictionary; -import enedis.lab.util.message.Request; -import enedis.tic.core.TICIdentifier; - -/** - * RequestReadTIC class - * - * Generated - */ -public class RequestReadTIC extends Request -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected static final String KEY_DATA = "data"; - - /** Message name */ - public static final String NAME = "ReadTIC"; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private List> keys = new ArrayList>(); - - protected KeyDescriptorDataDictionary kData; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected RequestReadTIC() - { - super(); - this.loadKeyDescriptors(); - - this.kName.setAcceptedValues(NAME); - } - - /** - * Constructor using map - * - * @param map - * @throws DataDictionaryException - */ - public RequestReadTIC(Map map) throws DataDictionaryException - { - this(); - this.copy(fromMap(map)); - } - - /** - * Constructor using datadictionary - * - * @param other - * @throws DataDictionaryException - */ - public RequestReadTIC(DataDictionary other) throws DataDictionaryException - { - this(); - this.copy(other); - } - - /** - * Constructor setting parameters to specific values - * - * @param data - * @throws DataDictionaryException - */ - public RequestReadTIC(TICIdentifier data) throws DataDictionaryException - { - this(); - - this.setData(data); - - this.checkAndUpdate(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// Request - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - protected void updateOptionalParameters() throws DataDictionaryException - { - if (!this.exists(KEY_NAME)) - { - this.setName(NAME); - } - super.updateOptionalParameters(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Get data - * - * @return the data - */ - public TICIdentifier getData() - { - return (TICIdentifier) this.data.get(KEY_DATA); - } - - /** - * Set data - * - * @param data - * @throws DataDictionaryException - */ - public void setData(TICIdentifier data) throws DataDictionaryException - { - this.setData((Object) data); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected void setData(Object data) throws DataDictionaryException - { - this.data.put(KEY_DATA, this.kData.convert(data)); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private void loadKeyDescriptors() - { - try - { - this.kData = new KeyDescriptorDataDictionary(KEY_DATA, true, TICIdentifier.class); - this.keys.add(this.kData); - - this.addAllKeyDescriptor(this.keys); - } - catch (DataDictionaryException e) - { - throw new RuntimeException(e.getMessage(), e); - } - } -} diff --git a/src/main/java/enedis/tic/service/message/RequestSubscribeTIC.java b/src/main/java/enedis/tic/service/message/RequestSubscribeTIC.java deleted file mode 100644 index 499917a..0000000 --- a/src/main/java/enedis/tic/service/message/RequestSubscribeTIC.java +++ /dev/null @@ -1,190 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.tic.service.message; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import enedis.lab.types.DataDictionary; -import enedis.lab.types.DataDictionaryException; -import enedis.lab.types.datadictionary.KeyDescriptor; -import enedis.lab.types.datadictionary.KeyDescriptorList; -import enedis.lab.util.message.Request; -import enedis.tic.core.TICIdentifier; - -/** - * RequestSubscribeTIC class - * - * Generated - */ -public class RequestSubscribeTIC extends Request -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected static final String KEY_DATA = "data"; - - /** Message name */ - public static final String NAME = "SubscribeTIC"; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private List> keys = new ArrayList>(); - - protected KeyDescriptorList kData; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected RequestSubscribeTIC() - { - super(); - this.loadKeyDescriptors(); - - this.kName.setAcceptedValues(NAME); - } - - /** - * Constructor using map - * - * @param map - * @throws DataDictionaryException - */ - public RequestSubscribeTIC(Map map) throws DataDictionaryException - { - this(); - this.copy(fromMap(map)); - } - - /** - * Constructor using datadictionary - * - * @param other - * @throws DataDictionaryException - */ - public RequestSubscribeTIC(DataDictionary other) throws DataDictionaryException - { - this(); - this.copy(other); - } - - /** - * Constructor setting parameters to specific values - * - * @param data - * @throws DataDictionaryException - */ - public RequestSubscribeTIC(List data) throws DataDictionaryException - { - this(); - - this.setData(data); - - this.checkAndUpdate(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// Request - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - protected void updateOptionalParameters() throws DataDictionaryException - { - if (!this.exists(KEY_NAME)) - { - this.setName(NAME); - } - super.updateOptionalParameters(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Get data - * - * @return the data - */ - @SuppressWarnings("unchecked") - public List getData() - { - return (List) this.data.get(KEY_DATA); - } - - /** - * Set data - * - * @param data - * @throws DataDictionaryException - */ - public void setData(List data) throws DataDictionaryException - { - this.setData((Object) data); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected void setData(Object data) throws DataDictionaryException - { - this.data.put(KEY_DATA, this.kData.convert(data)); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private void loadKeyDescriptors() - { - try - { - this.kData = new KeyDescriptorList(KEY_DATA, false, TICIdentifier.class); - this.keys.add(this.kData); - - this.addAllKeyDescriptor(this.keys); - } - catch (DataDictionaryException e) - { - throw new RuntimeException(e.getMessage(), e); - } - } -} diff --git a/src/main/java/enedis/tic/service/message/RequestUnsubscribeTIC.java b/src/main/java/enedis/tic/service/message/RequestUnsubscribeTIC.java deleted file mode 100644 index 6556d82..0000000 --- a/src/main/java/enedis/tic/service/message/RequestUnsubscribeTIC.java +++ /dev/null @@ -1,190 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.tic.service.message; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import enedis.lab.types.DataDictionary; -import enedis.lab.types.DataDictionaryException; -import enedis.lab.types.datadictionary.KeyDescriptor; -import enedis.lab.types.datadictionary.KeyDescriptorList; -import enedis.lab.util.message.Request; -import enedis.tic.core.TICIdentifier; - -/** - * RequestUnsubscribeTIC class - * - * Generated - */ -public class RequestUnsubscribeTIC extends Request -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected static final String KEY_DATA = "data"; - - /** Message name */ - public static final String NAME = "UnsubscribeTIC"; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private List> keys = new ArrayList>(); - - protected KeyDescriptorList kData; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected RequestUnsubscribeTIC() - { - super(); - this.loadKeyDescriptors(); - - this.kName.setAcceptedValues(NAME); - } - - /** - * Constructor using map - * - * @param map - * @throws DataDictionaryException - */ - public RequestUnsubscribeTIC(Map map) throws DataDictionaryException - { - this(); - this.copy(fromMap(map)); - } - - /** - * Constructor using datadictionary - * - * @param other - * @throws DataDictionaryException - */ - public RequestUnsubscribeTIC(DataDictionary other) throws DataDictionaryException - { - this(); - this.copy(other); - } - - /** - * Constructor setting parameters to specific values - * - * @param data - * @throws DataDictionaryException - */ - public RequestUnsubscribeTIC(List data) throws DataDictionaryException - { - this(); - - this.setData(data); - - this.checkAndUpdate(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// Request - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - protected void updateOptionalParameters() throws DataDictionaryException - { - if (!this.exists(KEY_NAME)) - { - this.setName(NAME); - } - super.updateOptionalParameters(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Get data - * - * @return the data - */ - @SuppressWarnings("unchecked") - public List getData() - { - return (List) this.data.get(KEY_DATA); - } - - /** - * Set data - * - * @param data - * @throws DataDictionaryException - */ - public void setData(List data) throws DataDictionaryException - { - this.setData((Object) data); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected void setData(Object data) throws DataDictionaryException - { - this.data.put(KEY_DATA, this.kData.convert(data)); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private void loadKeyDescriptors() - { - try - { - this.kData = new KeyDescriptorList(KEY_DATA, false, TICIdentifier.class); - this.keys.add(this.kData); - - this.addAllKeyDescriptor(this.keys); - } - catch (DataDictionaryException e) - { - throw new RuntimeException(e.getMessage(), e); - } - } -} diff --git a/src/main/java/enedis/tic/service/message/ResponseGetAvailableTICs.java b/src/main/java/enedis/tic/service/message/ResponseGetAvailableTICs.java deleted file mode 100644 index 8c92f4d..0000000 --- a/src/main/java/enedis/tic/service/message/ResponseGetAvailableTICs.java +++ /dev/null @@ -1,197 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.tic.service.message; - -import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import enedis.lab.types.DataDictionary; -import enedis.lab.types.DataDictionaryException; -import enedis.lab.types.datadictionary.KeyDescriptor; -import enedis.lab.types.datadictionary.KeyDescriptorList; -import enedis.lab.util.message.Response; -import enedis.tic.core.TICIdentifier; - -/** - * ResponseGetAvailableTICs class - * - * Generated - */ -public class ResponseGetAvailableTICs extends Response -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected static final String KEY_DATA = "data"; - - /** Message name */ - public static final String NAME = "GetAvailableTICs"; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private List> keys = new ArrayList>(); - - protected KeyDescriptorList kData; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected ResponseGetAvailableTICs() - { - super(); - this.loadKeyDescriptors(); - - this.kName.setAcceptedValues(NAME); - } - - /** - * Constructor using map - * - * @param map - * @throws DataDictionaryException - */ - public ResponseGetAvailableTICs(Map map) throws DataDictionaryException - { - this(); - this.copy(fromMap(map)); - } - - /** - * Constructor using datadictionary - * - * @param other - * @throws DataDictionaryException - */ - public ResponseGetAvailableTICs(DataDictionary other) throws DataDictionaryException - { - this(); - this.copy(other); - } - - /** - * Constructor setting parameters to specific values - * - * @param dateTime - * @param errorCode - * @param errorMessage - * @param data - * @throws DataDictionaryException - */ - public ResponseGetAvailableTICs(LocalDateTime dateTime, Number errorCode, String errorMessage, List data) throws DataDictionaryException - { - this(); - - this.setDateTime(dateTime); - this.setErrorCode(errorCode); - this.setErrorMessage(errorMessage); - this.setData(data); - - this.checkAndUpdate(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// Response - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - protected void updateOptionalParameters() throws DataDictionaryException - { - if (!this.exists(KEY_NAME)) - { - this.setName(NAME); - } - super.updateOptionalParameters(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Get data - * - * @return the data - */ - @SuppressWarnings("unchecked") - public List getData() - { - return (List) this.data.get(KEY_DATA); - } - - /** - * Set data - * - * @param data - * @throws DataDictionaryException - */ - public void setData(List data) throws DataDictionaryException - { - this.setData((Object) data); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected void setData(Object data) throws DataDictionaryException - { - this.data.put(KEY_DATA, this.kData.convert(data)); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private void loadKeyDescriptors() - { - try - { - this.kData = new KeyDescriptorList(KEY_DATA, false, TICIdentifier.class); - this.keys.add(this.kData); - - this.addAllKeyDescriptor(this.keys); - } - catch (DataDictionaryException e) - { - throw new RuntimeException(e.getMessage(), e); - } - } -} diff --git a/src/main/java/enedis/tic/service/message/ResponseGetModemsInfo.java b/src/main/java/enedis/tic/service/message/ResponseGetModemsInfo.java deleted file mode 100644 index 7a66ad1..0000000 --- a/src/main/java/enedis/tic/service/message/ResponseGetModemsInfo.java +++ /dev/null @@ -1,197 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.tic.service.message; - -import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import enedis.lab.io.tic.TICPortDescriptor; -import enedis.lab.types.DataDictionary; -import enedis.lab.types.DataDictionaryException; -import enedis.lab.types.datadictionary.KeyDescriptor; -import enedis.lab.types.datadictionary.KeyDescriptorList; -import enedis.lab.util.message.Response; - -/** - * ResponseGetModemsInfo class - * - * Generated - */ -public class ResponseGetModemsInfo extends Response -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected static final String KEY_DATA = "data"; - - /** Message name */ - public static final String NAME = "GetModemsInfo"; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private List> keys = new ArrayList>(); - - protected KeyDescriptorList kData; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected ResponseGetModemsInfo() - { - super(); - this.loadKeyDescriptors(); - - this.kName.setAcceptedValues(NAME); - } - - /** - * Constructor using map - * - * @param map - * @throws DataDictionaryException - */ - public ResponseGetModemsInfo(Map map) throws DataDictionaryException - { - this(); - this.copy(fromMap(map)); - } - - /** - * Constructor using datadictionary - * - * @param other - * @throws DataDictionaryException - */ - public ResponseGetModemsInfo(DataDictionary other) throws DataDictionaryException - { - this(); - this.copy(other); - } - - /** - * Constructor setting parameters to specific values - * - * @param dateTime - * @param errorCode - * @param errorMessage - * @param data - * @throws DataDictionaryException - */ - public ResponseGetModemsInfo(LocalDateTime dateTime, Number errorCode, String errorMessage, List data) throws DataDictionaryException - { - this(); - - this.setDateTime(dateTime); - this.setErrorCode(errorCode); - this.setErrorMessage(errorMessage); - this.setData(data); - - this.checkAndUpdate(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// Response - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - protected void updateOptionalParameters() throws DataDictionaryException - { - if (!this.exists(KEY_NAME)) - { - this.setName(NAME); - } - super.updateOptionalParameters(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Get data - * - * @return the data - */ - @SuppressWarnings("unchecked") - public List getData() - { - return (List) this.data.get(KEY_DATA); - } - - /** - * Set data - * - * @param data - * @throws DataDictionaryException - */ - public void setData(List data) throws DataDictionaryException - { - this.setData((Object) data); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected void setData(Object data) throws DataDictionaryException - { - this.data.put(KEY_DATA, this.kData.convert(data)); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private void loadKeyDescriptors() - { - try - { - this.kData = new KeyDescriptorList(KEY_DATA, false, TICPortDescriptor.class); - this.keys.add(this.kData); - - this.addAllKeyDescriptor(this.keys); - } - catch (DataDictionaryException e) - { - throw new RuntimeException(e.getMessage(), e); - } - } -} diff --git a/src/main/java/enedis/tic/service/message/ResponseReadTIC.java b/src/main/java/enedis/tic/service/message/ResponseReadTIC.java deleted file mode 100644 index 0a864cb..0000000 --- a/src/main/java/enedis/tic/service/message/ResponseReadTIC.java +++ /dev/null @@ -1,196 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.tic.service.message; - -import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import enedis.lab.types.DataDictionary; -import enedis.lab.types.DataDictionaryException; -import enedis.lab.types.datadictionary.KeyDescriptor; -import enedis.lab.types.datadictionary.KeyDescriptorDataDictionary; -import enedis.lab.util.message.Response; -import enedis.tic.core.TICCoreFrame; - -/** - * ResponseReadTIC class - * - * Generated - */ -public class ResponseReadTIC extends Response -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected static final String KEY_DATA = "data"; - - /** Message name */ - public static final String NAME = "ReadTIC"; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private List> keys = new ArrayList>(); - - protected KeyDescriptorDataDictionary kData; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected ResponseReadTIC() - { - super(); - this.loadKeyDescriptors(); - - this.kName.setAcceptedValues(NAME); - } - - /** - * Constructor using map - * - * @param map - * @throws DataDictionaryException - */ - public ResponseReadTIC(Map map) throws DataDictionaryException - { - this(); - this.copy(fromMap(map)); - } - - /** - * Constructor using datadictionary - * - * @param other - * @throws DataDictionaryException - */ - public ResponseReadTIC(DataDictionary other) throws DataDictionaryException - { - this(); - this.copy(other); - } - - /** - * Constructor setting parameters to specific values - * - * @param dateTime - * @param errorCode - * @param errorMessage - * @param data - * @throws DataDictionaryException - */ - public ResponseReadTIC(LocalDateTime dateTime, Number errorCode, String errorMessage, TICCoreFrame data) throws DataDictionaryException - { - this(); - - this.setDateTime(dateTime); - this.setErrorCode(errorCode); - this.setErrorMessage(errorMessage); - this.setData(data); - - this.checkAndUpdate(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// Response - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - protected void updateOptionalParameters() throws DataDictionaryException - { - if (!this.exists(KEY_NAME)) - { - this.setName(NAME); - } - super.updateOptionalParameters(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Get data - * - * @return the data - */ - public TICCoreFrame getData() - { - return (TICCoreFrame) this.data.get(KEY_DATA); - } - - /** - * Set data - * - * @param data - * @throws DataDictionaryException - */ - public void setData(TICCoreFrame data) throws DataDictionaryException - { - this.setData((Object) data); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected void setData(Object data) throws DataDictionaryException - { - this.data.put(KEY_DATA, this.kData.convert(data)); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private void loadKeyDescriptors() - { - try - { - this.kData = new KeyDescriptorDataDictionary(KEY_DATA, false, TICCoreFrame.class); - this.keys.add(this.kData); - - this.addAllKeyDescriptor(this.keys); - } - catch (DataDictionaryException e) - { - throw new RuntimeException(e.getMessage(), e); - } - } -} diff --git a/src/main/java/enedis/tic/service/message/ResponseSubscribeTIC.java b/src/main/java/enedis/tic/service/message/ResponseSubscribeTIC.java deleted file mode 100644 index 9577924..0000000 --- a/src/main/java/enedis/tic/service/message/ResponseSubscribeTIC.java +++ /dev/null @@ -1,160 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.tic.service.message; - -import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import enedis.lab.types.DataDictionary; -import enedis.lab.types.DataDictionaryException; -import enedis.lab.types.datadictionary.KeyDescriptor; -import enedis.lab.util.message.Response; - -/** - * ResponseSubscribeTIC class - * - * Generated - */ -public class ResponseSubscribeTIC extends Response -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** Message name */ - public static final String NAME = "SubscribeTIC"; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private List> keys = new ArrayList>(); - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected ResponseSubscribeTIC() - { - super(); - this.loadKeyDescriptors(); - - this.kName.setAcceptedValues(NAME); - } - - /** - * Constructor using map - * - * @param map - * @throws DataDictionaryException - */ - public ResponseSubscribeTIC(Map map) throws DataDictionaryException - { - this(); - this.copy(fromMap(map)); - } - - /** - * Constructor using datadictionary - * - * @param other - * @throws DataDictionaryException - */ - public ResponseSubscribeTIC(DataDictionary other) throws DataDictionaryException - { - this(); - this.copy(other); - } - - /** - * Constructor setting parameters to specific values - * - * @param dateTime - * @param errorCode - * @param errorMessage - * @throws DataDictionaryException - */ - public ResponseSubscribeTIC(LocalDateTime dateTime, Number errorCode, String errorMessage) throws DataDictionaryException - { - this(); - - this.setDateTime(dateTime); - this.setErrorCode(errorCode); - this.setErrorMessage(errorMessage); - - this.checkAndUpdate(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// Response - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - protected void updateOptionalParameters() throws DataDictionaryException - { - if (!this.exists(KEY_NAME)) - { - this.setName(NAME); - } - super.updateOptionalParameters(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private void loadKeyDescriptors() - { - try - { - - this.addAllKeyDescriptor(this.keys); - } - catch (DataDictionaryException e) - { - throw new RuntimeException(e.getMessage(), e); - } - } -} diff --git a/src/main/java/enedis/tic/service/message/ResponseUnsubscribeTIC.java b/src/main/java/enedis/tic/service/message/ResponseUnsubscribeTIC.java deleted file mode 100644 index b182e62..0000000 --- a/src/main/java/enedis/tic/service/message/ResponseUnsubscribeTIC.java +++ /dev/null @@ -1,160 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.tic.service.message; - -import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import enedis.lab.types.DataDictionary; -import enedis.lab.types.DataDictionaryException; -import enedis.lab.types.datadictionary.KeyDescriptor; -import enedis.lab.util.message.Response; - -/** - * ResponseUnsubscribeTIC class - * - * Generated - */ -public class ResponseUnsubscribeTIC extends Response -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** Message name */ - public static final String NAME = "UnsubscribeTIC"; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private List> keys = new ArrayList>(); - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected ResponseUnsubscribeTIC() - { - super(); - this.loadKeyDescriptors(); - - this.kName.setAcceptedValues(NAME); - } - - /** - * Constructor using map - * - * @param map - * @throws DataDictionaryException - */ - public ResponseUnsubscribeTIC(Map map) throws DataDictionaryException - { - this(); - this.copy(fromMap(map)); - } - - /** - * Constructor using datadictionary - * - * @param other - * @throws DataDictionaryException - */ - public ResponseUnsubscribeTIC(DataDictionary other) throws DataDictionaryException - { - this(); - this.copy(other); - } - - /** - * Constructor setting parameters to specific values - * - * @param dateTime - * @param errorCode - * @param errorMessage - * @throws DataDictionaryException - */ - public ResponseUnsubscribeTIC(LocalDateTime dateTime, Number errorCode, String errorMessage) throws DataDictionaryException - { - this(); - - this.setDateTime(dateTime); - this.setErrorCode(errorCode); - this.setErrorMessage(errorMessage); - - this.checkAndUpdate(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// Response - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - protected void updateOptionalParameters() throws DataDictionaryException - { - if (!this.exists(KEY_NAME)) - { - this.setName(NAME); - } - super.updateOptionalParameters(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private void loadKeyDescriptors() - { - try - { - - this.addAllKeyDescriptor(this.keys); - } - catch (DataDictionaryException e) - { - throw new RuntimeException(e.getMessage(), e); - } - } -} diff --git a/src/main/java/enedis/tic/service/message/factory/TIC2WebSocketEventFactory.java b/src/main/java/enedis/tic/service/message/factory/TIC2WebSocketEventFactory.java deleted file mode 100644 index 834533b..0000000 --- a/src/main/java/enedis/tic/service/message/factory/TIC2WebSocketEventFactory.java +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.tic.service.message.factory; - -import enedis.lab.util.message.factory.EventFactory; -import enedis.tic.service.message.EventOnError; -import enedis.tic.service.message.EventOnTICData; - -/** - * TIC2WebSocket request factory - */ -public class TIC2WebSocketEventFactory extends EventFactory -{ - /** - * Default constructor - */ - public TIC2WebSocketEventFactory() - { - super(); - this.addMessageClass(EventOnTICData.NAME, EventOnTICData.class); - this.addMessageClass(EventOnError.NAME, EventOnError.class); - } -} diff --git a/src/main/java/enedis/tic/service/message/factory/TIC2WebSocketMessageFactory.java b/src/main/java/enedis/tic/service/message/factory/TIC2WebSocketMessageFactory.java deleted file mode 100644 index e501d05..0000000 --- a/src/main/java/enedis/tic/service/message/factory/TIC2WebSocketMessageFactory.java +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.tic.service.message.factory; - -import enedis.lab.util.message.factory.MessageFactory; - -/** - * TIC2WebSocket message factory - */ -public class TIC2WebSocketMessageFactory extends MessageFactory -{ - /** - * Default constructor - */ - public TIC2WebSocketMessageFactory() - { - super(new TIC2WebSocketRequestFactory(), new TIC2WebSocketResponseFactory(), new TIC2WebSocketEventFactory()); - } -} diff --git a/src/main/java/enedis/tic/service/message/factory/TIC2WebSocketRequestFactory.java b/src/main/java/enedis/tic/service/message/factory/TIC2WebSocketRequestFactory.java deleted file mode 100644 index e76db79..0000000 --- a/src/main/java/enedis/tic/service/message/factory/TIC2WebSocketRequestFactory.java +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.tic.service.message.factory; - -import enedis.lab.util.message.factory.RequestFactory; -import enedis.tic.service.message.RequestGetAvailableTICs; -import enedis.tic.service.message.RequestGetModemsInfo; -import enedis.tic.service.message.RequestReadTIC; -import enedis.tic.service.message.RequestSubscribeTIC; -import enedis.tic.service.message.RequestUnsubscribeTIC; - -/** - * TIC2WebSocket request factory - */ -public class TIC2WebSocketRequestFactory extends RequestFactory -{ - /** - * Default constructor - */ - public TIC2WebSocketRequestFactory() - { - super(); - this.addMessageClass(RequestGetAvailableTICs.NAME, RequestGetAvailableTICs.class); - this.addMessageClass(RequestGetModemsInfo.NAME, RequestGetModemsInfo.class); - this.addMessageClass(RequestReadTIC.NAME, RequestReadTIC.class); - this.addMessageClass(RequestSubscribeTIC.NAME, RequestSubscribeTIC.class); - this.addMessageClass(RequestUnsubscribeTIC.NAME, RequestUnsubscribeTIC.class); - } -} diff --git a/src/main/java/enedis/tic/service/message/factory/TIC2WebSocketResponseFactory.java b/src/main/java/enedis/tic/service/message/factory/TIC2WebSocketResponseFactory.java deleted file mode 100644 index 13390e3..0000000 --- a/src/main/java/enedis/tic/service/message/factory/TIC2WebSocketResponseFactory.java +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.tic.service.message.factory; - -import enedis.lab.util.message.factory.ResponseFactory; -import enedis.tic.service.message.ResponseGetAvailableTICs; -import enedis.tic.service.message.ResponseGetModemsInfo; -import enedis.tic.service.message.ResponseReadTIC; -import enedis.tic.service.message.ResponseSubscribeTIC; -import enedis.tic.service.message.ResponseUnsubscribeTIC; - -/** - * TIC2WebSocket request factory - */ -public class TIC2WebSocketResponseFactory extends ResponseFactory -{ - /** - * Default constructor - */ - public TIC2WebSocketResponseFactory() - { - super(); - this.addMessageClass(ResponseGetAvailableTICs.NAME, ResponseGetAvailableTICs.class); - this.addMessageClass(ResponseGetModemsInfo.NAME, ResponseGetModemsInfo.class); - this.addMessageClass(ResponseReadTIC.NAME, ResponseReadTIC.class); - this.addMessageClass(ResponseSubscribeTIC.NAME, ResponseSubscribeTIC.class); - this.addMessageClass(ResponseUnsubscribeTIC.NAME, ResponseUnsubscribeTIC.class); - } -} \ No newline at end of file diff --git a/src/main/java/enedis/tic/service/netty/TIC2WebSocketChannelInitializer.java b/src/main/java/enedis/tic/service/netty/TIC2WebSocketChannelInitializer.java deleted file mode 100644 index 16e5518..0000000 --- a/src/main/java/enedis/tic/service/netty/TIC2WebSocketChannelInitializer.java +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.tic.service.netty; - -import io.netty.channel.ChannelInitializer; -import io.netty.channel.ChannelPipeline; -import io.netty.channel.socket.SocketChannel; -import io.netty.handler.codec.http.HttpObjectAggregator; -import io.netty.handler.codec.http.HttpServerCodec; -import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler; -import io.netty.handler.codec.http.websocketx.extensions.compression.WebSocketServerCompressionHandler; -import io.netty.handler.stream.ChunkedWriteHandler; - -import enedis.tic.service.client.TIC2WebSocketClientPool; -import enedis.tic.service.requesthandler.TIC2WebSocketRequestHandler; - -/** - * Channel initializer for TIC2WebSocket server - */ -public class TIC2WebSocketChannelInitializer extends ChannelInitializer -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private static final String WEBSOCKET_PATH = "/"; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private final TIC2WebSocketClientPool clientPool; - private final TIC2WebSocketRequestHandler requestHandler; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Constructor - * - * @param clientPool the client pool - * @param requestHandler the request handler - */ - public TIC2WebSocketChannelInitializer(TIC2WebSocketClientPool clientPool, TIC2WebSocketRequestHandler requestHandler) - { - this.clientPool = clientPool; - this.requestHandler = requestHandler; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - protected void initChannel(SocketChannel ch) throws Exception - { - ChannelPipeline pipeline = ch.pipeline(); - - // HTTP codec - pipeline.addLast(new HttpServerCodec()); - - // HTTP object aggregator - pipeline.addLast(new HttpObjectAggregator(65536)); - - // Chunked write handler for large messages - pipeline.addLast(new ChunkedWriteHandler()); - - // WebSocket compression - pipeline.addLast(new WebSocketServerCompressionHandler()); - - // WebSocket protocol handler - pipeline.addLast(new WebSocketServerProtocolHandler(WEBSOCKET_PATH, null, true)); - - // Custom TIC2WebSocket handler - pipeline.addLast(new TIC2WebSocketHandler(clientPool, requestHandler)); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -} diff --git a/src/main/java/enedis/tic/service/netty/TIC2WebSocketHandler.java b/src/main/java/enedis/tic/service/netty/TIC2WebSocketHandler.java deleted file mode 100644 index 65ae2a9..0000000 --- a/src/main/java/enedis/tic/service/netty/TIC2WebSocketHandler.java +++ /dev/null @@ -1,322 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.tic.service.netty; - -import java.util.List; -import java.util.Optional; - -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.SimpleChannelInboundHandler; -import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; -import io.netty.handler.codec.http.websocketx.WebSocketFrame; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import enedis.lab.types.DataDictionaryException; -import enedis.lab.util.message.Event; -import enedis.lab.util.message.Message; -import enedis.lab.util.message.Request; -import enedis.lab.util.message.Response; -import enedis.lab.util.message.exception.MessageInvalidContentException; -import enedis.lab.util.message.exception.MessageInvalidFormatException; -import enedis.lab.util.message.exception.MessageInvalidTypeException; -import enedis.lab.util.message.exception.MessageKeyNameDoesntExistException; -import enedis.lab.util.message.exception.MessageKeyTypeDoesntExistException; -import enedis.lab.util.message.exception.UnsupportedMessageException; -import enedis.tic.core.TICIdentifier; -import enedis.tic.service.client.TIC2WebSocketClient; -import enedis.tic.service.client.TIC2WebSocketClientPool; -import enedis.tic.service.endpoint.EventSender; -import enedis.tic.service.endpoint.TIC2WebSocketEndPointErrorCode; -import enedis.tic.service.message.RequestUnsubscribeTIC; -import enedis.tic.service.message.factory.TIC2WebSocketMessageFactory; -import enedis.tic.service.requesthandler.TIC2WebSocketRequestHandler; - -/** - * Netty WebSocket handler for TIC2WebSocket - */ -public class TIC2WebSocketHandler extends SimpleChannelInboundHandler implements EventSender -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private static final Logger logger = LogManager.getLogger(TIC2WebSocketHandler.class); - - private final TIC2WebSocketClientPool clientPool; - private final TIC2WebSocketRequestHandler requestHandler; - private final TIC2WebSocketMessageFactory factory; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Constructor - * - * @param clientPool the client pool - * @param requestHandler the request handler - */ - public TIC2WebSocketHandler(TIC2WebSocketClientPool clientPool, TIC2WebSocketRequestHandler requestHandler) - { - this.clientPool = clientPool; - this.requestHandler = requestHandler; - this.factory = new TIC2WebSocketMessageFactory(); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// EventSender - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public void sendEvent(Channel channel, Event event) - { - this.sendMessage(channel, event); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public void channelActive(ChannelHandlerContext ctx) throws Exception - { - Channel channel = ctx.channel(); - String channelId = channel.id().asLongText(); - - logger.info("Open channel " + channelId); - - if (!clientPool.exists(channelId)) - { - logger.info("Client create with channel id : " + channelId); - clientPool.createClient(channel, this); - } - else - { - logger.error("Client with channel id : " + channelId + " already exists ! "); - } - - super.channelActive(ctx); - } - - @Override - public void channelInactive(ChannelHandlerContext ctx) throws Exception - { - Channel channel = ctx.channel(); - String channelId = channel.id().asLongText(); - - logger.info("Close channel " + channelId); - - if (clientPool.exists(channelId)) - { - try - { - logger.info("Generate unsubscribe request"); - Request request = new RequestUnsubscribeTIC((List) null); - this.handleRequest(clientPool.getClient(channelId).get(), request); - - logger.info("Remove client with channel id : " + channelId); - clientPool.remove(channelId); - } - catch (DataDictionaryException e) - { - logger.error("Error during channel close", e); - } - } - else - { - logger.error("Client with channel id : " + channelId + " doesn't exist ! "); - } - - super.channelInactive(ctx); - } - - @Override - public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception - { - Channel channel = ctx.channel(); - String channelId = channel.id().asLongText(); - - logger.error("Error on channel " + channelId, cause); - - ctx.close(); - } - - @Override - protected void channelRead0(ChannelHandlerContext ctx, WebSocketFrame frame) throws Exception - { - if (frame instanceof TextWebSocketFrame) - { - TextWebSocketFrame textFrame = (TextWebSocketFrame) frame; - String text = textFrame.text(); - Channel channel = ctx.channel(); - String channelId = channel.id().asLongText(); - - logger.info("Message on channel " + channelId); - - TIC2WebSocketClient client = this.getClient(channel); - - Optional message = this.getMessage(channel, text); - if (!message.isPresent()) - { - return; - } - - Optional request = this.getRequest(channel, message.get()); - if (!request.isPresent()) - { - return; - } - - Response response = this.handleRequest(client, request.get()); - - this.sendMessage(channel, response); - } - else - { - // Handle other frame types if needed - logger.warn("Unsupported frame type: " + frame.getClass().getSimpleName()); - } - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private TIC2WebSocketClient getClient(Channel channel) - { - String channelId = channel.id().asLongText(); - Optional clientOpt = clientPool.getClient(channelId); - if (!clientOpt.isPresent()) - { - return clientPool.createClient(channel, this); - } - return clientOpt.get(); - } - - private Optional getMessage(Channel channel, String text) - { - Message message = null; - TIC2WebSocketEndPointErrorCode errorCode = TIC2WebSocketEndPointErrorCode.NO_ERROR; - String errorMessage = ""; - - try - { - message = this.factory.getMessage(text); - } - catch (MessageInvalidFormatException e) - { - errorCode = TIC2WebSocketEndPointErrorCode.INVALID_MESSAGE_FORMAT; - errorMessage = e.getMessage(); - } - catch (MessageInvalidTypeException e) - { - errorCode = TIC2WebSocketEndPointErrorCode.MESSAGE_TYPE_INVALID; - errorMessage = e.getMessage(); - } - catch (MessageKeyNameDoesntExistException e) - { - errorCode = TIC2WebSocketEndPointErrorCode.MESSAGE_NAME_MISSING; - errorMessage = e.getMessage(); - } - catch (MessageKeyTypeDoesntExistException e) - { - errorCode = TIC2WebSocketEndPointErrorCode.MESSAGE_TYPE_MISSING; - errorMessage = e.getMessage(); - } - catch (MessageInvalidContentException e) - { - errorCode = TIC2WebSocketEndPointErrorCode.INVALID_MESSAGE_CONTENT; - errorMessage = e.getMessage(); - } - catch (UnsupportedMessageException e) - { - errorCode = TIC2WebSocketEndPointErrorCode.UNSUPPORTED_MESSAGE; - errorMessage = e.getMessage(); - } - - if (errorCode != TIC2WebSocketEndPointErrorCode.NO_ERROR) - { - logger.error("Error parsing message: " + errorMessage); - // TODO: Send error event - return Optional.empty(); - } - - return Optional.of(message); - } - - private Optional getRequest(Channel channel, Message message) - { - if (!(message instanceof Request)) - { - logger.error("Message is not a request"); - // TODO: Send error event - return Optional.empty(); - } - - return Optional.of((Request) message); - } - - private Response handleRequest(TIC2WebSocketClient client, Request request) - { - return requestHandler.handle(request, client); - } - - private void sendMessage(Channel channel, Message message) - { - try - { - String json = message.toJSON().toString(); - TextWebSocketFrame frame = new TextWebSocketFrame(json); - channel.writeAndFlush(frame); - - logger.debug("Sent message to channel {}: {}", channel.id().asLongText(), json); - } - catch (Exception e) - { - logger.error("Error sending message to channel " + channel.id().asLongText(), e); - } - } -} diff --git a/src/main/java/enedis/tic/service/netty/TIC2WebSocketServer.java b/src/main/java/enedis/tic/service/netty/TIC2WebSocketServer.java deleted file mode 100644 index 2c22b8d..0000000 --- a/src/main/java/enedis/tic/service/netty/TIC2WebSocketServer.java +++ /dev/null @@ -1,190 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.tic.service.netty; - -import io.netty.bootstrap.ServerBootstrap; -import io.netty.channel.Channel; -import io.netty.channel.ChannelFuture; -import io.netty.channel.EventLoopGroup; -import io.netty.channel.nio.NioEventLoopGroup; -import io.netty.channel.socket.nio.NioServerSocketChannel; -import io.netty.handler.logging.LogLevel; -import io.netty.handler.logging.LoggingHandler; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import enedis.tic.service.client.TIC2WebSocketClientPool; -import enedis.tic.service.requesthandler.TIC2WebSocketRequestHandler; - -/** - * TIC2WebSocket Netty WebSocket Server - */ -public class TIC2WebSocketServer -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private static final Logger logger = LogManager.getLogger(TIC2WebSocketServer.class); - - private final String host; - private final int port; - private final TIC2WebSocketClientPool clientPool; - private final TIC2WebSocketRequestHandler requestHandler; - - private EventLoopGroup bossGroup; - private EventLoopGroup workerGroup; - private Channel serverChannel; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Constructor - * - * @param host the host to bind to - * @param port the port to bind to - * @param clientPool the client pool - * @param requestHandler the request handler - */ - public TIC2WebSocketServer(String host, int port, TIC2WebSocketClientPool clientPool, TIC2WebSocketRequestHandler requestHandler) - { - this.host = host; - this.port = port; - this.clientPool = clientPool; - this.requestHandler = requestHandler; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Start the WebSocket server - * - * @throws Exception if server startup fails - */ - public void start() throws Exception - { - logger.info("Starting TIC2WebSocket Netty server on {}:{}", host, port); - - bossGroup = new NioEventLoopGroup(1); - workerGroup = new NioEventLoopGroup(); - - try - { - ServerBootstrap bootstrap = new ServerBootstrap(); - bootstrap.group(bossGroup, workerGroup) - .channel(NioServerSocketChannel.class) - .handler(new LoggingHandler(LogLevel.INFO)) - .childHandler(new TIC2WebSocketChannelInitializer(clientPool, requestHandler)); - - ChannelFuture future = bootstrap.bind(host, port).sync(); - serverChannel = future.channel(); - - logger.info("TIC2WebSocket Netty server started successfully on {}:{}", host, port); - } - catch (Exception e) - { - logger.error("Failed to start TIC2WebSocket Netty server", e); - stop(); - throw e; - } - } - - /** - * Stop the WebSocket server - */ - public void stop() - { - logger.info("Stopping TIC2WebSocket Netty server"); - - try - { - if (serverChannel != null) - { - serverChannel.close().sync(); - } - } - catch (InterruptedException e) - { - logger.warn("Interrupted while closing server channel", e); - Thread.currentThread().interrupt(); - } - finally - { - if (bossGroup != null) - { - bossGroup.shutdownGracefully(); - } - if (workerGroup != null) - { - workerGroup.shutdownGracefully(); - } - } - - logger.info("TIC2WebSocket Netty server stopped"); - } - - /** - * Wait for the server to close - * - * @throws InterruptedException if interrupted while waiting - */ - public void waitForClose() throws InterruptedException - { - if (serverChannel != null) - { - serverChannel.closeFuture().sync(); - } - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -} diff --git a/src/main/java/enedis/tic/service/requesthandler/TIC2WebSocketRequestHandler.java b/src/main/java/enedis/tic/service/requesthandler/TIC2WebSocketRequestHandler.java deleted file mode 100644 index da0f444..0000000 --- a/src/main/java/enedis/tic/service/requesthandler/TIC2WebSocketRequestHandler.java +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.tic.service.requesthandler; - -import enedis.lab.util.message.Request; -import enedis.lab.util.message.Response; -import enedis.tic.service.client.TIC2WebSocketClient; - -/** - * TIC2WebSocket request handler interface - */ -public interface TIC2WebSocketRequestHandler -{ - /** - * Handle all TIC2WebSocket request - * - * @param request - * @param client - * @return request response - */ - public Response handle(Request request, TIC2WebSocketClient client); -} diff --git a/src/main/java/enedis/tic/service/requesthandler/TIC2WebSocketRequestHandlerBase.java b/src/main/java/enedis/tic/service/requesthandler/TIC2WebSocketRequestHandlerBase.java deleted file mode 100644 index 22f623b..0000000 --- a/src/main/java/enedis/tic/service/requesthandler/TIC2WebSocketRequestHandlerBase.java +++ /dev/null @@ -1,341 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.tic.service.requesthandler; - -import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import enedis.lab.io.tic.TICPortDescriptor; -import enedis.lab.types.DataDictionaryException; -import enedis.lab.util.message.Request; -import enedis.lab.util.message.Response; -import enedis.lab.util.message.ResponseBase; -import enedis.tic.core.TICCore; -import enedis.tic.core.TICCoreErrorCode; -import enedis.tic.core.TICCoreException; -import enedis.tic.core.TICCoreFrame; -import enedis.tic.core.TICIdentifier; -import enedis.tic.service.client.TIC2WebSocketClient; -import enedis.tic.service.endpoint.TIC2WebSocketEndPointErrorCode; -import enedis.tic.service.message.RequestGetAvailableTICs; -import enedis.tic.service.message.RequestGetModemsInfo; -import enedis.tic.service.message.RequestReadTIC; -import enedis.tic.service.message.RequestSubscribeTIC; -import enedis.tic.service.message.RequestUnsubscribeTIC; -import enedis.tic.service.message.ResponseGetAvailableTICs; -import enedis.tic.service.message.ResponseGetModemsInfo; -import enedis.tic.service.message.ResponseReadTIC; -import enedis.tic.service.message.ResponseSubscribeTIC; -import enedis.tic.service.message.ResponseUnsubscribeTIC; - -/** - * TIC2WebSocket client pool interface - */ -public class TIC2WebSocketRequestHandlerBase implements TIC2WebSocketRequestHandler -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private Logger logger; - private TICCore ticCore; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Default constructor - * - * @param ticCore - */ - public TIC2WebSocketRequestHandlerBase(TICCore ticCore) - { - super(); - this.logger = LogManager.getLogger(this.getClass()); - this.ticCore = ticCore; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// interfaceName - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public Response handle(Request request, TIC2WebSocketClient client) - { - Response response = null; - - switch (request.getName()) - { - case RequestGetAvailableTICs.NAME: - response = this.handleGetAvailableTICsRequest((RequestGetAvailableTICs) request); - break; - case RequestGetModemsInfo.NAME: - response = this.handleGetModemsInfoRequest((RequestGetModemsInfo) request); - break; - case RequestReadTIC.NAME: - response = this.handleReadTICRequest((RequestReadTIC) request); - break; - case RequestSubscribeTIC.NAME: - response = this.handleSubscribeTICRequest((RequestSubscribeTIC) request, client); - break; - case RequestUnsubscribeTIC.NAME: - response = this.handleUnsubscribeTICRequest((RequestUnsubscribeTIC) request, client); - break; - default: - this.logger.error("Request " + request.getName() + " not supported"); - response = this.createErrorResponse(request.getName(), TIC2WebSocketEndPointErrorCode.UNSUPPORTED_MESSAGE, "Request " + request.getName() + " not supported"); - break; - } - - return response; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private Response handleGetAvailableTICsRequest(RequestGetAvailableTICs request) - { - List ticIdentifiers = this.ticCore.getAvailableTICs(); - - Response response = null; - try - { - response = new ResponseGetAvailableTICs(LocalDateTime.now(), TIC2WebSocketEndPointErrorCode.NO_ERROR.value(), null, ticIdentifiers); - } - catch (DataDictionaryException e) - { - this.logger.error(e.getMessage(), e); - response = this.createErrorResponse(request.getName(), TIC2WebSocketEndPointErrorCode.INTERNAL_ERROR, e.getMessage()); - } - - return response; - } - - private Response handleGetModemsInfoRequest(RequestGetModemsInfo request) - { - List modemsInfo = this.ticCore.getModemsInfo(); - - Response response = null; - try - { - response = new ResponseGetModemsInfo(LocalDateTime.now(), TIC2WebSocketEndPointErrorCode.NO_ERROR.value(), null, modemsInfo); - } - catch (DataDictionaryException e) - { - this.logger.error(e.getMessage(), e); - response = this.createErrorResponse(request.getName(), TIC2WebSocketEndPointErrorCode.INTERNAL_ERROR, e.getMessage()); - } - - return response; - } - - private Response handleReadTICRequest(RequestReadTIC request) - { - Response response = null; - try - { - TICCoreFrame frame = this.ticCore.readNextFrame(request.getData()); - response = new ResponseReadTIC(LocalDateTime.now(), TIC2WebSocketEndPointErrorCode.NO_ERROR.value(), null, frame); - } - catch (DataDictionaryException e) - { - this.logger.error(e.getMessage(), e); - response = this.createErrorResponse(request.getName(), TIC2WebSocketEndPointErrorCode.INTERNAL_ERROR, e.getMessage()); - } - catch (TICCoreException e) - { - if(e.getErrorCode() == TICCoreErrorCode.STREAM_IDENTIFIER_NOT_FOUND.getCode()) - { - response = this.createErrorResponse(request.getName(), TIC2WebSocketEndPointErrorCode.IDENTIFIER_NOT_FOUND, e.getMessage()); - } - else if(e.getErrorCode() == TICCoreErrorCode.DATA_READ_TIMEOUT.getCode()) - { - response = this.createErrorResponse(request.getName(), TIC2WebSocketEndPointErrorCode.READ_TIMEOUT, e.getMessage()); - } - else - { - response = this.createErrorResponse(request.getName(), TIC2WebSocketEndPointErrorCode.INTERNAL_ERROR, e.getMessage()); - } - } - - return response; - } - - private Response handleSubscribeTICRequest(RequestSubscribeTIC request, TIC2WebSocketClient client) - { - Response response = null; - Optional> ticIdentifiers = Optional.ofNullable(request.getData()); - - if (ticIdentifiers.isPresent()) - { - List newSubscriptions = this.getNewSubcriptions(this.ticCore.getIndentifiers(client), ticIdentifiers.get()); - if(!newSubscriptions.isEmpty()) - { - for(TICIdentifier identifier : ticIdentifiers.get()) - { - try - { - this.ticCore.subscribe(identifier,client); - try - { - response = new ResponseSubscribeTIC(LocalDateTime.now(), TIC2WebSocketEndPointErrorCode.NO_ERROR.value(), null); - } - catch (DataDictionaryException e) - { - this.logger.error(e.getMessage(), e); - } - } - catch (TICCoreException e) - { - response = this.createErrorResponse(request.getName(), TIC2WebSocketEndPointErrorCode.SUBSCRIPTION_FAIL, e.getMessage()); - } - } - } - } - else - { - this.ticCore.subscribe(client); - try - { - response = new ResponseSubscribeTIC(LocalDateTime.now(), TIC2WebSocketEndPointErrorCode.NO_ERROR.value(), null); - } - catch (DataDictionaryException e) - { - this.logger.error(e.getMessage(), e); - } - } - - return response; - } - - private List getNewSubcriptions(List currentSubscriptions, List askedTicIdentifiers) - { - List newSubscriptions = new ArrayList(); - - for (TICIdentifier askedTicIdentifier : askedTicIdentifiers) - { - boolean newSub = true; - for (TICIdentifier currentSubscription : currentSubscriptions) - { - if (askedTicIdentifier.matches(currentSubscription)) - { - newSub = false; - break; - } - } - if (newSub) - { - newSubscriptions.add(askedTicIdentifier); - } - } - return newSubscriptions; - } - - private Response handleUnsubscribeTICRequest(RequestUnsubscribeTIC request, TIC2WebSocketClient client) - { - Response response = null; - Optional> ticIdentifiers = Optional.ofNullable(request.getData()); - - if (ticIdentifiers.isPresent()) - { - for(TICIdentifier identifier : ticIdentifiers.get()) - { - try - { - this.ticCore.unsubscribe(identifier,client); - try - { - response = new ResponseUnsubscribeTIC(LocalDateTime.now(), TIC2WebSocketEndPointErrorCode.NO_ERROR.value(), null); - } - catch (DataDictionaryException e) - { - this.logger.error(e.getMessage(), e); - } - } - catch (TICCoreException e) - { - response = this.createErrorResponse(request.getName(), TIC2WebSocketEndPointErrorCode.UNSUBSCRIPTION_FAIL, e.getMessage()); - } - } - } - else - { - this.ticCore.unsubscribe(client); - try - { - response = new ResponseUnsubscribeTIC(LocalDateTime.now(), TIC2WebSocketEndPointErrorCode.NO_ERROR.value(), null); - } - catch (DataDictionaryException e) - { - this.logger.error(e.getMessage(), e); - } - } - - return response; - } - - private Response createErrorResponse(String name, TIC2WebSocketEndPointErrorCode code, String message) - { - try - { - return new ResponseBase(name, LocalDateTime.now(), code.value(), message, null); - } - catch (DataDictionaryException e) - { - this.logger.error(e.getMessage(), e); - return null; - } - } - -} diff --git a/src/main/java/tic/core/ReadNextFrameSubscriber.java b/src/main/java/tic/core/ReadNextFrameSubscriber.java new file mode 100644 index 0000000..7ee9ae3 --- /dev/null +++ b/src/main/java/tic/core/ReadNextFrameSubscriber.java @@ -0,0 +1,57 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.core; + +/** + * Subscriber implementation for receiving the next frame and error notifications. + * + *

This class listens for frame and error events, storing the latest received frame or error. It + * provides methods to access the received data and to clear its state. + * + *

Common use cases include: + * + *

    + *
  • Receiving and processing the next available frame + *
  • Handling error notifications + *
  • Resetting subscriber state for reuse + *
+ * + * @author Enedis Smarties team + */ +public class ReadNextFrameSubscriber implements TICCoreSubscriber { + private TICCoreFrame frame; + private TICCoreError error; + + public ReadNextFrameSubscriber() { + super(); + this.clear(); + } + + @Override + public void onData(TICCoreFrame frame) { + this.frame = frame; + } + + @Override + public void onError(TICCoreError error) { + this.error = error; + } + + public TICCoreFrame getData() { + return this.frame; + } + + public TICCoreError getError() { + return this.error; + } + + public void clear() { + this.frame = null; + this.error = null; + } +} diff --git a/src/main/java/tic/core/TICCore.java b/src/main/java/tic/core/TICCore.java new file mode 100644 index 0000000..38a96b7 --- /dev/null +++ b/src/main/java/tic/core/TICCore.java @@ -0,0 +1,105 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.core; + +import java.util.List; +import tic.io.modem.ModemDescriptor; +import tic.util.task.Task; + +/** + * Core interface for managing frame reading and subscriber notifications. + * + *

This interface defines methods for reading frames, managing subscribers, and retrieving modem + * information. + * + *

Common use cases include: + * + *

    + *
  • Reading frames from available sources + *
  • Managing and notifying subscribers + *
  • Retrieving modem and identifier information + *
+ * + * @author Enedis Smarties team + */ +public interface TICCore extends Task { + /** + * Get available TICs + * + * @return The collection of TIC identifiers + */ + public List getAvailableTICs(); + + /** + * Get modems informations + * + * @return The collection of TIC port descriptors + */ + public List getModemsInfo(); + + /** + * Read next frame + * + * @param identifier the TIC identifier + * @return Frame read or null if timed out + * @throws TICCoreException if identifier not found or if any error occurs + */ + public TICCoreFrame readNextFrame(TICIdentifier identifier) throws TICCoreException; + + /** + * Read next frame + * + * @param identifier the TIC identifier + * @param timeout the read timeout in milliseconds + * @return Frame read or null if timed out + * @throws TICCoreException if identifier not found or if any error occurs + */ + public TICCoreFrame readNextFrame(TICIdentifier identifier, int timeout) throws TICCoreException; + + /** + * Add a subscriber + * + * @param subscriber + */ + public void subscribe(TICCoreSubscriber subscriber); + + /** + * Remove a subscriber + * + * @param subscriber + */ + public void unsubscribe(TICCoreSubscriber subscriber); + + /** + * Add a subscriber with identifier + * + * @param identifier the identifier used for subscription + * @param listener the subscriber reference + * @throws Exception on subscription failure + */ + public void subscribe(TICIdentifier identifier, TICCoreSubscriber listener) + throws TICCoreException; + + /** + * Remove a subscriber with identifier + * + * @param identifier the identifier used for subscription + * @param listener the subscriber reference + * @throws Exception if filter or listener not found + */ + public void unsubscribe(TICIdentifier identifier, TICCoreSubscriber listener) + throws TICCoreException; + + /** + * Get TICs identifier associated with a subscriber + * + * @param listener the subscriber reference + * @return The collection of TIC identifiers for the subscriber + */ + public List getIndentifiers(TICCoreSubscriber listener); +} diff --git a/src/main/java/tic/core/TICCoreBase.java b/src/main/java/tic/core/TICCoreBase.java new file mode 100644 index 0000000..4a2cc9b --- /dev/null +++ b/src/main/java/tic/core/TICCoreBase.java @@ -0,0 +1,524 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.core; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.function.Predicate; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import tic.core.codec.TICCoreErrorCodec; +import tic.core.codec.TICCoreFrameCodec; +import tic.frame.TICMode; +import tic.io.PlugSubscriber; +import tic.io.modem.ModemDescriptor; +import tic.io.modem.ModemFinder; +import tic.io.modem.ModemFinderBase; +import tic.io.modem.ModemJsonCodec; +import tic.io.modem.ModemPlugNotifier; +import tic.io.serialport.SerialPortFinderBase; +import tic.io.usb.UsbPortFinderBase; +import tic.util.task.FilteredNotifier; +import tic.util.task.FilteredNotifierBase; +import tic.util.task.Task; +import tic.util.task.TaskBase; +import tic.util.time.Time; + +/** + * Core implementation for managing frame reading and subscriber notifications. + * + *

This class provides mechanisms for reading frames, managing streams, handling subscribers, and + * notifying events. It implements the core contract for frame acquisition and event delivery. + * + *

Common use cases include: + * + *

    + *
  • Reading frames from available sources + *
  • Managing and notifying subscribers + *
  • Handling stream lifecycle and modem events + *
+ * + * @author Enedis Smarties team + */ +public class TICCoreBase implements TICCore, TICCoreSubscriber, PlugSubscriber { + private static final int PLUG_NOTIFIER_POLLING_PERIOD = 100; + private static final int READ_NEXT_FRAME_TIMEOUT = 30000; + private static final int READ_NEXT_FRAME_POLLING_PERIOD = 100; + + private ModemFinder modemFinder; + private ModemPlugNotifier plugNotifier; + private long plugNotifierPeriod; + private TICMode streamMode; + private List nativePortNamesOnStart; + private Collection streamList; + private FilteredNotifier eventNotifier; + private static Logger logger = LogManager.getLogger(); + + public TICCoreBase() { + this(TICMode.AUTO, null); + } + + public TICCoreBase(TICMode streamMode, List nativePortNamesStart) { + this( + ModemFinderBase.create(SerialPortFinderBase.getInstance(), UsbPortFinderBase.getInstance()), + PLUG_NOTIFIER_POLLING_PERIOD, + streamMode, + nativePortNamesStart); + } + + public TICCoreBase( + ModemFinder modemFinder, + long plugNotifierPeriod, + TICMode streamMode, + List nativePortNamesOnStart) { + super(); + this.modemFinder = modemFinder; + this.plugNotifierPeriod = plugNotifierPeriod; + if (streamMode == null) { + throw new IllegalArgumentException("TICMode should be defined"); + } + this.streamMode = streamMode; + this.nativePortNamesOnStart = nativePortNamesOnStart; + this.streamList = Collections.synchronizedSet(new HashSet()); + this.eventNotifier = new FilteredNotifierBase(); + } + + @Override + public List getAvailableTICs() { + List identifiers = new ArrayList<>(); + + for (TICCoreStream stream : this.streamList) { + if (stream == null) { + continue; + } + + TICIdentifier identifier = stream.getIdentifier(); + if (!identifiers.contains(identifier)) { + identifiers.add(identifier); + } + } + + return identifiers; + } + + @Override + public List getModemsInfo() { + List descriptors = new ArrayList<>(); + + for (TICCoreStream stream : this.streamList) { + if (stream == null) { + continue; + } + + TICIdentifier identifier = stream.getIdentifier(); + ModemDescriptor descriptor = null; + if (identifier != null && identifier.getPortName() != null) { + descriptor = this.modemFinder.findByPortName(identifier.getPortName()); + } + if (!descriptors.contains(descriptor)) { + descriptors.add(descriptor); + } + } + + return descriptors; + } + + @Override + public TICCoreFrame readNextFrame(TICIdentifier identifier) throws TICCoreException { + return this.readNextFrame(identifier, READ_NEXT_FRAME_TIMEOUT); + } + + @Override + public TICCoreFrame readNextFrame(TICIdentifier identifier, int timeout) throws TICCoreException { + TICCoreFrame frame = null; + ModemDescriptor descriptor = null; + TICCoreStream stream = this.findStream(identifier); + + if (stream == null) { + descriptor = this.modemFinder.findNative(identifier.getPortName()); + if (descriptor == null) { + TICCoreException exception = + new TICCoreException( + TICCoreErrorCode.STREAM_IDENTIFIER_NOT_FOUND.getCode(), + "Stream " + identifier + " not found!"); + logger.error(exception.getMessage()); + throw exception; + } + stream = this.startNewStream(descriptor); + } + ReadNextFrameSubscriber subscriber = new ReadNextFrameSubscriber(); + stream.subscribe(subscriber); + + long begin = System.nanoTime(); + long elapsed = 0; + while (elapsed < timeout) { + if (subscriber.getError() != null) { + TICCoreException exception = + new TICCoreException( + subscriber.getError().getErrorCode().intValue(), + subscriber.getError().getErrorMessage()); + logger.error(exception.getMessage()); + stream.unsubscribe(subscriber); + this.closeNativeStream(identifier, stream, subscriber); + throw exception; + } + if (subscriber.getData() != null) { + frame = subscriber.getData(); + break; + } + Time.sleep(READ_NEXT_FRAME_POLLING_PERIOD); + elapsed = (System.nanoTime() - begin) / 1000000; + } + stream.unsubscribe(subscriber); + this.closeNativeStream(identifier, stream, subscriber); + if (elapsed >= timeout) { + TICCoreException exception = + new TICCoreException( + TICCoreErrorCode.DATA_READ_TIMEOUT.getCode(), + "Stream " + identifier + " data read timeout !"); + logger.error(exception.getMessage()); + throw exception; + } + return frame; + } + + @Override + public void subscribe(TICIdentifier identifier, TICCoreSubscriber subscriber) + throws TICCoreException { + TICCoreStream stream = this.findStream(identifier); + + if (stream == null) { + ModemDescriptor descriptor = this.modemFinder.findNative(identifier.getPortName()); + if (descriptor == null) { + TICCoreException exception = + new TICCoreException( + TICCoreErrorCode.STREAM_IDENTIFIER_NOT_FOUND.getCode(), + "Stream " + identifier + " not found!"); + logger.error(exception.getMessage(), exception); + throw exception; + } + this.startNewStream(descriptor); + } + try { + this.eventNotifier.subscribe(identifier, subscriber); + } catch (Exception e) { + logger.error(e.getMessage(), e); + } + } + + @Override + public void unsubscribe(TICIdentifier identifier, TICCoreSubscriber subscriber) + throws TICCoreException { + ModemDescriptor descriptor = this.modemFinder.findNative(identifier.getPortName()); + if (descriptor != null) { + if (this.nativePortNamesOnStart == null + || !this.nativePortNamesOnStart.contains(identifier.getPortName())) { + Collection subscribers = this.findSubscribers(identifier, false); + if (subscribers.contains(subscriber) && subscribers.size() == 1) { + this.stopStream(descriptor); + } + } + } + try { + this.eventNotifier.unsubscribe(identifier, subscriber); + } catch (Exception e) { + logger.error(e.getMessage(), e); + } + } + + @Override + public void subscribe(TICCoreSubscriber subscriber) { + this.eventNotifier.subscribe(subscriber); + } + + @Override + public void unsubscribe(TICCoreSubscriber subscriber) { + this.eventNotifier.unsubscribe(subscriber); + } + + @Override + public List getIndentifiers(TICCoreSubscriber listener) { + List identifiers = new ArrayList(); + + if (this.eventNotifier.getSubscribers(true, false).contains(listener)) { + identifiers.addAll(this.getAvailableTICs()); + } else if (this.eventNotifier.getSubscribers(false, true).contains(listener)) { + identifiers.addAll(this.eventNotifier.getFilters(listener)); + } + + return identifiers; + } + + @Override + public void onData(TICCoreFrame frame) { + try { + logger.trace("TICCore frame:\n" + TICCoreFrameCodec.getInstance().encodeToJsonString(frame)); + } catch (Exception e) { + logger.error("Error encoding TICCore frame to JSON string", e); + } + Collection subscriberList = + this.findSubscribers(frame.getIdentifier(), true); + Task task = + new TaskBase() { + @Override + public void process() { + TICCoreBase.this.notifyOnData(frame, subscriberList); + } + }; + task.start(); + } + + @Override + public void onError(TICCoreError error) { + try { + logger.trace("TICCore error:\n" + TICCoreErrorCodec.getInstance().encodeToJsonString(error)); + } catch (Exception e) { + logger.error("Error encoding TICCore error to JSON string", e); + } + Collection subscriberList = + this.findSubscribers(error.getIdentifier(), true); + Task task = + new TaskBase() { + public void process() { + TICCoreBase.this.notifyOnError(error, subscriberList); + } + }; + task.start(); + } + + @Override + public void onPlugged(ModemDescriptor descriptor) { + try { + logger.info("TICCore modem plugged:\n" + ModemJsonCodec.getInstance().encodeToJsonString(descriptor)); + } catch (Exception e) { + logger.error("Error encoding ModemDescriptor to JSON string", e); + } + this.startNewStream(descriptor); + } + + @Override + public void onUnplugged(ModemDescriptor descriptor) { + try { + logger.info("TICCore modem unplugged:\n" + ModemJsonCodec.getInstance().encodeToJsonString(descriptor)); + } catch (Exception e) { + logger.error("Error encoding ModemDescriptor to JSON string", e); + } + TICIdentifier identifier = this.stopStream(descriptor); + Task task = + new TaskBase() { + @Override + public void process() { + TICCoreBase.this.notifyOnUnpluggedAndUnsubscribe(identifier); + } + }; + task.start(); + } + + @Override + public void start() { + if (!this.isRunning()) { + logger.info("Starting TICCore"); + logger.debug("Starting TIC port plug notifier"); + this.plugNotifier = new ModemPlugNotifier(this.plugNotifierPeriod, this.modemFinder); + this.plugNotifier.subscribe(this); + this.plugNotifier.start(); + logger.debug("TIC port plug notifier started"); + if (this.nativePortNamesOnStart != null && this.nativePortNamesOnStart.size() > 0) { + logger.debug( + "Starting natives TIC port: " + Arrays.toString(this.nativePortNamesOnStart.toArray())); + for (String portName : this.nativePortNamesOnStart) { + ModemDescriptor descriptor = this.modemFinder.findNative(portName); + try { + logger.debug( + "Starting native TIC port " + portName + " : " + ModemJsonCodec.getInstance().encodeToJsonString(descriptor)); + } catch (Exception e) { + logger.error("Error encoding ModemDescriptor to JSON string", e); + } + if (descriptor != null && this.findStream(descriptor) == null) { + this.startNewStream(descriptor); + } + } + } + } + } + + @Override + public void stop() { + logger.info("Stopping TICCore"); + logger.debug("Stopping TIC port plug notifier"); + this.plugNotifier.unsubscribe(this); + this.plugNotifier.stop(); + logger.debug("Stopping all streams"); + for (TICCoreStream stream : this.streamList) { + stream.unsubscribe(this); + stream.stop(); + } + this.streamList.clear(); + logger.debug("Removing all subscribers"); + this.unsubscribe(this.eventNotifier.getSubscribers()); + } + + @Override + public boolean isRunning() { + return (this.plugNotifier != null) ? this.plugNotifier.isRunning() : false; + } + + private TICCoreStream findStream(TICIdentifier identifier) { + for (TICCoreStream stream : this.streamList) { + if (stream.getIdentifier().matches(identifier)) { + return stream; + } + } + + return null; + } + + private TICCoreStream findStream(ModemDescriptor descriptor) { + for (TICCoreStream stream : this.streamList) { + TICIdentifier identifier = stream.getIdentifier(); + if (descriptor.portId() != null && identifier.getPortId() != null) { + if (descriptor.portId().equals(identifier.getPortId())) { + return stream; + } + } + if (descriptor.portName() != null && identifier.getPortName() != null) { + if (descriptor.portName().equals(identifier.getPortName())) { + return stream; + } + } + } + + return null; + } + + private TICCoreStream startNewStream(ModemDescriptor descriptor) { + if (descriptor == null) { + return null; + } + + TICCoreStream existing = this.findStream(descriptor); + if (existing != null) { + if (existing.isRunning()) { + return existing; + } + this.streamList.remove(existing); + } + + try { + logger.debug("TICCore starting new stream : " + ModemJsonCodec.getInstance().encodeToJsonString(descriptor)); + } catch (Exception e) { + logger.error("Error encoding ModemDescriptor to JSON string", e); + } + try { + TICCoreStream stream = + TICCoreStreamBase.create( + descriptor.portId(), descriptor.portName(), this.streamMode, this.modemFinder); + + stream.subscribe(this); + stream.start(); + this.streamList.add(stream); + try { + logger.debug("TICCore started new stream : " + ModemJsonCodec.getInstance().encodeToJsonString(descriptor)); + } catch (Exception e) { + logger.error("Error encoding ModemDescriptor to JSON string", e); + } + return stream; + } catch (Exception e) { + logger.error(e.getMessage(), e); + return null; + } + } + + private TICIdentifier stopStream(ModemDescriptor descriptor) { + TICIdentifier identifier = null; + TICCoreStream stream = this.findStream(descriptor); + try { + logger.debug("TICCore stopping stream : " + ModemJsonCodec.getInstance().encodeToJsonString(descriptor)); + } catch (Exception e) { + logger.error("Error encoding ModemDescriptor to JSON string", e); + } + if (stream != null) { + identifier = stream.getIdentifier(); + stream.unsubscribe(this); + stream.stop(); + this.streamList.remove(stream); + try { + logger.debug("TICCore stopped stream : " + ModemJsonCodec.getInstance().encodeToJsonString(descriptor)); + } catch (Exception e) { + logger.error("Error encoding ModemDescriptor to JSON string", e); + } + } + + return identifier; + } + + private void closeNativeStream( + TICIdentifier identifier, TICCoreStream stream, ReadNextFrameSubscriber subscriber) { + ModemDescriptor nativeDescriptor = this.modemFinder.findNative(identifier.getPortName()); + if (nativeDescriptor != null) { + if (this.nativePortNamesOnStart == null + || !this.nativePortNamesOnStart.contains(identifier.getPortName())) { + Collection streamSubscribers = stream.getSubscribers(); + Collection ticCoreSubscribers = this.findSubscribers(identifier, false); + if (!streamSubscribers.contains(subscriber) + && streamSubscribers.contains(this) + && streamSubscribers.size() == 1 + && ticCoreSubscribers.size() == 0) { + this.stopStream(nativeDescriptor); + } + } + } + } + + private Collection findSubscribers( + TICIdentifier sourceIdentifier, boolean globalSubscribers) { + Predicate predicate = + new Predicate() { + @Override + public boolean test(TICIdentifier identifier) { + return sourceIdentifier.matches(identifier); + } + }; + + return this.eventNotifier.getSubscribers(predicate, globalSubscribers); + } + + private void notifyOnUnpluggedAndUnsubscribe(TICIdentifier identifier) { + TICCoreError error = + new TICCoreError( + identifier, + TICCoreErrorCode.STREAM_UNPLUGGED.getCode(), + "TICCore stream " + identifier + " has been unplugged (unsubscribe has been forced)"); + Collection subscriberList = this.findSubscribers(identifier, true); + this.notifyOnError(error, subscriberList); + subscriberList = this.findSubscribers(identifier, false); + this.unsubscribe(subscriberList); + } + + private void notifyOnData(TICCoreFrame frame, Collection subscriberList) { + for (TICCoreSubscriber subscriber : subscriberList) { + subscriber.onData(frame); + } + } + + private void notifyOnError(TICCoreError error, Collection subscriberList) { + for (TICCoreSubscriber subscriber : subscriberList) { + subscriber.onError(error); + } + } + + private void unsubscribe(Collection subscriberList) { + for (TICCoreSubscriber subscriber : subscriberList) { + this.unsubscribe(subscriber); + } + } +} diff --git a/src/main/java/tic/core/TICCoreError.java b/src/main/java/tic/core/TICCoreError.java new file mode 100644 index 0000000..85c4c0d --- /dev/null +++ b/src/main/java/tic/core/TICCoreError.java @@ -0,0 +1,112 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.core; + +import java.util.Objects; + +import tic.frame.TICFrame; + +/** + * Class representing a core error with identifier, code, message, and optional data. + * + *

This class provides mechanisms for constructing, accessing, and managing error information + * including error codes, messages, and associated data. It is designed for general-purpose error + * handling. + * + *

Common use cases include: + * + *

    + *
  • Representing errors with structured data + *
  • Managing error codes and messages + *
  • Associating additional data with errors + *
+ * + * @author Enedis Smarties team + */ +public class TICCoreError { + + private final TICIdentifier identifier; + private final Number errorCode; + private final String errorMessage; + private final TICFrame frame; + + /** + * Constructor setting parameters to specific values + * + * @param identifier + * @param errorCode + * @param errorMessage + */ + public TICCoreError(TICIdentifier identifier, Number errorCode, String errorMessage) { + this(identifier, errorCode, errorMessage, null); + } + + /** + * Constructor setting parameters to specific values + * + * @param identifier + * @param errorCode + * @param errorMessage + * @param frame + */ + public TICCoreError( + TICIdentifier identifier, Number errorCode, String errorMessage, TICFrame frame) { + this.identifier = Objects.requireNonNull(identifier, "identifier must not be null"); + this.errorCode = Objects.requireNonNull(errorCode, "errorCode must not be null"); + this.errorMessage = Objects.requireNonNull(errorMessage, "errorMessage must not be null"); + this.frame = frame; + } + + /** + * Get identifier + * + * @return the identifier + */ + public TICIdentifier getIdentifier() { + return this.identifier; + } + + /** + * Get error code + * + * @return the error code + */ + public Number getErrorCode() { + return this.errorCode; + } + + /** + * Get error message + * + * @return the error message + */ + public String getErrorMessage() { + return this.errorMessage; + } + + /** + * Get frame + * + * @return the frame + */ + public TICFrame getFrame() { + return this.frame; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("TICCoreError {\n"); + sb.append(" identifier: ").append(this.identifier).append(",\n"); + sb.append(" errorCode: ").append(this.errorCode).append(",\n"); + sb.append(" errorMessage: ").append(this.errorMessage).append(",\n"); + sb.append(" frame: ").append(this.frame).append("\n"); + sb.append("}"); + return sb.toString(); + } +} diff --git a/src/main/java/tic/core/TICCoreErrorCode.java b/src/main/java/tic/core/TICCoreErrorCode.java new file mode 100644 index 0000000..b25acf7 --- /dev/null +++ b/src/main/java/tic/core/TICCoreErrorCode.java @@ -0,0 +1,55 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.core; + +/** + * Enumeration of core error codes for error handling and diagnostics. + * + *

This enum defines error codes used to represent various error conditions in core operations. + * It provides a structured way to manage and interpret error states. + * + *

Common use cases include: + * + *

    + *
  • Representing error states in core logic + *
  • Supporting diagnostics and error reporting + *
  • Mapping error codes to messages + *
+ * + * @author Enedis Smarties team + */ +public enum TICCoreErrorCode { + /** No error occurred. */ + NO_ERROR(0), + /** The specified port ID was not found. */ + STREAM_PORT_ID_NOT_FOUND(1), + /** The specified port name was not found. */ + STREAM_PORT_NAME_NOT_FOUND(2), + /** The port descriptor is empty or missing required information. */ + STREAM_PORT_DESCRIPTOR_EMPTY(3), + /** The stream mode is not defined or invalid. */ + STREAM_MODE_NOT_DEFINED(4), + /** The stream identifier was not found or does not match any known stream. */ + STREAM_IDENTIFIER_NOT_FOUND(5), + /** The stream was unplugged or disconnected. */ + STREAM_UNPLUGGED(6), + /** Data read operation timed out before completion. */ + DATA_READ_TIMEOUT(7), + /** An error occurred for another or unspecified reason. */ + OTHER_REASON(99); + + private int code; + + private TICCoreErrorCode(int code) { + this.code = code; + } + + public int getCode() { + return this.code; + } +} diff --git a/src/main/java/tic/core/TICCoreException.java b/src/main/java/tic/core/TICCoreException.java new file mode 100644 index 0000000..815210f --- /dev/null +++ b/src/main/java/tic/core/TICCoreException.java @@ -0,0 +1,41 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.core; + +/** + * Exception class for representing core errors and failures. + * + *

This class provides mechanisms for constructing exceptions with error codes and messages, + * supporting structured error handling and reporting. + * + * @author Enedis Smarties team + */ +public class TICCoreException extends Exception { + private static final long serialVersionUID = -3285641164559292710L; + + private final int errorCode; + private final String errorInfo; + + public TICCoreException(int errorCode, String errorInfo) { + this.errorCode = errorCode; + this.errorInfo = errorInfo; + } + + @Override + public String getMessage() { + return this.errorInfo + " (" + this.errorCode + ")"; + } + + public int getErrorCode() { + return this.errorCode; + } + + public String getErrorInfo() { + return this.errorInfo; + } +} diff --git a/src/main/java/tic/core/TICCoreFrame.java b/src/main/java/tic/core/TICCoreFrame.java new file mode 100644 index 0000000..2904fc9 --- /dev/null +++ b/src/main/java/tic/core/TICCoreFrame.java @@ -0,0 +1,96 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.core; + +import java.time.LocalDateTime; +import java.util.Objects; +import tic.frame.TICFrame; +import tic.frame.TICMode; + +/** + * Class representing a core frame with identifier, mode, capture time, and content. + * + *

This class provides mechanisms for constructing, accessing, and managing frame information + * including identifiers, modes, timestamps, and associated content. It is designed for + * general-purpose frame handling. + * + *

Common use cases include: + * + *

    + *
  • Representing frames with structured data + *
  • Managing frame identifiers and modes + *
  • Associating content and timestamps with frames + *
+ * + * @author Enedis Smarties team + */ +public class TICCoreFrame { + + private final TICIdentifier identifier; + private final TICMode mode; + private final LocalDateTime captureDateTime; + private final TICFrame frame; + + public TICCoreFrame( + TICIdentifier identifier, TICMode mode, LocalDateTime captureDateTime, TICFrame frame) { + this.identifier = Objects.requireNonNull(identifier, "identifier must not be null"); + this.mode = Objects.requireNonNull(mode, "mode must not be null"); + this.captureDateTime = + Objects.requireNonNull(captureDateTime, "captureDateTime must not be null"); + this.frame = Objects.requireNonNull(frame, "frame must not be null"); + } + + /** + * Get identifier + * + * @return the identifier + */ + public TICIdentifier getIdentifier() { + return this.identifier; + } + + /** + * Get mode + * + * @return the mode + */ + public TICMode getMode() { + return this.mode; + } + + /** + * Get capture date time + * + * @return the capture date time + */ + public LocalDateTime getCaptureDateTime() { + return this.captureDateTime; + } + + /** + * Get content + * + * @return the content + */ + public TICFrame getFrame() { + return this.frame; + } + + @Override + public String toString() { + return "{identifier=" + + this.identifier + + ", mode=" + + this.mode + + ", captureDateTime=" + + this.captureDateTime + + ", frame=" + + this.frame + + "}"; + } +} diff --git a/src/main/java/tic/core/TICCoreStream.java b/src/main/java/tic/core/TICCoreStream.java new file mode 100644 index 0000000..b1351dd --- /dev/null +++ b/src/main/java/tic/core/TICCoreStream.java @@ -0,0 +1,36 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.core; + +import tic.util.task.Notifier; +import tic.util.task.Task; + +/** + * Interface for managing core streams, frame acquisition, and subscriber notifications. + * + *

This interface defines methods for accessing stream identifiers and managing subscribers. It + * provides a contract for implementations that handle frame delivery and event notification. + * + *

Common use cases include: + * + *

    + *
  • Acquiring frames from streams + *
  • Managing and notifying subscribers + *
  • Supporting event-driven stream operations + *
+ * + * @author Enedis Smarties team + */ +public interface TICCoreStream extends Notifier, Task { + /** + * Get identifier + * + * @return The TICIdentifier associated with the stream + */ + public TICIdentifier getIdentifier(); +} diff --git a/src/main/java/tic/core/TICCoreStreamBase.java b/src/main/java/tic/core/TICCoreStreamBase.java new file mode 100644 index 0000000..d569a23 --- /dev/null +++ b/src/main/java/tic/core/TICCoreStreamBase.java @@ -0,0 +1,277 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.core; + +import java.time.LocalDateTime; +import java.util.Collection; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import tic.frame.TICFrame; +import tic.frame.TICMode; +import tic.frame.group.TICGroup; +import tic.io.modem.ModemDescriptor; +import tic.io.modem.ModemFinder; +import tic.stream.TICStream; +import tic.stream.TICStreamListener; +import tic.stream.configuration.TICStreamConfiguration; +import tic.stream.identifier.SerialPortName; +import tic.stream.identifier.TICStreamIdentifier; +import tic.util.task.Notifier; +import tic.util.task.NotifierBase; +import tic.util.task.Task; +import tic.util.task.TaskBase; + +/** + * Core stream implementation for frame acquisition and subscriber notifications. + * + *

This class provides mechanisms for managing streams, acquiring frames, handling errors, and + * notifying subscribers. It implements the contract for event-driven stream operations. + * + *

Common use cases include: + * + *

    + *
  • Acquiring frames from streams + *
  • Managing and notifying subscribers + *
  • Handling errors and stream lifecycle + *
+ * + * @author Enedis Smarties team + */ +public class TICCoreStreamBase implements TICCoreStream { + + private final Object identifierLock = new Object(); + private TICIdentifier identifier; + private final TICStream stream; + private final TICStreamListener streamListener; + private final Notifier notifier; + private static Logger logger = LogManager.getLogger(); + + public static TICCoreStream create( + String portId, String portName, TICMode ticMode, ModemFinder modemFinder) + throws TICCoreException { + ModemDescriptor descriptor = null; + TICIdentifier identifier = null; + TICStream stream = null; + Notifier notifier = null; + + if (portId != null) { + descriptor = modemFinder.findByPortId(portId); + if (descriptor == null) { + TICCoreException exception = + new TICCoreException( + TICCoreErrorCode.STREAM_PORT_ID_NOT_FOUND.getCode(), + "TICCore stream port id " + portId + " not found!"); + logger.error(exception.getMessage(), exception); + throw exception; + } + } else if (portName != null) { + descriptor = modemFinder.findByPortName(portName); + if (descriptor == null) { + descriptor = modemFinder.findNative(portName); + if (descriptor == null) { + TICCoreException exception = + new TICCoreException( + TICCoreErrorCode.STREAM_PORT_NAME_NOT_FOUND.getCode(), + "TICCore stream port name " + portName + " not found!"); + logger.error(exception.getMessage(), exception); + throw exception; + } + } + } else { + TICCoreException exception = + new TICCoreException( + TICCoreErrorCode.STREAM_PORT_DESCRIPTOR_EMPTY.getCode(), + "TICCore stream port descriptor empty!"); + logger.error(exception.getMessage(), exception); + throw exception; + } + if (ticMode == null) { + TICCoreException exception = + new TICCoreException( + TICCoreErrorCode.STREAM_MODE_NOT_DEFINED.getCode(), + "TICCore stream mode not defined!"); + logger.error(exception.getMessage(), exception); + throw exception; + } + + String resolvedPortId = descriptor.portId(); + String resolvedPortName = descriptor.portName(); + if (resolvedPortName == null || resolvedPortName.trim().isEmpty()) { + TICCoreException exception = + new TICCoreException( + TICCoreErrorCode.STREAM_PORT_NAME_NOT_FOUND.getCode(), + "TICCore stream resolved port name is empty!"); + logger.error(exception.getMessage(), exception); + throw exception; + } + + identifier = + new TICIdentifier.Builder() + .portId(resolvedPortId) + .portName(resolvedPortName) + .build(); + notifier = new NotifierBase(); + + TICStreamIdentifier streamIdentifier = + new TICStreamIdentifier(new SerialPortName(resolvedPortName)); + TICStreamConfiguration configuration = + new TICStreamConfiguration( + ticMode, streamIdentifier, TICStreamConfiguration.DEFAULT_TIMEOUT); + stream = new TICStream(configuration); + + return new TICCoreStreamBase(identifier, stream, notifier); + } + + private TICCoreStreamBase( + TICIdentifier identifier, TICStream stream, Notifier notifier) + throws TICCoreException { + this.identifier = identifier; + this.stream = stream; + this.notifier = notifier; + + this.streamListener = + new TICStreamListener() { + @Override + public void onFrame(TICFrame ticFrame) { + TICCoreStreamBase.this.onFrame(ticFrame); + } + + @Override + public void onError(String errorMessage) { + TICCoreStreamBase.this.onError(errorMessage); + } + }; + } + + @Override + public TICIdentifier getIdentifier() { + synchronized (this.identifierLock) { + return this.identifier; + } + } + + @Override + public Collection getSubscribers() { + return this.notifier.getSubscribers(); + } + + @Override + public boolean hasSubscriber(TICCoreSubscriber subscriber) { + return this.notifier.hasSubscriber(subscriber); + } + + @Override + public void subscribe(TICCoreSubscriber subscriber) { + this.notifier.subscribe(subscriber); + } + + @Override + public void unsubscribe(TICCoreSubscriber subscriber) { + this.notifier.unsubscribe(subscriber); + } + + @Override + public void start() { + this.stream.subscribe(this.streamListener); + this.stream.start(); + } + + @Override + public void stop() { + this.stream.unsubscribe(this.streamListener); + this.stream.stop(); + } + + @Override + public boolean isRunning() { + return this.stream.isRunning(); + } + + private void onFrame(TICFrame ticFrame) { + if (ticFrame == null) { + return; + } + + String serialNumber = null; + if (ticFrame.getMode() == TICMode.STANDARD) { + TICGroup group = ticFrame.getGroup("ADSC"); + serialNumber = group != null ? group.getValue() : null; + } else if (ticFrame.getMode() == TICMode.HISTORIC) { + TICGroup group = ticFrame.getGroup("ADCO"); + serialNumber = group != null ? group.getValue() : null; + } + + TICIdentifier frameIdentifier; + synchronized (this.identifierLock) { + this.identifier = new TICIdentifier.Builder() + .portId(this.identifier.getPortId()) + .portName(this.identifier.getPortName()) + .serialNumber(serialNumber) + .build(); + frameIdentifier = this.identifier; + } + + TICCoreFrame frame = + new TICCoreFrame(frameIdentifier, ticFrame.getMode(), LocalDateTime.now(), ticFrame); + this.notifyOnData(frame); + } + + private void onError(String errorMessage) { + int code = TICCoreErrorCode.OTHER_REASON.getCode(); + if (errorMessage != null && errorMessage.toLowerCase().contains("timeout")) { + code = TICCoreErrorCode.DATA_READ_TIMEOUT.getCode(); + } + TICCoreError error = + new TICCoreError(this.getIdentifier(), code, errorMessage == null ? "" : errorMessage); + this.notifyOnError(error); + } + + private void notifyOnData(TICCoreFrame frame) { + if (frame == null) { + return; + } + + Collection subscriberList = this.notifier.getSubscribers(); + Task task = + new TaskBase() { + @Override + public void process() { + for (TICCoreSubscriber subscriber : subscriberList) { + try { + subscriber.onData(frame); + } catch (Exception exception) { + logger.error("TICCoreStream subscriber onData aborted", exception); + } + } + } + }; + task.start(); + } + + private void notifyOnError(TICCoreError error) { + if (error == null) { + return; + } + + Collection subscriberList = this.notifier.getSubscribers(); + Task task = + new TaskBase() { + @Override + public void process() { + for (TICCoreSubscriber subscriber : subscriberList) { + try { + subscriber.onError(error); + } catch (Exception exception) { + logger.error("TICCoreStream subscriber onError aborted", exception); + } + } + } + }; + task.start(); + } +} diff --git a/src/main/java/tic/core/TICCoreSubscriber.java b/src/main/java/tic/core/TICCoreSubscriber.java new file mode 100644 index 0000000..42f5764 --- /dev/null +++ b/src/main/java/tic/core/TICCoreSubscriber.java @@ -0,0 +1,42 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.core; + +import tic.util.task.Subscriber; + +/** + * Interface for subscribing to core frame and error notifications. + * + *

This interface defines methods for receiving frame and error events. It is used as a contract + * for objects that handle event-driven notifications in core operations. + * + *

Common use cases include: + * + *

    + *
  • Receiving frame notifications + *
  • Handling error events + *
  • Implementing event-driven logic + *
+ * + * @author Enedis Smarties team + */ +public interface TICCoreSubscriber extends Subscriber { + /** + * Notify when data + * + * @param frame the frame received + */ + public void onData(TICCoreFrame frame); + + /** + * Notify when error + * + * @param error the error detected + */ + public void onError(TICCoreError error); +} diff --git a/src/main/java/tic/core/TICIdentifier.java b/src/main/java/tic/core/TICIdentifier.java new file mode 100644 index 0000000..cdc029c --- /dev/null +++ b/src/main/java/tic/core/TICIdentifier.java @@ -0,0 +1,167 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.core; + +import java.util.Objects; + +/** + * Class representing a core identifier with port ID, port name, and serial number. + * + *

This class provides mechanisms for constructing, accessing, and managing identifier + * information including port IDs, port names, and serial numbers. It is designed for + * general-purpose identifier handling. + * + *

Common use cases include: + * + *

    + *
  • Representing identifiers with structured data + *
  • Matching identifiers for streams and devices + *
  • Managing port and serial information + *
+ * + * @author Enedis Smarties team + */ +public class TICIdentifier { + private final String portId; + private final String portName; + private final String serialNumber; + + public static class Builder { + private String portId; + private String portName; + private String serialNumber; + + /** + * Sets the portId field. + * + * @param portId the port ID + * @return the Builder instance + */ + public Builder portId(String portId) { + this.portId = portId; + return this; + } + + /** + * Sets the portName field. + * + * @param portName the port name + * @return the Builder instance + */ + public Builder portName(String portName) { + this.portName = portName; + return this; + } + + /** + * Sets the serialNumber field. + * + * @param serialNumber the serial number + * @return the Builder instance + */ + public Builder serialNumber(String serialNumber) { + this.serialNumber = serialNumber; + return this; + } + + /** + * Validates the builder's fields. + * + * @throws IllegalArgumentException if any required field is invalid + */ + protected void validate() { + if (this.portId == null && this.portName == null && this.serialNumber == null) { + throw new IllegalArgumentException("Empty TICIdentifier not allowed!"); + } + } + + public TICIdentifier build() { + this.validate(); + return new TICIdentifier(this.portId, this.portName, this.serialNumber); + } + } + + private TICIdentifier(String portId, String portName, String serialNumber) { + this.portId = portId; + this.portName = portName; + this.serialNumber = serialNumber; + } + + public boolean matches(TICIdentifier identifier) { + if (identifier != null) { + if (this.getSerialNumber() != null && identifier.getSerialNumber() != null) { + return this.getSerialNumber().equals(identifier.getSerialNumber()); + } + if (this.getPortId() != null && identifier.getPortId() != null) { + return this.getPortId().equals(identifier.getPortId()); + } + if (this.getPortName() != null && identifier.getPortName() != null) { + return this.getPortName().equals(identifier.getPortName()); + } + } + + return false; + } + + /** + * Get port id + * + * @return the port id + */ + public String getPortId() { + return this.portId; + } + + /** + * Get port name + * + * @return the port name + */ + public String getPortName() { + return this.portName; + } + + /** + * Get serial number + * + * @return the serial number + */ + public String getSerialNumber() { + return this.serialNumber; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof TICIdentifier)) { + return false; + } + TICIdentifier that = (TICIdentifier) o; + return Objects.equals(this.portId, that.portId) + && Objects.equals(this.portName, that.portName) + && Objects.equals(this.serialNumber, that.serialNumber); + } + + @Override + public int hashCode() { + return Objects.hash(this.portId, this.portName, this.serialNumber); + } + + @Override + public String toString() { + return "{portId=" + + this.portId + + ", portName=" + + this.portName + + ", serialNumber=" + + this.serialNumber + + "}"; + } +} diff --git a/src/main/java/tic/core/codec/TICCoreErrorCodec.java b/src/main/java/tic/core/codec/TICCoreErrorCodec.java new file mode 100644 index 0000000..19d5fd5 --- /dev/null +++ b/src/main/java/tic/core/codec/TICCoreErrorCodec.java @@ -0,0 +1,71 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.core.codec; + +import org.json.JSONObject; +import tic.core.TICCoreError; +import tic.frame.TICFrame; +import tic.frame.codec.TICFrameCodec; +import tic.util.codec.JsonObjectCodec; +import tic.util.codec.JsonStringCodec; + +/** + * Codec utilities for {@link tic.core.TICCoreError}. + * + *

Currently focuses on JSON encoding (pretty-printed) for diagnostics and logging. + */ +public final class TICCoreErrorCodec + implements JsonStringCodec, JsonObjectCodec { + + public static TICCoreErrorCodec instance = new TICCoreErrorCodec(); + + public static TICCoreErrorCodec getInstance() { + if (instance == null) { + instance = new TICCoreErrorCodec(); + } + return instance; + } + + private TICCoreErrorCodec() {} + + @Override + public Object encodeToJsonObject(TICCoreError error) throws Exception { + if (error == null) { + throw new IllegalArgumentException("error cannot be null"); + } + + JSONObject json = new JSONObject(); + json.put( + "identifier", TICIdentifierCodec.getInstance().encodeToJsonObject(error.getIdentifier())); + json.put("errorMessage", error.getErrorMessage()); + json.put("errorCode", error.getErrorCode()); + + TICFrame frame = error.getFrame(); + if (frame != null) { + json.put("frame", TICFrameCodec.encode(frame)); + } + return json; + } + + @Override + public TICCoreError decodeFromJsonObject(Object jsonObject) throws Exception { + throw new UnsupportedOperationException("Unimplemented method 'decodeFromJsonObject'"); + } + + @Override + public String encodeToJsonString(TICCoreError error, int indentFactor) throws Exception { + JSONObject json = (JSONObject) encodeToJsonObject(error); + return indentFactor > 0 ? json.toString(indentFactor) : json.toString(); + } + + @Override + public TICCoreError decodeFromJsonString(String jsonString, int indentFactor) throws Exception { + throw new UnsupportedOperationException("Unimplemented method 'decodeFromJsonString'"); + } +} diff --git a/src/main/java/tic/core/codec/TICCoreFrameCodec.java b/src/main/java/tic/core/codec/TICCoreFrameCodec.java new file mode 100644 index 0000000..f7fc354 --- /dev/null +++ b/src/main/java/tic/core/codec/TICCoreFrameCodec.java @@ -0,0 +1,66 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.core.codec; + +import org.json.JSONObject; +import tic.core.TICCoreFrame; +import tic.frame.codec.TICFrameSummarizedCodec; +import tic.util.codec.JsonObjectCodec; +import tic.util.codec.JsonStringCodec; + +/** + * Codec utilities for {@link tic.core.TICCoreFrame}. + * + *

Currently focuses on JSON encoding (pretty-printed) for diagnostics and logging. + */ +public final class TICCoreFrameCodec + implements JsonStringCodec, JsonObjectCodec { + + public static TICCoreFrameCodec instance = new TICCoreFrameCodec(); + + private TICCoreFrameCodec() {} + + public static TICCoreFrameCodec getInstance() { + if (instance == null) { + instance = new TICCoreFrameCodec(); + } + return instance; + } + + @Override + public Object encodeToJsonObject(TICCoreFrame frame) throws Exception { + if (frame == null) { + throw new IllegalArgumentException("frame cannot be null"); + } + + JSONObject json = new JSONObject(); + json.put( + "identifier", TICIdentifierCodec.getInstance().encodeToJsonObject(frame.getIdentifier())); + json.put("mode", frame.getMode().name()); + json.put("captureDateTime", frame.getCaptureDateTime().toString()); + json.put("frame", TICFrameSummarizedCodec.getInstance().encodeToJsonObject(frame.getFrame())); + + return json; + } + + @Override + public TICCoreFrame decodeFromJsonObject(Object jsonObject) throws Exception { + throw new UnsupportedOperationException("Unimplemented method 'decodeFromJsonObject'"); + } + + @Override + public String encodeToJsonString(TICCoreFrame frame, int indentFactor) throws Exception { + JSONObject json = (JSONObject) encodeToJsonObject(frame); + return indentFactor < 0 ? json.toString() : json.toString(indentFactor); + } + + @Override + public TICCoreFrame decodeFromJsonString(String jsonString, int indentFactor) throws Exception { + throw new UnsupportedOperationException("Unimplemented method 'decodeFromJsonString'"); + } +} diff --git a/src/main/java/tic/core/codec/TICIdentifierCodec.java b/src/main/java/tic/core/codec/TICIdentifierCodec.java new file mode 100644 index 0000000..8911af1 --- /dev/null +++ b/src/main/java/tic/core/codec/TICIdentifierCodec.java @@ -0,0 +1,119 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.core.codec; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import org.json.JSONArray; +import org.json.JSONObject; +import tic.core.TICIdentifier; +import tic.util.codec.JsonArrayCodec; +import tic.util.codec.JsonObjectCodec; +import tic.util.codec.JsonStringCodec; + +/** + * Codec utilities for {@link tic.core.TICIdentifier}. + * + *

Currently focuses on JSON encoding (pretty-printed) for diagnostics and logging. + */ +public final class TICIdentifierCodec + implements JsonObjectCodec, + JsonStringCodec, + JsonArrayCodec> { + + public static TICIdentifierCodec instance = null; + + public static final TICIdentifierCodec getInstance() { + if (instance == null) { + return new TICIdentifierCodec(); + } + return instance; + } + + private TICIdentifierCodec() {} + + @Override + public JSONObject encodeToJsonObject(TICIdentifier identifier) { + if (identifier == null) { + throw new IllegalArgumentException("identifier cannot be null"); + } + + JSONObject json = new JSONObject(); + json.put( + "portName", identifier.getPortName() == null ? JSONObject.NULL : identifier.getPortName()); + json.put("portId", identifier.getPortId() == null ? JSONObject.NULL : identifier.getPortId()); + json.put( + "serialNumber", + identifier.getSerialNumber() == null ? JSONObject.NULL : identifier.getSerialNumber()); + return json; + } + + @Override + public TICIdentifier decodeFromJsonObject(Object object) { + if (object == null || object instanceof JSONObject == false) { + throw new IllegalArgumentException("Input is not a valid JSON object"); + } + + JSONObject jsonObject = (JSONObject) object; + + String portName = jsonObject.isNull("portName") ? null : jsonObject.getString("portName"); + String portId = jsonObject.isNull("portId") ? null : jsonObject.getString("portId"); + String serialNumber = + jsonObject.isNull("serialNumber") ? null : jsonObject.getString("serialNumber"); + + return new TICIdentifier.Builder() + .portName(portName) + .portId(portId) + .serialNumber(serialNumber) + .build(); + } + + @Override + public JSONArray encodeToJsonArray(List identifiers) { + List safeList = identifiers == null ? Collections.emptyList() : identifiers; + JSONArray jsonArray = new JSONArray(); + + for (TICIdentifier identifier : safeList) { + jsonArray.put(encodeToJsonObject(identifier)); + } + return jsonArray; + } + + @Override + public List decodeFromJsonArray(Object object) { + if (object == null || object instanceof JSONArray == false) { + throw new IllegalArgumentException("Input is not a valid JSON array"); + } + + JSONArray jsonArray = (JSONArray) object; + + List identifiers = new ArrayList<>(); + for (int i = 0; i < jsonArray.length(); i++) { + JSONObject jsonObject = jsonArray.getJSONObject(i); + TICIdentifier identifier = decodeFromJsonObject(jsonObject); + identifiers.add(identifier); + } + return identifiers; + } + + @Override + public String encodeToJsonString(TICIdentifier identifier, int indentFactor) { + if (identifier == null) { + throw new IllegalArgumentException("identifier cannot be null"); + } + + JSONObject json = encodeToJsonObject(identifier); + return indentFactor < 0 ? json.toString() : json.toString(indentFactor); + } + + @Override + public TICIdentifier decodeFromJsonString(String jsonString, int indentFactor) { + throw new UnsupportedOperationException("Unimplemented method 'decodeFromJsonString'"); + } +} diff --git a/src/main/java/tic/diagnostic/core/TICCoreApp.java b/src/main/java/tic/diagnostic/core/TICCoreApp.java new file mode 100644 index 0000000..a1a9fc5 --- /dev/null +++ b/src/main/java/tic/diagnostic/core/TICCoreApp.java @@ -0,0 +1,16 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.diagnostic.core; + +/** Minimal launcher: all CLI parsing lives in {@link TICCoreCli}. */ +public final class TICCoreApp { + public static void main(String[] args) { + int exitCode = TICCoreCli.execute(args); + System.exit(exitCode); + } +} diff --git a/src/main/java/tic/diagnostic/core/TICCoreCli.java b/src/main/java/tic/diagnostic/core/TICCoreCli.java new file mode 100644 index 0000000..ae84d21 --- /dev/null +++ b/src/main/java/tic/diagnostic/core/TICCoreCli.java @@ -0,0 +1,188 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.diagnostic.core; + +import java.util.Collections; +import java.util.List; +import java.util.concurrent.Callable; +import picocli.CommandLine; +import picocli.CommandLine.Command; +import picocli.CommandLine.ExitCode; +import picocli.CommandLine.Model.CommandSpec; +import picocli.CommandLine.Option; +import picocli.CommandLine.Spec; +import tic.core.TICCoreBase; +import tic.core.TICCoreError; +import tic.core.TICCoreFrame; +import tic.core.TICCoreSubscriber; +import tic.core.TICIdentifier; +import tic.diagnostic.core.commands.TICCoreAvailableCommand; +import tic.diagnostic.core.commands.TICCoreModemsCommand; +import tic.diagnostic.core.commands.TICCoreReadCommand; +import tic.diagnostic.core.commands.TICCoreSubscribeCommand; +import tic.frame.TICMode; +import tic.io.modem.ModemDescriptor; +import tic.io.modem.ModemFinder; +import tic.io.modem.ModemFinderBase; +import tic.io.serialport.SerialPortFinderBase; +import tic.io.usb.UsbPortFinderBase; +import tic.util.time.Time; + +/** + * Root Picocli command for TICCore diagnostic. + * + *

This class contains all CLI parsing and shared behaviors; {@link TICCoreApp} should only + * delegate to it. + */ +@Command( + name = "tic-core", + mixinStandardHelpOptions = true, + description = + "TICCore diagnostic (getAvailableTICs, getModemsInfo, readNextFrame, subscribe," + + " unsubscribe).", + subcommands = { + TICCoreAvailableCommand.class, + TICCoreModemsCommand.class, + TICCoreReadCommand.class, + TICCoreSubscribeCommand.class + }) +public final class TICCoreCli implements Callable { + private static final TICCoreSubscriber NOOP_SUBSCRIBER = + new TICCoreSubscriber() { + @Override + public void onData(TICCoreFrame frame) { + // no-op + } + + @Override + public void onError(TICCoreError error) { + // no-op + } + }; + + @Spec CommandSpec spec; + + public static int execute(String[] args) { + return new CommandLine(new TICCoreCli()).execute(args); + } + + @Option( + names = {"-m", "--mode"}, + defaultValue = "AUTO", + description = "TIC mode: ${COMPLETION-CANDIDATES} (default: ${DEFAULT-VALUE})") + TICMode mode = TICMode.AUTO; + + @Option( + names = {"--startPort"}, + paramLabel = "PORT", + description = + "Ports to start at launch (useful if discovery is slow). " + "Example: --startPort COM3") + String startPort; + + @Option( + names = {"--waitMs"}, + defaultValue = "200", + paramLabel = "MS", + description = "Wait after startup to let discovery happen (default: ${DEFAULT-VALUE}).") + int waitMs = 200; + + @Option( + names = {"--scan"}, + negatable = true, + defaultValue = "true", + description = + "Immediately scan already-plugged modems (recommended). Use --no-scan to disable.") + boolean scanAlreadyPlugged = true; + + @Override + public Integer call() { + // If no subcommand is provided, show usage. + if (this.spec != null) { + this.spec.commandLine().usage(System.out); + } + return ExitCode.USAGE; + } + + public TICCoreBase startCore() { + List startPorts = + (this.startPort == null || this.startPort.trim().isEmpty()) + ? null + : Collections.singletonList(this.startPort.trim()); + + TICCoreBase ticCore = new TICCoreBase(this.mode, startPorts); + System.out.println("Starting TICCore (mode=" + this.mode + ")..."); + ticCore.start(); + + if (this.waitMs > 0) { + Time.sleep(this.waitMs); + } + + if (this.scanAlreadyPlugged) { + this.scanAndStartAlreadyPluggedStreams(ticCore); + } + + return ticCore; + } + + public void stopCore(TICCoreBase ticCore) { + if (ticCore == null) { + return; + } + try { + System.out.println("Stopping TICCore..."); + ticCore.stop(); + } catch (Exception e) { + System.err.println("[WARN] Failed to stop TICCore: " + e.getMessage()); + e.printStackTrace(System.err); + } + } + + void scanAndStartAlreadyPluggedStreams(TICCoreBase ticCore) { + // Start streams immediately to avoid waiting for the notifier tick. + try { + ModemFinder modemFinder = + ModemFinderBase.create( + SerialPortFinderBase.getInstance(), UsbPortFinderBase.getInstance()); + List detected = modemFinder.findAll(); + if (detected == null || detected.isEmpty()) { + return; + } + for (ModemDescriptor descriptor : detected) { + if (descriptor == null) { + continue; + } + + TICIdentifier identifier = new TICIdentifier.Builder() + .portId(descriptor.portId()) + .portName(descriptor.portName()) + .build(); + + // subscribe() will start the stream if needed. + ticCore.subscribe(identifier, NOOP_SUBSCRIBER); + } + } catch (Exception e) { + System.err.println("[WARN] Unable to scan already-plugged modems: " + e.getMessage()); + e.printStackTrace(System.err); + } + } + + public TICIdentifier resolveIdentifier(TICCoreBase ticCore, TICCoreIdentifierOptions idOptions) + throws IllegalArgumentException { + TICIdentifier specified = (idOptions == null) ? null : idOptions.toIdentifierOrNull(); + if (specified != null) { + return specified; + } + + List available = ticCore.getAvailableTICs(); + if (available == null || available.isEmpty()) { + throw new IllegalArgumentException( + "No TIC detected. Plug a modem or provide --portName/--portId/--serialNumber."); + } + return available.get(0); + } +} diff --git a/src/main/java/tic/diagnostic/core/TICCoreIdentifierOptions.java b/src/main/java/tic/diagnostic/core/TICCoreIdentifierOptions.java new file mode 100644 index 0000000..e960460 --- /dev/null +++ b/src/main/java/tic/diagnostic/core/TICCoreIdentifierOptions.java @@ -0,0 +1,43 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.diagnostic.core; + +import picocli.CommandLine.Option; +import tic.core.TICIdentifier; + +/** Options to identify a TIC (portName/portId/serialNumber). */ +public final class TICCoreIdentifierOptions { + @Option( + names = {"--portName"}, + paramLabel = "NAME", + description = "Port name (e.g. COM3, /dev/ttyUSB0).") + String portName; + + @Option( + names = {"--portId"}, + paramLabel = "ID", + description = "Port identifier (if available).") + String portId; + + @Option( + names = {"--serialNumber"}, + paramLabel = "SN", + description = "Modem serial number (if available).") + String serialNumber; + + TICIdentifier toIdentifierOrNull() { + if (this.portName == null && this.portId == null && this.serialNumber == null) { + return null; + } + return new TICIdentifier.Builder() + .portId(this.portId) + .portName(this.portName) + .serialNumber(this.serialNumber) + .build(); + } +} diff --git a/src/main/java/tic/diagnostic/core/TICCorePrintingSubscriber.java b/src/main/java/tic/diagnostic/core/TICCorePrintingSubscriber.java new file mode 100644 index 0000000..3244a59 --- /dev/null +++ b/src/main/java/tic/diagnostic/core/TICCorePrintingSubscriber.java @@ -0,0 +1,64 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.diagnostic.core; + +import tic.core.TICCoreError; +import tic.core.TICCoreFrame; +import tic.core.TICCoreSubscriber; +import tic.core.codec.TICCoreErrorCodec; +import tic.core.codec.TICCoreFrameCodec; + +/** Subscriber that prints received frames/errors to stdout/stderr. */ +public final class TICCorePrintingSubscriber implements TICCoreSubscriber { + private final int indent; + private volatile long frameCount; + private volatile TICCoreError lastError; + + public TICCorePrintingSubscriber(int indent) { + this.indent = indent; + this.frameCount = 0; + this.lastError = null; + } + + @Override + public void onData(TICCoreFrame frame) { + this.frameCount++; + System.out.println("--- Frame #" + this.frameCount + " ---"); + try { + System.out.println(frame == null ? "null" : TICCoreFrameCodec.getInstance().encodeToJsonString(frame, this.indent)); + } catch (Exception e) { + System.err.println("[ERROR] Failed to encode frame to JSON string: " + e.getMessage()); + } + } + + @Override + public void onError(TICCoreError error) { + this.lastError = error; + System.err.println("--- Error ---"); + try { + System.err.println( + error == null + ? "null" + : TICCoreErrorCodec.getInstance().encodeToJsonString(error, this.indent)); + } catch (Exception e) { + System.err.println("[ERROR] Failed to encode error to JSON string: " + e.getMessage()); + } + } + + public long getFrameCount() { + return this.frameCount; + } + + public boolean hasError() { + return this.lastError != null; + } + + public String getLastErrorMessage() { + return this.lastError == null ? null : this.lastError.getErrorMessage(); + } +} diff --git a/src/main/java/tic/diagnostic/core/commands/TICCoreAvailableCommand.java b/src/main/java/tic/diagnostic/core/commands/TICCoreAvailableCommand.java new file mode 100644 index 0000000..f583e53 --- /dev/null +++ b/src/main/java/tic/diagnostic/core/commands/TICCoreAvailableCommand.java @@ -0,0 +1,48 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.diagnostic.core.commands; + +import java.util.List; +import java.util.concurrent.Callable; +import picocli.CommandLine; +import picocli.CommandLine.Command; +import picocli.CommandLine.ExitCode; +import tic.core.TICCoreBase; +import tic.core.TICIdentifier; +import tic.diagnostic.core.TICCoreCli; + +@Command( + name = "available", + mixinStandardHelpOptions = true, + description = "List available TICs (TICCore.getAvailableTICs).") +public final class TICCoreAvailableCommand implements Callable { + @CommandLine.ParentCommand TICCoreCli parent; + + @Override + public Integer call() { + TICCoreBase ticCore = null; + try { + ticCore = parent.startCore(); + List available = ticCore.getAvailableTICs(); + int count = (available == null) ? 0 : available.size(); + System.out.println("Available TICs (" + count + "):"); + if (available != null) { + for (TICIdentifier id : available) { + System.out.println("- " + id); + } + } + return ExitCode.OK; + } catch (Exception e) { + System.err.println("[ERROR] " + e.getMessage()); + e.printStackTrace(System.err); + return ExitCode.SOFTWARE; + } finally { + parent.stopCore(ticCore); + } + } +} diff --git a/src/main/java/tic/diagnostic/core/commands/TICCoreModemsCommand.java b/src/main/java/tic/diagnostic/core/commands/TICCoreModemsCommand.java new file mode 100644 index 0000000..368dde5 --- /dev/null +++ b/src/main/java/tic/diagnostic/core/commands/TICCoreModemsCommand.java @@ -0,0 +1,49 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.diagnostic.core.commands; + +import java.util.List; +import java.util.concurrent.Callable; +import picocli.CommandLine; +import picocli.CommandLine.Command; +import picocli.CommandLine.ExitCode; +import tic.core.TICCoreBase; +import tic.diagnostic.core.TICCoreCli; +import tic.io.modem.ModemDescriptor; +import tic.io.modem.ModemJsonCodec; + +@Command( + name = "modems", + mixinStandardHelpOptions = true, + description = "Show modem information (TICCore.getModemsInfo).") +public final class TICCoreModemsCommand implements Callable { + @CommandLine.ParentCommand TICCoreCli parent; + + @Override + public Integer call() { + TICCoreBase ticCore = null; + try { + ticCore = parent.startCore(); + List modems = ticCore.getModemsInfo(); + int count = (modems == null) ? 0 : modems.size(); + System.out.println("Modems (" + count + "):"); + if (modems != null) { + for (ModemDescriptor modem : modems) { + System.out.println("- " + (modem == null ? "null" : ModemJsonCodec.getInstance().encodeToJsonString(modem))); + } + } + return ExitCode.OK; + } catch (Exception e) { + System.err.println("[ERROR] " + e.getMessage()); + e.printStackTrace(System.err); + return ExitCode.SOFTWARE; + } finally { + parent.stopCore(ticCore); + } + } +} diff --git a/src/main/java/tic/diagnostic/core/commands/TICCoreReadCommand.java b/src/main/java/tic/diagnostic/core/commands/TICCoreReadCommand.java new file mode 100644 index 0000000..9ac28cf --- /dev/null +++ b/src/main/java/tic/diagnostic/core/commands/TICCoreReadCommand.java @@ -0,0 +1,70 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.diagnostic.core.commands; + +import java.util.concurrent.Callable; +import picocli.CommandLine; +import picocli.CommandLine.Command; +import picocli.CommandLine.ExitCode; +import picocli.CommandLine.Mixin; +import picocli.CommandLine.Option; +import tic.core.TICCoreBase; +import tic.core.TICCoreFrame; +import tic.core.TICIdentifier; +import tic.core.codec.TICCoreFrameCodec; +import tic.diagnostic.core.TICCoreCli; +import tic.diagnostic.core.TICCoreIdentifierOptions; + +@Command( + name = "read", + mixinStandardHelpOptions = true, + description = "Read the next frame (TICCore.readNextFrame).") +public final class TICCoreReadCommand implements Callable { + @CommandLine.ParentCommand TICCoreCli parent; + + @Mixin TICCoreIdentifierOptions identifierOptions = new TICCoreIdentifierOptions(); + + @Option( + names = {"--timeoutMs"}, + defaultValue = "30000", + paramLabel = "MS", + description = "Read timeout in milliseconds (default: ${DEFAULT-VALUE}).") + int timeoutMs = 30000; + + @Option( + names = {"--indent"}, + defaultValue = "2", + paramLabel = "N", + description = "Frame JSON indentation (default: ${DEFAULT-VALUE}).") + int indent = 2; + + @Override + public Integer call() { + TICCoreBase ticCore = null; + try { + ticCore = parent.startCore(); + TICIdentifier identifier = parent.resolveIdentifier(ticCore, identifierOptions); + System.out.println("Reading next frame from " + identifier + " ..."); + TICCoreFrame frame = ticCore.readNextFrame(identifier, timeoutMs); + System.out.println( + frame == null + ? "null" + : TICCoreFrameCodec.getInstance().encodeToJsonString(frame, indent)); + return ExitCode.OK; + } catch (IllegalArgumentException e) { + System.err.println("[ERROR] " + e.getMessage()); + return ExitCode.USAGE; + } catch (Exception e) { + System.err.println("[ERROR] " + e.getMessage()); + e.printStackTrace(System.err); + return ExitCode.SOFTWARE; + } finally { + parent.stopCore(ticCore); + } + } +} diff --git a/src/main/java/tic/diagnostic/core/commands/TICCoreSubscribeCommand.java b/src/main/java/tic/diagnostic/core/commands/TICCoreSubscribeCommand.java new file mode 100644 index 0000000..b893366 --- /dev/null +++ b/src/main/java/tic/diagnostic/core/commands/TICCoreSubscribeCommand.java @@ -0,0 +1,115 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.diagnostic.core.commands; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.util.concurrent.Callable; +import picocli.CommandLine; +import picocli.CommandLine.Command; +import picocli.CommandLine.ExitCode; +import picocli.CommandLine.Mixin; +import picocli.CommandLine.Option; +import tic.core.TICCoreBase; +import tic.core.TICIdentifier; +import tic.diagnostic.core.TICCoreCli; +import tic.diagnostic.core.TICCoreIdentifierOptions; +import tic.diagnostic.core.TICCorePrintingSubscriber; +import tic.util.time.Time; + +@Command( + name = "subscribe", + mixinStandardHelpOptions = true, + description = + "Subscribe to a TIC and print received frames (TICCore.subscribe). " + + "Subscription is automatically cancelled at the end (TICCore.unsubscribe).") +public final class TICCoreSubscribeCommand implements Callable { + @CommandLine.ParentCommand TICCoreCli parent; + + @Mixin TICCoreIdentifierOptions identifierOptions = new TICCoreIdentifierOptions(); + + @Option( + names = {"--durationSec"}, + defaultValue = "0", + paramLabel = "S", + description = + "Listen duration in seconds (default: ${DEFAULT-VALUE}). " + + "Use 0 to wait until Enter is pressed.") + int durationSec = 0; + + @Option( + names = {"--frames"}, + defaultValue = "0", + paramLabel = "N", + description = "Stop after N frames (0 = unlimited).") + int maxFrames = 0; + + @Option( + names = {"--indent"}, + defaultValue = "2", + paramLabel = "N", + description = "Frame JSON indentation (default: ${DEFAULT-VALUE}).") + int indent = 2; + + @Override + public Integer call() { + TICCoreBase ticCore = null; + TICCorePrintingSubscriber subscriber = null; + TICIdentifier identifier = null; + try { + ticCore = parent.startCore(); + identifier = parent.resolveIdentifier(ticCore, identifierOptions); + + subscriber = new TICCorePrintingSubscriber(indent); + System.out.println("Subscribing to " + identifier + " ..."); + ticCore.subscribe(identifier, subscriber); + + if (durationSec <= 0) { + System.out.println("Listening. Press Enter to stop..."); + BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); + br.readLine(); + } else { + long deadlineMs = System.currentTimeMillis() + (durationSec * 1000L); + System.out.println("Listening for " + durationSec + "s (Ctrl+C to interrupt)..."); + while (System.currentTimeMillis() < deadlineMs) { + if (subscriber.hasError()) { + break; + } + if (maxFrames > 0 && subscriber.getFrameCount() >= maxFrames) { + break; + } + Time.sleep(200); + } + } + + if (subscriber.hasError()) { + System.err.println("[ERROR] Error received: " + subscriber.getLastErrorMessage()); + return ExitCode.SOFTWARE; + } + return ExitCode.OK; + } catch (IllegalArgumentException e) { + System.err.println("[ERROR] " + e.getMessage()); + return ExitCode.USAGE; + } catch (Exception e) { + System.err.println("[ERROR] " + e.getMessage()); + e.printStackTrace(System.err); + return ExitCode.SOFTWARE; + } finally { + // Explicit unsubscribe test with the same subscriber instance. + if (ticCore != null && subscriber != null && identifier != null) { + try { + System.out.println("Unsubscribing from " + identifier + " ..."); + ticCore.unsubscribe(identifier, subscriber); + } catch (Exception e) { + System.err.println("[WARN] Unsubscribe failed: " + e.getMessage()); + } + } + parent.stopCore(ticCore); + } + } +} diff --git a/src/main/java/tic/diagnostic/modem/ModemFinderApp.java b/src/main/java/tic/diagnostic/modem/ModemFinderApp.java new file mode 100644 index 0000000..1f13675 --- /dev/null +++ b/src/main/java/tic/diagnostic/modem/ModemFinderApp.java @@ -0,0 +1,39 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.diagnostic.modem; + +import java.util.List; + +import org.json.JSONArray; + +import tic.io.modem.ModemDescriptor; +import tic.io.modem.ModemFinder; +import tic.io.modem.ModemFinderBase; +import tic.io.modem.ModemJsonCodec; +import tic.io.serialport.SerialPortFinderBase; +import tic.io.usb.UsbPortFinderBase; + +public class ModemFinderApp { + + /** + * Program writing the modem descriptor list (JSON format) on the output stream + * + * @param args not used + */ + public static void main(String[] args) { + try { + ModemFinder modemFinder = + ModemFinderBase.create( + SerialPortFinderBase.getInstance(), UsbPortFinderBase.getInstance()); + List descriptors = modemFinder.findAll(); + System.out.println((JSONArray) ModemJsonCodec.getInstance().encodeToJsonArray(descriptors)); + } catch (Exception exception) { + System.err.println(exception.getMessage()); + } + } +} diff --git a/src/main/java/tic/diagnostic/modem/ModemPlugNotifierApp.java b/src/main/java/tic/diagnostic/modem/ModemPlugNotifierApp.java new file mode 100644 index 0000000..afa08e4 --- /dev/null +++ b/src/main/java/tic/diagnostic/modem/ModemPlugNotifierApp.java @@ -0,0 +1,69 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.diagnostic.modem; + +import java.util.Arrays; +import java.util.List; + +import org.json.JSONArray; + +import tic.io.PlugSubscriber; +import tic.io.PortPlugNotifier; +import tic.io.modem.ModemDescriptor; +import tic.io.modem.ModemFinder; +import tic.io.modem.ModemFinderBase; +import tic.io.modem.ModemJsonCodec; +import tic.io.modem.ModemPlugNotifier; +import tic.io.serialport.SerialPortFinderBase; +import tic.io.usb.UsbPortFinderBase; + +public class ModemPlugNotifierApp { + + /** + * Program writing on the output stream when a modem has been plugged or unplugged + * + * @param args not used + */ + public static void main(String[] args) { + ModemFinder modemFinder = + ModemFinderBase.create(SerialPortFinderBase.getInstance(), UsbPortFinderBase.getInstance()); + /* 1. Create notification service */ + ModemPlugNotifier notifier = new ModemPlugNotifier(1000, modemFinder); + /* 2. Create subscriber to print when a modem has been plugged or unplugged */ + PlugSubscriber subscriber = + new PlugSubscriber() { + @Override + public void onPlugged(ModemDescriptor descriptor) { + List list = new java.util.ArrayList<>(Arrays.asList(descriptor)); + JSONArray array; + try { + array = (JSONArray) ModemJsonCodec.getInstance().encodeToJsonArray(list); + } catch (Exception e) { + array = new JSONArray(); + } + String payload = array.toString(2); + System.out.println("onPlugged event:\n" + payload + "\n"); + } + + @Override + public void onUnplugged(ModemDescriptor descriptor) { + List list = new java.util.ArrayList<>(Arrays.asList(descriptor)); + JSONArray array; + try { + array = (JSONArray) ModemJsonCodec.getInstance().encodeToJsonArray(list); + } catch (Exception e) { + array = new JSONArray(); + } + String payload = array.toString(2); + System.out.println("onUnplugged event:\n" + payload + "\n"); + } + }; + /* 3. Run program printing when a modem has been plugged or unplugged until CTRL+C is pressed */ + PortPlugNotifier.main(notifier, subscriber); + } +} diff --git a/src/main/java/tic/diagnostic/serialport/SerialPortFinderApp.java b/src/main/java/tic/diagnostic/serialport/SerialPortFinderApp.java new file mode 100644 index 0000000..e5d385f --- /dev/null +++ b/src/main/java/tic/diagnostic/serialport/SerialPortFinderApp.java @@ -0,0 +1,33 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.diagnostic.serialport; + +import java.util.List; +import tic.io.serialport.SerialPortDescriptor; +import tic.io.serialport.SerialPortFinderBase; +import tic.io.serialport.SerialPortJsonEncoder; + +public class SerialPortFinderApp { + + /** + * Main method that outputs all serial port descriptors in JSON format. + * + *

This utility method can be used to quickly inspect available serial ports on the system. The + * output is JSON-formatted with an indentation of 2 spaces. + * + * @param args command-line arguments (not used) + */ + public static void main(String[] args) { + try { + List descriptors = SerialPortFinderBase.getInstance().findAll(); + System.out.println(SerialPortJsonEncoder.encode(descriptors)); + } catch (Exception exception) { + System.err.println(exception.getMessage()); + } + } +} diff --git a/src/main/java/tic/diagnostic/usb/UsbPortFinderApp.java b/src/main/java/tic/diagnostic/usb/UsbPortFinderApp.java new file mode 100644 index 0000000..50b0f5d --- /dev/null +++ b/src/main/java/tic/diagnostic/usb/UsbPortFinderApp.java @@ -0,0 +1,30 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.diagnostic.usb; + +import java.util.List; +import tic.io.usb.UsbPortDescriptor; +import tic.io.usb.UsbPortFinderBase; +import tic.io.usb.UsbPortJsonEncoder; + +public class UsbPortFinderApp { + + /** + * Program writing the USB port descriptor list (JSON format) on the output stream + * + * @param args not used + */ + public static void main(String[] args) { + try { + List descriptors = UsbPortFinderBase.getInstance().findAll(); + System.out.println(UsbPortJsonEncoder.encode(descriptors)); + } catch (Exception exception) { + System.err.println(exception.getMessage()); + } + } +} diff --git a/src/main/java/tic/frame/TICFrame.java b/src/main/java/tic/frame/TICFrame.java new file mode 100644 index 0000000..28b5283 --- /dev/null +++ b/src/main/java/tic/frame/TICFrame.java @@ -0,0 +1,111 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.frame; + +import java.util.ArrayList; +import java.util.List; +import tic.frame.group.TICGroup; + +/** + * Abstract base class for TIC frames. + * + *

This class provides the structure for TIC frames. + * + * @author Enedis Smarties team + */ +public class TICFrame { + + private TICMode mode = null; + private List groupList = new ArrayList<>(); + + /** + * Constructs a TIC frame with the specified mode. + * + * @param mode the TIC mode + */ + public TICFrame(TICMode mode) { + if (mode == null) { + throw new IllegalArgumentException("TICFrame mode must not be null"); + } + if (mode == TICMode.AUTO) { + throw new IllegalArgumentException("TICFrame cannot be created with AUTO mode"); + } + this.mode = mode; + } + + /** + * Adds a new group to the TIC frame. + * + * @param group the TIC group to add + */ + public void addGroup(TICGroup group) { + this.groupList.add(group); + } + + /** + * Returns the TIC mode for this frame. + * + * @return the TIC mode + */ + public TICMode getMode() { + return this.mode; + } + + /** + * Returns the list of info groups in this TIC frame. + * + * @return the list of info groups + */ + public List getGroupList() { + return this.groupList; + } + + /** + * Retrieves the TIC group with the specified label. + * + * @param label the label of the group to retrieve + * @return the TIC group with the specified label, or null if not found + */ + public TICGroup getGroup(String label) { + for (TICGroup group : this.groupList) { + if (group.getLabel().equals(label)) { + return group; + } + } + return null; + } + + /** + * Checks if the TIC frame contains any invalid groups. + * + * @return true if there is at least one invalid group, false otherwise + */ + public boolean hasInvalidGroup() { + for (TICGroup group : this.groupList) { + if (!group.isValid()) { + return true; + } + } + return false; + } + + /** + * Checks if the TIC frame contains a group with the specified label. + * + * @param label the label to search for + * @return true if a group with the specified label exists, false otherwise + */ + public boolean containsGroupLabel(String label) { + return (this.getGroup(label) != null) ? true : false; + } + + @Override + public String toString() { + return "mode=" + this.mode + ", groupList=" + this.groupList; + } +} diff --git a/src/main/java/enedis/lab/io/channels/ChannelStatus.java b/src/main/java/tic/frame/TICMode.java similarity index 50% rename from src/main/java/enedis/lab/io/channels/ChannelStatus.java rename to src/main/java/tic/frame/TICMode.java index acae4c5..efc3508 100644 --- a/src/main/java/enedis/lab/io/channels/ChannelStatus.java +++ b/src/main/java/tic/frame/TICMode.java @@ -1,22 +1,22 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.io.channels; - -/** - * Enumeration of channel status - * - */ -public enum ChannelStatus -{ - /** Stopped */ - STOPPED, - /** Started */ - STARTED, - /** Error */ - ERROR -} +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.frame; + +/** + * Enumeration of TIC modes. + * + * @author Enedis Smarties team + */ +public enum TICMode { + /** Standard mode. */ + STANDARD, + /** Historic mode. */ + HISTORIC, + /** Auto-detect mode. */ + AUTO; +} diff --git a/src/main/java/tic/frame/TICModeDetector.java b/src/main/java/tic/frame/TICModeDetector.java new file mode 100644 index 0000000..858a26a --- /dev/null +++ b/src/main/java/tic/frame/TICModeDetector.java @@ -0,0 +1,86 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.frame; + +import java.util.Arrays; +import tic.frame.delimiter.TICSeparator; +import tic.frame.delimiter.TICStartPattern; + +/** + * Utility class for detecting TIC modes from frame or group buffers. + * + *

This class provides methods to identify the TIC mode (STANDARD, HISTORIC) based on the + * contents of frame or group byte arrays. + * + * @author Enedis Smarties team + */ +public class TICModeDetector { + + private TICModeDetector() {} + + /** + * Detects the TIC mode from the given frame buffer. + * + * @param frameBuffer the byte array containing the frame start + * @return the detected {@link TICMode}, or null if not recognized + */ + public static TICMode findModeFromFrameBuffer(byte[] frameBuffer) { + if (frameBuffer == null) { + throw new IllegalArgumentException("Tic frame buffer is null, unable to determine TIC Mode!"); + } + byte[] frameBufferStart = new byte[TICStartPattern.length()]; + if (frameBuffer.length < frameBufferStart.length) { + throw new IllegalArgumentException( + "Tic frame buffer 0x" + bytesToHex(frameBuffer) + " too short to determine TIC Mode!"); + } + System.arraycopy(frameBuffer, 0, frameBufferStart, 0, frameBufferStart.length); + if (Arrays.equals(frameBufferStart, TICStartPattern.HISTORIC.getValue())) { + return TICMode.HISTORIC; + } else { + if (Arrays.equals(frameBufferStart, TICStartPattern.STANDARD.getValue())) { + return TICMode.STANDARD; + } + return null; + } + } + + /** + * Detects the TIC mode from the given group buffer. + * + * @param groupBuffer the byte array containing the group data + * @return the detected {@link TICMode}, or null if not recognized + */ + public static TICMode findModeFromGroupBuffer(byte[] groupBuffer) { + if (groupBuffer == null) { + throw new IllegalArgumentException("Tic group buffer is null, unable to determine TIC Mode!"); + } + for (int i = 0; i < groupBuffer.length; i++) { + if (groupBuffer[i] == TICSeparator.HISTORIC.getValue()) { + return TICMode.HISTORIC; + } else if (groupBuffer[i] == TICSeparator.STANDARD.getValue()) { + return TICMode.STANDARD; + } + } + return null; + } + + /** + * Converts a byte array to a hexadecimal string (replacement for + * DatatypeConverter.printHexBinary). + * + * @param bytes the byte array to convert + * @return the hexadecimal string representation + */ + private static String bytesToHex(byte[] bytes) { + StringBuilder result = new StringBuilder(); + for (byte b : bytes) { + result.append(String.format("%02X", b)); + } + return result.toString(); + } +} diff --git a/src/main/java/tic/frame/checksum/TICChecksum.java b/src/main/java/tic/frame/checksum/TICChecksum.java new file mode 100644 index 0000000..d8e75f3 --- /dev/null +++ b/src/main/java/tic/frame/checksum/TICChecksum.java @@ -0,0 +1,106 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.frame.checksum; + +import tic.frame.TICMode; + +public class TICChecksum { + + private TICChecksum() {} + + /** + * Verifies the checksum for the given byte array. + * + * @param groupBuffer the byte array to verify the checksum for. Starting with and ending + * with + * @param mode the TIC mode used. If auto mode is used, the mode will be detected from the group + * buffer + * @return true if the checksum is valid, false otherwise + */ + public static boolean verifyChecksum(byte[] groupBuffer, TICMode mode) { + int offsetBegin = TICChecksumOffset.getOffsetBegin(); + int offsetEnd = TICChecksumOffset.getOffsetEnd(groupBuffer, mode); + + return verifyChecksum(groupBuffer, offsetBegin, offsetEnd); + } + + /** + * Computes the checksum for the given byte array. + * + * @param groupBuffer the byte array to compute the checksum for. Starting with and ending + * with + * @param mode the TIC mode used. If auto mode is used, the mode will be detected from the group + * buffer + * @return the computed checksum byte + */ + public static int computeChecksum(byte[] groupBuffer, TICMode mode) { + int offsetBegin = TICChecksumOffset.getOffsetBegin(); + int offsetEnd = TICChecksumOffset.getOffsetEnd(groupBuffer, mode); + + return computeChecksum(groupBuffer, offsetBegin, offsetEnd); + } + + /** + * Verifies the checksum for the given byte array between the specified offsets. + * + * @param groupBuffer the byte array to verify the checksum for. Starting with and ending + * with + * @param offsetBegin tthe begin offset for checksum computation + * @param offsetEnd the end offset for checksum computation + * @return true if the checksum is valid, false otherwise + */ + private static boolean verifyChecksum(byte[] groupBuffer, int offsetBegin, int offsetEnd) { + int computedChecksum = computeChecksum(groupBuffer, offsetBegin, offsetEnd); + int offsetChecksum = TICChecksumOffset.getOffsetChecksum(groupBuffer); + int receivedChecksum = groupBuffer[offsetChecksum] & 0xFF; + + return computedChecksum == receivedChecksum; + } + + /** + * Computes the checksum for the given byte array between the specified offsets. + * + * @param buffer the byte array to compute the checksum for. Starting with and ending with + * + * @param offsetBegin the begin offset for checksum computation + * @param offsetEnd the end offset for checksum computation + * @return the computed checksum byte + */ + private static int computeChecksum(byte[] buffer, int offsetBegin, int offsetEnd) { + int crc = 0; + + TICChecksumOffset.checkBufferOffsets(buffer, offsetBegin, offsetEnd); + + for (int i = offsetBegin; i < offsetEnd; i++) { + crc = computeUpdate(crc, buffer[i]); + } + + return computeEnd(crc); + } + + /** + * Update checksum computation of a TIC group + * + * @param crc current checksum value + * @param octet current byte of the TIC group + * @return checksum updated + */ + private static int computeUpdate(int crc, byte octet) { + return crc + (octet & 0xff); + } + + /** + * Terminate checksum computation of a TIC group + * + * @param crc current checksum value + * @return checksum computed + */ + private static int computeEnd(int crc) { + return (crc & 0x3F) + 0x20; + } +} diff --git a/src/main/java/tic/frame/checksum/TICChecksumOffset.java b/src/main/java/tic/frame/checksum/TICChecksumOffset.java new file mode 100644 index 0000000..3277f73 --- /dev/null +++ b/src/main/java/tic/frame/checksum/TICChecksumOffset.java @@ -0,0 +1,113 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.frame.checksum; + +import java.util.Objects; +import tic.frame.TICMode; +import tic.frame.TICModeDetector; + +public class TICChecksumOffset { + public static final int OFFSET_BEGIN = 1; + public static final int OFFSET_END_HISTORIC = 3; // excluding + public static final int OFFSET_END_STANDARD = 2; // excluding + public static final int OFFSET_CHECKSUM = 1; // excluding + + private TICChecksumOffset() {} + + /** + * Gets the begin offset for checksum computation. + * + * @return the begin offset for checksum computation + */ + public static int getOffsetBegin() { + return OFFSET_BEGIN; + } + + public static int getOffsetEnd(byte[] groupBuffer) { + return getOffsetEnd(groupBuffer, TICMode.AUTO); + } + + public static int getOffsetChecksum(byte[] groupBuffer) { + Objects.requireNonNull(groupBuffer, "groupBuffer must not be null"); + return getOffsetChecksum(groupBuffer, groupBuffer.length - 1); + } + + /** + * Determines the end offset for checksum computation based on the TIC mode. + * + * @param groupBuffer the byte array containing the group data + * @param mode the TIC mode used. If auto mode is used, the mode will be detected from the group + * buffer + * @return the end offset for checksum computation, or null if mode is unknown + */ + public static int getOffsetEnd(byte[] groupBuffer, TICMode mode) { + Objects.requireNonNull(groupBuffer, "groupBuffer must not be null"); + return getOffsetEnd(groupBuffer, mode, 0, groupBuffer.length - 1); + } + + public static int getOffsetChecksum(byte[] buffer, int endOffset) { + return endOffset - OFFSET_CHECKSUM; + } + + /** + * Determines the end offset for checksum computation based on the TIC mode and a given offset. + * + * @param buffer the byte array containing the group data + * @param mode the TIC mode used. If auto mode is used, the mode will be detected from the group + * @param beginOffset the begin offset for the buffer + * @return the end offset for checksum computation, or null if mode is unknown + */ + public static int getOffsetEnd(byte[] buffer, TICMode mode, int beginOffset, int endOffset) { + checkBufferOffsets(buffer, beginOffset, endOffset); + if (mode == null) { + throw new IllegalArgumentException("mode must not be null"); + } + if (mode == TICMode.AUTO) { + mode = TICModeDetector.findModeFromGroupBuffer(buffer); + } + if (mode == null) { + throw new IllegalArgumentException("Unable to determine TIC mode from group buffer"); + } + int length = endOffset - beginOffset + 1; + if (mode == TICMode.HISTORIC) { + return beginOffset + (length - OFFSET_END_HISTORIC); + } else { + return beginOffset + (length - OFFSET_END_STANDARD); + } + } + + /** + * Check if the buffer length is valid for checksum computation + * + * @param buffer the TIC buffer to check + * @param offsetBegin the begin offset for checksum computation + * @param offsetEnd the end offset for checksum computation + */ + public static void checkBufferOffsets(byte[] buffer, int offsetBegin, int offsetEnd) { + Objects.requireNonNull(buffer, "groupBuffer must not be null"); + if (offsetBegin < 0) { + throw new IllegalArgumentException( + "Invalid offsetBegin for checksum computation (must be positive)"); + } + + if (offsetEnd > buffer.length) { + throw new IllegalArgumentException( + "Invalid offsetEnd for checksum computation (must be lower than data length)"); + } + + if (offsetBegin >= offsetEnd) { + throw new IllegalArgumentException( + "Invalid offset range for checksum computation (offsetBegin must be lower than" + + " offsetEnd)"); + } + if (offsetEnd - offsetBegin + 1 > buffer.length) { + throw new IllegalArgumentException( + "Invalid length for checksum computation (length must be lower than data length)"); + } + } +} diff --git a/src/main/java/tic/frame/codec/TICFrameCodec.java b/src/main/java/tic/frame/codec/TICFrameCodec.java new file mode 100644 index 0000000..abd8a0d --- /dev/null +++ b/src/main/java/tic/frame/codec/TICFrameCodec.java @@ -0,0 +1,136 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.frame.codec; + +import tic.frame.TICFrame; +import tic.frame.TICMode; +import tic.frame.TICModeDetector; +import tic.frame.checksum.TICChecksum; +import tic.frame.checksum.TICChecksumOffset; +import tic.frame.delimiter.TICFrameDelimiter; +import tic.frame.delimiter.TICGroupDelimiter; +import tic.frame.delimiter.TICSeparator; +import tic.frame.group.TICGroup; + +public class TICFrameCodec { + + private TICFrameCodec() {} + + public static TICFrame decode(byte[] frameBuffer) { + TICMode mode = checkFrameBuffer(frameBuffer); + TICFrame frame = new TICFrame(mode); + StringBuffer groupBuffer = new StringBuffer(); + + for (int i = 1; i < frameBuffer.length; i++) { + if (groupBuffer.length() == 0) { + if (frameBuffer[i] == TICGroupDelimiter.BEGIN.getValue()) { + groupBuffer.append((char) frameBuffer[i]); + } + } else { + groupBuffer.append((char) frameBuffer[i]); + if (frameBuffer[i] == TICGroupDelimiter.END.getValue()) { + TICGroup group = decodeGroup(groupBuffer.toString().getBytes(), mode); + frame.addGroup(group); + groupBuffer.setLength(0); + } + } + } + + return frame; + } + + public static byte[] encode(TICFrame frame) { + if (frame == null) { + throw new IllegalArgumentException("frame cannot be null"); + } + StringBuffer frameBuffer = new StringBuffer(); + frameBuffer.append((char) TICFrameDelimiter.BEGIN.getValue()); + for (TICGroup group : frame.getGroupList()) { + byte[] groupBuffer = encodeGroup(group, frame.getMode()); + frameBuffer.append(new String(groupBuffer)); + } + frameBuffer.append((char) TICFrameDelimiter.END.getValue()); + return frameBuffer.toString().getBytes(); + } + + private static TICGroup decodeGroup(byte[] groupBuffer, TICMode mode) { + boolean endLabelFound = false; + StringBuffer label = new StringBuffer(); + StringBuffer value = new StringBuffer(); + byte separator = TICSeparator.getValueFromMode(mode); + int beginChecksumOffset = TICChecksumOffset.getOffsetBegin(); + int checksumOffset = TICChecksumOffset.getOffsetChecksum(groupBuffer); + int endValueOffset = checksumOffset - 1; // excluding separator before checksum + + for (int i = beginChecksumOffset; i < endValueOffset; i++) { + if (!endLabelFound) { + if (groupBuffer[i] == separator) { + endLabelFound = true; + continue; + } + label.append((char) groupBuffer[i]); + } else { + value.append((char) groupBuffer[i]); + } + } + boolean isValid = TICChecksum.verifyChecksum(groupBuffer, mode); + TICGroup group = new TICGroup(label.toString(), value.toString(), isValid); + + return group; + } + + private static byte[] encodeGroup(TICGroup group, TICMode mode) { + int checksum = 0; + byte separator = TICSeparator.getValueFromMode(mode); + StringBuffer groupBuffer = new StringBuffer(); + + groupBuffer.append((char) TICGroupDelimiter.BEGIN.getValue()); + groupBuffer.append(group.getLabel()); + groupBuffer.append((char) separator); + groupBuffer.append(group.getValue()); + groupBuffer.append((char) separator); + groupBuffer.append((char) checksum); + groupBuffer.append((char) TICGroupDelimiter.END.getValue()); + byte[] groupBufferBytes = groupBuffer.toString().getBytes(); + checksum = TICChecksum.computeChecksum(groupBufferBytes, mode); + if (!group.isValid()) { + checksum = (checksum + 1) & 0xFF; + } + int checksumOffset = TICChecksumOffset.getOffsetChecksum(groupBufferBytes); + groupBuffer.setCharAt(checksumOffset, (char) checksum); + + return groupBuffer.toString().getBytes(); + } + + private static TICMode checkFrameBuffer(byte[] frameBuffer) { + if (frameBuffer == null) { + throw new IllegalArgumentException("frameBuffer cannot be null"); + } + if (frameBuffer.length + < TICFrameDelimiter.values().length + TICGroupDelimiter.values().length) { + throw new IllegalArgumentException( + "frameBuffer length must be >= " + + (TICFrameDelimiter.values().length + TICGroupDelimiter.values().length) + + " bytes"); + } + if (frameBuffer[0] != TICFrameDelimiter.BEGIN.getValue()) { + throw new IllegalArgumentException( + "frameBuffer begin must be " + TICFrameDelimiter.BEGIN.getValue()); + } + if (frameBuffer[frameBuffer.length - 1] != TICFrameDelimiter.END.getValue()) { + throw new IllegalArgumentException( + "frameBuffer end must be " + TICFrameDelimiter.END.getValue()); + } + TICMode mode = TICModeDetector.findModeFromFrameBuffer(frameBuffer); + if (mode == null) { + throw new IllegalArgumentException("Unable to determine TIC Mode from frame buffer!"); + } + + return mode; + } +} diff --git a/src/main/java/tic/frame/codec/TICFrameDetailledCodec.java b/src/main/java/tic/frame/codec/TICFrameDetailledCodec.java new file mode 100644 index 0000000..9e68ccf --- /dev/null +++ b/src/main/java/tic/frame/codec/TICFrameDetailledCodec.java @@ -0,0 +1,67 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.frame.codec; + +import java.util.List; +import org.json.JSONArray; +import org.json.JSONObject; +import tic.frame.TICFrame; +import tic.frame.group.TICGroup; +import tic.util.codec.JsonObjectCodec; +import tic.util.codec.JsonStringCodec; + +public class TICFrameDetailledCodec implements JsonObjectCodec, JsonStringCodec { + public static TICFrameDetailledCodec instance = null; + + private TICFrameDetailledCodec() {} + + public static final TICFrameDetailledCodec getInstance() { + if (instance == null) { + instance = new TICFrameDetailledCodec(); + } + return instance; + } + + @Override + public String encodeToJsonString(TICFrame frame, int indentFactor) throws Exception { + if (frame == null) { + throw new IllegalArgumentException("frame cannot be null"); + } + JSONObject jsonFrame = (JSONObject) encodeToJsonObject(frame); + return indentFactor > 0 ? jsonFrame.toString(indentFactor) : jsonFrame.toString(); + } + + @Override + public TICFrame decodeFromJsonString(String jsonString, int indentFactor) throws Exception { + throw new UnsupportedOperationException("Unimplemented method 'decodeFromJsonString'"); + } + + @Override + public Object encodeToJsonObject(TICFrame frame) throws Exception { + JSONObject jsonFrame = new JSONObject(); + jsonFrame.put("mode", frame.getMode().name()); + List groups = frame.getGroupList(); + JSONArray jsonGroups = new JSONArray(); + groups.forEach( + group -> { + JSONObject jsonGroup = new JSONObject(); + jsonGroup.put("label", group.getLabel()); + jsonGroup.put("value", group.getValue()); + jsonGroup.put("isValid", group.isValid()); + jsonGroups.put(jsonGroup); + }); + jsonFrame.put("groupList", jsonGroups); + return jsonFrame; + } + + @Override + public TICFrame decodeFromJsonObject(Object jsonObject) throws Exception { + throw new UnsupportedOperationException("Unimplemented method 'decodeFromJsonObject'"); + } + +} diff --git a/src/main/java/tic/frame/codec/TICFrameSummarizedCodec.java b/src/main/java/tic/frame/codec/TICFrameSummarizedCodec.java new file mode 100644 index 0000000..a93afa0 --- /dev/null +++ b/src/main/java/tic/frame/codec/TICFrameSummarizedCodec.java @@ -0,0 +1,61 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.frame.codec; + +import java.util.List; +import org.json.JSONObject; +import tic.frame.TICFrame; +import tic.frame.group.TICGroup; +import tic.util.codec.JsonObjectCodec; +import tic.util.codec.JsonStringCodec; + +public class TICFrameSummarizedCodec + implements JsonStringCodec, JsonObjectCodec { + + public static TICFrameSummarizedCodec instance = null; + + private TICFrameSummarizedCodec() {} + + public static final TICFrameSummarizedCodec getInstance() { + if (instance == null) { + instance = new TICFrameSummarizedCodec(); + } + return instance; + } + + @Override + public String encodeToJsonString(TICFrame frame, int indentFactor) throws Exception { + JSONObject jsonFrame = (JSONObject) encodeToJsonObject(frame); + return indentFactor < 0 ? jsonFrame.toString() : jsonFrame.toString(indentFactor); + } + + @Override + public TICFrame decodeFromJsonString(String jsonString, int indentFactor) throws Exception { + throw new UnsupportedOperationException("Unimplemented method 'decodeFromJsonString'"); + } + + @Override + public Object encodeToJsonObject(TICFrame frame) throws Exception { + List groups = frame.getGroupList(); + JSONObject jsonFrame = new JSONObject(); + groups.forEach( + group -> { + if (group.isValid()) { + jsonFrame.put(group.getLabel(), group.getValue()); + } else { + jsonFrame.put("!" + group.getLabel(), group.getValue()); + } + }); + return jsonFrame; + } + + @Override + public TICFrame decodeFromJsonObject(Object jsonObject) throws Exception { + throw new UnsupportedOperationException("Unimplemented method 'decodeFromJsonObject'"); + } +} diff --git a/src/main/java/tic/frame/delimiter/TICFrameDelimiter.java b/src/main/java/tic/frame/delimiter/TICFrameDelimiter.java new file mode 100644 index 0000000..ea11779 --- /dev/null +++ b/src/main/java/tic/frame/delimiter/TICFrameDelimiter.java @@ -0,0 +1,30 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.frame.delimiter; + +public enum TICFrameDelimiter { + /** Begin byte (STX, 0x02) for TIC frames. */ + BEGIN((byte) 0x02), + /** End byte (ETX, 0x03) for TIC frames. */ + END((byte) 0x03); + + private final byte value; + + private TICFrameDelimiter(byte value) { + this.value = value; + } + + /** + * Gets the hexadecimal value of the delimiter. + * + * @return the hexadecimal value as a byte + */ + public byte getValue() { + return value; + } +} diff --git a/src/main/java/tic/frame/delimiter/TICGroupDelimiter.java b/src/main/java/tic/frame/delimiter/TICGroupDelimiter.java new file mode 100644 index 0000000..2d5dc4c --- /dev/null +++ b/src/main/java/tic/frame/delimiter/TICGroupDelimiter.java @@ -0,0 +1,30 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.frame.delimiter; + +public enum TICGroupDelimiter { + /** Begin byte (Line Feed, 0x0A) for TIC groups. */ + BEGIN((byte) 0x0A), + /** End byte (Carriage Return, 0x0D) for TIC groups. */ + END((byte) 0x0D); + + private final byte value; + + private TICGroupDelimiter(byte value) { + this.value = value; + } + + /** + * Gets the hexadecimal value of the delimiter. + * + * @return the hexadecimal value as a byte + */ + public byte getValue() { + return value; + } +} diff --git a/src/main/java/tic/frame/delimiter/TICSeparator.java b/src/main/java/tic/frame/delimiter/TICSeparator.java new file mode 100644 index 0000000..051bd7e --- /dev/null +++ b/src/main/java/tic/frame/delimiter/TICSeparator.java @@ -0,0 +1,56 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.frame.delimiter; + +import tic.frame.TICMode; + +/** Enumeration representing TIC frame separators for different TIC modes. */ +public enum TICSeparator { + /** Separator character (SPACE = 0x20) for historic TIC frames. */ + HISTORIC((byte) 0x20), + /** Separator character (TAB = 0x09) for standard TIC frames. */ + STANDARD((byte) 0x09); + + private final byte value; + + /** + * Constructs a TICSeparator with the specified hexadecimal value. + * + * @param value the hexadecimal byte value of the separator + */ + private TICSeparator(byte value) { + this.value = value; + } + + /** + * Gets the hexadecimal value of the separator. + * + * @return the hexadecimal value as a byte + */ + public byte getValue() { + return value; + } + + /** + * Gets the separator value corresponding to the given TIC mode. + * + * @param mode the TIC mode + * @return the separator value as a byte + */ + public static byte getValueFromMode(TICMode mode) { + if (mode == null) { + throw new IllegalArgumentException("cannot get separator value from null mode"); + } + if (mode == TICMode.HISTORIC) { + return HISTORIC.getValue(); + } else if (mode == TICMode.STANDARD) { + return STANDARD.getValue(); + } + throw new IllegalArgumentException("cannot get separator value from " + mode.name() + " mode"); + } +} diff --git a/src/main/java/tic/frame/delimiter/TICStartPattern.java b/src/main/java/tic/frame/delimiter/TICStartPattern.java new file mode 100644 index 0000000..b65b623 --- /dev/null +++ b/src/main/java/tic/frame/delimiter/TICStartPattern.java @@ -0,0 +1,67 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.frame.delimiter; + +import tic.frame.TICMode; + +/** Enumeration representing TIC frame start patterns for different TIC modes. */ +public enum TICStartPattern { + /** Start pattern (STX, LF, A, D, C, O, SPACE) for historic TIC frames. */ + HISTORIC(new byte[] {2, 10, 65, 68, 67, 79, 32}), + /** Start pattern (STX, LF, A, D, S, C, TAB) for standard TIC frames. */ + STANDARD(new byte[] {2, 10, 65, 68, 83, 67, 9}); + + private final byte[] value; + + /** + * Constructs a TICStartPattern with the specified hexadecimal value. + * + * @param value the byte array representing the start pattern + */ + private TICStartPattern(byte[] value) { + this.value = value; + } + + /** + * Gets the hexadecimal value of the start pattern. + * + * @return the hexadecimal value as a byte array + */ + public byte[] getValue() { + return value; + } + + /** + * Gets the start pattern value corresponding to the given TIC mode. + * + * @param mode the TIC mode + * @return the byte array representing the start pattern for the specified mode + * @throws IllegalArgumentException if the TIC mode is unsupported + */ + public static byte[] getValueFromMode(TICMode mode) { + if (mode == null) { + throw new IllegalArgumentException("cannot get start pattern value from null mode"); + } + if (mode == TICMode.HISTORIC) { + return HISTORIC.getValue(); + } else if (mode == TICMode.STANDARD) { + return STANDARD.getValue(); + } + throw new IllegalArgumentException( + "cannot get start pattern value from " + mode.name() + " mode"); + } + + /** + * Gets the length of the start pattern. + * + * @return the length as an integer + */ + public static int length() { + return 7; + } +} diff --git a/src/main/java/tic/frame/group/TICGroup.java b/src/main/java/tic/frame/group/TICGroup.java new file mode 100644 index 0000000..e345815 --- /dev/null +++ b/src/main/java/tic/frame/group/TICGroup.java @@ -0,0 +1,90 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.frame.group; + +public class TICGroup { + private String label; + private String value; + private boolean isValid; + + /** + * Constructs a TIC group with the specified label and value. + * + * @param label the label of the group + * @param value the value of the group + */ + public TICGroup(String label, String value) { + this.label = label; + this.value = value; + this.isValid = true; + } + + /** + * Constructs a TIC group with the specified label, value, and validity. + * + * @param label the label of the group + * @param value the value of the group + * @param isValid the validity of the group + */ + public TICGroup(String label, String value, boolean isValid) { + this.label = label; + this.value = value; + this.isValid = isValid; + } + + @Override + public int hashCode() { + return this.label.hashCode() + this.value.hashCode() + Boolean.hashCode(this.isValid); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || this.getClass() != obj.getClass()) { + return false; + } + TICGroup other = (TICGroup) obj; + return this.label.equals(other.label) + && this.value.equals(other.value) + && this.isValid == other.isValid; + } + + /** + * Sets the validity of the TIC group. + * + * @param isValid true if the group is valid, false otherwise + */ + public boolean isValid() { + return this.isValid; + } + + /** + * Returns the label of the TIC group. + * + * @return the label of the group + */ + public String getLabel() { + return this.label; + } + + /** + * Returns the value of the TIC group. + * + * @return the value of the group + */ + public String getValue() { + return this.value; + } + + @Override + public String toString() { + return "(label=" + this.label + ", value=" + this.value + ", isValid=" + this.isValid + ")"; + } +} diff --git a/src/main/java/tic/io/PlugSubscriber.java b/src/main/java/tic/io/PlugSubscriber.java new file mode 100644 index 0000000..2be9052 --- /dev/null +++ b/src/main/java/tic/io/PlugSubscriber.java @@ -0,0 +1,50 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.io; + +import tic.util.task.Subscriber; + +/** + * Listener interface for receiving plug and unplug events from devices or hardware. + * + *

This interface extends {@link Subscriber} and defines callback methods that are invoked when + * hardware devices are connected (plugged) or disconnected (unplugged) from the system. + * Implementations of this interface can be registered with device monitors or port finders to + * receive notifications about hardware state changes. + * + *

The interface uses generics to allow different types of information to be passed with the + * plug/unplug events, such as device descriptors, port information, or other device-specific + * details. + * + * @param the type of information associated with plugged or unplugged notifications + * @author Enedis Smarties team + * @see Subscriber + */ +public interface PlugSubscriber extends Subscriber { + /** + * Called when a device has been plugged into the system. + * + *

This method is invoked when the system detects that a new device has been connected. + * Implementations should handle the new device information according to their specific + * requirements. + * + * @param info the information about the device that has been plugged in + */ + public void onPlugged(T info); + + /** + * Called when a device has been unplugged from the system. + * + *

This method is invoked when the system detects that a device has been disconnected. + * Implementations should handle the removal appropriately, such as closing connections or + * releasing resources associated with the device. + * + * @param info the information about the device that has been unplugged + */ + public void onUnplugged(T info); +} diff --git a/src/main/java/tic/io/PortFinder.java b/src/main/java/tic/io/PortFinder.java new file mode 100644 index 0000000..ee2b66d --- /dev/null +++ b/src/main/java/tic/io/PortFinder.java @@ -0,0 +1,38 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.io; + +import java.util.List; + +/** + * Generic interface for discovering and enumerating ports on the system. + * + *

This interface defines a contract for port discovery implementations that can find and return + * information about available ports. It uses generics to support different types of port + * descriptors, such as serial ports, USB ports, or other communication ports. + * + *

Implementations of this interface are responsible for querying the underlying system (via + * OS-specific APIs, device managers, or file systems) to enumerate all available ports and return + * their descriptors. + * + * @param the type of port descriptor returned by this finder + * @author Enedis Smarties team + * @see List + */ +public interface PortFinder { + /** + * Discovers and returns all available ports on the system. + * + *

This method queries the system to find all ports that are currently available. The specific + * discovery mechanism depends on the implementation and may involve platform-specific APIs or + * system queries. + * + * @return a list of port descriptors representing all discovered ports + */ + public List findAll(); +} diff --git a/src/main/java/tic/io/PortPlugNotifier.java b/src/main/java/tic/io/PortPlugNotifier.java new file mode 100644 index 0000000..4950109 --- /dev/null +++ b/src/main/java/tic/io/PortPlugNotifier.java @@ -0,0 +1,217 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.io; + +import tic.util.time.Time; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.concurrent.atomic.AtomicReference; +import tic.util.task.TaskPeriodicWithSubscribers; + +/** + * Periodic monitor that detects and notifies when ports are plugged or unplugged. + * + *

This class extends {@link TaskPeriodicWithSubscribers} to provide automatic detection of port + * connection and disconnection events. It periodically polls the system using a {@link PortFinder} + * to discover available ports, compares the results with the previous state, and notifies + * registered {@link PlugSubscriber} instances of any changes. + * + *

The notifier maintains a cached list of known port descriptors and performs delta detection to + * identify: + * + *

    + *
  • Newly plugged ports (present in current scan but not in previous) + *
  • Unplugged ports (present in previous scan but not in current) + *
+ * + *

The class is thread-safe and uses atomic references for the finder and synchronized access for + * the descriptor list to ensure consistency during concurrent access. + * + * @param the port finder type that extends PortFinder + * @param the port descriptor type + * @author Enedis Smarties team + * @see PortFinder + * @see PlugSubscriber + * @see TaskPeriodicWithSubscribers + */ +public class PortPlugNotifier, T> + extends TaskPeriodicWithSubscribers> { + private AtomicReference finder = new AtomicReference(); + private List descriptors = new ArrayList(); + + /** + * Main utility method that runs a port plug monitoring loop. + * + *

This method sets up a shutdown hook to gracefully stop the notifier when CTRL+C is pressed, + * subscribes the provided subscriber, starts the notifier, and runs an infinite loop until the + * notifier is stopped. + * + *

This is typically used for testing or standalone monitoring applications. + * + * @param the port finder type that extends PortFinder + * @param the port descriptor type + * @param notifier the port plug notifier instance to run + * @param subscriber the subscriber to receive plug/unplug notifications + */ + public static , T> void main( + PortPlugNotifier notifier, PlugSubscriber subscriber) { + /* 1. Add program shutdown hook when CTRL+C is pressed to exit program properly */ + Runtime.getRuntime() + .addShutdownHook( + new Thread( + new Runnable() { + @Override + public void run() { + notifier.unsubscribe(subscriber); + notifier.stop(); + } + })); + /* 4. Add a subscriber to notification service */ + notifier.subscribe(subscriber); + /* 5. Start the notification service */ + notifier.start(); + /* 6. Execute forever loop until CTRL+C is pressed */ + while (notifier.isRunning()) { + Time.sleep(1000); + } + } + + /** + * Constructs a PortPlugNotifier with the specified polling period and port finder. + * + *

The notifier will periodically scan for ports using the provided finder at the specified + * interval. The period determines the responsiveness of plug/unplug detection. + * + * @param period the polling period in milliseconds + * @param finder the port finder used to discover available ports + */ + public PortPlugNotifier(long period, F finder) { + super(period); + this.setFinder(finder); + } + + /** + * Sets the port finder used to discover available ports. + * + *

This method updates the finder used for port discovery. The finder is stored in an atomic + * reference to ensure thread-safe access during periodic polling. + * + * @param finder the port finder to use for discovering ports + * @throws IllegalArgumentException if finder is null + */ + public void setFinder(F finder) { + if (finder == null) { + throw new IllegalArgumentException("Cannot set null finder"); + } + this.finder.set(finder); + } + + /** + * Periodically executed process that detects port changes and notifies subscribers. + * + *

This method is called at each polling interval and performs the following steps: + * + *

    + *
  1. Discovers currently available ports using the finder + *
  2. Checks for unplugged ports (in old list but not in new list) + *
  3. Checks for newly plugged ports (in new list but not in old list) + *
  4. Updates the internal descriptor cache with the new state + *
+ */ + @Override + protected void process() { + List newDescriptors = this.finder.get().findAll(); + + this.checkAndNotifyIfUnplugged(newDescriptors); + this.checkAndNotifyIfPlugged(newDescriptors); + this.updateDescriptors(newDescriptors); + } + + /** + * Checks for unplugged ports and notifies subscribers. + * + *

This method compares the current descriptor list with the new list to identify ports that + * were present before but are no longer available. For each unplugged port, it notifies all + * subscribers. + * + * @param newDescriptors the newly discovered list of port descriptors + */ + private void checkAndNotifyIfUnplugged(List newDescriptors) { + Iterator it = this.descriptors.iterator(); + + while (it.hasNext()) { + T descriptor = it.next(); + if (!newDescriptors.contains(descriptor)) { + this.notifyOnUnplugged(descriptor); + } + } + } + + /** + * Checks for newly plugged ports and notifies subscribers. + * + *

This method compares the new descriptor list with the current list to identify ports that + * are newly available. For each newly plugged port, it notifies all subscribers. + * + * @param newDescriptors the newly discovered list of port descriptors + */ + private void checkAndNotifyIfPlugged(List newDescriptors) { + Iterator it = newDescriptors.iterator(); + + while (it.hasNext()) { + T newDescriptor = it.next(); + if (!this.descriptors.contains(newDescriptor)) { + this.notifyOnPlugged(newDescriptor); + } + } + } + + /** + * Updates the internal descriptor cache with the new list of ports. + * + *

This method clears the current descriptor list and replaces it with the newly discovered + * ports. The operation is synchronized to ensure thread-safe access. + * + * @param newDescriptors the new list of port descriptors to cache + */ + private void updateDescriptors(List newDescriptors) { + synchronized (this.descriptors) { + this.descriptors.clear(); + this.descriptors.addAll(newDescriptors); + } + } + + /** + * Notifies all subscribers that a port has been plugged in. + * + *

This method iterates through all subscribed listeners and calls their onPlugged method with + * the port information. + * + * @param info the information about the port that was plugged in + */ + private void notifyOnPlugged(T info) { + for (PlugSubscriber subscriber : this.notifier.getSubscribers()) { + subscriber.onPlugged(info); + } + } + + /** + * Notifies all subscribers that a port has been unplugged. + * + *

This method iterates through all subscribed listeners and calls their onUnplugged method + * with the port information. + * + * @param info the information about the port that was unplugged + */ + private void notifyOnUnplugged(T info) { + for (PlugSubscriber subscriber : this.notifier.getSubscribers()) { + subscriber.onUnplugged(info); + } + } +} diff --git a/src/main/java/tic/io/modem/ModemDescriptor.java b/src/main/java/tic/io/modem/ModemDescriptor.java new file mode 100644 index 0000000..fa41ce0 --- /dev/null +++ b/src/main/java/tic/io/modem/ModemDescriptor.java @@ -0,0 +1,126 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.io.modem; + +import java.util.Objects; +import tic.io.serialport.SerialPortDescriptor; +import tic.io.usb.UsbPortDescriptor; + +/** Descriptor of a modem. */ +public class ModemDescriptor extends SerialPortDescriptor { + private ModemType modemType; + + public static class Builder> extends SerialPortDescriptor.Builder { + private ModemType modemType; + + public T modemType(ModemType modemType) { + this.modemType = modemType; + if (modemType == null) { + this.productId = null; + this.vendorId = null; + } else { + this.productId = modemType.productId(); + this.vendorId = modemType.vendorId(); + } + return self(); + } + + public T copy(SerialPortDescriptor serialPortDescriptor) { + this.portId = serialPortDescriptor.portId(); + this.portName = serialPortDescriptor.portName(); + this.description = serialPortDescriptor.description(); + this.productId = serialPortDescriptor.productId(); + this.vendorId = serialPortDescriptor.vendorId(); + this.productName = serialPortDescriptor.productName(); + this.manufacturer = serialPortDescriptor.manufacturer(); + this.serialNumber = serialPortDescriptor.serialNumber(); + return self(); + } + + public T copy(UsbPortDescriptor usbPortDescriptor) { + this.productId = usbPortDescriptor.idProduct(); + this.vendorId = usbPortDescriptor.idVendor(); + this.productName = usbPortDescriptor.product(); + this.manufacturer = usbPortDescriptor.manufacturer(); + this.serialNumber = usbPortDescriptor.serialNumber(); + return self(); + } + + /** + * Validates the builder's fields. + * + * @throws IllegalArgumentException if any required field is invalid + */ + protected void validate() { + super.validate(); + if (this.modemType != null) { + if (this.productId == null) { + throw new IllegalArgumentException( + "Modem type is specified while productId is not provided"); + } + if (this.productId != this.modemType.productId()) { + throw new IllegalArgumentException("Modem type is inconsistent with the productId"); + } + if (this.vendorId == null) { + throw new IllegalArgumentException( + "Modem type is specified while vendorId is not provided"); + } + if (this.vendorId != this.modemType.vendorId()) { + throw new IllegalArgumentException("Modem type is inconsistent with the vendorId"); + } + } + } + + public ModemDescriptor build() { + this.validate(); + return new ModemDescriptor(this); + } + } + + /** + * Constructs a ModemDescriptor with all parameters explicitly set. + * + *

This constructor creates a descriptor with all serial port and USB device properties + * specified according to the modem type. + * + * @param builder the builder instance containing all the parameters + */ + public ModemDescriptor(Builder builder) { + super(builder); + this.modemType = builder.modemType; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof ModemDescriptor)) { + return false; + } + ModemDescriptor other = (ModemDescriptor) obj; + if (this.modemType != other.modemType) { + return false; + } + return super.equals(obj); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), this.modemType); + } + + /** + * Get modem type + * + * @return the modem type + */ + public ModemType modemType() { + return this.modemType; + } +} diff --git a/src/main/java/tic/io/modem/ModemFinder.java b/src/main/java/tic/io/modem/ModemFinder.java new file mode 100644 index 0000000..040fd75 --- /dev/null +++ b/src/main/java/tic/io/modem/ModemFinder.java @@ -0,0 +1,69 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.io.modem; + +import java.util.List; +import tic.io.PortFinder; + +/** Interface used to find all modem descriptors */ +public interface ModemFinder extends PortFinder { + /** + * Find modem descriptor matching with port id. + * + * @param portId the unique port identifier desired + * @return modem descriptor found, or null if nothing matches with portId + */ + public default ModemDescriptor findByPortId(String portId) { + return this.findAll().stream() + .filter(p -> (p.portId() != null) ? p.portId().equals(portId) : portId == null) + .findFirst() + .orElse(null); + } + + /** + * Find modem descriptor matching with port name. + * + * @param portName the port name desired + * @return modem descriptor found, or null if nothing matches with portName + */ + public default ModemDescriptor findByPortName(String portName) { + return this.findAll().stream() + .filter( + p -> (p.portName() != null) ? p.portName().equals(portName) : portName == null) + .findFirst() + .orElse(null); + } + + /** + * Find native modem (not USB) descriptor matching with port name. + * + * @param portName the port name desired + * @return modem descriptor found, or null if nothing matches with portName + */ + public ModemDescriptor findNative(String portName); + + /** + * Find modem descriptor matching with port id or port name. + * + * @param portId the unique port identifier desired + * @param portName the port name desired + * @return modem descriptor found, or null if nothing matches with portName + */ + public default ModemDescriptor findByPortIdOrPortName(String portId, String portName) { + ModemDescriptor descriptor = this.findByPortId(portId); + + if (descriptor == null) { + descriptor = this.findByPortName(portName); + } + + return descriptor; + } + + @Override + List findAll(); +} diff --git a/src/main/java/tic/io/modem/ModemFinderBase.java b/src/main/java/tic/io/modem/ModemFinderBase.java new file mode 100644 index 0000000..bbdc06e --- /dev/null +++ b/src/main/java/tic/io/modem/ModemFinderBase.java @@ -0,0 +1,114 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.io.modem; + +import java.util.ArrayList; +import java.util.List; +import tic.io.serialport.SerialPortDescriptor; +import tic.io.serialport.SerialPortFinder; +import tic.io.usb.UsbPortDescriptor; +import tic.io.usb.UsbPortFinder; + +/** Class used to find all modem descriptors */ +public class ModemFinderBase implements ModemFinder { + + /** + * Create ModemFinder instance + * + * @param serialPortFinder the SerialPortFinder instance + * @param usbPortFinder the UsbPortFinder instance + * @return ModemFinder instance created + * @throws IllegalArgumentException if any input instance is null + */ + public static ModemFinder create(SerialPortFinder serialPortFinder, UsbPortFinder usbPortFinder) { + + if (serialPortFinder == null) { + throw new IllegalArgumentException("Cannot set null serial port finder"); + } + if (usbPortFinder == null) { + throw new IllegalArgumentException("Cannot set null USB port finder"); + } + + return new ModemFinderBase(serialPortFinder, usbPortFinder); + } + + private final SerialPortFinder serialPortFinder; + private final UsbPortFinder usbPortFinder; + + /** + * Constructor with finder parameters + * + * @param serialPortFinder the serial port finder interface + * @param usbPortFinder the USB port finder interface + */ + private ModemFinderBase(SerialPortFinder serialPortFinder, UsbPortFinder usbPortFinder) { + this.serialPortFinder = serialPortFinder; + this.usbPortFinder = usbPortFinder; + } + + @Override + public List findAll() { + List descriptors = new ArrayList<>(); + + for (ModemType modemType : ModemType.values()) { + List tmpSerialPort = + this.serialPortFinder.findByProductIdAndVendorId( + modemType.productId(), modemType.vendorId()); + + if (tmpSerialPort.isEmpty()) { + List tmpUSBPort = + this.usbPortFinder.findByProductIdAndVendorId( + modemType.productId(), modemType.vendorId()); + + for (UsbPortDescriptor upd : tmpUSBPort) { + try { + ModemDescriptor descriptor = + new ModemDescriptor.Builder<>() + .copy(upd) + .modemType(modemType) + .build(); + descriptors.add(descriptor); + } catch (IllegalArgumentException e) { + // Ignore descriptors that fail validation + } + } + } else { + for (SerialPortDescriptor spd : tmpSerialPort) { + try { + ModemDescriptor descriptor = + new ModemDescriptor.Builder<>() + .copy(spd) + .modemType(modemType) + .build(); + descriptors.add(descriptor); + } catch (IllegalArgumentException e) { + // Ignore descriptors that fail validation + } + } + } + } + + return descriptors; + } + + @Override + public ModemDescriptor findNative(String portName) { + ModemDescriptor modemDescriptor = null; + SerialPortDescriptor serialPortDescriptor = this.serialPortFinder.findNative(portName); + + if (serialPortDescriptor != null) { + try { + modemDescriptor = new ModemDescriptor.Builder<>().copy(serialPortDescriptor).build(); + } catch (IllegalArgumentException e) { + // Ignore descriptors that fail validation + } + } + + return modemDescriptor; + } +} diff --git a/src/main/java/tic/io/modem/ModemJsonCodec.java b/src/main/java/tic/io/modem/ModemJsonCodec.java new file mode 100644 index 0000000..6297207 --- /dev/null +++ b/src/main/java/tic/io/modem/ModemJsonCodec.java @@ -0,0 +1,94 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.io.modem; + +import java.util.Collections; +import java.util.List; +import org.json.JSONArray; +import org.json.JSONObject; +import tic.util.codec.JsonArrayCodec; +import tic.util.codec.JsonObjectCodec; +import tic.util.codec.JsonStringCodec; + +/** Utility class to convert modem descriptors to their JSON representation. */ +public final class ModemJsonCodec + implements JsonArrayCodec>, + JsonObjectCodec, + JsonStringCodec { + + private static ModemJsonCodec instance = new ModemJsonCodec(); + + public static ModemJsonCodec getInstance() { + if (instance == null) { + instance = new ModemJsonCodec(); + } + return instance; + } + + private ModemJsonCodec() {} + + @Override + public Object encodeToJsonArray(List descriptors) throws Exception { + List safeList = descriptors == null ? Collections.emptyList() : descriptors; + + JSONArray array = new JSONArray(); + safeList.forEach( + descriptor -> { + try { + array.put(encodeToJsonObject(descriptor)); + } catch (Exception e) { + array.put(JSONObject.NULL); + } + }); + + return array; + } + + @Override + public List decodeFromJsonArray(Object jsonArray) throws Exception { + throw new UnsupportedOperationException("Unimplemented method 'decodeFromJsonArray'"); + } + + @Override + public Object encodeToJsonObject(ModemDescriptor descriptor) throws Exception { + JSONObject jsonObject = new JSONObject(); + jsonObject.put("portId", descriptor.portId()); + jsonObject.put("portName", descriptor.portName()); + jsonObject.put("description", descriptor.description()); + jsonObject.put("productId", descriptor.productId()); + jsonObject.put("vendorId", descriptor.vendorId()); + jsonObject.put("productName", descriptor.productName()); + jsonObject.put("manufacturer", descriptor.manufacturer()); + jsonObject.put("serialNumber", descriptor.serialNumber()); + jsonObject.put( + "modemType", + descriptor.modemType() == null ? JSONObject.NULL : descriptor.modemType().name()); + return jsonObject; + } + + @Override + public ModemDescriptor decodeFromJsonObject(Object jsonObject) throws Exception { + throw new UnsupportedOperationException("Unimplemented method 'decodeFromJsonObject'"); + } + + @Override + public String encodeToJsonString(ModemDescriptor descriptor, int indentFactor) throws Exception { + if (descriptor == null) { + throw new IllegalArgumentException("descriptor cannot be null"); + } + + JSONObject json = (JSONObject) encodeToJsonObject(descriptor); + return indentFactor < 0 ? json.toString() : json.toString(indentFactor); + } + + @Override + public ModemDescriptor decodeFromJsonString(String jsonString, int indentFactor) + throws Exception { + throw new UnsupportedOperationException("Unimplemented method 'decodeFromJsonString'"); + } +} diff --git a/src/main/java/tic/io/modem/ModemPlugNotifier.java b/src/main/java/tic/io/modem/ModemPlugNotifier.java new file mode 100644 index 0000000..3b58e8e --- /dev/null +++ b/src/main/java/tic/io/modem/ModemPlugNotifier.java @@ -0,0 +1,24 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.io.modem; + +import tic.io.PortPlugNotifier; + +/** Class used to notify when a modem has been plugged or unplugged */ +public class ModemPlugNotifier extends PortPlugNotifier { + + /** + * Constructor with all parameters + * + * @param period the period (in milliseconds) used to look for plugged or unplugged modems + * @param finder the modem finder interface used to find all modem descriptors + */ + public ModemPlugNotifier(long period, ModemFinder finder) { + super(period, finder); + } +} diff --git a/src/main/java/tic/io/modem/ModemType.java b/src/main/java/tic/io/modem/ModemType.java new file mode 100644 index 0000000..532741d --- /dev/null +++ b/src/main/java/tic/io/modem/ModemType.java @@ -0,0 +1,42 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.io.modem; + +/** Supported modem types. */ +public enum ModemType { + /** Modem michaud */ + MICHAUD((short) 0x6001, (short) 0x0403), + /** Télé info */ + TELEINFO((short) 0x6015, (short) 0x0403); + + private final short productId; + private final short vendorId; + + ModemType(short productId, short vendorId) { + this.productId = productId; + this.vendorId = vendorId; + } + + /** + * Get product id + * + * @return product id + */ + public short productId() { + return this.productId; + } + + /** + * Get vendor id + * + * @return vendor id + */ + public short vendorId() { + return this.vendorId; + } +} diff --git a/src/main/java/tic/io/serialport/SerialPortDescriptor.java b/src/main/java/tic/io/serialport/SerialPortDescriptor.java new file mode 100644 index 0000000..34c24b4 --- /dev/null +++ b/src/main/java/tic/io/serialport/SerialPortDescriptor.java @@ -0,0 +1,269 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.io.serialport; + +import java.util.Objects; +import tic.util.ValueChecker; + +/** + * Descriptor class for serial port information and USB device properties. + * + *

This class provides a structured way to store and access serial port information, including + * both native serial ports and USB-based serial devices, without relying on the legacy + * DataDictionary infrastructure. It encapsulates all relevant properties needed to identify, + * configure, and connect to serial ports. + * + *

The descriptor includes the following information: + * + *

    + *
  • Port unique identifier + *
  • Port name used to open the serial port + *
  • Port description + *
  • USB device product identifier (PID) + *
  • USB device vendor identifier (VID) + *
  • USB device product name + *
  • USB device manufacturer + *
  • USB device serial number + *
+ * + *

The class supports distinguishing between native serial ports (e.g., COM ports) and USB serial + * devices through the {@link #isNative()} method. + * + * @author Enedis Smarties team + */ +public class SerialPortDescriptor { + + private String portId; + private String portName; + private String description; + private Short productId; + private Short vendorId; + private String productName; + private String manufacturer; + private String serialNumber; + + /** Builder class for constructing SerialPortDescriptor instances. */ + public static class Builder> { + protected String portId; + protected String portName; + protected String description; + protected Short productId; + protected Short vendorId; + protected String productName; + protected String manufacturer; + protected String serialNumber; + + @SuppressWarnings("unchecked") + public T self() { + return (T) this; + } + + public T portId(String portId) { + this.portId = portId; + return self(); + } + + public T portName(String portName) { + this.portName = portName; + return self(); + } + + public T description(String description) { + this.description = description; + return self(); + } + + public T productId(Short productId) { + this.productId = productId; + return self(); + } + + public T vendorId(Short vendorId) { + this.vendorId = vendorId; + return self(); + } + + public T productName(String productName) { + this.productName = productName; + return self(); + } + + public T manufacturer(String manufacturer) { + this.manufacturer = manufacturer; + return self(); + } + + public T serialNumber(String serialNumber) { + this.serialNumber = serialNumber; + return self(); + } + + /** + * Validates the builder's fields. + * + * @throws IllegalArgumentException if any required field is invalid + */ + protected void validate() { + ValueChecker.validateString(this.portId, "portId", true, false); + ValueChecker.validateString(this.portName, "portName", true, false); + ValueChecker.validateString(this.description, "description", true, false); + ValueChecker.validateNumber(this.productId, "productId", true); + ValueChecker.validateNumber(this.vendorId, "vendorId", true); + ValueChecker.validateString(this.productName, "productName", true, false); + ValueChecker.validateString(this.manufacturer, "manufacturer", true, false); + ValueChecker.validateString(this.serialNumber, "serialNumber", true, false); + } + + /** + * Builds the SerialPortDescriptor instance with the provided parameters. + * + * @return the constructed SerialPortDescriptor instance + * @throws IllegalArgumentException if any required field is invalid + */ + public SerialPortDescriptor build() { + this.validate(); + + return new SerialPortDescriptor(this); + } + } + + /** + * Constructs a SerialPortDescriptor with all parameters explicitly set. + * + *

This constructor creates a descriptor with all serial port and USB device properties + * specified. + * + * @param builder the builder instance containing all the parameters + */ + protected SerialPortDescriptor(Builder builder) { + this.portId = builder.portId; + this.portName = builder.portName; + this.description = builder.description; + this.productId = builder.productId; + this.vendorId = builder.vendorId; + this.productName = builder.productName; + this.manufacturer = builder.manufacturer; + this.serialNumber = builder.serialNumber; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof SerialPortDescriptor)) { + return false; + } + SerialPortDescriptor other = (SerialPortDescriptor) obj; + return Objects.equals(this.portId, other.portId) + && Objects.equals(this.portName, other.portName) + && Objects.equals(this.description, other.description) + && Objects.equals(this.productId, other.productId) + && Objects.equals(this.vendorId, other.vendorId) + && Objects.equals(this.productName, other.productName) + && Objects.equals(this.manufacturer, other.manufacturer) + && Objects.equals(this.serialNumber, other.serialNumber); + } + + @Override + public int hashCode() { + return Objects.hash( + this.portId, + this.portName, + this.description, + this.productId, + this.vendorId, + this.productName, + this.manufacturer, + this.serialNumber); + } + + /** + * Returns the port unique identifier. + * + * @return the port unique identifier + */ + public String portId() { + return this.portId; + } + + /** + * Returns the port name used to open the serial port. + * + * @return the port name used to open the serial port + */ + public String portName() { + return this.portName; + } + + /** + * Returns the port description. + * + * @return the port description + */ + public String description() { + return this.description; + } + + /** + * Returns the USB device product identifier (PID). + * + * @return the USB device product identifier in range [0-65535] + */ + public Short productId() { + return this.productId; + } + + /** + * Returns the USB device vendor identifier (VID). + * + * @return the USB device vendor identifier in range [0-65535] + */ + public Short vendorId() { + return this.vendorId; + } + + /** + * Returns the USB device product name. + * + * @return the USB device product name + */ + public String productName() { + return this.productName; + } + + /** + * Returns the USB device manufacturer. + * + * @return the USB device manufacturer + */ + public String manufacturer() { + return this.manufacturer; + } + + /** + * Returns the USB device serial number. + * + * @return the USB device serial number + */ + public String serialNumber() { + return this.serialNumber; + } + + /** + * Checks if this serial port is a native port (not USB). + * + *

A port is considered native if it has a port name but no port ID. This typically indicates a + * built-in serial port (e.g., COM1) rather than a USB-to-serial adapter. + * + * @return true if this is a native serial port, false if it's a USB device + */ + public boolean isNative() { + return this.portName != null && this.portId == null; + } +} diff --git a/src/main/java/tic/io/serialport/SerialPortFinder.java b/src/main/java/tic/io/serialport/SerialPortFinder.java new file mode 100644 index 0000000..b7c10d1 --- /dev/null +++ b/src/main/java/tic/io/serialport/SerialPortFinder.java @@ -0,0 +1,135 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.io.serialport; + +import java.util.ArrayList; +import java.util.List; +import tic.io.PortFinder; + +/** + * Interface for discovering and searching serial ports on the system. + * + *

This interface extends {@link PortFinder} with {@link SerialPortDescriptor} support, providing + * specialized methods for finding serial ports based on various criteria such as port ID, port + * name, USB product/vendor identifiers, or native port detection. + * + *

The interface provides default implementations for all search methods, allowing + * implementations to focus on the {@link PortFinder#findAll()} method which retrieves all available + * serial ports on the system. + * + * @author Enedis Smarties team + * @see PortFinder + * @see SerialPortDescriptor + */ +public interface SerialPortFinder extends PortFinder { + /** + * Finds a serial port descriptor matching the specified port ID. + * + *

This method searches through all available serial ports and returns the first descriptor + * with a matching port ID. The port ID is typically a unique identifier for USB serial devices. + * + * @param portId the unique port identifier to search for + * @return the matching serial port descriptor, or null if no match is found + */ + public default SerialPortDescriptor findByPortId(String portId) { + return this.findAll().stream() + .filter(k -> (k.portId() != null) ? k.portId().equals(portId) : portId == null) + .findFirst() + .orElse(null); + } + + /** + * Finds a serial port descriptor matching the specified port name. + * + *

This method searches through all available serial ports and returns the first descriptor + * with a matching port name. The port name is the system identifier used to open the serial port + * (e.g., COM1, /dev/ttyUSB0). + * + * @param portName the port name to search for + * @return the matching serial port descriptor, or null if no match is found + */ + public default SerialPortDescriptor findByPortName(String portName) { + return this.findAll().stream() + .filter(k -> (k.portName() != null) ? k.portName().equals(portName) : portName == null) + .findFirst() + .orElse(null); + } + + /** + * Finds a native serial port (not USB) matching the specified port name. + * + *

This method searches specifically for native serial ports, excluding USB-to-serial adapters. + * A port is considered native if it has a port name but no port ID, typically indicating a + * built-in hardware serial port. + * + * @param portName the port name to search for + * @return the matching native serial port descriptor, or null if no match is found + */ + public default SerialPortDescriptor findNative(String portName) { + return this.findAll().stream() + .filter(k -> k.isNative() && k.portName().equals(portName)) + .findFirst() + .orElse(null); + } + + /** + * Finds a serial port descriptor matching either port ID or port name, with port ID having + * priority. + * + *

This method provides a convenient way to search by either identifier. If a port ID is + * provided, it is used first. If no port ID is provided but a port name is available, the search + * is performed by port name. If neither is provided, null is returned. + * + * @param portId the unique port identifier to search for (has priority) + * @param portName the port name to search for (used if portId is null) + * @return the matching serial port descriptor, or null if no match is found + */ + public default SerialPortDescriptor findByPortIdOrPortName(String portId, String portName) { + SerialPortDescriptor descriptor; + + if (portId != null) { + descriptor = this.findByPortId(portId); + } else if (portName != null) { + descriptor = this.findByPortName(portName); + } else { + descriptor = null; + } + + return descriptor; + } + + /** + * Finds all serial port descriptors matching the specified USB product and vendor identifiers. + * + *

This method searches for USB serial devices matching both the product ID (PID) and vendor ID + * (VID). Both identifiers must match for a descriptor to be included in the results. This is + * useful for finding specific USB serial devices from a particular manufacturer. + * + * @param productId the USB device product identifier (PID) to match + * @param vendorId the USB device vendor identifier (VID) to match + * @return a list of matching serial port descriptors (empty list if no matches found) + */ + public default List findByProductIdAndVendorId( + Short productId, Short vendorId) { + List descriptorList = new ArrayList<>(); + + for (SerialPortDescriptor descriptor : this.findAll()) { + if (descriptor.productId() == null && productId != null) { + continue; + } + if (descriptor.vendorId() == null && vendorId != null) { + continue; + } + if (descriptor.productId().equals(productId) && descriptor.vendorId().equals(vendorId)) { + descriptorList.add(descriptor); + } + } + + return descriptorList; + } +} diff --git a/src/main/java/tic/io/serialport/SerialPortFinderBase.java b/src/main/java/tic/io/serialport/SerialPortFinderBase.java new file mode 100644 index 0000000..079e757 --- /dev/null +++ b/src/main/java/tic/io/serialport/SerialPortFinderBase.java @@ -0,0 +1,89 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.io.serialport; + +import java.util.List; +import org.apache.commons.lang3.SystemUtils; + +/** + * Cross-platform serial port finder implementation with automatic OS detection. + * + *

This class implements {@link SerialPortFinder} and provides a unified interface for + * discovering serial ports across different operating systems. It automatically detects the current + * OS and delegates to the appropriate platform-specific implementation. + * + *

Supported operating systems: + * + *

    + *
  • Windows - uses {@code SerialPortFinderForWindows} + *
  • Linux - uses {@code SerialPortFinderForLinux} + *
+ * + *

The class follows the singleton pattern with lazy initialization, ensuring only one instance + * exists for the lifetime of the application. + * + * @author Enedis Smarties team + * @see SerialPortFinder + * @see SerialPortDescriptor + */ +public class SerialPortFinderBase implements SerialPortFinder { + + /** + * Returns the singleton instance of the serial port finder. + * + *

This method performs lazy initialization and automatically selects the appropriate + * platform-specific implementation based on the detected operating system. The instance is cached + * after the first call. + * + *

Supported platforms are detected using Apache Commons SystemUtils: + * + *

    + *
  • Windows - returns Windows-specific finder + *
  • Linux - returns Linux-specific finder + *
  • Mac OS X - returns Mac OS X-specific finder + *
+ * + * @return the singleton SerialPortFinder instance for the current OS + * @throws RuntimeException if the current operating system is not supported + */ + public static SerialPortFinder getInstance() { + if (SystemUtils.IS_OS_WINDOWS) { + return SerialPortFinderForWindows.getInstance(); + } else if (SystemUtils.IS_OS_LINUX) { + return SerialPortFinderForLinux.getInstance(); + } else if (SystemUtils.IS_OS_MAC_OSX) { + return SerialPortFinderForMacOsX.getInstance(); + } else { + throw new RuntimeException( + "Operating system " + + SystemUtils.OS_NAME + + " is not handled by " + + SerialPortFinderBase.class.getName()); + } + } + + /** + * Private constructor to prevent direct instantiation. + * + *

Use {@link #getInstance()} to obtain the singleton instance. + */ + private SerialPortFinderBase() {} + + /** + * Finds all available serial ports on the system. + * + *

This method delegates to the platform-specific instance obtained through {@link + * #getInstance()}. The actual implementation depends on the detected operating system. + * + * @return a list of all serial port descriptors available on the system + */ + @Override + public List findAll() { + return getInstance().findAll(); + } +} diff --git a/src/main/java/tic/io/serialport/SerialPortFinderForLinux.java b/src/main/java/tic/io/serialport/SerialPortFinderForLinux.java new file mode 100644 index 0000000..c7bd2c3 --- /dev/null +++ b/src/main/java/tic/io/serialport/SerialPortFinderForLinux.java @@ -0,0 +1,661 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.io.serialport; + +import com.sun.jna.platform.linux.Udev; +import com.sun.jna.platform.linux.Udev.UdevContext; +import com.sun.jna.platform.linux.Udev.UdevDevice; +import com.sun.jna.platform.linux.Udev.UdevEnumerate; +import com.sun.jna.platform.linux.Udev.UdevListEntry; +import java.io.File; +import java.io.FileFilter; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Linux-specific implementation of serial port discovery. + * + *

This class implements {@link SerialPortFinder} and provides specialized functionality for + * discovering serial ports on Linux systems. It uses multiple detection methods with fallback + * strategies to ensure comprehensive port discovery: + * + *

    + *
  • Udev - Primary method using the Linux udev device manager (most reliable) + *
  • Sysfs - Fallback method reading from /sys/class/tty + *
  • Device filtering - Final fallback scanning /dev for known device patterns + *
+ * + *

The class supports a wide range of serial devices + * + *

The class follows the singleton pattern with lazy initialization. + * + * @author Enedis Smarties team + * @see SerialPortFinder + * @see SerialPortDescriptor + */ +public class SerialPortFinderForLinux implements SerialPortFinder { + private static String MOXA_IDENTIFIER = "ttyr"; + private static Pattern MOXA_PATTERN = Pattern.compile("(.*)" + MOXA_IDENTIFIER + "(\\d+)"); + private static String MOXA_FORMAT = MOXA_IDENTIFIER + "%02d"; + + private static SerialPortFinderForLinux instance; + + /** + * Returns the singleton instance of the Linux serial port finder. + * + *

This method performs lazy initialization and caches the instance for subsequent calls. + * + * @return the singleton SerialPortFinderForLinux instance + */ + public static SerialPortFinderForLinux getInstance() { + if (instance == null) { + instance = new SerialPortFinderForLinux(); + } + + return instance; + } + + /** + * Private constructor to prevent direct instantiation. + * + *

Use {@link #getInstance()} to obtain the singleton instance. + */ + private SerialPortFinderForLinux() {} + + /** + * Finds all available serial ports on the Linux system. + * + *

This method uses a cascading fallback strategy with three detection methods: + * + *

    + *
  1. Udev - Queries the Linux device manager for tty devices (preferred) + *
  2. Sysfs - Reads from /sys/class/tty if udev fails or returns no results + *
  3. Device filtering - Scans /dev for known serial device patterns as last resort + *
+ * + * @return a list of all serial port descriptors found on the system + */ + @Override + public List findAll() { + List serialPortDescriptorList = new ArrayList<>(); + + serialPortDescriptorList = availablePortsByUdev(); + if (serialPortDescriptorList.isEmpty()) { + serialPortDescriptorList = availablePortsBySysfs(); + } + if (serialPortDescriptorList.isEmpty()) { + serialPortDescriptorList = availablePortsByFiltersOfDevices(); + } + + return serialPortDescriptorList; + } + + /** + * Discovers serial ports using the Linux udev device manager. + * + *

This is the primary and most reliable method for finding serial ports on Linux. It queries + * the udev subsystem for all tty devices, extracts USB device information (PID, VID, + * manufacturer, serial number), and creates descriptors for each port. + * + *

The method filters out invalid serial8250 ports and includes special handling for rfcomm, + * virtual null modem, gadget serial, and MOXA devices. + * + * @return a list of serial port descriptors discovered via udev + */ + private static List availablePortsByUdev() { + UdevContext udev = Udev.INSTANCE.udev_new(); + UdevEnumerate enumerate = Udev.INSTANCE.udev_enumerate_new(udev); + Udev.INSTANCE.udev_enumerate_add_match_subsystem(enumerate, "tty"); + Udev.INSTANCE.udev_enumerate_scan_devices(enumerate); + + List serialPortDescriptorList = new ArrayList<>(); + + for (UdevListEntry dev_list_entry = Udev.INSTANCE.udev_enumerate_get_list_entry(enumerate); + dev_list_entry != null; + dev_list_entry = dev_list_entry.getNext()) { + UdevDevice device = + Udev.INSTANCE.udev_device_new_from_syspath( + udev, Udev.INSTANCE.udev_list_entry_get_name(dev_list_entry)); + if (device == null) { + break; + } + SerialPortDescriptor serialPortDescriptor; + + String location = deviceLocation(device); + String portName = deviceName(device); + + UdevDevice parentdev = Udev.INSTANCE.udev_device_get_parent(device); + + if (parentdev != null) { + String driverName = deviceDriver(parentdev); + if (isSerial8250Driver(driverName) && !isValidSerial8250(location)) { + Udev.INSTANCE.udev_device_unref(device); + continue; + } + String description = deviceDescription(device); + String portId = devicePortId(device); + String manufacturer = deviceManufacturer(device); + String serialNumber = deviceSerialNumber(device); + Short vendorIdentifier = deviceVendorIdentifier(device); + Short productIdentifier = deviceProductIdentifier(device); + String productName = deviceProductName(device); + try { + serialPortDescriptor = + new SerialPortDescriptor.Builder<>() + .portId(portId) + .portName(location) + .description(description) + .productId(productIdentifier) + .vendorId(vendorIdentifier) + .productName(productName) + .manufacturer(manufacturer) + .serialNumber(serialNumber) + .build(); + } catch (IllegalArgumentException e) { + e.printStackTrace(System.err); + Udev.INSTANCE.udev_device_unref(device); + continue; + } + } else { + if (!isRfcommDevice(portName) + && !isVirtualNullModemDevice(portName) + && !isGadgetDevice(portName) + && !isMoxaDevice(portName)) { + Udev.INSTANCE.udev_device_unref(device); + continue; + } + try { + serialPortDescriptor = + new SerialPortDescriptor.Builder<>() + .portId(null) + .portName(location) + .description(null) + .productId(null) + .vendorId(null) + .productName(null) + .manufacturer(null) + .serialNumber(null) + .build(); + } catch (IllegalArgumentException e) { + e.printStackTrace(System.err); + Udev.INSTANCE.udev_device_unref(device); + continue; + } + } + serialPortDescriptorList.add(serialPortDescriptor); + Udev.INSTANCE.udev_device_unref(device); + } + Udev.INSTANCE.udev_enumerate_unref(enumerate); + Udev.INSTANCE.udev_unref(udev); + + return serialPortDescriptorList; + } + + /** + * Discovers serial ports by reading from the sysfs filesystem. + * + *

This method serves as a fallback when udev is not available or returns no results. It reads + * from /sys/class/tty and follows symbolic links to extract device information. The method + * traverses the device hierarchy to find USB properties. + * + * @return a list of serial port descriptors discovered via sysfs + */ + private static List availablePortsBySysfs() { + List serialPortDescriptorList = new ArrayList<>(); + File ttySysClassDir = new File("/sys/class/tty"); + + if (!(ttySysClassDir.exists() && ttySysClassDir.canRead())) { + return serialPortDescriptorList; + } + FileFilter filter = + new FileFilter() { + @Override + public boolean accept(File pathname) { + + return pathname.isDirectory() + && !pathname.getName().equals(".") + && !pathname.getName().equals(".."); + } + }; + File[] fileInfos = ttySysClassDir.listFiles(filter); + for (File fileInfo : fileInfos) { + if (!Files.isSymbolicLink(fileInfo.toPath())) { + continue; + } + File targetDir = fileInfo.getAbsoluteFile(); + SerialPortDescriptor serialPortDescriptor; + + String portName = deviceName(targetDir); + if (portName == null) { + continue; + } + String driverName = deviceDriver(targetDir); + if (driverName == null) { + if (!isRfcommDevice(portName) + && !isVirtualNullModemDevice(portName) + && !isGadgetDevice(portName) + && !isMoxaDevice(portName)) { + continue; + } + } + + String device = portNameToSystemLocation(portName); + if (isSerial8250Driver(driverName) && !isValidSerial8250(device)) { + continue; + } + String description = null; + String manufacturer = null; + String serialNumber = null; + Short vendorIdentifier = null; + Short productIdentifier = null; + String productName = null; + do { + if (description == null) { + description = deviceDescription(targetDir); + } + if (manufacturer == null) { + manufacturer = deviceManufacturer(targetDir); + } + if (serialNumber == null) { + serialNumber = deviceSerialNumber(targetDir); + } + if (vendorIdentifier == null) { + vendorIdentifier = deviceVendorIdentifier(targetDir); + } + if (productIdentifier == null) { + productIdentifier = deviceProductIdentifier(targetDir); + } + if (productName == null) { + productName = deviceProductName(targetDir); + } + if (description != null + || manufacturer != null + || serialNumber != null + || vendorIdentifier != null + || productIdentifier != null + || productName != null) { + break; + } + targetDir = targetDir.getParentFile(); + } while (targetDir != null); + try { + serialPortDescriptor = + new SerialPortDescriptor.Builder<>() + .portId(null) + .portName(portName) + .description(description) + .productId(productIdentifier) + .vendorId(vendorIdentifier) + .productName(productName) + .manufacturer(manufacturer) + .serialNumber(serialNumber) + .build(); + } catch (IllegalArgumentException e) { + e.printStackTrace(System.err); + continue; + } + serialPortDescriptorList.add(serialPortDescriptor); + } + + return serialPortDescriptorList; + } + + /** + * Discovers serial ports by scanning /dev for known device file patterns. + * + *

This is the last resort fallback method when both udev and sysfs fail. It scans the /dev + * directory for files matching known serial port patterns (ttyS*, ttyUSB*, ttyACM*, etc.) and + * creates minimal descriptors without USB device information. + * + * @return a list of serial port descriptors discovered by device file filtering + */ + private static List availablePortsByFiltersOfDevices() { + List serialPortDescriptorList = new ArrayList<>(); + + List deviceFilePaths = filteredDeviceFilePaths(); + for (String deviceFilePath : deviceFilePaths) { + SerialPortDescriptor serialPortDescriptor; + String portName = portNameFromSystemLocation(deviceFilePath); + try { + serialPortDescriptor = + new SerialPortDescriptor.Builder<>() + .portId(null) + .portName(portName) + .description(null) + .productId(null) + .vendorId(null) + .productName(null) + .manufacturer(null) + .serialNumber(null) + .build(); + } catch (IllegalArgumentException e) { + e.printStackTrace(System.err); + continue; + } + serialPortDescriptorList.add(serialPortDescriptor); + } + + return serialPortDescriptorList; + } + + /** + * Returns a list of device file paths matching known serial port patterns. + * + *

This method scans the /dev directory and filters files based on predefined patterns that + * correspond to various types of serial devices on Linux, FreeBSD, and QNX systems. It excludes + * symbolic links and certain non-serial files (.init, .lock). + * + * @return a list of absolute paths to potential serial port device files + */ + private static List filteredDeviceFilePaths() { + List deviceFileNameFilterList = new ArrayList(); + + // Linux + deviceFileNameFilterList.add("ttyS*"); // Standard UART 8250 and etc. + deviceFileNameFilterList.add("ttyO*"); // OMAP UART 8250 and etc. + deviceFileNameFilterList.add("ttyUSB*"); // Usb/serial converters PL2303 and etc. + deviceFileNameFilterList.add("ttyACM*"); // CDC_ACM converters (i.e. Mobile Phones). + deviceFileNameFilterList.add( + "ttyGS*"); // Gadget serial device (i.e. Mobile Phones with gadget serial driver). + deviceFileNameFilterList.add("ttyMI*"); // MOXA pci/serial converters. + deviceFileNameFilterList.add("ttymxc*"); // Motorola IMX serial ports (i.e. Freescale i.MX). + deviceFileNameFilterList.add( + "ttyAMA*"); // AMBA serial device for embedded platform on ARM (i.e. Raspberry Pi). + deviceFileNameFilterList.add( + "ttyTHS*"); // Serial device for embedded platform on ARM (i.e. Tegra Jetson TK1). + deviceFileNameFilterList.add("rfcomm*"); // Bluetooth serial device. + deviceFileNameFilterList.add("ircomm*"); // IrDA serial device. + deviceFileNameFilterList.add("tnt*"); // Virtual tty0tty serial device. + deviceFileNameFilterList.add(MOXA_IDENTIFIER + "*"); // MOXA ethernet device. + // FreeBSD + deviceFileNameFilterList.add("cu*"); + // QNX + deviceFileNameFilterList.add("ser*"); + + List result = new ArrayList(); + + File deviceDir = new File("/dev"); + if (deviceDir.exists()) { + FileFilter deviceFileNameFilter = + new FileFilter() { + @Override + public boolean accept(File pathname) { + Path path = pathname.toPath(); + + return deviceFileNameFilterList.contains(pathname.getName()) + && pathname.isFile() + && !Files.isSymbolicLink(path); + } + }; + File[] deviceFileInfos = deviceDir.listFiles(deviceFileNameFilter); + for (File deviceFileInfo : deviceFileInfos) { + String deviceAbsoluteFilePath = deviceFileInfo.getAbsolutePath(); + // it is a quick workaround to skip the non-serial devices (FreeBSD) + if (deviceAbsoluteFilePath.endsWith(".init") || deviceAbsoluteFilePath.endsWith(".lock")) { + continue; + } + if (!result.contains(deviceAbsoluteFilePath)) { + result.add(deviceAbsoluteFilePath); + } + } + } + + return result; + } + + private static boolean isSerial8250Driver(String driverName) { + return (driverName == "serial8250"); + } + + private static boolean isValidSerial8250(String systemLocation) { + return false; + } + + private static boolean isRfcommDevice(String portName) { + if (!portName.startsWith("rfcomm")) { + return false; + } + try { + String number = portName.substring(6); + int portNumber = Integer.parseInt(number); + if (portNumber < 0 || portNumber > 255) { + return false; + } + } catch (Exception e) { + return false; + } + return true; + } + + // provided by the tty0tty driver + private static boolean isVirtualNullModemDevice(String portName) { + return portName.startsWith("tnt"); + } + + // provided by the g_serial driver + private static boolean isGadgetDevice(String portName) { + return portName.startsWith("ttyGS"); + } + + // provided by the MOXA driver + private static boolean isMoxaDevice(String portName) { + return portName.startsWith(MOXA_IDENTIFIER); + } + + private static String devicePortId(UdevDevice dev) { + return deviceProperty(dev, "ID_PATH"); + } + + private static String deviceDescription(UdevDevice dev) { + String description = deviceProperty(dev, "ID_MODEL_FROM_DATABASE"); + + return (description != null) ? description.replace('_', ' ') : null; + } + + private static String deviceDescription(File targetDir) { + return deviceProperty(new File(targetDir, "product").getAbsolutePath()); + } + + private static String deviceManufacturer(UdevDevice dev) { + String manufacturer = deviceProperty(dev, "ID_VENDOR"); + + return (manufacturer != null) ? manufacturer.replace('_', ' ') : null; + } + + private static String deviceManufacturer(File targetDir) { + return deviceProperty(new File(targetDir, "manufacturer").getAbsolutePath()); + } + + private static Short deviceProductIdentifier(UdevDevice dev) { + Short identifierValue; + try { + String indentifierText = deviceProperty(dev, "ID_MODEL_ID"); + identifierValue = (indentifierText != null) ? Short.parseShort(indentifierText, 16) : null; + } catch (Exception e) { + identifierValue = null; + } + return identifierValue; + } + + private static String deviceProductName(UdevDevice dev) { + return deviceProperty(dev, "ID_MODEL"); + } + + private static String deviceProductName(File targetDir) { + return deviceProperty(new File(targetDir, "product").getAbsolutePath()); + } + + private static Short deviceProductIdentifier(File targetDir) { + String indentifierText = deviceProperty(new File(targetDir, "idProduct").getAbsolutePath()); + + if (indentifierText == null) { + indentifierText = deviceProperty(new File(targetDir, "device").getAbsolutePath()); + } + Short identifierValue; + try { + identifierValue = (indentifierText != null) ? Short.parseShort(indentifierText, 16) : null; + } catch (Exception e) { + identifierValue = null; + } + return identifierValue; + } + + private static Short deviceVendorIdentifier(File targetDir) { + String indentifierText = deviceProperty(new File(targetDir, "idVendor").getAbsolutePath()); + + if (indentifierText == null) { + indentifierText = deviceProperty(new File(targetDir, "vendor").getAbsolutePath()); + } + Short identifierValue; + try { + identifierValue = (indentifierText != null) ? Short.parseShort(indentifierText, 16) : null; + } catch (Exception e) { + identifierValue = null; + } + return identifierValue; + } + + private static String deviceSerialNumber(File targetDir) { + return deviceProperty(new File(targetDir, "serial").getAbsolutePath()); + } + + private static Short deviceVendorIdentifier(UdevDevice dev) { + Short identifierValue; + try { + String indentifierText = deviceProperty(dev, "ID_VENDOR_ID"); + identifierValue = (indentifierText != null) ? Short.parseShort(indentifierText, 16) : null; + } catch (Exception e) { + identifierValue = null; + } + return identifierValue; + } + + private static String deviceSerialNumber(UdevDevice dev) { + return deviceProperty(dev, "ID_SERIAL_SHORT"); + } + + private static String deviceProperty(UdevDevice dev, String name) { + return Udev.INSTANCE.udev_device_get_property_value(dev, name); + } + + private static String deviceProperty(String targetFilePath) { + FileInputStream f; + + try { + f = new FileInputStream(targetFilePath); + } catch (FileNotFoundException e) { + e.printStackTrace(); + return null; + } + String text; + try { + int available = f.available(); + byte[] buffer = new byte[available]; + f.read(buffer); + text = new String(buffer); + } catch (IOException e) { + e.printStackTrace(); + return null; + } finally { + try { + f.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + return text.trim(); + } + + private static String deviceDriver(UdevDevice dev) { + return null; + } + + private static String deviceDriver(File targetDir) { + File deviceDir = new File(targetDir, "device"); + + return ueventProperty(deviceDir, "DRIVER="); + } + + private static String deviceName(UdevDevice dev) { + return Udev.INSTANCE.udev_device_get_sysname(dev); + } + + static String deviceName(File targetDir) { + return ueventProperty(targetDir, "DEVNAME="); + } + + private static String deviceLocation(UdevDevice dev) { + String location = Udev.INSTANCE.udev_device_get_devnode(dev); + // Patch for MOXA device + // Udev prints location as /dev/ttyrN but only /dev/ttyr0N exists (with N belongs to [1-4]) + // So we are renaming location from /dev/ttyrN to /dev/ttyr0N + Matcher matcher = MOXA_PATTERN.matcher(location); + + if (matcher.matches()) { + String prefix = ""; + String indexValue; + if (matcher.groupCount() == 2) { + prefix = matcher.group(1); + indexValue = matcher.group(2); + } else { + indexValue = matcher.group(2); + } + int index = Integer.parseUnsignedInt(indexValue); + location = String.format("%s" + MOXA_FORMAT, prefix, index); + } + + return location; + } + + private static String portNameToSystemLocation(String source) { + return (source.startsWith("/") || source.startsWith("./") || source.startsWith("../")) + ? source + : (("/dev/") + source); + } + + private static String portNameFromSystemLocation(String source) { + return source.startsWith("/dev/") ? source.substring(5) : source; + } + + @SuppressWarnings("resource") + private static String ueventProperty(File targetDir, String pattern) { + FileInputStream f; + + try { + f = new FileInputStream(new File(targetDir, "uevent")); + } catch (FileNotFoundException e) { + e.printStackTrace(); + return null; + } + String content; + try { + int available = f.available(); + byte[] buffer = new byte[available]; + f.read(buffer); + content = new String(buffer); + } catch (IOException e) { + e.printStackTrace(); + return null; + } + int firstbound = content.indexOf(pattern); + if (firstbound == -1) { + return null; + } + int lastbound = content.indexOf('\n', firstbound); + + return content.substring(firstbound, lastbound); + } +} diff --git a/src/main/java/tic/io/serialport/SerialPortFinderForMacOsX.java b/src/main/java/tic/io/serialport/SerialPortFinderForMacOsX.java new file mode 100644 index 0000000..eb1a621 --- /dev/null +++ b/src/main/java/tic/io/serialport/SerialPortFinderForMacOsX.java @@ -0,0 +1,370 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.io.serialport; + +import com.sun.jna.Memory; +import com.sun.jna.Pointer; +import com.sun.jna.platform.mac.CoreFoundation; +import com.sun.jna.platform.mac.CoreFoundation.CFAllocatorRef; +import com.sun.jna.platform.mac.CoreFoundation.CFIndex; +import com.sun.jna.platform.mac.CoreFoundation.CFMutableDictionaryRef; +import com.sun.jna.platform.mac.CoreFoundation.CFNumberRef; +import com.sun.jna.platform.mac.CoreFoundation.CFStringRef; +import com.sun.jna.platform.mac.CoreFoundation.CFTypeID; +import com.sun.jna.platform.mac.CoreFoundation.CFTypeRef; +import com.sun.jna.platform.mac.IOKit; +import com.sun.jna.platform.mac.IOKit.IOIterator; +import com.sun.jna.platform.mac.IOKit.IORegistryEntry; +import com.sun.jna.ptr.IntByReference; +import com.sun.jna.ptr.PointerByReference; +import com.sun.jna.ptr.ShortByReference; +import java.util.ArrayList; +import java.util.List; + +/** Class used to find all serial port descriptor for MAC OS X */ +public class SerialPortFinderForMacOsX implements SerialPortFinder { + + private static final String kIOSerialBSDServiceValue = "IOSerialBSDClient"; + private static final String kIOSerialBSDTypeKey = "IOSerialBSDClientType"; + private static final String kIOSerialBSDAllTypes = "IOSerialStream"; + private static final String kIOCalloutDeviceKey = "IOCalloutDevice"; + private static final String kIOServicePlane = "IOService"; + private static final String kIODialinDeviceKey = "IODialinDevice"; + private static final String kIOPropertyProductNameKey = "Product Name"; + private static final String kUSBProductString = "USB Product Name"; + private static final String kUSBVendorString = "USB Vendor Name"; + private static final String kUSBSerialNumberString = "USB Serial Number"; + private static final String kUSBVendorID = "idVendor"; + private static final String kUSBProductID = "idProduct"; + private static final CFAllocatorRef kCFAllocatorDefault = + CoreFoundation.INSTANCE.CFAllocatorGetDefault(); + // Encodages CFString + private static final int kCFStringEncodingUTF8 = 0x08000100; + private static final int kCFNumberSInt16Type = 2; + private static final int kCFNumberSInt32Type = 3; + + /** + * Get instance + * + * @return Unique instance + */ + public static SerialPortFinderForMacOsX getInstance() { + if (instance == null) { + instance = new SerialPortFinderForMacOsX(); + } + + return instance; + } + + private static SerialPortFinderForMacOsX instance; + + private SerialPortFinderForMacOsX() {} + + @Override + public List findAll() { + List serialPortDescriptorList = new ArrayList(); + + CFMutableDictionaryRef serialPortDictionary = + IOKit.INSTANCE.IOServiceMatching(kIOSerialBSDServiceValue); + if (serialPortDictionary == null) { + return serialPortDescriptorList; + } + + CFStringRef key = CFStringRef.createCFString(kIOSerialBSDTypeKey); + CFStringRef value = CFStringRef.createCFString(kIOSerialBSDAllTypes); + + serialPortDictionary.setValue(key, value); + + IntByReference kIOMasterPortDefault = new IntByReference(); + int errorCode = IOKit.INSTANCE.IOMasterPort(0, kIOMasterPortDefault); + if (errorCode != 0) { + return serialPortDescriptorList; + } + PointerByReference serialPortIteratorRef = new PointerByReference(); + errorCode = + IOKit.INSTANCE.IOServiceGetMatchingServices( + kIOMasterPortDefault.getValue(), serialPortDictionary, serialPortIteratorRef); + if (errorCode != 0) { + return serialPortDescriptorList; + } + IOIterator serialPortIterator = new IOIterator(serialPortIteratorRef.getValue()); + + for (; ; ) { + IORegistryEntry serialPortService = serialPortIterator.next(); + if (serialPortService == null) { + break; + } + String calloutDevice = null; + String dialinDevice = null; + Integer locationId = null; + String deviceDescription = null; + String manufacturer = null; + String serialNumber = null; + Short vendorIdentifier = null; + Short productIdentifier = null; + + for (; ; ) { + if (calloutDevice == null) { + calloutDevice = calloutDeviceSystemLocation(serialPortService); + } + if (dialinDevice == null) { + dialinDevice = dialinDeviceSystemLocation(serialPortService); + } + if (locationId == null) { + locationId = deviceLocationId(serialPortService); + } + if (deviceDescription == null) { + deviceDescription = deviceDescription(serialPortService); + } + if (manufacturer == null) { + manufacturer = deviceManufacturer(serialPortService); + } + if (serialNumber == null) { + serialNumber = deviceSerialNumber(serialPortService); + } + if (vendorIdentifier == null) { + vendorIdentifier = deviceVendorIdentifier(serialPortService); + } + if (productIdentifier == null) { + productIdentifier = deviceProductIdentifier(serialPortService); + } + if (isCompleteInfo( + calloutDevice, + dialinDevice, + manufacturer, + deviceDescription, + serialNumber, + vendorIdentifier, + productIdentifier)) { + serialPortService.release(); + break; + } + serialPortService = serialPortService.getParentEntry(kIOServicePlane); + if (serialPortService == null) { + break; + } + } + String portId = (locationId != null) ? locationId.toString() : null; + SerialPortDescriptor calloutCandidate = + new SerialPortDescriptor.Builder<>() + .portId(portId) + .portName(calloutDevice) + .description(deviceDescription) + .productId(productIdentifier) + .vendorId(vendorIdentifier) + .productName(deviceDescription) + .manufacturer(manufacturer) + .serialNumber(serialNumber) + .build(); + serialPortDescriptorList.add(calloutCandidate); + + SerialPortDescriptor dialinCandidate = + new SerialPortDescriptor.Builder<>() + .portId(portId) + .portName(dialinDevice) + .description(deviceDescription) + .productId(productIdentifier) + .vendorId(vendorIdentifier) + .productName(deviceDescription) + .manufacturer(manufacturer) + .serialNumber(serialNumber) + .build(); + serialPortDescriptorList.add(dialinCandidate); + } + serialPortIterator.release(); + + return serialPortDescriptorList; + } + + private static boolean isCompleteInfo( + String calloutDevice, + String dialinDevice, + String manufacturer, + String description, + String serialNumber, + Short vendorIdentifier, + Short productIdentifier) { + return calloutDevice != null + && dialinDevice != null + && manufacturer != null + && description != null + && serialNumber != null + && vendorIdentifier != null + && vendorIdentifier != null; + } + + private static String calloutDeviceSystemLocation(IORegistryEntry ioRegistryEntry) { + return searchStringProperty(ioRegistryEntry, kIOCalloutDeviceKey); + } + + private static String dialinDeviceSystemLocation(IORegistryEntry ioRegistryEntry) { + return searchStringProperty(ioRegistryEntry, kIODialinDeviceKey); + } + + private static Integer deviceLocationId(IORegistryEntry ioRegistryEntry) { + return searchIntProperty(ioRegistryEntry, "locationID"); + } + + private static String deviceDescription(IORegistryEntry ioRegistryEntry) { + String result = searchStringProperty(ioRegistryEntry, kIOPropertyProductNameKey); + if (result == null || result.isEmpty()) { + result = searchStringProperty(ioRegistryEntry, kUSBProductString); + } + if (result == null || result.isEmpty()) { + result = searchStringProperty(ioRegistryEntry, "BTName"); + } + return result; + } + + private static String deviceManufacturer(IORegistryEntry ioRegistryEntry) { + return searchStringProperty(ioRegistryEntry, kUSBVendorString); + } + + private static String deviceSerialNumber(IORegistryEntry ioRegistryEntry) { + return searchStringProperty(ioRegistryEntry, kUSBSerialNumberString); + } + + private static Short deviceVendorIdentifier(IORegistryEntry ioRegistryEntry) { + return searchShortIntProperty(ioRegistryEntry, kUSBVendorID); + } + + private static Short deviceProductIdentifier(IORegistryEntry ioRegistryEntry) { + return searchShortIntProperty(ioRegistryEntry, kUSBProductID); + } + + private static String searchStringProperty(IORegistryEntry ioRegistryEntry, String propertyKey) { + CoreFoundation.CFTypeRef container = searchProperty(ioRegistryEntry, propertyKey); + String result = convertCFTypeRefToString(container); + if (container != null) { + container.release(); + } + + return result; + } + + private static Short searchShortIntProperty(IORegistryEntry ioRegistryEntry, String propertyKey) { + CoreFoundation.CFTypeRef container = searchProperty(ioRegistryEntry, propertyKey); + Short result = convertCFTypeRefToShort(container); + if (container != null) { + container.release(); + } + + return result; + } + + private static Integer searchIntProperty(IORegistryEntry ioRegistryEntry, String propertyKey) { + CoreFoundation.CFTypeRef container = searchProperty(ioRegistryEntry, propertyKey); + Integer result = convertCFTypeRefToInteger(container); + if (container != null) { + container.release(); + } + + return result; + } + + private static CoreFoundation.CFTypeRef searchProperty( + IORegistryEntry ioRegistryEntry, String propertyKey) { + + return IOKit.INSTANCE.IORegistryEntrySearchCFProperty( + ioRegistryEntry, + kIOServicePlane, + CFStringRef.createCFString(propertyKey), + kCFAllocatorDefault, + 0); + } + + private static String convertCFTypeRefToString(CFTypeRef cfTypeRef) { + if (cfTypeRef == null) { + return null; + } + + CFTypeID typeID = CoreFoundation.INSTANCE.CFGetTypeID(cfTypeRef); + CFTypeID stringTypeID = CoreFoundation.INSTANCE.CFStringGetTypeID(); + + if (!typeID.equals(stringTypeID)) { + return null; + } + + CFStringRef cfStringRef = new CFStringRef(cfTypeRef.getPointer()); + + CFIndex length = CoreFoundation.INSTANCE.CFStringGetLength(cfStringRef); + if (length.longValue() == 0) { + return ""; + } + + CFIndex maxSize = + CoreFoundation.INSTANCE.CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8); + + int bufferSize = (int) maxSize.longValue() + 1; + Pointer buffer = new Memory(bufferSize); + + CFIndex bufferLength = new CFIndex(bufferSize); + + byte success = + CoreFoundation.INSTANCE.CFStringGetCString( + cfStringRef, buffer, bufferLength, kCFStringEncodingUTF8); + + if (success == 0) { + return null; + } + + return buffer.getString(0, "UTF-8"); + } + + private static Integer convertCFTypeRefToInteger(CFTypeRef cfTypeRef) { + if (cfTypeRef == null) { + return null; + } + + CFTypeID typeID = CoreFoundation.INSTANCE.CFGetTypeID(cfTypeRef); + CFTypeID numberTypeID = CoreFoundation.INSTANCE.CFNumberGetTypeID(); + + if (!typeID.equals(numberTypeID)) { + return null; + } + + CFNumberRef cfNumberRef = new CFNumberRef(cfTypeRef.getPointer()); + + CFIndex numberType = new CFIndex(kCFNumberSInt32Type); + + IntByReference value = new IntByReference(); + byte success = CoreFoundation.INSTANCE.CFNumberGetValue(cfNumberRef, numberType, value); + + if (success == 0) { + return null; + } + + return value.getValue(); + } + + private static Short convertCFTypeRefToShort(CFTypeRef cfTypeRef) { + if (cfTypeRef == null) { + return null; + } + + CFTypeID typeID = CoreFoundation.INSTANCE.CFGetTypeID(cfTypeRef); + CFTypeID numberTypeID = CoreFoundation.INSTANCE.CFNumberGetTypeID(); + + if (!typeID.equals(numberTypeID)) { + return null; + } + + CFNumberRef cfNumberRef = new CFNumberRef(cfTypeRef.getPointer()); + + CFIndex numberType = new CFIndex(kCFNumberSInt16Type); + + ShortByReference value = new ShortByReference(); + byte success = CoreFoundation.INSTANCE.CFNumberGetValue(cfNumberRef, numberType, value); + + if (success == 0) { + return null; + } + + return value.getValue(); + } +} diff --git a/src/main/java/tic/io/serialport/SerialPortFinderForWindows.java b/src/main/java/tic/io/serialport/SerialPortFinderForWindows.java new file mode 100644 index 0000000..a963307 --- /dev/null +++ b/src/main/java/tic/io/serialport/SerialPortFinderForWindows.java @@ -0,0 +1,443 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.io.serialport; + +import static com.sun.jna.platform.win32.SetupApi.DICS_FLAG_GLOBAL; +import static com.sun.jna.platform.win32.SetupApi.DIGCF_DEVICEINTERFACE; +import static com.sun.jna.platform.win32.SetupApi.DIGCF_PRESENT; +import static com.sun.jna.platform.win32.SetupApi.DIREG_DEV; +import static com.sun.jna.platform.win32.SetupApi.GUID_DEVINTERFACE_COMPORT; +import static com.sun.jna.platform.win32.SetupApi.SPDRP_DEVICEDESC; +import static com.sun.jna.platform.win32.WinBase.INVALID_HANDLE_VALUE; +import static com.sun.jna.platform.win32.WinDef.MAX_PATH; +import static com.sun.jna.platform.win32.WinError.ERROR_SUCCESS; +import static com.sun.jna.platform.win32.WinNT.KEY_QUERY_VALUE; +import static com.sun.jna.platform.win32.WinNT.KEY_READ; +import static com.sun.jna.platform.win32.WinNT.REG_DWORD; +import static com.sun.jna.platform.win32.WinNT.REG_SZ; +import static com.sun.jna.platform.win32.WinReg.HKEY_LOCAL_MACHINE; + +import com.sun.jna.Memory; +import com.sun.jna.Pointer; +import com.sun.jna.platform.win32.Advapi32; +import com.sun.jna.platform.win32.Advapi32Util; +import com.sun.jna.platform.win32.Cfgmgr32; +import com.sun.jna.platform.win32.Cfgmgr32Util; +import com.sun.jna.platform.win32.Guid.GUID; +import com.sun.jna.platform.win32.SetupApi; +import com.sun.jna.platform.win32.SetupApi.SP_DEVINFO_DATA; +import com.sun.jna.platform.win32.Win32Exception; +import com.sun.jna.platform.win32.WinNT.HANDLE; +import com.sun.jna.platform.win32.WinReg.HKEY; +import com.sun.jna.ptr.IntByReference; +import java.util.ArrayList; +import java.util.List; + +/** + * Windows-specific implementation of serial port discovery. + * + *

This class implements {@link SerialPortFinder} and provides specialized functionality for + * discovering serial ports on Windows systems. It uses the Windows Setup API and registry access to + * enumerate COM ports and modem devices. + * + *

The class extracts detailed information about each port including USB device identifiers + * (VID/PID), manufacturer, serial numbers, and device descriptions. It supports both hardware COM + * ports and USB-to-serial adapters. + * + *

The class follows the singleton pattern with lazy initialization. + * + * @author Enedis Smarties team + * @see SerialPortFinder + * @see SerialPortDescriptor + */ +public class SerialPortFinderForWindows implements SerialPortFinder { + private static final int SPDRP_MFG = 0x0000000B; + private static final int SPDRP_ADDRESS = 0x0000001C; + private static final int PROPERTY_MAX_SIZE = 1024; + + private static final GUID GUID_DEVCLASS_PORTS = + new GUID("{4d36e978-e325-11ce-bfc1-08002be10318}"); + private static final GUID GUID_DEVCLASS_MODEM = + new GUID("{4d36e96d-e325-11ce-bfc1-08002be10318}"); + private static final GUID GUID_DEVINTERFACE_MODEM = + new GUID("{2c7089aa-2e0e-11d1-b114-00c04fc2aae4}"); + + private static SerialPortFinderForWindows instance; + + /** + * Returns the singleton instance of the Windows serial port finder. + * + *

This method performs lazy initialization and caches the instance for subsequent calls. + * + * @return the singleton SerialPortFinderForWindows instance + */ + public static SerialPortFinderForWindows getInstance() { + if (instance == null) { + instance = new SerialPortFinderForWindows(); + } + + return instance; + } + + /** + * Private constructor to prevent direct instantiation. + * + *

Use {@link #getInstance()} to obtain the singleton instance. + */ + private SerialPortFinderForWindows() {} + + /** + * Finds all available serial ports on the Windows system. + * + *

This method uses the Windows Setup API to enumerate devices across multiple device classes + * and interfaces: + * + *

    + *
  • Ports device class (GUID_DEVCLASS_PORTS) + *
  • Modem device class (GUID_DEVCLASS_MODEM) + *
  • COM port device interface (GUID_DEVINTERFACE_COMPORT) + *
  • Modem device interface (GUID_DEVINTERFACE_MODEM) + *
+ * + *

For each device, it extracts port name, description, manufacturer, USB VID/PID, and serial + * number. The method filters out LPT (parallel) ports and duplicates. As a fallback, it scans the + * Windows registry HARDWARE\DEVICEMAP\SERIALCOMM to find any ports not discovered through + * SetupAPI. + * + * @return a list of all serial port descriptors found on the system + */ + @Override + public List findAll() { + final class SetupToken { + public GUID guid; + public int flags; + + public SetupToken(GUID guid, int flags) { + super(); + this.guid = guid; + this.flags = flags; + } + } + + SetupToken[] setupTokens = + new SetupToken[] { + new SetupToken(GUID_DEVCLASS_PORTS, DIGCF_PRESENT), + new SetupToken(GUID_DEVCLASS_MODEM, DIGCF_PRESENT), + new SetupToken(GUID_DEVINTERFACE_COMPORT, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE), + new SetupToken(GUID_DEVINTERFACE_MODEM, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE) + }; + + List serialPortDescriptorList = new ArrayList<>(); + + for (int i = 0; i < setupTokens.length; ++i) { + HANDLE deviceInfoSet = + SetupApi.INSTANCE.SetupDiGetClassDevs( + setupTokens[i].guid, null, null, setupTokens[i].flags); + if (deviceInfoSet == INVALID_HANDLE_VALUE) { + return serialPortDescriptorList; + } + SP_DEVINFO_DATA deviceInfoData = new SP_DEVINFO_DATA(); + int index = 0; + while (SetupApi.INSTANCE.SetupDiEnumDeviceInfo(deviceInfoSet, index++, deviceInfoData)) { + SerialPortDescriptor serialPortDescriptor; + + String portName = devicePortName(deviceInfoSet, deviceInfoData); + if (portName == null || portName.isEmpty() || portName.contains("LPT")) { + continue; + } + if (anyOfPorts(serialPortDescriptorList, portName)) { + continue; + } + String description = deviceDescription(deviceInfoSet, deviceInfoData); + String address = deviceAddress(deviceInfoSet, deviceInfoData); + String manufacturer = deviceManufacturer(deviceInfoSet, deviceInfoData); + String instanceIdentifier = deviceInstanceIdentifier(deviceInfoData.DevInst); + String serialNumber = deviceSerialNumber(instanceIdentifier, deviceInfoData.DevInst); + Short vendorIdentifier = deviceVendorIdentifier(instanceIdentifier); + Short productIdentifier = deviceProductIdentifier(instanceIdentifier); + try { + serialPortDescriptor = + new SerialPortDescriptor.Builder<>() + .portId(address) + .portName(portName) + .description(description) + .productId(productIdentifier) + .vendorId(vendorIdentifier) + .productName(null) + .manufacturer(manufacturer) + .serialNumber(serialNumber) + .build(); + } catch (IllegalArgumentException e) { + e.printStackTrace(System.err); + continue; + } + serialPortDescriptorList.add(serialPortDescriptor); + } + SetupApi.INSTANCE.SetupDiDestroyDeviceInfoList(deviceInfoSet); + } + + List portNames = portNamesFromHardwareDeviceMap(); + for (String portName : portNames) { + if (!anyOfPorts(serialPortDescriptorList, portName)) { + try { + SerialPortDescriptor serialPortDescriptor = + new SerialPortDescriptor.Builder<>() + .portId(null) + .portName(portName) + .description(null) + .productId(null) + .vendorId(null) + .productName(null) + .manufacturer(null) + .serialNumber(null) + .build(); + serialPortDescriptorList.add(serialPortDescriptor); + } catch (IllegalArgumentException e) { + e.printStackTrace(System.err); + } + } + } + + return serialPortDescriptorList; + } + + /** + * Checks if a port with the given name already exists in the descriptor list. + * + * @param descriptors the list of serial port descriptors to check + * @param portName the port name to search for + * @return true if the port name is found in the list, false otherwise + */ + private static boolean anyOfPorts(List descriptors, String portName) { + if (descriptors == null) { + return false; + } + for (SerialPortDescriptor descriptor : descriptors) { + if (descriptor.portName() == null) { + if (portName != null) { + continue; + } else { + return true; + } + } + if (descriptor.portName().equals(portName)) { + return true; + } + } + + return false; + } + + /** + * Retrieves the port name (e.g., COM1, COM2) for a device from the Windows registry. + * + * @param deviceInfoSet handle to the device information set + * @param deviceInfoData device information data structure + * @return the port name string, or null if not found + */ + private static String devicePortName(HANDLE deviceInfoSet, SP_DEVINFO_DATA deviceInfoData) { + HKEY key = + SetupApi.INSTANCE.SetupDiOpenDevRegKey( + deviceInfoSet, deviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ); + + if (key == INVALID_HANDLE_VALUE) { + return null; + } + String[] keyTokens = {"PortName", "PortNumber"}; + String portName = null; + for (int i = 0; i < keyTokens.length && portName == null; i++) { + portName = Advapi32Util.registryGetStringValue(key, keyTokens[i]); + } + + return portName; + } + + private static String deviceDescription(HANDLE deviceInfoSet, SP_DEVINFO_DATA deviceInfoData) { + return (String) deviceRegistryProperty(deviceInfoSet, deviceInfoData, SPDRP_DEVICEDESC); + } + + private static String deviceManufacturer(HANDLE deviceInfoSet, SP_DEVINFO_DATA deviceInfoData) { + return (String) deviceRegistryProperty(deviceInfoSet, deviceInfoData, SPDRP_MFG); + } + + private static String deviceAddress(HANDLE deviceInfoSet, SP_DEVINFO_DATA deviceInfoData) { + Integer address = + (Integer) deviceRegistryProperty(deviceInfoSet, deviceInfoData, SPDRP_ADDRESS); + return (address != null) ? address.toString() : null; + } + + private static Short deviceVendorIdentifier(String instanceIdentifier) { + final int vendorIdentifierSize = 4; + + Short result = parseDeviceIdentifier(instanceIdentifier, "VID_", vendorIdentifierSize); + if (result == null) { + result = parseDeviceIdentifier(instanceIdentifier, "VEN_", vendorIdentifierSize); + } + + return result; + } + + private static Short deviceProductIdentifier(String instanceIdentifier) { + final int productIdentifierSize = 4; + + Short result = parseDeviceIdentifier(instanceIdentifier, "PID_", productIdentifierSize); + if (result == null) { + result = parseDeviceIdentifier(instanceIdentifier, "DEV_", productIdentifierSize); + } + + return result; + } + + private static String deviceInstanceIdentifier(int deviceInstanceNumber) { + return Cfgmgr32Util.CM_Get_Device_ID(deviceInstanceNumber); + } + + private static String deviceSerialNumber(String instanceIdentifier, int deviceInstanceNumber) { + for (; ; ) { + String serialNumber = parseDeviceSerialNumber(instanceIdentifier); + if (serialNumber != null) { + return serialNumber; + } + deviceInstanceNumber = parentDeviceInstanceNumber(deviceInstanceNumber); + if (deviceInstanceNumber == 0) { + break; + } + instanceIdentifier = deviceInstanceIdentifier(deviceInstanceNumber); + if (instanceIdentifier.isEmpty()) { + break; + } + } + + return null; + } + + private static Object deviceRegistryProperty( + HANDLE deviceInfoSet, SP_DEVINFO_DATA deviceInfoData, int property) { + Object propertyValue = null; + IntByReference dataType = new IntByReference(0); + Pointer outputBuffer = new Memory(PROPERTY_MAX_SIZE); + IntByReference bytesRequired = new IntByReference(PROPERTY_MAX_SIZE); + + if (SetupApi.INSTANCE.SetupDiGetDeviceRegistryProperty( + deviceInfoSet, + deviceInfoData, + property, + dataType, + outputBuffer, + bytesRequired.getValue(), + bytesRequired)) { + switch (dataType.getValue()) { + case REG_DWORD: + propertyValue = outputBuffer.getInt(0); + break; + case REG_SZ: + propertyValue = outputBuffer.getWideString(0); + break; + } + } + + return propertyValue; + } + + private static int parentDeviceInstanceNumber(int childDeviceInstanceNumber) { + IntByReference parentInstanceNumber = new IntByReference(0); + if (Cfgmgr32.INSTANCE.CM_Get_Parent(parentInstanceNumber, childDeviceInstanceNumber, 0) + != Cfgmgr32.CR_SUCCESS) { + return 0; + } + return parentInstanceNumber.getValue(); + } + + private static String parseDeviceSerialNumber(String instanceIdentifier) { + int firstbound = instanceIdentifier.lastIndexOf('\\'); + int lastbound = instanceIdentifier.indexOf('_', firstbound); + if (instanceIdentifier.startsWith("USB\\")) { + if (lastbound != instanceIdentifier.length() - 3) lastbound = instanceIdentifier.length(); + int ampersand = instanceIdentifier.indexOf('&', firstbound); + if (ampersand != -1 && ampersand < lastbound) return null; + } else if (instanceIdentifier.startsWith("FTDIBUS\\")) { + firstbound = instanceIdentifier.lastIndexOf('+'); + lastbound = instanceIdentifier.indexOf('\\', firstbound); + if (lastbound == -1) return null; + } else { + return null; + } + + return instanceIdentifier.substring(firstbound + 1, lastbound); + } + + private static Short parseDeviceIdentifier( + String instanceIdentifier, String identifierPrefix, int identifierSize) { + int index = instanceIdentifier.indexOf(identifierPrefix); + + if (index == -1) { + return null; + } + String indentifierText = + instanceIdentifier.substring( + index + identifierPrefix.length(), index + identifierPrefix.length() + identifierSize); + Short identifierValue; + try { + identifierValue = Short.parseShort(indentifierText, 16); + } catch (Exception e) { + identifierValue = null; + } + + return identifierValue; + } + + /** + * Retrieves port names from the Windows registry HARDWARE\DEVICEMAP\SERIALCOMM key. + * + *

This method serves as a fallback to discover serial ports that may not be detected through + * the Setup API. It directly reads the registry key where Windows maps device identifiers to COM + * port names. + * + * @return a list of port names found in the registry + */ + private static List portNamesFromHardwareDeviceMap() { + List result = new ArrayList(); + HKEY hKey = null; + try { + hKey = + Advapi32Util.registryGetKey( + HKEY_LOCAL_MACHINE, "HARDWARE\\DEVICEMAP\\SERIALCOMM", KEY_QUERY_VALUE) + .getValue(); + } catch (Win32Exception exception) { + return result; + } + int index = 0; + for (; ; ) { + // This is a maximum length of value name, see: + // https://msdn.microsoft.com/en-us/library/windows/desktop/ms724872%28v=vs.85%29.aspx + IntByReference requiredValueNameChars = new IntByReference(16383); + char[] outputValueName = new char[requiredValueNameChars.getValue()]; + Pointer outputBuffer = new Memory(MAX_PATH); + IntByReference bytesRequired = new IntByReference(MAX_PATH); + int ret = + Advapi32.INSTANCE.RegEnumValue( + hKey, + index, + outputValueName, + requiredValueNameChars, + null, + null, + outputBuffer, + bytesRequired); + if (ret == ERROR_SUCCESS) { + result.add(outputBuffer.getWideString(0)); + ++index; + } else { + break; + } + } + Advapi32.INSTANCE.RegCloseKey(hKey); + + return result; + } +} diff --git a/src/main/java/tic/io/serialport/SerialPortJsonEncoder.java b/src/main/java/tic/io/serialport/SerialPortJsonEncoder.java new file mode 100644 index 0000000..e9d5f5e --- /dev/null +++ b/src/main/java/tic/io/serialport/SerialPortJsonEncoder.java @@ -0,0 +1,61 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.io.serialport; + +import java.util.Collections; +import java.util.List; +import org.json.JSONArray; +import org.json.JSONObject; + +/** Utility class to convert serial port descriptors to their JSON representation. */ +public final class SerialPortJsonEncoder { + private static final int DEFAULT_INDENT = 2; + + private SerialPortJsonEncoder() {} + + /** + * Encodes the provided serial port descriptors list into a JSON string using the default + * indentation factor (2 spaces). + * + * @param descriptors descriptors to encode; {@code null} is treated as an empty list + * @return the JSON string + */ + public static String encode(List descriptors) { + return encode(descriptors, DEFAULT_INDENT); + } + + /** + * Encodes the provided serial port descriptors list into a JSON string. + * + * @param descriptors descriptors to encode; {@code null} is treated as an empty list + * @param indentFactor indentation factor forwarded to {@link JSONArray#toString(int)}. If the + * value is negative the compact form is returned + * @return the JSON string + */ + public static String encode(List descriptors, int indentFactor) { + List safeDescriptors = + descriptors == null ? Collections.emptyList() : descriptors; + + JSONArray array = new JSONArray(); + safeDescriptors.forEach( + descriptor -> { + JSONObject jsonObject = new JSONObject(); + jsonObject.put("portId", descriptor.portId()); + jsonObject.put("portName", descriptor.portName()); + jsonObject.put("description", descriptor.description()); + jsonObject.put("productId", descriptor.productId()); + jsonObject.put("vendorId", descriptor.vendorId()); + jsonObject.put("productName", descriptor.productName()); + jsonObject.put("manufacturer", descriptor.manufacturer()); + jsonObject.put("serialNumber", descriptor.serialNumber()); + array.put(jsonObject); + }); + + return indentFactor < 0 ? array.toString() : array.toString(indentFactor); + } +} diff --git a/src/main/java/tic/io/usb/UsbPortDescriptor.java b/src/main/java/tic/io/usb/UsbPortDescriptor.java new file mode 100644 index 0000000..ee0681a --- /dev/null +++ b/src/main/java/tic/io/usb/UsbPortDescriptor.java @@ -0,0 +1,541 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.io.usb; + +import java.util.Objects; +import tic.util.ValueChecker; + +/** + * A structure representing the standard USB device descriptor with additional string descriptors + * (manufacturer, product, serial number) if provided. This USB device descriptor is documented in + * section 9.6.1 of the USB 3.0 specification. All multiple-byte fields are represented in + * host-endian format. + */ +public class UsbPortDescriptor { + + private short bcdDevice; + private short bcdUSB; + private byte bDescriptorType; + private byte bDeviceClass; + private byte bDeviceProtocol; + private byte bDeviceSubClass; + private byte bLength; + private byte bMaxPacketSize0; + private byte bNumConfigurations; + private short idProduct; + private short idVendor; + private byte iManufacturer; + private byte iProduct; + private byte iSerialNumber; + private String manufacturer; + private String product; + private String serialNumber; + + /** Builder class for constructing UsbPortDescriptor instances. */ + public static class Builder { + private short bcdDevice; + private short bcdUSB; + private byte bDescriptorType; + private byte bDeviceClass; + private byte bDeviceProtocol; + private byte bDeviceSubClass; + private byte bLength; + private byte bMaxPacketSize0; + private byte bNumConfigurations; + private short idProduct; + private short idVendor; + private byte iManufacturer; + private byte iProduct; + private byte iSerialNumber; + private String manufacturer; + private String product; + private String serialNumber; + + /** + * Sets the bcdDevice field. + * + * @param bcdDevice the binary-coded decimal device release number + * @return the Builder instance + */ + public Builder bcdDevice(short bcdDevice) { + this.bcdDevice = bcdDevice; + return this; + } + + /** + * Sets the bcdUSB field. + * + * @param bcdUSB the binary-coded decimal USB specification release number + * @return the Builder instance + */ + public Builder bcdUSB(short bcdUSB) { + this.bcdUSB = bcdUSB; + return this; + } + + /** + * Sets the bDescriptorType field. + * + * @param bDescriptorType the USB descriptor type + * @return the Builder instance + */ + public Builder bDescriptorType(byte bDescriptorType) { + this.bDescriptorType = bDescriptorType; + return this; + } + + /** + * Sets the bDeviceClass field. + * + * @param bDeviceClass the USB device class + * @return the Builder instance + */ + public Builder bDeviceClass(byte bDeviceClass) { + this.bDeviceClass = bDeviceClass; + return this; + } + + /** + * Sets the bDeviceProtocol field. + * + * @param bDeviceProtocol the USB device protocol + * @return the Builder instance + */ + public Builder bDeviceProtocol(byte bDeviceProtocol) { + this.bDeviceProtocol = bDeviceProtocol; + return this; + } + + /** + * Sets the bDeviceSubClass field. + * + * @param bDeviceSubClass the USB device subclass + * @return the Builder instance + */ + public Builder bDeviceSubClass(byte bDeviceSubClass) { + this.bDeviceSubClass = bDeviceSubClass; + return this; + } + + /** + * Sets the bLength field. + * + * @param bLength the length of the USB device descriptor + * @return the Builder instance + */ + public Builder bLength(byte bLength) { + this.bLength = bLength; + return this; + } + + /** + * Sets the bMaxPacketSize0 field. + * + * @param bMaxPacketSize0 the maximum packet size for endpoint 0 + * @return the Builder instance + */ + public Builder bMaxPacketSize0(byte bMaxPacketSize0) { + this.bMaxPacketSize0 = bMaxPacketSize0; + return this; + } + + /** + * Sets the bNumConfigurations field. + * + * @param bNumConfigurations the number of possible configurations + * @return the Builder instance + */ + public Builder bNumConfigurations(byte bNumConfigurations) { + this.bNumConfigurations = bNumConfigurations; + return this; + } + + /** + * Sets the idProduct field. + * + * @param idProduct the USB product ID + * @return the Builder instance + */ + public Builder idProduct(short idProduct) { + this.idProduct = idProduct; + return this; + } + + /** + * Sets the idVendor field. + * + * @param idVendor the USB vendor ID + * @return the Builder instance + */ + public Builder idVendor(short idVendor) { + this.idVendor = idVendor; + return this; + } + + /** + * Sets the iManufacturer field. + * + * @param iManufacturer the index of the manufacturer string descriptor + * @return the Builder instance + */ + public Builder iManufacturer(byte iManufacturer) { + this.iManufacturer = iManufacturer; + return this; + } + + /** + * Sets the iProduct field. + * + * @param iProduct the index of the product string descriptor + * @return the Builder instance + */ + public Builder iProduct(byte iProduct) { + this.iProduct = iProduct; + return this; + } + + /** + * Sets the iSerialNumber field. + * + * @param iSerialNumber the index of the serial number string descriptor + * @return the Builder instance + */ + public Builder iSerialNumber(byte iSerialNumber) { + this.iSerialNumber = iSerialNumber; + return this; + } + + /** + * Sets the manufacturer field. + * + * @param manufacturer the manufacturer string + * @return the Builder instance + */ + public Builder manufacturer(String manufacturer) { + this.manufacturer = manufacturer; + return this; + } + + /** + * Sets the product field. + * + * @param product the product string + * @return the Builder instance + */ + public Builder product(String product) { + this.product = product; + return this; + } + + /** + * Sets the serialNumber field. + * + * @param serialNumber the serial number string + * @return the Builder instance + */ + public Builder serialNumber(String serialNumber) { + this.serialNumber = serialNumber; + return this; + } + + /** + * Builds the USBPortDescriptor instance. + * + * @return the constructed USBPortDescriptor instance + * @throws IllegalArgumentException if any required field is invalid + */ + public UsbPortDescriptor build() { + ValueChecker.validateString(this.manufacturer, "manufacturer", true, false); + ValueChecker.validateString(this.product, "product", true, false); + ValueChecker.validateString(this.serialNumber, "serialNumber", true, false); + + return new UsbPortDescriptor( + this.bcdDevice, + this.bcdUSB, + this.bDescriptorType, + this.bDeviceClass, + this.bDeviceProtocol, + this.bDeviceSubClass, + this.bLength, + this.bMaxPacketSize0, + this.bNumConfigurations, + this.idProduct, + this.idVendor, + this.iManufacturer, + this.iProduct, + this.iSerialNumber, + this.manufacturer, + this.product, + this.serialNumber); + } + } + + /** + * Constructor setting parameters to specific values + * + * @param bcdDevice the USB device release number in binary-coded decimal + * @param bcdUSB the USB specification release number in binary-coded decimal + * @param bDescriptorType the type of descriptor + * @param bDeviceClass the class of device + * @param bDeviceProtocol the protocol of device + * @param bDeviceSubClass the subclass of device + * @param bLength the length of the descriptor + * @param bMaxPacketSize0 the maximum packet size for endpoint 0 + * @param bNumConfigurations the number of possible configurations + * @param idProduct the product ID + * @param idVendor the vendor ID + * @param iManufacturer the index of the manufacturer string descriptor + * @param iProduct the index of the product string descriptor + * @param iSerialNumber the index of the serial number string descriptor + * @param manufacturer the manufacturer + * @param product the product + * @param serialNumber the serial number + */ + private UsbPortDescriptor( + short bcdDevice, + short bcdUSB, + byte bDescriptorType, + byte bDeviceClass, + byte bDeviceProtocol, + byte bDeviceSubClass, + byte bLength, + byte bMaxPacketSize0, + byte bNumConfigurations, + short idProduct, + short idVendor, + byte iManufacturer, + byte iProduct, + byte iSerialNumber, + String manufacturer, + String product, + String serialNumber) { + this.bcdDevice = bcdDevice; + this.bcdUSB = bcdUSB; + this.bDescriptorType = bDescriptorType; + this.bDeviceClass = bDeviceClass; + this.bDeviceProtocol = bDeviceProtocol; + this.bDeviceSubClass = bDeviceSubClass; + this.bLength = bLength; + this.bMaxPacketSize0 = bMaxPacketSize0; + this.bNumConfigurations = bNumConfigurations; + this.idProduct = idProduct; + this.idVendor = idVendor; + this.iManufacturer = iManufacturer; + this.iProduct = iProduct; + this.iSerialNumber = iSerialNumber; + this.manufacturer = manufacturer; + this.product = product; + this.serialNumber = serialNumber; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof UsbPortDescriptor)) { + return false; + } + UsbPortDescriptor other = (UsbPortDescriptor) obj; + return this.bcdDevice == other.bcdDevice + && this.bcdUSB == other.bcdUSB + && this.bDescriptorType == other.bDescriptorType + && this.bDeviceClass == other.bDeviceClass + && this.bDeviceProtocol == other.bDeviceProtocol + && this.bDeviceSubClass == other.bDeviceSubClass + && this.bLength == other.bLength + && this.bMaxPacketSize0 == other.bMaxPacketSize0 + && this.bNumConfigurations == other.bNumConfigurations + && this.idProduct == other.idProduct + && this.idVendor == other.idVendor + && this.iManufacturer == other.iManufacturer + && this.iProduct == other.iProduct + && this.iSerialNumber == other.iSerialNumber + && Objects.equals(this.manufacturer, other.manufacturer) + && Objects.equals(this.product, other.product) + && Objects.equals(this.serialNumber, other.serialNumber); + } + + @Override + public int hashCode() { + return Objects.hash( + this.bcdDevice, + this.bcdUSB, + this.bDescriptorType, + this.bDeviceClass, + this.bDeviceProtocol, + this.bDeviceSubClass, + this.bLength, + this.bMaxPacketSize0, + this.bNumConfigurations, + this.idProduct, + this.idVendor, + this.iManufacturer, + this.iProduct, + this.iSerialNumber, + this.manufacturer, + this.product, + this.serialNumber); + } + + /** + * Returns the USB device release number in binary-coded decimal. + * + * @return The USB device release number. + */ + public short bcdDevice() { + return this.bcdDevice; + } + + /** + * Returns the USB specification release number in binary-coded decimal. A value of 0x0200 + * indicates USB 2.0, 0x0110 indicates USB 1.1, etc. + * + * @return The USB specification release number. + */ + public short bcdUSB() { + return this.bcdUSB; + } + + /** + * Returns the USB descriptor type. + * + * @return The USB descriptor type. + */ + public byte bDescriptorType() { + return this.bDescriptorType; + } + + /** + * Returns the USB-IF class code for the device. + * + * @return The USB-IF class code. + */ + public byte bDeviceClass() { + return this.bDeviceClass; + } + + /** + * Returns the USB-IF protocol code for the device, qualified by the bDeviceClass and + * bDeviceSubClass values + * + * @return The USB-IF protocol code. + */ + public byte bDeviceProtocol() { + return this.bDeviceProtocol; + } + + /** + * Returns the USB-IF subclass code for the device, qualified by the bDeviceClass value. + * + * @return The USB-IF subclass code. + */ + public byte bDeviceSubClass() { + return this.bDeviceSubClass; + } + + /** + * Returns the size of the USB device descriptor (in bytes) without + * manufacturer/product/serialNumber fields. + * + * @return The size of this descriptor (in bytes). + */ + public byte bLength() { + return this.bLength; + } + + /** + * Returns the maximum packet size for endpoint 0. + * + * @return The maximum packet site for endpoint 0. + */ + public byte bMaxPacketSize0() { + return this.bMaxPacketSize0; + } + + /** + * Returns the number of possible configurations. + * + * @return The number of possible configurations. + */ + public byte bNumConfigurations() { + return this.bNumConfigurations; + } + + /** + * Returns the USB-IF product ID. + * + * @return The product ID. + */ + public short idProduct() { + return this.idProduct; + } + + /** + * Returns the USB-IF vendor ID. + * + * @return The vendor ID. + */ + public short idVendor() { + return this.idVendor; + } + + /** + * Returns the index of the string descriptor describing manufacturer. + * + * @return The manufacturer string descriptor index. + */ + public byte iManufacturer() { + return this.iManufacturer; + } + + /** + * Returns the index of the string descriptor describing product. + * + * @return The product string descriptor index. + */ + public byte iProduct() { + return this.iProduct; + } + + /** + * Returns the index of the string descriptor containing device serial number. + * + * @return The serial number string descriptor index. + */ + public byte iSerialNumber() { + return this.iSerialNumber; + } + + /** + * Returns the USB device manufacturer. + * + * @return The USB device manufacturer if exists or null otherwise. + */ + public String manufacturer() { + return this.manufacturer; + } + + /** + * Returns the USB device product. + * + * @return The USB device product if exists or null otherwise. + */ + public String product() { + return this.product; + } + + /** + * Returns the USB device serial number. + * + * @return The USB device serial number if exists or null otherwise. + */ + public String serialNumber() { + return this.serialNumber; + } +} diff --git a/src/main/java/tic/io/usb/UsbPortFinder.java b/src/main/java/tic/io/usb/UsbPortFinder.java new file mode 100644 index 0000000..c2d10e6 --- /dev/null +++ b/src/main/java/tic/io/usb/UsbPortFinder.java @@ -0,0 +1,55 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.io.usb; + +import java.util.List; +import java.util.stream.Collectors; +import tic.io.PortFinder; + +/** Interface used to find all USB port descriptor */ +public interface UsbPortFinder extends PortFinder { + /** + * Find USB device with the given product id + * + * @param idProduct the USB product identifier + * @return the USB descriptor data list of all USB device connected with the given product id + */ + public default List findByProductId(short idProduct) { + return this.findAll().stream() + .filter(d -> d.idProduct() == idProduct) + .collect(Collectors.toList()); + } + + /** + * Find USB device with the given vendor id + * + * @param idVendor the USB vendor identifier + * @return the USB descriptor data list of all USB device connected with the given vendor id + */ + public default List findByVendorId(short idVendor) { + return this.findAll().stream() + .filter(d -> d.idVendor() == idVendor) + .collect(Collectors.toList()); + } + + /** + * Find USB device with the given product id and vendor id + * + * @param idProduct the USB product identifier + * @param idVendor the USB vendor identifier + * @return the USB descriptor data list of all USB device connected with the given product id and + * vendor id + */ + public default List findByProductIdAndVendorId( + short idProduct, short idVendor) { + return this.findAll().stream() + .filter(d -> d.idProduct() == idProduct) + .filter(d -> d.idVendor() == idVendor) + .collect(Collectors.toList()); + } +} diff --git a/src/main/java/tic/io/usb/UsbPortFinderBase.java b/src/main/java/tic/io/usb/UsbPortFinderBase.java new file mode 100644 index 0000000..b1b6352 --- /dev/null +++ b/src/main/java/tic/io/usb/UsbPortFinderBase.java @@ -0,0 +1,114 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.io.usb; + +import java.util.ArrayList; +import java.util.List; +import org.usb4java.Context; +import org.usb4java.Device; +import org.usb4java.DeviceDescriptor; +import org.usb4java.DeviceHandle; +import org.usb4java.DeviceList; +import org.usb4java.LibUsb; + +/** Class used to find all USB port descriptor */ +public class UsbPortFinderBase implements UsbPortFinder { + + /** + * Get instance + * + * @return Unique instance + */ + public static UsbPortFinder getInstance() { + if (instance == null) { + instance = new UsbPortFinderBase(); + } + + return instance; + } + + private static UsbPortFinder instance; + + private UsbPortFinderBase() {} + + @Override + public List findAll() { + List usbPortList = new ArrayList<>(); + + Context context = new Context(); + DeviceList deviceList = new DeviceList(); + + // Initialize USB library access + int result = LibUsb.init(context); + if (result != LibUsb.SUCCESS) { + return usbPortList; + } + + // Get available USB device list + result = LibUsb.getDeviceList(context, deviceList); + if (result < 0) { + return usbPortList; + } + + // For each USB device + for (Device device : deviceList) { + DeviceDescriptor descriptor = new DeviceDescriptor(); + + // Get USB device descriptor + result = LibUsb.getDeviceDescriptor(device, descriptor); + if (result != LibUsb.SUCCESS) { + continue; + } + String productName = null; + String manufacturer = null; + String serialNumber = null; + // If USB device has string descriptors + if (descriptor.idProduct() != 0) { + // Get string descriptors for USB device + DeviceHandle handle = new DeviceHandle(); + result = LibUsb.open(device, handle); + if (result == LibUsb.SUCCESS) { + productName = LibUsb.getStringDescriptor(handle, descriptor.iProduct()); + manufacturer = LibUsb.getStringDescriptor(handle, descriptor.iManufacturer()); + serialNumber = LibUsb.getStringDescriptor(handle, descriptor.iSerialNumber()); + LibUsb.close(handle); + } + } + + try { + UsbPortDescriptor usbPort = + new UsbPortDescriptor.Builder() + .bcdDevice(descriptor.bcdDevice()) + .bcdUSB(descriptor.bcdUSB()) + .bDescriptorType(descriptor.bDescriptorType()) + .bDeviceClass(descriptor.bDeviceClass()) + .bDeviceProtocol(descriptor.bDeviceProtocol()) + .bDeviceSubClass(descriptor.bDeviceSubClass()) + .bLength(descriptor.bLength()) + .bMaxPacketSize0(descriptor.bMaxPacketSize0()) + .bNumConfigurations(descriptor.bNumConfigurations()) + .idProduct(descriptor.idProduct()) + .idVendor(descriptor.idVendor()) + .iManufacturer(descriptor.iManufacturer()) + .iProduct(descriptor.iProduct()) + .iSerialNumber(descriptor.iSerialNumber()) + .manufacturer(manufacturer) + .product(productName) + .serialNumber(serialNumber) + .build(); + usbPortList.add(usbPort); + } catch (IllegalArgumentException e) { + } + } + + // Finalize USB library access + LibUsb.freeDeviceList(deviceList, true); + LibUsb.exit(context); + return usbPortList; + } +} diff --git a/src/main/java/tic/io/usb/UsbPortJsonEncoder.java b/src/main/java/tic/io/usb/UsbPortJsonEncoder.java new file mode 100644 index 0000000..8a03ad6 --- /dev/null +++ b/src/main/java/tic/io/usb/UsbPortJsonEncoder.java @@ -0,0 +1,70 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.io.usb; + +import java.util.Collections; +import java.util.List; +import org.json.JSONArray; +import org.json.JSONObject; + +/** Utility class to convert USB port descriptors to their JSON representation. */ +public final class UsbPortJsonEncoder { + private static final int DEFAULT_INDENT = 2; + + private UsbPortJsonEncoder() {} + + /** + * Encodes the provided USB descriptors list into a JSON string using the default indentation + * factor (2 spaces). + * + * @param descriptors descriptors to encode; {@code null} is treated as an empty list + * @return the JSON string + */ + public static String encode(List descriptors) { + return encode(descriptors, DEFAULT_INDENT); + } + + /** + * Encodes the provided USB descriptors list into a JSON string. + * + * @param descriptors descriptors to encode; {@code null} is treated as an empty list + * @param indentFactor indentation factor forwarded to {@link JSONArray#toString(int)}. If the + * value is negative the compact form is returned + * @return the JSON string + */ + public static String encode(List descriptors, int indentFactor) { + List safeDescriptors = + descriptors == null ? Collections.emptyList() : descriptors; + + JSONArray array = new JSONArray(); + safeDescriptors.forEach( + descriptor -> { + JSONObject jsonObject = new JSONObject(); + jsonObject.put("bcdDevice", descriptor.bcdDevice()); + jsonObject.put("bcdUSB", descriptor.bcdUSB()); + jsonObject.put("bDescriptorType", descriptor.bDescriptorType()); + jsonObject.put("bDeviceClass", descriptor.bDeviceClass()); + jsonObject.put("bDeviceProtocol", descriptor.bDeviceProtocol()); + jsonObject.put("bDeviceSubClass", descriptor.bDeviceSubClass()); + jsonObject.put("bLength", descriptor.bLength()); + jsonObject.put("bMaxPacketSize0", descriptor.bMaxPacketSize0()); + jsonObject.put("bNumConfigurations", descriptor.bNumConfigurations()); + jsonObject.put("idProduct", descriptor.idProduct()); + jsonObject.put("idVendor", descriptor.idVendor()); + jsonObject.put("iManufacturer", descriptor.iManufacturer()); + jsonObject.put("iProduct", descriptor.iProduct()); + jsonObject.put("iSerialNumber", descriptor.iSerialNumber()); + jsonObject.put("manufacturer", descriptor.manufacturer()); + jsonObject.put("product", descriptor.product()); + jsonObject.put("serialNumber", descriptor.serialNumber()); + array.put(jsonObject); + }); + + return indentFactor < 0 ? array.toString() : array.toString(indentFactor); + } +} diff --git a/src/main/java/tic/service/TIC2WebSocketApplication.java b/src/main/java/tic/service/TIC2WebSocketApplication.java new file mode 100644 index 0000000..2795fc6 --- /dev/null +++ b/src/main/java/tic/service/TIC2WebSocketApplication.java @@ -0,0 +1,371 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.service; + +import tic.core.TICCore; +import tic.core.TICCoreBase; +import tic.service.client.TIC2WebSocketClientPool; +import tic.service.client.TIC2WebSocketClientPoolBase; +import tic.service.config.TIC2WebSocketConfiguration; +import tic.service.config.TIC2WebSocketConfigurationLoader; +import tic.service.netty.TIC2WebSocketServer; +import tic.service.requesthandler.TIC2WebSocketRequestHandler; +import tic.service.requesthandler.TIC2WebSocketRequestHandlerBase; +import java.io.File; +import java.io.InputStream; +import java.util.Properties; +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.core.LoggerContext; +import picocli.CommandLine; +import picocli.CommandLine.IVersionProvider; +import picocli.CommandLine.ParseResult; + +/** + * Main application class for TIC2WebSocket. + * + *

This class manages the lifecycle of the TIC2WebSocket application, including initialization, + * configuration loading, command-line parsing, server startup and shutdown, and error handling. + * It integrates with the core TIC logic, client pool, request handler, and Netty server to provide + * a complete WebSocket-based interface for TIC data exchange. + * + *

Responsibilities include: + *

    + *
  • Parsing command-line arguments and loading configuration + *
  • Starting and stopping the TIC2WebSocket server and core + *
  • Managing application state and error codes + *
  • Handling logging configuration and shutdown hooks + *
  • Providing entry point and main execution loop + *
+ * + * @author Enedis Smarties team + * @see TIC2WebSocketServer + * @see TIC2WebSocketClientPool + * @see TIC2WebSocketRequestHandler + * @see TICCore + */ +public class TIC2WebSocketApplication { + /** Project properties loaded from TIC2WebSocket.properties. */ + public static final Properties PROJECT_PROPERTIES = new Properties(); + + static { + try { + InputStream stream = + TIC2WebSocketApplication.class + .getClassLoader() + .getResourceAsStream("TIC2WebSocket.properties"); + + if (stream == null) { + System.err.println("Can't find projet property file!"); + } else { + TIC2WebSocketApplication.PROJECT_PROPERTIES.load(stream); + } + } catch (Exception exception) { + System.err.println("Can't load projet property file!"); + exception.printStackTrace(System.err); + } + } + + /** Project name ("project_name" from project.properties). */ + public static final String NAME = PROJECT_PROPERTIES.getProperty("project_name", ""); + + /** Project version ("project_version" from project.properties). */ + public static final String VERSION = PROJECT_PROPERTIES.getProperty("project_version", ""); + + /** Project description ("project_description" from project.properties). */ + public static final String DESCRIPTION = + PROJECT_PROPERTIES.getProperty("project_description", ""); + + /** + * Program entry point for TIC2WebSocket. + * + *

Initializes and runs the application, handling any startup errors. + * + * @param args command line arguments + */ + public static void main(String[] args) { + try { + TIC2WebSocketApplication application = new TIC2WebSocketApplication(args); + int result = application.run(); + System.exit(result); + } catch (Exception exception) { + exception.printStackTrace(System.err); + System.exit(-1); + } + } + + private String[] commandLineArgs; + private CommandLine commandLineParser; + private TIC2WebSocketCommandLine commandLine; + private Logger logger; + private boolean started; + private TIC2WebSocketConfiguration configuration; + + private TIC2WebSocketClientPool clientPool; + private TIC2WebSocketServer server; + private TIC2WebSocketRequestHandler requestHandler; + private TICCore ticCore; + + /** + * Constructs a new TIC2WebSocketApplication instance. + * + * @param args command line arguments + */ + public TIC2WebSocketApplication(String[] args) { + this.commandLineArgs = args; + this.commandLine = new TIC2WebSocketCommandLine(); + this.commandLineParser = new CommandLine(this.commandLine); + this.commandLineParser.setCommandName(TIC2WebSocketApplication.NAME); + this.commandLineParser + .getCommandSpec() + .versionProvider( + new IVersionProvider() { + @Override + public String[] getVersion() throws Exception { + return new String[] { + TIC2WebSocketApplication.NAME + " v" + TIC2WebSocketApplication.VERSION + }; + } + }); + this.commandLineParser.registerConverter( + Level.class, new TIC2WebSocketCommandLine.VerboseLevelConverter()); + this.updateLoggerConfiguration(Level.ERROR); + this.started = false; + } + + /** + * Executes the application main loop. + * + *

Initializes, starts, and manages the application lifecycle, including shutdown handling. + * + * @return 0 if success, else an error code + * @throws InterruptedException if the application thread is interrupted + * @see TIC2WebSocketApplicationErrorCode + */ + public int run() throws InterruptedException { + int result = this.init(); + + if (result != TIC2WebSocketApplicationErrorCode.NO_ERROR.code()) { + return result; + } + result = this.start(); + if (result != TIC2WebSocketApplicationErrorCode.NO_ERROR.code()) { + return result; + } + + Runtime.getRuntime() + .addShutdownHook( + new Thread( + new Runnable() { + @Override + public void run() { + TIC2WebSocketApplication.this.stop(); + } + })); + + while (this.isStarted()) { + Thread.sleep(1000); + } + + return TIC2WebSocketApplicationErrorCode.NO_ERROR.code(); + } + + /** + * Initializes the application and its components. + * + *

Parses command-line arguments, loads configuration, and prepares core components. + * + * @return 0 if success, else an error code + * @see TIC2WebSocketApplicationErrorCode + */ + public int init() { + if (this.isStarted()) { + this.logger.error("Application already started!"); + return TIC2WebSocketApplicationErrorCode.APPLICATION_ALREADY_STARTED.code(); + } + int result = this.parseCommandLine(); + if (result != TIC2WebSocketApplicationErrorCode.NO_ERROR.code()) { + return result; + } + result = this.updateLoggerConfiguration(this.commandLine.verboseLevel); + if (result != TIC2WebSocketApplicationErrorCode.NO_ERROR.code()) { + return result; + } + + result = this.loadConfiguration(); + if (result != TIC2WebSocketApplicationErrorCode.NO_ERROR.code()) { + return result; + } + + this.logger.info(TIC2WebSocketApplication.NAME + " initialized"); + + this.ticCore = + new TICCoreBase(this.configuration.getTicMode(), this.configuration.getTicPortNames()); + this.clientPool = new TIC2WebSocketClientPoolBase(); + this.requestHandler = new TIC2WebSocketRequestHandlerBase(this.ticCore); + + this.server = + new TIC2WebSocketServer( + "localhost", + this.configuration.getServerPort(), + this.clientPool, + this.requestHandler); + + return TIC2WebSocketApplicationErrorCode.NO_ERROR.code(); + } + + /** + * Starts the application and its main services. + * + *

Starts the TIC core and WebSocket server, and logs startup events. + * + * @return 0 if success, else an error code + */ + public int start() { + if (this.commandLineParser.isUsageHelpRequested()) { + this.commandLineParser.usage(System.out); + } + if (this.commandLineParser.isVersionHelpRequested()) { + this.commandLineParser.printVersionHelp(System.out); + } + this.logger.info(TIC2WebSocketApplication.NAME + " starting"); + + try { + this.ticCore.start(); + this.server.start(); + } catch (Exception exception) { + this.logger.error(exception.getMessage(), exception); + return TIC2WebSocketApplicationErrorCode.LOAD_CONFIGURATION_FAILURE.code(); + } + + this.logger.info(TIC2WebSocketApplication.NAME + " started"); + this.started = true; + + return TIC2WebSocketApplicationErrorCode.NO_ERROR.code(); + } + + /** + * Indicates whether the application is currently started. + * + * @return true if the application is started, false otherwise + */ + public boolean isStarted() { + return this.started; + } + + /** + * Stops the application and releases resources. + * + *

Stops the WebSocket server and TIC core, and logs shutdown events. + * + * @return 0 if success, else an error code + * @see TIC2WebSocketApplicationErrorCode + */ + public int stop() { + if (!this.isStarted()) { + this.logger.error("Application not started!"); + return TIC2WebSocketApplicationErrorCode.APPLICATION_NOT_STARTED.code(); + } + + try { + this.server.stop(); + this.ticCore.stop(); + } catch (Exception exception) { + this.logger.error(exception.getMessage(), exception); + return TIC2WebSocketApplicationErrorCode.LOAD_CONFIGURATION_FAILURE.code(); + } + + this.logger.info(TIC2WebSocketApplication.NAME + " stopped"); + this.started = false; + + return TIC2WebSocketApplicationErrorCode.NO_ERROR.code(); + } + + /** + * Parses command-line arguments and validates them. + * + *

Logs errors for invalid arguments and returns appropriate error codes. + * + * @return 0 if success, else an error code + */ + private int parseCommandLine() { + try { + ParseResult parseResult = this.commandLineParser.parseArgs(this.commandLineArgs); + if (parseResult.errors().size() > 0) { + this.logger.error("Invalid command line!"); + for (int i = 0; i < parseResult.errors().size(); i++) { + this.logger.error(parseResult.errors().get(i).getMessage()); + } + return TIC2WebSocketApplicationErrorCode.COMMAND_LINE_INVALID.code(); + } + } catch (Exception exception) { + this.logger.error("Invalid command line!"); + this.logger.error(exception.getMessage()); + return TIC2WebSocketApplicationErrorCode.COMMAND_LINE_INVALID.code(); + } + + return TIC2WebSocketApplicationErrorCode.NO_ERROR.code(); + } + + /** + * Updates the logger configuration based on the specified log level. + * + *

Reconfigures Log4j and sets the application logger. + * + * @param level the log level to use + * @return 0 if success, else an error code + */ + private int updateLoggerConfiguration(Level level) { + try { + System.setProperty( + "log4j.configurationFile", "log4j2-" + level.name().toLowerCase() + ".xml"); + LoggerContext context = (LoggerContext) LogManager.getContext(false); + context.reconfigure(); + this.logger = LogManager.getLogger(); + } catch (Exception exception) { + System.err.println("Log configuration update failure!"); + System.err.println(exception.getMessage()); + return TIC2WebSocketApplicationErrorCode.UPDATE_LOGGER_CONFIGURATION_FAILURE.code(); + } + + return TIC2WebSocketApplicationErrorCode.NO_ERROR.code(); + } + + /** + * Loads the application configuration from file. + * + *

Reads the configuration file and initializes the configuration object. + * + * @return 0 if success, else an error code + */ + private int loadConfiguration() { + String configFile = null; + + if (this.commandLine.configFile != null) { + configFile = this.commandLine.configFile; + } else { + configFile = System.getProperty("configFile", NAME + "Configuration.json"); + } + File configPath = new File(configFile); + if (!configPath.exists()) { + this.logger.error( + "No configuration file path '" + configPath.getAbsolutePath() + "' not found"); + return TIC2WebSocketApplicationErrorCode.LOAD_CONFIGURATION_FAILURE.code(); + } + try { + this.logger.info("Loading configuration file " + configPath); + this.configuration = TIC2WebSocketConfigurationLoader.load(configPath.getAbsolutePath()); + } catch (Exception exception) { + this.logger.error("Loading configuration file " + configPath + " failed", exception); + return TIC2WebSocketApplicationErrorCode.LOAD_CONFIGURATION_FAILURE.code(); + } + + return TIC2WebSocketApplicationErrorCode.NO_ERROR.code(); + } +} diff --git a/src/main/java/tic/service/TIC2WebSocketApplicationErrorCode.java b/src/main/java/tic/service/TIC2WebSocketApplicationErrorCode.java new file mode 100644 index 0000000..e933a52 --- /dev/null +++ b/src/main/java/tic/service/TIC2WebSocketApplicationErrorCode.java @@ -0,0 +1,61 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.service; + +/** + * Enumeration of application error codes for TIC2WebSocket. + * + *

This enum defines error codes used throughout the TIC2WebSocket application to indicate + * specific error conditions, such as invalid command line arguments, configuration failures, + * and application state errors. Each error code is associated with an integer value for + * consistent error reporting and handling. + * + *

Common use cases include: + *

    + *
  • Reporting application initialization and runtime errors + *
  • Standardizing error codes for logging and responses + *
  • Facilitating error handling in the main application logic + *
+ * + * @author Enedis Smarties team + */ +public enum TIC2WebSocketApplicationErrorCode { + /** No error (success). */ + NO_ERROR(0), + /** Command line is invalid. */ + COMMAND_LINE_INVALID(1), + /** Logger configuration update failure. */ + UPDATE_LOGGER_CONFIGURATION_FAILURE(2), + /** Application is already started. */ + APPLICATION_ALREADY_STARTED(3), + /** Application is not started. */ + APPLICATION_NOT_STARTED(4), + /** Configuration loading failure. */ + LOAD_CONFIGURATION_FAILURE(5); + + /** Integer value of the error code. */ + private int code; + + /** + * Constructs an error code enum value. + * + * @param code the integer value of the error code + */ + private TIC2WebSocketApplicationErrorCode(int code) { + this.code = code; + } + + /** + * Returns the integer value of the error code. + * + * @return the error code value + */ + public int code() { + return this.code; + } +} diff --git a/src/main/java/tic/service/TIC2WebSocketCommandLine.java b/src/main/java/tic/service/TIC2WebSocketCommandLine.java new file mode 100644 index 0000000..90c6c90 --- /dev/null +++ b/src/main/java/tic/service/TIC2WebSocketCommandLine.java @@ -0,0 +1,128 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.service; + +import org.apache.logging.log4j.Level; +import picocli.CommandLine.Command; +import picocli.CommandLine.ITypeConverter; +import picocli.CommandLine.Option; +import picocli.CommandLine.TypeConversionException; + +/** + * Command line options and converters for TIC2WebSocket. + * + *

This class defines the command line arguments, options, and type converters used to configure + * and launch the TIC2WebSocket application. It leverages Picocli annotations for option parsing + * and provides a custom converter for verbosity levels. + * + *

Responsibilities include: + *

    + *
  • Defining supported command line options (help, version, verbosity, config file) + *
  • Providing a converter for log verbosity levels + *
  • Storing parsed option values for use in application initialization + *
+ * + * @author Enedis Smarties team + */ +@Command() +public class TIC2WebSocketCommandLine { + /** + * Picocli type converter for log verbosity levels. + * + *

Converts integer or string values to Log4j {@link Level} instances for controlling + * application logging verbosity. + */ + static class VerboseLevelConverter implements ITypeConverter { + /** + * Converts a string value to a Log4j {@link Level}. + * + *

Accepts both integer and string representations of log levels. + * + * @param value the string value to convert + * @return the corresponding Log4j Level + * @throws Exception if conversion fails + */ + @Override + public Level convert(String value) throws Exception { + try { + switch (Integer.parseInt(value)) { + case 0: + return Level.OFF; + case 1: + return Level.FATAL; + case 2: + return Level.ERROR; + case 3: + return Level.WARN; + case 4: + return Level.INFO; + case 5: + return Level.DEBUG; + case 6: + return Level.TRACE; + default: + throw new TypeConversionException(value); + } + } catch (NumberFormatException exception) { + Level level = Level.getLevel(value); + if (level == null) { + throw new TypeConversionException(value); + } + return level; + } + } + } + + /** + * Option to display help information. + */ + @Option( + names = {"-h", "--help"}, + usageHelp = true, + description = "Display help") + boolean helpRequested = false; + + /** + * Option to display version information. + */ + @Option( + names = {"--version"}, + versionHelp = true, + description = "Display version") + boolean versionRequested = false; + + // @formatter:off + /** + * Option to set the log verbosity level. + */ + @Option( + names = {"-v", "--verbose"}, + defaultValue = "2", + paramLabel = "LEVEL", + description = + "Define verbosity level:\n" + + "0 ou OFF = muted\n" + + "1 ou FATAL = critical errors\n" + + "2 ou ERROR = error (default)\n" + + "3 ou WARN = warnings\n" + + "4 ou INFO = informations\n" + + "5 ou DEBUG = debugging\n" + + "6 ou TRACE = traces\n") + Level verboseLevel; + + // @formatter:on + + /** + * Option to specify the configuration file path. + */ + @Option( + names = {"--configFile"}, + paramLabel = "PATH", + description = "Set configuration file") + String configFile = null; +} diff --git a/src/main/java/tic/service/client/TIC2WebSocketClient.java b/src/main/java/tic/service/client/TIC2WebSocketClient.java new file mode 100644 index 0000000..fde36b4 --- /dev/null +++ b/src/main/java/tic/service/client/TIC2WebSocketClient.java @@ -0,0 +1,97 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.service.client; + +import io.netty.channel.Channel; +import java.time.LocalDateTime; +import tic.core.TICCoreError; +import tic.core.TICCoreFrame; +import tic.core.TICCoreSubscriber; +import tic.service.endpoint.EventSender; +import tic.service.message.EventOnError; +import tic.service.message.EventOnTICData; +import tic.util.message.Event; + +/** + * WebSocket client for TIC2WebSocket service. + * + *

This class implements {@link TICCoreSubscriber} to handle TIC data and error events, + * forwarding them to the WebSocket channel using the provided {@link EventSender}. + * + *

Key features include: + * + *

    + *
  • Receives TIC data frames and error notifications + *
  • Forwards events to the associated Netty WebSocket channel + *
  • Handles event serialization and transmission + *
+ * + * @author Enedis Smarties team + * @see TICCoreSubscriber + * @see EventSender + * @see Channel + */ +public class TIC2WebSocketClient implements TICCoreSubscriber { + + /** Associated Netty WebSocket channel for communication. */ + private final Channel channel; + + /** Event sender for dispatching TIC events to the channel. */ + private final EventSender eventSender; + + /** + * Constructs a new TIC2WebSocketClient instance. + * + *

Initializes the client with the specified WebSocket channel and event sender. + * + * @param channel the Netty WebSocket channel for communication + * @param eventSender the event sender responsible for dispatching events + */ + public TIC2WebSocketClient(Channel channel, EventSender eventSender) { + super(); + this.channel = channel; + this.eventSender = eventSender; + } + + /** + * Handles incoming TIC data frames. + * + *

This method is called when a new TIC data frame is received. It creates an {@link + * EventOnTICData} event and sends it to the WebSocket channel. + * + * @param frame the TIC data frame received + */ + @Override + public void onData(TICCoreFrame frame) { + Event event = new EventOnTICData(LocalDateTime.now(), frame); + this.eventSender.sendEvent(this.channel, event); + } + + /** + * Handles TIC error notifications. + * + *

This method is called when a TIC error occurs. It creates an {@link EventOnError} event and + * sends it to the WebSocket channel. + * + * @param error the TIC error detected + */ + @Override + public void onError(TICCoreError error) { + Event event = new EventOnError(LocalDateTime.now(), error); + this.eventSender.sendEvent(this.channel, event); + } + + /** + * Returns the associated WebSocket channel for this client. + * + * @return the Netty WebSocket channel + */ + public Channel getChannel() { + return this.channel; + } +} diff --git a/src/main/java/tic/service/client/TIC2WebSocketClientPool.java b/src/main/java/tic/service/client/TIC2WebSocketClientPool.java new file mode 100644 index 0000000..c81d8c3 --- /dev/null +++ b/src/main/java/tic/service/client/TIC2WebSocketClientPool.java @@ -0,0 +1,76 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.service.client; + +import tic.service.endpoint.EventSender; +import io.netty.channel.Channel; +import java.util.Optional; + +/** + * Pool interface for managing TIC2WebSocketClient instances. + * + *

This interface defines methods for creating, retrieving, checking, and removing {@link + * TIC2WebSocketClient} objects associated with Netty WebSocket channels. It provides centralized + * management of client lifecycles and lookup by channel identifier. + * + *

Key features include: + * + *

    + *
  • Client creation and registration + *
  • Client lookup by channel ID + *
  • Existence checks for active clients + *
  • Client removal and cleanup + *
+ * + * @author Enedis Smarties team + * @see TIC2WebSocketClient + * @see Channel + * @see EventSender + */ +public interface TIC2WebSocketClientPool { + /** + * Retrieves the client associated with the specified channel ID. + * + *

Returns an {@link Optional} containing the client if found, or empty if no client exists for + * the given channel ID. + * + * @param channelId the unique identifier of the WebSocket channel + * @return an Optional containing the client, or empty if not found + */ + Optional getClient(String channelId); + + /** + * Checks if a client exists for the specified channel ID. + * + *

Returns true if a client is registered for the given channel ID, false otherwise. + * + * @param channelId the unique identifier of the WebSocket channel + * @return true if a client exists, false otherwise + */ + boolean exists(String channelId); + + /** + * Creates and registers a new client for the specified channel and event sender. + * + *

Initializes a new {@link TIC2WebSocketClient} and associates it with the given channel. + * + * @param channel the Netty WebSocket channel for communication + * @param sender the event sender responsible for dispatching events + * @return the newly created client instance + */ + TIC2WebSocketClient createClient(Channel channel, EventSender sender); + + /** + * Removes the client associated with the specified channel ID. + * + *

Unregisters and cleans up the client for the given channel ID, if present. + * + * @param channelId the unique identifier of the WebSocket channel + */ + void remove(String channelId); +} diff --git a/src/main/java/tic/service/client/TIC2WebSocketClientPoolBase.java b/src/main/java/tic/service/client/TIC2WebSocketClientPoolBase.java new file mode 100644 index 0000000..ca8e304 --- /dev/null +++ b/src/main/java/tic/service/client/TIC2WebSocketClientPoolBase.java @@ -0,0 +1,129 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.service.client; + +import tic.service.endpoint.EventSender; +import io.netty.channel.Channel; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.CopyOnWriteArraySet; + +/** + * Default implementation of the TIC2WebSocket client pool. + * + *

This class manages a thread-safe set of {@link TIC2WebSocketClient} instances, providing + * creation, lookup, existence checks, and removal by channel ID. It implements the {@link + * TIC2WebSocketClientPool} interface for centralized client management in the WebSocket service. + * + *

Key features include: + * + *

    + *
  • Thread-safe client storage using {@link CopyOnWriteArraySet} + *
  • Efficient lookup and registration by channel ID + *
  • Argument validation for client creation + *
+ * + * @author Enedis Smarties team + * @see TIC2WebSocketClientPool + * @see TIC2WebSocketClient + * @see Channel + * @see EventSender + */ +public class TIC2WebSocketClientPoolBase implements TIC2WebSocketClientPool { + /** Thread-safe set of registered clients. */ + private final Set clients; + + /** Constructs a new client pool with an empty set of clients. */ + public TIC2WebSocketClientPoolBase() { + super(); + this.clients = new CopyOnWriteArraySet<>(); + } + + /** + * Retrieves the client associated with the specified channel ID. + * + *

Searches the pool for a client whose channel matches the given ID. + * + * @param channelId the unique identifier of the WebSocket channel + * @return an Optional containing the client, or empty if not found + */ + @Override + public Optional getClient(String channelId) { + return this.clients.stream() + .filter(c -> c.getChannel().id().asLongText().equals(channelId)) + .findAny(); + } + + /** + * Checks if a client exists for the specified channel ID. + * + * @param channelId the unique identifier of the WebSocket channel + * @return true if a client exists, false otherwise + */ + @Override + public boolean exists(String channelId) { + return this.getClient(channelId).isPresent(); + } + + /** + * Creates and registers a new client for the specified channel and event sender. + * + *

If a client for the channel already exists, returns the existing client. Otherwise, creates + * a new client, registers it, and returns it. + * + * @param channel the Netty WebSocket channel for communication + * @param sender the event sender responsible for dispatching events + * @return the newly created or existing client instance + * @throws IllegalArgumentException if channel or sender is null + */ + @Override + public TIC2WebSocketClient createClient(Channel channel, EventSender sender) { + this.checkArguments(channel, sender); + + String channelId = channel.id().asLongText(); + Optional client = this.getClient(channelId); + if (!client.isPresent()) { + TIC2WebSocketClient newClient = new TIC2WebSocketClient(channel, sender); + this.clients.add(newClient); + return newClient; + } else { + return client.get(); + } + } + + /** + * Removes the client associated with the specified channel ID. + * + *

Unregisters and cleans up the client for the given channel ID, if present. + * + * @param channelId the unique identifier of the WebSocket channel + */ + @Override + public void remove(String channelId) { + Optional client = this.getClient(channelId); + if (client.isPresent()) { + this.clients.remove(client.get()); + } + } + + /** + * Validates arguments for client creation. + * + *

Throws an exception if either argument is null. + * + * @param channel the Netty WebSocket channel + * @param sender the event sender + * @throws IllegalArgumentException if channel or sender is null + */ + private void checkArguments(Channel channel, EventSender sender) { + if (channel == null || sender == null) { + throw new IllegalArgumentException( + "Cannot create client with a null Channel or null EventSender"); + } + } +} diff --git a/src/main/java/tic/service/config/TIC2WebSocketConfiguration.java b/src/main/java/tic/service/config/TIC2WebSocketConfiguration.java new file mode 100644 index 0000000..f05f262 --- /dev/null +++ b/src/main/java/tic/service/config/TIC2WebSocketConfiguration.java @@ -0,0 +1,141 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.service.config; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import tic.frame.TICMode; + +/** + * Configuration class for TIC2WebSocket service. + * + *

This class manages configuration parameters for the TIC2WebSocket server, including server + * port, TIC mode, and the list of TIC port names. It provides validation and conversion logic for + * each parameter, ensuring correct types and values. + * + *

Key features include: + * + *

    + *
  • Validation of server port range and TIC port names + *
  • Support for multiple construction methods (map, DataDictionary, explicit values) + *
  • Integration with the configuration base and key descriptor system + *
+ * + * @author Enedis Smarties team + * @see ConfigurationBase + * @see TICMode + */ +public class TIC2WebSocketConfiguration { + + public static final String KEY_SERVER_PORT = "serverPort"; + public static final String KEY_TIC_MODE = "ticMode"; + public static final String KEY_TIC_PORT_NAMES = "ticPortNames"; + + public static final int SERVER_PORT_MIN = 1; + public static final int SERVER_PORT_MAX = 65535; + + public static final TICMode DEFAULT_TIC_MODE = TICMode.AUTO; + + private int serverPort; + private TICMode ticMode; + private List ticPortNames; + + /** + * Constructs a configuration with a mandatory server port. + * + * @param serverPort the server port number + */ + public TIC2WebSocketConfiguration(int serverPort) { + this(serverPort, null, null); + } + + /** + * Constructs a configuration with a mandatory server port, and optional TIC mode and port names. + * + * @param serverPort the server port number + * @param ticMode the TIC mode (optional, defaults to {@link #DEFAULT_TIC_MODE} when null) + * @param ticPortNames list of TIC native port names (optional, null/empty means not set) + */ + public TIC2WebSocketConfiguration(int serverPort, TICMode ticMode, List ticPortNames) { + this.setServerPort(serverPort); + this.setTicMode(ticMode); + this.setTicPortNames(ticPortNames); + } + + public int getServerPort() { + return this.serverPort; + } + + public TICMode getTicMode() { + return this.ticMode; + } + + /** + * Returns the list of configured TIC port names. + * + * @return an unmodifiable list, or null if not set + */ + public List getTicPortNames() { + return this.ticPortNames; + } + + private void setServerPort(int serverPort) { + checkServerPort(serverPort); + this.serverPort = serverPort; + } + + private void setTicMode(TICMode ticMode) { + this.ticMode = (ticMode == null) ? DEFAULT_TIC_MODE : ticMode; + } + + private void setTicPortNames(List ticPortNames) { + this.ticPortNames = normalizeAndCheckPortNames(ticPortNames); + } + + private static void checkServerPort(int serverPort) { + if (serverPort < SERVER_PORT_MIN || serverPort > SERVER_PORT_MAX) { + throw new IllegalArgumentException( + "Server port must be between " + SERVER_PORT_MIN + " and " + SERVER_PORT_MAX); + } + } + + private static List normalizeAndCheckPortNames(List ticPortNames) { + if (ticPortNames == null || ticPortNames.isEmpty()) { + return null; + } + + List normalized = new ArrayList<>(ticPortNames.size()); + Set seen = new HashSet<>(); + + for (int i = 0; i < ticPortNames.size(); i++) { + String portName = ticPortNames.get(i); + if (portName == null) { + throw new IllegalArgumentException( + "Key " + KEY_TIC_PORT_NAMES + ": value at index " + i + " cannot be null"); + } + + String trimmed = portName.trim(); + if (trimmed.isEmpty()) { + throw new IllegalArgumentException( + "Key " + KEY_TIC_PORT_NAMES + ": value at index " + i + " cannot be empty"); + } + + if (!seen.add(trimmed)) { + throw new IllegalArgumentException( + "Key " + KEY_TIC_PORT_NAMES + ": duplicate value '" + trimmed + "'"); + } + + normalized.add(trimmed); + } + + return Collections.unmodifiableList(normalized); + } +} diff --git a/src/main/java/tic/service/config/TIC2WebSocketConfigurationCodec.java b/src/main/java/tic/service/config/TIC2WebSocketConfigurationCodec.java new file mode 100644 index 0000000..934c2e8 --- /dev/null +++ b/src/main/java/tic/service/config/TIC2WebSocketConfigurationCodec.java @@ -0,0 +1,123 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.service.config; + +import java.util.ArrayList; +import java.util.List; +import org.json.JSONArray; +import org.json.JSONObject; +import org.json.JSONTokener; +import tic.frame.TICMode; +import tic.util.codec.JsonObjectCodec; +import tic.util.codec.JsonStringCodec; + +public class TIC2WebSocketConfigurationCodec + implements JsonStringCodec, + JsonObjectCodec { + + private static TIC2WebSocketConfigurationCodec instance = null; + + public static TIC2WebSocketConfigurationCodec getInstance() { + if (instance == null) { + instance = new TIC2WebSocketConfigurationCodec(); + } + return instance; + } + + private TIC2WebSocketConfigurationCodec() {} + + @Override + public String encodeToJsonString(TIC2WebSocketConfiguration object, int indentFactor) + throws Exception { + throw new UnsupportedOperationException("Unimplemented method 'encodeToJsonString'"); + } + + @Override + public TIC2WebSocketConfiguration decodeFromJsonString(String jsonString, int indentFactor) + throws Exception { + JSONObject rootObject = new JSONObject(new JSONTokener(jsonString)); + return decodeFromJsonObject(rootObject); + } + + @Override + public Object encodeToJsonObject(TIC2WebSocketConfiguration object) throws Exception { + throw new UnsupportedOperationException("Unimplemented method 'encodeToJsonObject'"); + } + + @Override + public TIC2WebSocketConfiguration decodeFromJsonObject(Object jsonObject) throws Exception { + + JSONObject root = (JSONObject) jsonObject; + + int serverPort = parseServerPort(root); + TICMode ticMode = parseTicMode(root); + List ticPortNames = parseTicPortNames(root); + + return new TIC2WebSocketConfiguration(serverPort, ticMode, ticPortNames); + } + + private int parseServerPort(JSONObject root) { + if (!root.has(TIC2WebSocketConfiguration.KEY_SERVER_PORT)) { + throw new IllegalArgumentException( + "Key '" + TIC2WebSocketConfiguration.KEY_SERVER_PORT + "' is required"); + } + + int serverPort = root.getInt(TIC2WebSocketConfiguration.KEY_SERVER_PORT); + if (serverPort < TIC2WebSocketConfiguration.SERVER_PORT_MIN + || serverPort > TIC2WebSocketConfiguration.SERVER_PORT_MAX) { + throw new IllegalArgumentException( + "Key '" + + TIC2WebSocketConfiguration.KEY_SERVER_PORT + + "' must be between " + + TIC2WebSocketConfiguration.SERVER_PORT_MIN + + " and " + + TIC2WebSocketConfiguration.SERVER_PORT_MAX); + } + + return serverPort; + } + + private static TICMode parseTicMode(JSONObject root) { + String modeValue = + root.optString( + TIC2WebSocketConfiguration.KEY_TIC_MODE, + TIC2WebSocketConfiguration.DEFAULT_TIC_MODE.name()); + return TICMode.valueOf(modeValue.toUpperCase()); + } + + private static List parseTicPortNames(JSONObject root) { + JSONArray array = root.optJSONArray(TIC2WebSocketConfiguration.KEY_TIC_PORT_NAMES); + if (array == null || array.length() == 0) { + return null; + } + + List ticPortNames = new ArrayList<>(array.length()); + for (int i = 0; i < array.length(); i++) { + String portName = array.getString(i); + if (portName == null) { + throw new IllegalArgumentException( + "Key '" + + TIC2WebSocketConfiguration.KEY_TIC_PORT_NAMES + + "': value at index " + + i + + " cannot be null"); + } + if (portName.isEmpty()) { + throw new IllegalArgumentException( + "Key '" + + TIC2WebSocketConfiguration.KEY_TIC_PORT_NAMES + + "': value at index " + + i + + " cannot be empty"); + } + ticPortNames.add(portName); + } + + return ticPortNames; + } +} diff --git a/src/main/java/tic/service/config/TIC2WebSocketConfigurationLoader.java b/src/main/java/tic/service/config/TIC2WebSocketConfigurationLoader.java new file mode 100644 index 0000000..51f29c6 --- /dev/null +++ b/src/main/java/tic/service/config/TIC2WebSocketConfigurationLoader.java @@ -0,0 +1,39 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.service.config; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +public final class TIC2WebSocketConfigurationLoader { + + private TIC2WebSocketConfigurationLoader() {} + + /** + * Load TIC2WebSocket application configuration from a JSON file. + * + * @param filepath the path to the configuration file + * @return the loaded configuration + * @throws IllegalStateException if there is an error loading or parsing the configuration + */ + public static TIC2WebSocketConfiguration load(String filepath) { + try { + String json = readFileAsString(filepath); + return TIC2WebSocketConfigurationCodec.getInstance().decodeFromJsonString(json); + } catch (Exception exception) { + throw new IllegalStateException("Unable to load TIC2WebSocket configuration", exception); + } + } + + private static String readFileAsString(String filepath) throws IOException { + Path path = Paths.get(filepath); + return new String(Files.readAllBytes(path)); + } +} diff --git a/src/main/java/tic/service/endpoint/EventSender.java b/src/main/java/tic/service/endpoint/EventSender.java new file mode 100644 index 0000000..3a8d079 --- /dev/null +++ b/src/main/java/tic/service/endpoint/EventSender.java @@ -0,0 +1,42 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.service.endpoint; + +import tic.util.message.Event; +import io.netty.channel.Channel; + +/** + * Interface for sending event messages to a WebSocket channel. + * + *

This interface defines the contract for dispatching {@link Event} objects to a specified Netty + * {@link Channel}. Implementations are responsible for serializing and transmitting event data over + * the channel. + * + *

Key features include: + * + *

    + *
  • Abstracts event delivery to WebSocket clients + *
  • Supports custom event serialization and transmission strategies + *
+ * + * @author Enedis Smarties team + * @see Event + * @see Channel + */ +public interface EventSender { + /** + * Sends an event message to the specified WebSocket channel. + * + *

Implementations should serialize the event and transmit it to the client associated with the + * given channel. + * + * @param channel the Netty WebSocket channel to send the event to + * @param event the event message to be sent + */ + void sendEvent(Channel channel, Event event); +} diff --git a/src/main/java/tic/service/endpoint/TIC2WebSocketEndPointErrorCode.java b/src/main/java/tic/service/endpoint/TIC2WebSocketEndPointErrorCode.java new file mode 100644 index 0000000..4fc9abe --- /dev/null +++ b/src/main/java/tic/service/endpoint/TIC2WebSocketEndPointErrorCode.java @@ -0,0 +1,73 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.service.endpoint; + +/** + * Error codes for TIC2WebSocket endpoint operations. + * + *

This enumeration defines error codes used to represent the result of endpoint operations, + * including message validation, subscription management, and internal errors. Each code is + * associated with a unique integer value for protocol communication. + * + *

Key features include: + * + *

    + *
  • Success and error codes for message handling + *
  • Subscription and unsubscription error codes + *
  • Timeout and identifier errors + *
+ * + * @author Enedis Smarties team + */ +public enum TIC2WebSocketEndPointErrorCode { + /** Operation completed successfully. */ + NO_ERROR(0), + /** Message format is invalid. */ + INVALID_MESSAGE_FORMAT(-1), + /** Message type is missing. */ + MESSAGE_TYPE_MISSING(-2), + /** Message name is missing. */ + MESSAGE_NAME_MISSING(-3), + /** Message type is invalid. */ + MESSAGE_TYPE_INVALID(-4), + /** Message is not supported. */ + UNSUPPORTED_MESSAGE(-5), + /** Message content is invalid. */ + INVALID_MESSAGE_CONTENT(-6), + /** Internal server error occurred. */ + INTERNAL_ERROR(-7), + /** Subscription request failed. */ + SUBSCRIPTION_FAIL(-10), + /** Unsubscription request failed. */ + UNSUBSCRIPTION_FAIL(-11), + /** TIC identifier not found. */ + IDENTIFIER_NOT_FOUND(-12), + /** TIC read operation timed out. */ + READ_TIMEOUT(-13); + + /** Integer value associated with the error code. */ + private final int value; + + /** + * Constructs an error code with the specified integer value. + * + * @param value the integer value for the error code + */ + TIC2WebSocketEndPointErrorCode(int value) { + this.value = value; + } + + /** + * Returns the integer value associated with this error code. + * + * @return the error code value + */ + public int value() { + return this.value; + } +} diff --git a/src/main/java/tic/service/endpoint/TIC2WebSocketEndPointException.java b/src/main/java/tic/service/endpoint/TIC2WebSocketEndPointException.java new file mode 100644 index 0000000..3867512 --- /dev/null +++ b/src/main/java/tic/service/endpoint/TIC2WebSocketEndPointException.java @@ -0,0 +1,88 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.service.endpoint; + +/** + * Exception class for TIC2WebSocket endpoint errors. + * + *

This exception encapsulates an error code from {@link TIC2WebSocketEndPointErrorCode}, + * providing detailed context for endpoint operation failures. It supports multiple constructors for + * message and cause chaining. + * + *

Key features include: + * + *

    + *
  • Associates an error code with each exception + *
  • Supports message and cause chaining for diagnostics + *
+ * + * @author Enedis Smarties team + * @see TIC2WebSocketEndPointErrorCode + */ +public class TIC2WebSocketEndPointException extends Exception { + + /** Serial version UID for serialization. */ + private static final long serialVersionUID = -2263755971102386572L; + + /** Error code associated with this exception. */ + private final TIC2WebSocketEndPointErrorCode code; + + /** + * Constructs an exception with the specified error code. + * + * @param code the error code + */ + public TIC2WebSocketEndPointException(TIC2WebSocketEndPointErrorCode code) { + super(); + this.code = code; + } + + /** + * Constructs an exception with the specified error code, message, and cause. + * + * @param code the error code + * @param message the detail message + * @param cause the cause of the exception + */ + public TIC2WebSocketEndPointException( + TIC2WebSocketEndPointErrorCode code, String message, Throwable cause) { + super(message, cause); + this.code = code; + } + + /** + * Constructs an exception with the specified error code and message. + * + * @param code the error code + * @param message the detail message + */ + public TIC2WebSocketEndPointException(TIC2WebSocketEndPointErrorCode code, String message) { + super(message); + this.code = code; + } + + /** + * Constructs an exception with the specified error code and cause. + * + * @param code the error code + * @param cause the cause of the exception + */ + public TIC2WebSocketEndPointException(TIC2WebSocketEndPointErrorCode code, Throwable cause) { + super(cause); + this.code = code; + } + + /** + * Returns the error code associated with this exception. + * + * @return the endpoint error code + */ + public TIC2WebSocketEndPointErrorCode getCode() { + return this.code; + } +} diff --git a/src/main/java/tic/service/message/EventOnError.java b/src/main/java/tic/service/message/EventOnError.java new file mode 100644 index 0000000..ed51c1f --- /dev/null +++ b/src/main/java/tic/service/message/EventOnError.java @@ -0,0 +1,68 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.service.message; + +import java.time.LocalDateTime; +import tic.core.TICCoreError; +import tic.util.message.Event; + +/** + * Event message representing an error in the TIC2WebSocket protocol. + * + *

This class encapsulates error information using a {@link TICCoreError} object and provides + * constructors for various initialization scenarios. It integrates with the event messaging system + * for error notification and handling. + * + *

Key features include: + * + *

    + *
  • Encapsulates error data for protocol events + *
  • Supports construction from map, DataDictionary, or explicit values + *
  • Validates and manages error data using key descriptors + *
+ * + * @author Enedis Smarties team + * @see Event + * @see TICCoreError + */ +public class EventOnError extends Event { + /** Message name for error events. */ + public static final String NAME = "OnError"; + + private TICCoreError data; + + /** + * Constructs an error event with explicit date/time and error data. + * + * @param dateTime the event timestamp + * @param data the error data + */ + public EventOnError(LocalDateTime dateTime, TICCoreError data) { + super(NAME, dateTime); + this.setData(data); + } + + /** + * Returns the error data associated with this event. + * + * @return the error data + */ + public TICCoreError getData() { + return this.data; + } + + /** + * Sets the error data for this event. + * + * @param data the error data + * @throws DataDictionaryException if validation fails + */ + public void setData(TICCoreError data) { + this.data = data; + } +} diff --git a/src/main/java/tic/service/message/EventOnTICData.java b/src/main/java/tic/service/message/EventOnTICData.java new file mode 100644 index 0000000..dc41f53 --- /dev/null +++ b/src/main/java/tic/service/message/EventOnTICData.java @@ -0,0 +1,68 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.service.message; + +import java.time.LocalDateTime; +import tic.core.TICCoreFrame; +import tic.util.message.Event; + +/** + * Event message representing TIC data in the TIC2WebSocket protocol. + * + *

This class encapsulates TIC data using a {@link TICCoreFrame} object and provides constructors + * for various initialization scenarios. It integrates with the event messaging system for data + * notification and handling. + * + *

Key features include: + * + *

    + *
  • Encapsulates TIC data for protocol events + *
  • Supports construction from map, DataDictionary, or explicit values + *
  • Validates and manages TIC data using key descriptors + *
+ * + * @author Enedis Smarties team + * @see Event + * @see TICCoreFrame + */ +public class EventOnTICData extends Event { + /** Message name for TIC data events. */ + public static final String NAME = "OnTICData"; + + private TICCoreFrame data; + + /** + * Constructs a TIC data event with explicit date/time and TIC data. + * + * @param dateTime the event timestamp + * @param data the TIC data + */ + public EventOnTICData(LocalDateTime dateTime, TICCoreFrame data) { + super(NAME, dateTime); + this.setData(data); + } + + /** + * Returns the TIC data associated with this event. + * + * @return the TIC data + */ + public TICCoreFrame getData() { + return this.data; + } + + /** + * Sets the TIC data for this event. + * + * @param data the TIC data + * @throws DataDictionaryException if validation fails + */ + public void setData(TICCoreFrame data) { + this.data = data; + } +} diff --git a/src/main/java/tic/service/message/RequestGetAvailableTICs.java b/src/main/java/tic/service/message/RequestGetAvailableTICs.java new file mode 100644 index 0000000..ab04e90 --- /dev/null +++ b/src/main/java/tic/service/message/RequestGetAvailableTICs.java @@ -0,0 +1,37 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.service.message; + +import tic.util.message.Request; + +/** + * Request message for retrieving available TICs. + * + *

This class represents a request to obtain the list of available TICs. It provides constructors + * for various initialization scenarios and integrates with the request messaging system. + * + *

Key features include: + * + *

    + *
  • Encapsulates request for available TICs + *
  • Supports construction from map, DataDictionary, or default values + *
  • Validates and manages request parameters + *
+ * + * @author Enedis Smarties team + * @see Request + */ +public class RequestGetAvailableTICs extends Request { + /** Message name for this request. */ + public static final String NAME = "GetAvailableTICs"; + + /** Constructs a request for available TICs with default values. */ + public RequestGetAvailableTICs() { + super(NAME); + } +} diff --git a/src/main/java/tic/service/message/RequestGetModemsInfo.java b/src/main/java/tic/service/message/RequestGetModemsInfo.java new file mode 100644 index 0000000..252d318 --- /dev/null +++ b/src/main/java/tic/service/message/RequestGetModemsInfo.java @@ -0,0 +1,37 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.service.message; + +import tic.util.message.Request; + +/** + * Request message for retrieving modem information. + * + *

This class represents a request to obtain information about available modems. It provides + * constructors for various initialization scenarios and integrates with the request messaging + * system. + * + *

Key features include: + * + *

    + *
  • Encapsulates request for modem information + *
  • Validates and manages request parameters + *
+ * + * @author Enedis Smarties team + * @see Request + */ +public class RequestGetModemsInfo extends Request { + /** Message name for this request. */ + public static final String NAME = "GetModemsInfo"; + + /** Constructs a request for modem information with default values. */ + public RequestGetModemsInfo() { + super(NAME); + } +} diff --git a/src/main/java/tic/service/message/RequestReadTIC.java b/src/main/java/tic/service/message/RequestReadTIC.java new file mode 100644 index 0000000..07ea78e --- /dev/null +++ b/src/main/java/tic/service/message/RequestReadTIC.java @@ -0,0 +1,65 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.service.message; + +import tic.core.TICIdentifier; +import tic.util.message.Request; + +/** + * Request message for reading TIC data in the TIC2WebSocket protocol. + * + *

This class represents a request to read TIC data for a specific identifier. It provides + * constructors for various initialization scenarios and integrates with the request messaging + * system. + * + *

Key features include: + * + *

    + *
  • Encapsulates request for reading TIC data + *
  • Supports construction from map, DataDictionary, or explicit identifier + *
  • Validates and manages request parameters using key descriptors + *
+ * + * @author Enedis Smarties team + * @see Request + * @see TICIdentifier + */ +public class RequestReadTIC extends Request { + /** Message name for this request. */ + public static final String NAME = "ReadTIC"; + + private TICIdentifier data; + + /** + * Constructs a request for reading TIC data with a specific identifier. + * + * @param data the TIC identifier + */ + public RequestReadTIC(TICIdentifier data) { + super(NAME); + this.setData(data); + } + + /** + * Returns the TIC identifier data associated with this request. + * + * @return the TIC identifier + */ + public TICIdentifier getData() { + return this.data; + } + + /** + * Sets the TIC identifier data for this request. + * + * @param data the TIC identifier + */ + public void setData(TICIdentifier data) { + this.data = data; + } +} diff --git a/src/main/java/tic/service/message/RequestSubscribeTIC.java b/src/main/java/tic/service/message/RequestSubscribeTIC.java new file mode 100644 index 0000000..fe14db9 --- /dev/null +++ b/src/main/java/tic/service/message/RequestSubscribeTIC.java @@ -0,0 +1,66 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.service.message; + +import tic.util.message.Request; +import tic.core.TICIdentifier; +import java.util.List; + +/** + * Request message for subscribing to TIC data. + * + *

This class represents a request to subscribe to TIC data for one or more identifiers. It + * provides constructors for various initialization scenarios and integrates with the request + * messaging system. + * + *

Key features include: + * + *

    + *
  • Encapsulates request for TIC data subscription + *
  • Supports construction from map, DataDictionary, or explicit identifier list + *
  • Validates and manages request parameters using key descriptors + *
+ * + * @author Enedis Smarties team + * @see Request + * @see TICIdentifier + */ +public class RequestSubscribeTIC extends Request { + /** Message name for this request. */ + public static final String NAME = "SubscribeTIC"; + + private List data; + + /** + * Constructs a request for subscribing to TIC data with a specific list of identifiers. + * + * @param data the list of TIC identifiers + */ + public RequestSubscribeTIC(List data) { + super(NAME); + this.setData(data); + } + + /** + * Returns the list of TIC identifier data associated with this request. + * + * @return the list of TIC identifiers + */ + public List getData() { + return this.data; + } + + /** + * Sets the list of TIC identifier data for this request. + * + * @param data the list of TIC identifiers + */ + public void setData(List data) { + this.data = data; + } +} diff --git a/src/main/java/tic/service/message/RequestUnsubscribeTIC.java b/src/main/java/tic/service/message/RequestUnsubscribeTIC.java new file mode 100644 index 0000000..947f54e --- /dev/null +++ b/src/main/java/tic/service/message/RequestUnsubscribeTIC.java @@ -0,0 +1,66 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.service.message; + +import tic.util.message.Request; +import tic.core.TICIdentifier; +import java.util.List; + +/** + * Request message for unsubscribing from TIC data in the TIC2WebSocket protocol. + * + *

This class represents a request to unsubscribe from TIC data for one or more identifiers. It + * provides constructors for various initialization scenarios and integrates with the request + * messaging system. + * + *

Key features include: + * + *

    + *
  • Encapsulates request for TIC data unsubscription + *
  • Supports construction from map, DataDictionary, or explicit identifier list + *
  • Validates and manages request parameters using key descriptors + *
+ * + * @author Enedis Smarties team + * @see Request + * @see TICIdentifier + */ +public class RequestUnsubscribeTIC extends Request { + /** Message name for this request. */ + public static final String NAME = "UnsubscribeTIC"; + + private List data; + + /** + * Constructs a request for unsubscribing from TIC data with a specific list of identifiers. + * + * @param data the list of TIC identifiers + */ + public RequestUnsubscribeTIC(List data) { + super(NAME); + this.setData(data); + } + + /** + * Returns the list of TIC identifier data associated with this request. + * + * @return the list of TIC identifiers + */ + public List getData() { + return this.data; + } + + /** + * Sets the list of TIC identifier data for this request. + * + * @param data the list of TIC identifiers + */ + public void setData(List data) { + this.data = data; + } +} diff --git a/src/main/java/tic/service/message/ResponseError.java b/src/main/java/tic/service/message/ResponseError.java new file mode 100644 index 0000000..33a03b6 --- /dev/null +++ b/src/main/java/tic/service/message/ResponseError.java @@ -0,0 +1,26 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.service.message; + +import tic.util.message.Response; +import java.time.LocalDateTime; + +public class ResponseError extends Response { + /** + * Constructs a generic response with explicit parameters. + * + * @param name the message name + * @param dateTime the response date and time + * @param errorCode the error code, if any + * @param errorMessage the error message, if any + */ + public ResponseError(String name, + LocalDateTime dateTime, Number errorCode, String errorMessage) { + super(name, dateTime, errorCode, errorMessage); + } +} diff --git a/src/main/java/tic/service/message/ResponseGetAvailableTICs.java b/src/main/java/tic/service/message/ResponseGetAvailableTICs.java new file mode 100644 index 0000000..22e92f1 --- /dev/null +++ b/src/main/java/tic/service/message/ResponseGetAvailableTICs.java @@ -0,0 +1,74 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.service.message; + +import java.time.LocalDateTime; +import java.util.List; +import tic.core.TICIdentifier; +import tic.util.message.Response; +import tic.util.message.ResponseWithData; + +/** + * Response message for available TIC identifiers. + * + *

This class represents a response containing the list of available TIC identifiers. It provides + * constructors for various initialization scenarios and integrates with the response messaging + * system. + * + *

Key features include: + * + *

    + *
  • Encapsulates response for available TIC identifiers + *
  • Supports construction from map, DataDictionary, or explicit parameter list + *
  • Validates and manages response parameters using key descriptors + *
+ * + * @author Enedis Smarties team + * @see Response + * @see TICIdentifier + */ +public class ResponseGetAvailableTICs extends ResponseWithData> { + /** Message name for this response. */ + public static final String NAME = "GetAvailableTICs"; + + private List ticIdentifiers; + + /** + * Constructs a response for available TIC identifiers with explicit parameters. + * + * @param dateTime the response date and time + * @param errorCode the error code, if any + * @param errorMessage the error message, if any + * @param data the list of available TIC identifiers + */ + public ResponseGetAvailableTICs( + LocalDateTime dateTime, Number errorCode, String errorMessage, List data) { + super(NAME, dateTime, errorCode, errorMessage, data); + this.ticIdentifiers = data; + } + + /** + * Returns the list of available TIC identifier data associated with this response. + * + * @return the list of TIC identifiers + */ + @Override + public List getData() { + return this.ticIdentifiers; + } + + /** + * Sets the list of available TIC identifier data for this response. + * + * @param data the list of TIC identifiers + */ + @Override + public void setData(List data) { + this.ticIdentifiers = data; + } +} diff --git a/src/main/java/tic/service/message/ResponseGetModemsInfo.java b/src/main/java/tic/service/message/ResponseGetModemsInfo.java new file mode 100644 index 0000000..e29de54 --- /dev/null +++ b/src/main/java/tic/service/message/ResponseGetModemsInfo.java @@ -0,0 +1,73 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.service.message; + +import java.time.LocalDateTime; +import java.util.List; +import tic.io.modem.ModemDescriptor; +import tic.util.message.ResponseWithData; + +/** + * Response message for modem information. + * + *

This class represents a response containing the list of modem port descriptors. It provides + * constructors for various initialization scenarios and integrates with the response messaging + * system. + * + *

Key features include: + * + *

    + *
  • Encapsulates response for modem information + *
  • Supports construction from map, DataDictionary, or explicit parameter list + *
  • Validates and manages response parameters using key descriptors + *
+ * + * @author Enedis Smarties team + * @see Response + * @see ModemDescriptor + */ +public class ResponseGetModemsInfo extends ResponseWithData> { + /** Message name for this response. */ + public static final String NAME = "GetModemsInfo"; + + private List modemDescriptors; + + /** + * Constructs a response for modem information with explicit parameters. + * + * @param dateTime the response date and time + * @param errorCode the error code, if any + * @param errorMessage the error message, if any + * @param data the list of modem port descriptors + */ + public ResponseGetModemsInfo( + LocalDateTime dateTime, Number errorCode, String errorMessage, List data) { + super(NAME, dateTime, errorCode, errorMessage, data); + this.modemDescriptors = data; + } + + /** + * Returns the list of modem port descriptor data associated with this response. + * + * @return the list of modem descriptors + */ + @Override + public List getData() { + return this.modemDescriptors; + } + + /** + * Sets the list of modem port descriptor data for this response. + * + * @param data the list of modem descriptors + */ + @Override + public void setData(List data) { + this.modemDescriptors = data; + } +} \ No newline at end of file diff --git a/src/main/java/tic/service/message/ResponseReadTIC.java b/src/main/java/tic/service/message/ResponseReadTIC.java new file mode 100644 index 0000000..b189682 --- /dev/null +++ b/src/main/java/tic/service/message/ResponseReadTIC.java @@ -0,0 +1,61 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.service.message; + +import tic.util.message.Response; +import tic.util.message.ResponseWithData; +import tic.core.TICCoreFrame; +import java.time.LocalDateTime; + +/** + * Response message for TIC frame data. + * + *

This class represents a response containing a TIC frame. It provides constructors for various + * initialization scenarios and integrates with the response messaging system. + * + *

Key features include: + * + *

    + *
  • Encapsulates response for TIC frame data + *
  • Supports construction from map, DataDictionary, or explicit parameter list + *
  • Validates and manages response parameters using key descriptors + *
+ * + * @author Enedis Smarties team + * @see Response + * @see TICCoreFrame + */ +public class ResponseReadTIC extends ResponseWithData { + /** Message name for this response. */ + public static final String NAME = "ReadTIC"; + private TICCoreFrame ticCoreFrame; + + /** + * Constructs a response for TIC frame data with explicit parameters. + * + * @param dateTime the response date and time + * @param errorCode the error code, if any + * @param errorMessage the error message, if any + * @param data the TIC frame data + */ + public ResponseReadTIC( + LocalDateTime dateTime, Number errorCode, String errorMessage, TICCoreFrame data) { + super(NAME, dateTime, errorCode, errorMessage, data); + this.ticCoreFrame = data; +} + + @Override + public TICCoreFrame getData() { + return this.ticCoreFrame; + } + + @Override + public void setData(TICCoreFrame data) { + this.ticCoreFrame = data; + } +} \ No newline at end of file diff --git a/src/main/java/tic/service/message/ResponseSubscribeTIC.java b/src/main/java/tic/service/message/ResponseSubscribeTIC.java new file mode 100644 index 0000000..5d5342d --- /dev/null +++ b/src/main/java/tic/service/message/ResponseSubscribeTIC.java @@ -0,0 +1,44 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.service.message; + +import tic.util.message.Response; +import java.time.LocalDateTime; + +/** + * Response message for TIC subscription. + * + *

This class represents a response to a TIC subscription request. It provides constructors for + * various initialization scenarios and integrates with the response messaging system. + * + *

Key features include: + * + *

    + *
  • Encapsulates response for TIC subscription + *
  • Supports construction from map, DataDictionary, or explicit parameter list + *
  • Validates and manages response parameters using key descriptors + *
+ * + * @author Enedis Smarties team + * @see Response + */ +public class ResponseSubscribeTIC extends Response { + /** Message name for this response. */ + public static final String NAME = "SubscribeTIC"; + + /** + * Constructs a response for TIC subscription with explicit parameters. + * + * @param dateTime the response date and time + * @param errorCode the error code, if any + * @param errorMessage the error message, if any + */ + public ResponseSubscribeTIC(LocalDateTime dateTime, Number errorCode, String errorMessage) { + super(NAME, dateTime, errorCode, errorMessage); + } +} diff --git a/src/main/java/tic/service/message/ResponseUnsubscribeTIC.java b/src/main/java/tic/service/message/ResponseUnsubscribeTIC.java new file mode 100644 index 0000000..a34eedf --- /dev/null +++ b/src/main/java/tic/service/message/ResponseUnsubscribeTIC.java @@ -0,0 +1,44 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.service.message; + +import tic.util.message.Response; +import java.time.LocalDateTime; + +/** + * Response message for TIC unsubscription. + * + *

This class represents a response to a TIC unsubscription request. It provides constructors for + * various initialization scenarios and integrates with the response messaging system. + * + *

Key features include: + * + *

    + *
  • Encapsulates response for TIC unsubscription + *
  • Supports construction from map, DataDictionary, or explicit parameter list + *
  • Validates and manages response parameters using key descriptors + *
+ * + * @author Enedis Smarties team + * @see Response + */ +public class ResponseUnsubscribeTIC extends Response { + /** Message name for this response. */ + public static final String NAME = "UnsubscribeTIC"; + + /** + * Constructs a response for TIC unsubscription with explicit parameters. + * + * @param dateTime the response date and time + * @param errorCode the error code, if any + * @param errorMessage the error message, if any + */ + public ResponseUnsubscribeTIC(LocalDateTime dateTime, Number errorCode, String errorMessage) { + super(NAME, dateTime, errorCode, errorMessage); + } +} diff --git a/src/main/java/tic/service/netty/TIC2WebSocketChannelInitializer.java b/src/main/java/tic/service/netty/TIC2WebSocketChannelInitializer.java new file mode 100644 index 0000000..d86d6fe --- /dev/null +++ b/src/main/java/tic/service/netty/TIC2WebSocketChannelInitializer.java @@ -0,0 +1,84 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.service.netty; + +import tic.service.client.TIC2WebSocketClientPool; +import tic.service.requesthandler.TIC2WebSocketRequestHandler; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.ChannelPipeline; +import io.netty.channel.socket.SocketChannel; +import io.netty.handler.codec.http.HttpObjectAggregator; +import io.netty.handler.codec.http.HttpServerCodec; +import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler; +import io.netty.handler.codec.http.websocketx.extensions.compression.WebSocketServerCompressionHandler; +import io.netty.handler.stream.ChunkedWriteHandler; + +/** + * Netty channel initializer for configuring the WebSocket server pipeline. + * + *

This class sets up the Netty channel pipeline for incoming socket connections, adding HTTP and WebSocket + * handlers, compression, chunked writing, and custom request handling. It is responsible for preparing each + * channel to handle WebSocket communication and routing requests to the appropriate handler. + * + *

Main responsibilities: + *

    + *
  • Configure HTTP and WebSocket protocol handlers
  • + *
  • Enable compression and chunked writing for large messages
  • + *
  • Route requests to the custom request handler
  • + *
  • Manage client pool for active connections
  • + *
+ * + *

Typical usage: + *

    + *
  • Instantiate with a client pool and request handler
  • + *
  • Attach to a Netty server bootstrap for WebSocket support
  • + *
+ * + * @author Enedis Smarties team + */ +public class TIC2WebSocketChannelInitializer extends ChannelInitializer { + private static final String WEBSOCKET_PATH = "/"; + + private final TIC2WebSocketClientPool clientPool; + private final TIC2WebSocketRequestHandler requestHandler; + + /** + * Constructor + * + * @param clientPool the client pool + * @param requestHandler the request handler + */ + public TIC2WebSocketChannelInitializer( + TIC2WebSocketClientPool clientPool, TIC2WebSocketRequestHandler requestHandler) { + this.clientPool = clientPool; + this.requestHandler = requestHandler; + } + + @Override + protected void initChannel(SocketChannel ch) throws Exception { + ChannelPipeline pipeline = ch.pipeline(); + + // HTTP codec + pipeline.addLast(new HttpServerCodec()); + + // HTTP object aggregator + pipeline.addLast(new HttpObjectAggregator(65536)); + + // Chunked write handler for large messages + pipeline.addLast(new ChunkedWriteHandler()); + + // WebSocket compression + pipeline.addLast(new WebSocketServerCompressionHandler()); + + // WebSocket protocol handler + pipeline.addLast(new WebSocketServerProtocolHandler(WEBSOCKET_PATH, null, true)); + + // Custom TIC2WebSocket handler + pipeline.addLast(new TIC2WebSocketHandler(clientPool, requestHandler)); + } +} diff --git a/src/main/java/tic/service/netty/TIC2WebSocketHandler.java b/src/main/java/tic/service/netty/TIC2WebSocketHandler.java new file mode 100644 index 0000000..0584b4a --- /dev/null +++ b/src/main/java/tic/service/netty/TIC2WebSocketHandler.java @@ -0,0 +1,344 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.service.netty; + +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.SimpleChannelInboundHandler; +import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; +import io.netty.handler.codec.http.websocketx.WebSocketFrame; +import java.time.LocalDateTime; +import java.util.List; +import java.util.Optional; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import tic.core.TICIdentifier; +import tic.service.client.TIC2WebSocketClient; +import tic.service.client.TIC2WebSocketClientPool; +import tic.service.endpoint.EventSender; +import tic.service.endpoint.TIC2WebSocketEndPointErrorCode; +import tic.service.message.RequestUnsubscribeTIC; +import tic.service.message.ResponseError; +import tic.service.requesthandler.TIC2WebSocketRequestHandler; +import tic.util.message.Event; +import tic.util.message.Message; +import tic.util.message.Request; +import tic.util.message.Response; +import tic.util.message.codec.MessageJsonCodec; +import tic.util.message.exception.MessageException; +import tic.util.message.exception.MessageInvalidContentException; +import tic.util.message.exception.MessageInvalidFormatException; +import tic.util.message.exception.MessageInvalidTypeException; +import tic.util.message.exception.MessageKeyNameDoesntExistException; +import tic.util.message.exception.MessageKeyTypeDoesntExistException; +import tic.util.message.exception.UnsupportedMessageException; + +/** + * Netty WebSocket handler for TIC2WebSocket. + * + *

This handler manages WebSocket connections for TIC2WebSocket, handling incoming WebSocket + * frames, client lifecycle events, and message dispatching. It integrates with the client pool and + * request handler to process requests and send responses or events over the WebSocket channel. + * + *

Responsibilities include: + * + *

    + *
  • Managing client connections and their lifecycle + *
  • Parsing and validating incoming WebSocket messages + *
  • Handling requests and generating responses + *
  • Sending events and messages to clients + *
  • Logging and error handling for channel operations + *
+ * + *

This class is intended to be used as a Netty handler in the server pipeline for real-time TIC + * data exchange. + * + * @author Enedis Smarties team + * @see TIC2WebSocketClientPool + * @see TIC2WebSocketRequestHandler + * @see EventSender + */ +public class TIC2WebSocketHandler extends SimpleChannelInboundHandler + implements EventSender { + /** Logger for this handler. */ + private static final Logger logger = LogManager.getLogger(TIC2WebSocketHandler.class); + + /** Pool managing active WebSocket clients. */ + private final TIC2WebSocketClientPool clientPool; + + /** Handler for processing incoming requests. */ + private final TIC2WebSocketRequestHandler requestHandler; + + private MessageJsonCodec messageJsonCodec = MessageJsonCodec.getInstance(); + + /** + * Constructs a new TIC2WebSocketHandler. + * + * @param clientPool the pool managing WebSocket clients + * @param requestHandler the handler for processing requests + */ + public TIC2WebSocketHandler( + TIC2WebSocketClientPool clientPool, TIC2WebSocketRequestHandler requestHandler) { + this.clientPool = clientPool; + this.requestHandler = requestHandler; + } + + /** + * Sends an event message to the specified channel. + * + * @param channel the Netty channel to send the event to + * @param event the event message to send + */ + @Override + public void sendEvent(Channel channel, Event event) { + this.sendMessage(channel, event); + } + + /** + * Invoked when a new channel becomes active. + * + *

Creates a new client for the channel if it does not already exist. + * + * @param ctx the channel handler context + * @throws Exception if an error occurs during activation + */ + @Override + public void channelActive(ChannelHandlerContext ctx) throws Exception { + Channel channel = ctx.channel(); + String channelId = channel.id().asLongText(); + + logger.debug("Open channel " + channelId); + + if (!clientPool.exists(channelId)) { + logger.debug("Client create with channel id : " + channelId); + clientPool.createClient(channel, this); + } else { + logger.error("Client with channel id : " + channelId + " already exists ! "); + } + + super.channelActive(ctx); + } + + /** + * Invoked when a channel becomes inactive. + * + *

Handles client removal and sends an unsubscribe request if necessary. + * + * @param ctx the channel handler context + * @throws Exception if an error occurs during deactivation + */ + @Override + public void channelInactive(ChannelHandlerContext ctx) throws Exception { + Channel channel = ctx.channel(); + String channelId = channel.id().asLongText(); + + logger.debug("Close channel " + channelId); + + if (clientPool.exists(channelId)) { + try { + logger.debug("Generate unsubscribe request"); + Request request = new RequestUnsubscribeTIC((List) null); + this.handleRequest(clientPool.getClient(channelId).get(), request); + + logger.debug("Remove client with channel id : " + channelId); + clientPool.remove(channelId); + } catch (Exception e) { + logger.error("Error during channel close", e); + } + } else { + logger.error("Client with channel id : " + channelId + " doesn't exist ! "); + } + + super.channelInactive(ctx); + } + + /** + * Handles exceptions caught during channel operations. + * + *

Logs the error and closes the channel. + * + * @param ctx the channel handler context + * @param cause the exception that was caught + * @throws Exception if an error occurs during exception handling + */ + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { + Channel channel = ctx.channel(); + String channelId = channel.id().asLongText(); + + logger.error("Error on channel " + channelId, cause); + + ctx.close(); + } + + /** + * Handles incoming WebSocket frames. + * + *

Processes text frames as TIC2WebSocket messages, validates and dispatches requests, and + * sends responses. Unsupported frame types are logged as warnings. + * + * @param ctx the channel handler context + * @param frame the received WebSocket frame + * @throws Exception if an error occurs during frame processing + */ + @Override + protected void channelRead0(ChannelHandlerContext ctx, WebSocketFrame frame) throws Exception { + if (frame instanceof TextWebSocketFrame) { + TextWebSocketFrame textFrame = (TextWebSocketFrame) frame; + String text = textFrame.text(); + Channel channel = ctx.channel(); + String channelId = channel.id().asLongText(); + + logger.debug("Message on channel " + channelId); + + TIC2WebSocketClient client = this.getClient(channel); + + Optional message = this.getMessage(channel, text); + if (!message.isPresent()) { + return; + } + + Optional request = this.getRequest(channel, message.get()); + if (!request.isPresent()) { + return; + } + + Response response = this.handleRequest(client, request.get()); + + this.sendMessage(channel, response); + } else { + // Handle other frame types if needed + logger.warn("Unsupported frame type: " + frame.getClass().getSimpleName()); + } + } + + /** + * Retrieves the TIC2WebSocketClient associated with the given channel. + * + *

If no client exists for the channel, a new one is created and registered. + * + * @param channel the Netty channel + * @return the associated TIC2WebSocketClient + */ + private TIC2WebSocketClient getClient(Channel channel) { + String channelId = channel.id().asLongText(); + Optional clientOpt = clientPool.getClient(channelId); + if (!clientOpt.isPresent()) { + return clientPool.createClient(channel, this); + } + return clientOpt.get(); + } + + /** + * Parses and validates a message from the given text. + * + *

Returns an empty Optional if the message is invalid or an error occurs. + * + * @param channel the Netty channel + * @param text the raw message text + * @return an Optional containing the parsed Message, or empty if invalid + */ + private Optional getMessage(Channel channel, String text) { + Message message = null; + TIC2WebSocketEndPointErrorCode errorCode = TIC2WebSocketEndPointErrorCode.NO_ERROR; + String errorMessage = ""; + + try { + message = messageJsonCodec.decodeFromJsonString(text); + } catch (MessageException e) { + if (e instanceof MessageInvalidFormatException) { + errorCode = TIC2WebSocketEndPointErrorCode.INVALID_MESSAGE_FORMAT; + errorMessage = e.getMessage(); + } else if (e instanceof MessageInvalidTypeException) { + errorCode = TIC2WebSocketEndPointErrorCode.MESSAGE_TYPE_INVALID; + errorMessage = e.getMessage(); + } else if (e instanceof MessageKeyNameDoesntExistException) { + errorCode = TIC2WebSocketEndPointErrorCode.MESSAGE_NAME_MISSING; + errorMessage = e.getMessage(); + } else if (e instanceof MessageKeyTypeDoesntExistException) { + errorCode = TIC2WebSocketEndPointErrorCode.MESSAGE_TYPE_MISSING; + errorMessage = e.getMessage(); + } else if (e instanceof MessageInvalidContentException) { + errorCode = TIC2WebSocketEndPointErrorCode.INVALID_MESSAGE_CONTENT; + errorMessage = e.getMessage(); + } else if (e instanceof UnsupportedMessageException) { + errorCode = TIC2WebSocketEndPointErrorCode.UNSUPPORTED_MESSAGE; + errorMessage = e.getMessage(); + } + } catch (Exception e) { + errorCode = TIC2WebSocketEndPointErrorCode.INTERNAL_ERROR; + errorMessage = "Internal error: " + e.getMessage(); + } + + if (errorCode != TIC2WebSocketEndPointErrorCode.NO_ERROR) { + logger.error("Error parsing message: " + errorMessage); + this.sendErrorMessage(channel, errorCode, errorMessage); + return Optional.empty(); + } + + return Optional.of(message); + } + + /** + * Extracts a Request from the given Message if possible. + * + *

Returns an empty Optional if the message is not a Request. + * + * @param channel the Netty channel + * @param message the parsed Message + * @return an Optional containing the Request, or empty if not applicable + */ + private Optional getRequest(Channel channel, Message message) { + if (!(message instanceof Request)) { + logger.error("Message is not a request"); + this.sendErrorMessage( + channel, TIC2WebSocketEndPointErrorCode.MESSAGE_TYPE_INVALID, "Message is not a request"); + return Optional.empty(); + } + + return Optional.of((Request) message); + } + + /** + * Handles the given request using the request handler and client. + * + * @param client the TIC2WebSocketClient + * @param request the request to handle + * @return the generated Response + */ + private Response handleRequest(TIC2WebSocketClient client, Request request) { + return requestHandler.handle(request, client); + } + + private void sendErrorMessage( + Channel channel, TIC2WebSocketEndPointErrorCode errorCode, String errorMessage) { + ResponseError responseError = + new ResponseError("ErrorResponse", LocalDateTime.now(), errorCode.value(), errorMessage); + this.sendMessage(channel, responseError); + } + + /** + * Sends a message to the specified channel as a JSON WebSocket frame. + * + *

Logs the sent message and handles any errors during transmission. + * + * @param channel the Netty channel to send the message to + * @param message the message to send + */ + private void sendMessage(Channel channel, Message message) { + try { + String json = messageJsonCodec.encodeToJsonString(message); + TextWebSocketFrame frame = new TextWebSocketFrame(json); + channel.writeAndFlush(frame); + + logger.debug("Sent message to channel {}: {}", channel.id().asLongText(), json); + } catch (Exception e) { + logger.error("Error sending message to channel " + channel.id().asLongText(), e); + } + } +} diff --git a/src/main/java/tic/service/netty/TIC2WebSocketServer.java b/src/main/java/tic/service/netty/TIC2WebSocketServer.java new file mode 100644 index 0000000..4788cb8 --- /dev/null +++ b/src/main/java/tic/service/netty/TIC2WebSocketServer.java @@ -0,0 +1,157 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.service.netty; + +import tic.service.client.TIC2WebSocketClientPool; +import tic.service.requesthandler.TIC2WebSocketRequestHandler; +import io.netty.bootstrap.ServerBootstrap; +import io.netty.channel.Channel; +import io.netty.channel.ChannelFuture; +import io.netty.channel.EventLoopGroup; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.nio.NioServerSocketChannel; +import io.netty.handler.logging.LogLevel; +import io.netty.handler.logging.LoggingHandler; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +/** + * TIC2WebSocket Netty WebSocket Server. + * + *

This class manages the lifecycle of the WebSocket server, including startup, + * shutdown, and connection handling. It configures the Netty pipeline and integrates with the client pool + * and request handler to support real-time TIC data exchange over WebSocket. + * + *

Responsibilities include: + *

    + *
  • Starting and stopping the WebSocket server + *
  • Managing server channel and event loop groups + *
  • Binding to the specified host and port + *
  • Integrating with TIC2WebSocket client pool and request handler + *
  • Logging server lifecycle events and errors + *
+ * + *

This class is intended to be used as the main entry point for launching the TIC2WebSocket server. + * + * @author Enedis Smarties team + * @see TIC2WebSocketClientPool + * @see TIC2WebSocketRequestHandler + * @see TIC2WebSocketChannelInitializer + */ +public class TIC2WebSocketServer { + /** Logger for server lifecycle and events. */ + private static final Logger logger = LogManager.getLogger(TIC2WebSocketServer.class); + + /** Host address to bind the server. */ + private final String host; + /** Port to bind the server. */ + private final int port; + /** Pool managing active WebSocket clients. */ + private final TIC2WebSocketClientPool clientPool; + /** Handler for processing incoming requests. */ + private final TIC2WebSocketRequestHandler requestHandler; + + /** Netty boss event loop group (accepts connections). */ + private EventLoopGroup bossGroup; + /** Netty worker event loop group (handles traffic). */ + private EventLoopGroup workerGroup; + /** Main server channel. */ + private Channel serverChannel; + + /** + * Constructs a new TIC2WebSocketServer. + * + * @param host the host address to bind the server + * @param port the port to bind the server + * @param clientPool the pool managing WebSocket clients + * @param requestHandler the handler for processing requests + */ + public TIC2WebSocketServer( + String host, + int port, + TIC2WebSocketClientPool clientPool, + TIC2WebSocketRequestHandler requestHandler) { + this.host = host; + this.port = port; + this.clientPool = clientPool; + this.requestHandler = requestHandler; + } + + /** + * Starts the WebSocket server and binds to the configured host and port. + * + *

Initializes Netty event loop groups and configures the server pipeline. Logs startup events and + * handles errors during server initialization. + * + * @throws Exception if server startup fails + */ + public void start() throws Exception { + logger.info("Starting TIC2WebSocket Netty server on {}:{}", host, port); + + bossGroup = new NioEventLoopGroup(1); + workerGroup = new NioEventLoopGroup(); + + try { + ServerBootstrap bootstrap = new ServerBootstrap(); + bootstrap + .group(bossGroup, workerGroup) + .channel(NioServerSocketChannel.class) + .handler(new LoggingHandler(LogLevel.INFO)) + .childHandler(new TIC2WebSocketChannelInitializer(clientPool, requestHandler)); + + ChannelFuture future = bootstrap.bind(host, port).sync(); + serverChannel = future.channel(); + + logger.info("TIC2WebSocket Netty server started successfully on {}:{}", host, port); + } catch (Exception e) { + logger.error("Failed to start TIC2WebSocket Netty server", e); + stop(); + throw e; + } + } + + /** + * Stops the WebSocket server and releases resources. + * + *

Closes the server channel and gracefully shuts down event loop groups. Logs shutdown events. + */ + public void stop() { + logger.info("Stopping TIC2WebSocket Netty server"); + + try { + if (serverChannel != null) { + serverChannel.close().sync(); + } + } catch (InterruptedException e) { + logger.warn("Interrupted while closing server channel", e); + Thread.currentThread().interrupt(); + } finally { + if (bossGroup != null) { + bossGroup.shutdownGracefully(); + } + if (workerGroup != null) { + workerGroup.shutdownGracefully(); + } + } + + logger.info("TIC2WebSocket Netty server stopped"); + } + + /** + * Waits for the server channel to close. + * + *

Blocks until the server channel is closed, allowing for graceful shutdown. + * + * @throws InterruptedException if interrupted while waiting + */ + public void waitForClose() throws InterruptedException { + if (serverChannel != null) { + serverChannel.closeFuture().sync(); + } + } +} diff --git a/src/main/java/tic/service/requesthandler/TIC2WebSocketRequestHandler.java b/src/main/java/tic/service/requesthandler/TIC2WebSocketRequestHandler.java new file mode 100644 index 0000000..bfb4939 --- /dev/null +++ b/src/main/java/tic/service/requesthandler/TIC2WebSocketRequestHandler.java @@ -0,0 +1,46 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.service.requesthandler; + +import tic.util.message.Request; +import tic.util.message.Response; +import tic.service.client.TIC2WebSocketClient; + +/** + * Interface for handling TIC2WebSocket requests. + * + *

This interface defines the contract for processing incoming TIC2WebSocket requests and generating + * appropriate responses. Implementations of this interface are responsible for interpreting requests, + * performing necessary operations, and returning a response to the client. + * + *

Common use cases include: + *

    + *
  • Validating and dispatching TIC2WebSocket requests + *
  • Managing client-specific operations + *
  • Generating responses based on request type and client state + *
  • Error handling and reporting + *
+ * + * @author Enedis Smarties team + * @see Request + * @see Response + * @see TIC2WebSocketClient + */ +public interface TIC2WebSocketRequestHandler { + /** + * Handles a TIC2WebSocket request and returns a response. + * + *

Processes the given request for the specified client, performing any necessary operations + * and returning the corresponding response. + * + * @param request the TIC2WebSocket request to handle + * @param client the client associated with the request + * @return the response generated for the request + */ + public Response handle(Request request, TIC2WebSocketClient client); +} diff --git a/src/main/java/tic/service/requesthandler/TIC2WebSocketRequestHandlerBase.java b/src/main/java/tic/service/requesthandler/TIC2WebSocketRequestHandlerBase.java new file mode 100644 index 0000000..70f176d --- /dev/null +++ b/src/main/java/tic/service/requesthandler/TIC2WebSocketRequestHandlerBase.java @@ -0,0 +1,379 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.service.requesthandler; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import tic.core.TICCore; +import tic.core.TICCoreErrorCode; +import tic.core.TICCoreException; +import tic.core.TICCoreFrame; +import tic.core.TICIdentifier; +import tic.io.modem.ModemDescriptor; +import tic.service.client.TIC2WebSocketClient; +import tic.service.endpoint.TIC2WebSocketEndPointErrorCode; +import tic.service.message.RequestGetAvailableTICs; +import tic.service.message.RequestGetModemsInfo; +import tic.service.message.RequestReadTIC; +import tic.service.message.RequestSubscribeTIC; +import tic.service.message.RequestUnsubscribeTIC; +import tic.service.message.ResponseError; +import tic.service.message.ResponseGetAvailableTICs; +import tic.service.message.ResponseGetModemsInfo; +import tic.service.message.ResponseReadTIC; +import tic.service.message.ResponseSubscribeTIC; +import tic.service.message.ResponseUnsubscribeTIC; +import tic.util.message.Request; +import tic.util.message.Response; + +/** + * Base implementation of the TIC2WebSocket request handler. + * + *

This class provides the default logic for handling TIC2WebSocket requests, including + * subscription, unsubscription, reading TIC frames, and retrieving available TICs and modem + * information. It integrates with the TICCore to perform operations and generate appropriate + * responses for each request type. + * + *

Responsibilities include: + * + *

    + *
  • Dispatching and processing supported TIC2WebSocket requests + *
  • Managing client subscriptions and unsubscriptions + *
  • Interfacing with TICCore for data operations + *
  • Generating error responses for unsupported or failed operations + *
  • Logging request handling and errors + *
+ * + * @author Enedis Smarties team + * @see TIC2WebSocketRequestHandler + * @see TIC2WebSocketClient + * @see TICCore + */ +public class TIC2WebSocketRequestHandlerBase implements TIC2WebSocketRequestHandler { + /** Logger for request handling and errors. */ + private Logger logger; + + /** TICCore instance for data operations. */ + private TICCore ticCore; + + /** + * Constructs a new TIC2WebSocketRequestHandlerBase. + * + * @param ticCore the TICCore instance for data operations + */ + public TIC2WebSocketRequestHandlerBase(TICCore ticCore) { + super(); + this.logger = LogManager.getLogger(this.getClass()); + this.ticCore = ticCore; + } + + /** + * Handles a TIC2WebSocket request and returns a response. + * + *

Dispatches the request to the appropriate handler method based on its type. Generates error + * responses for unsupported requests. + * + * @param request the TIC2WebSocket request to handle + * @param client the client associated with the request + * @return the response generated for the request + */ + @Override + public Response handle(Request request, TIC2WebSocketClient client) { + Response response = null; + + logger.info("Handling request: " + request.getName()); + switch (request.getName()) { + case RequestGetAvailableTICs.NAME: + response = this.handleGetAvailableTICsRequest(request); + break; + case RequestGetModemsInfo.NAME: + response = this.handleGetModemsInfoRequest(request); + break; + case RequestReadTIC.NAME: + response = this.handleReadTICRequest(request); + break; + case RequestSubscribeTIC.NAME: + response = this.handleSubscribeTICRequest(request, client); + break; + case RequestUnsubscribeTIC.NAME: + response = this.handleUnsubscribeTICRequest(request, client); + break; + default: + this.logger.error("Request " + request.getName() + " not supported"); + response = + this.createErrorResponse( + request.getName(), + TIC2WebSocketEndPointErrorCode.UNSUPPORTED_MESSAGE, + "Request " + request.getName() + " not supported"); + break; + } + + return response; + } + + /** + * Handles a request to get available TIC identifiers. + * + * @param request the request to process + * @return the response containing available TIC identifiers or an error + */ + private Response handleGetAvailableTICsRequest(Request request) { + List ticIdentifiers = this.ticCore.getAvailableTICs(); + + Response response = null; + + try { + response = + new ResponseGetAvailableTICs( + LocalDateTime.now(), + TIC2WebSocketEndPointErrorCode.NO_ERROR.value(), + null, + ticIdentifiers); + } catch (Exception e) { + this.logger.error(e.getMessage(), e); + response = + this.createErrorResponse( + request.getName(), TIC2WebSocketEndPointErrorCode.INTERNAL_ERROR, e.getMessage()); + } + + return response; + } + + /** + * Handles a request to get modem information. + * + * @param request the request to process + * @return the response containing modem information or an error + */ + private Response handleGetModemsInfoRequest(Request request) { + List modemsInfo = this.ticCore.getModemsInfo(); + + Response response = null; + try { + response = + new ResponseGetModemsInfo( + LocalDateTime.now(), + TIC2WebSocketEndPointErrorCode.NO_ERROR.value(), + null, + modemsInfo); + } catch (Exception e) { + this.logger.error(e.getMessage(), e); + response = + this.createErrorResponse( + request.getName(), TIC2WebSocketEndPointErrorCode.INTERNAL_ERROR, e.getMessage()); + } + + return response; + } + + /** + * Handles a request to read a TIC frame. + * + * @param request the request to process + * @return the response containing the TIC frame or an error + */ + private Response handleReadTICRequest(Request request) { + Response response = null; + try { + if (!(request instanceof RequestReadTIC)) { + return this.createErrorResponse( + request.getName(), + TIC2WebSocketEndPointErrorCode.INTERNAL_ERROR, + "Invalid request type for " + request.getName()); + } + + TICIdentifier identifier = ((RequestReadTIC) request).getData(); + + TICCoreFrame frame = this.ticCore.readNextFrame(identifier); + response = + new ResponseReadTIC( + LocalDateTime.now(), TIC2WebSocketEndPointErrorCode.NO_ERROR.value(), null, frame); + } catch (TICCoreException e) { + if (e.getErrorCode() == TICCoreErrorCode.STREAM_IDENTIFIER_NOT_FOUND.getCode()) { + response = + this.createErrorResponse( + request.getName(), + TIC2WebSocketEndPointErrorCode.IDENTIFIER_NOT_FOUND, + e.getMessage()); + } else if (e.getErrorCode() == TICCoreErrorCode.DATA_READ_TIMEOUT.getCode()) { + response = + this.createErrorResponse( + request.getName(), TIC2WebSocketEndPointErrorCode.READ_TIMEOUT, e.getMessage()); + } else { + response = + this.createErrorResponse( + request.getName(), TIC2WebSocketEndPointErrorCode.INTERNAL_ERROR, e.getMessage()); + } + } + + return response; + } + + /** + * Handles a request to subscribe to TIC identifiers for a client. + * + * @param request the subscription request + * @param client the client to subscribe + * @return the response indicating subscription success or failure + */ + private Response handleSubscribeTICRequest(Request request, TIC2WebSocketClient client) { + Response response = null; + + if (!(request instanceof RequestSubscribeTIC)) { + return this.createErrorResponse( + request.getName(), + TIC2WebSocketEndPointErrorCode.INTERNAL_ERROR, + "Invalid request type for " + request.getName()); + } + + List requestedIdentifiers = ((RequestSubscribeTIC) request).getData(); + + Optional> ticIdentifiers = Optional.ofNullable(requestedIdentifiers); + + if (ticIdentifiers.isPresent()) { + List newSubscriptions = + this.getNewSubcriptions(this.ticCore.getIndentifiers(client), ticIdentifiers.get()); + if (!newSubscriptions.isEmpty()) { + for (TICIdentifier identifier : ticIdentifiers.get()) { + try { + this.ticCore.subscribe(identifier, client); + try { + response = + new ResponseSubscribeTIC( + LocalDateTime.now(), TIC2WebSocketEndPointErrorCode.NO_ERROR.value(), null); + } catch (Exception e) { + this.logger.error(e.getMessage(), e); + } + } catch (TICCoreException e) { + response = + this.createErrorResponse( + request.getName(), + TIC2WebSocketEndPointErrorCode.SUBSCRIPTION_FAIL, + e.getMessage()); + } + } + } + } else { + this.ticCore.subscribe(client); + try { + response = + new ResponseSubscribeTIC( + LocalDateTime.now(), TIC2WebSocketEndPointErrorCode.NO_ERROR.value(), null); + } catch (Exception e) { + this.logger.error(e.getMessage(), e); + } + } + + return response; + } + + /** + * Determines new TIC subscriptions requested by the client. + * + *

Compares current subscriptions with requested identifiers and returns only new + * subscriptions. + * + * @param currentSubscriptions the client's current subscriptions + * @param askedTicIdentifiers the requested TIC identifiers + * @return a list of new TIC identifiers to subscribe + */ + private List getNewSubcriptions( + List currentSubscriptions, List askedTicIdentifiers) { + List newSubscriptions = new ArrayList(); + + for (TICIdentifier askedTicIdentifier : askedTicIdentifiers) { + boolean newSub = true; + for (TICIdentifier currentSubscription : currentSubscriptions) { + if (askedTicIdentifier.matches(currentSubscription)) { + newSub = false; + break; + } + } + if (newSub) { + newSubscriptions.add(askedTicIdentifier); + } + } + return newSubscriptions; + } + + /** + * Handles a request to unsubscribe from TIC identifiers for a client. + * + * @param request the unsubscription request + * @param client the client to unsubscribe + * @return the response indicating unsubscription success or failure + */ + private Response handleUnsubscribeTICRequest(Request request, TIC2WebSocketClient client) { + Response response = null; + + if (!(request instanceof RequestUnsubscribeTIC)) { + return this.createErrorResponse( + request.getName(), + TIC2WebSocketEndPointErrorCode.INTERNAL_ERROR, + "Invalid request type for " + request.getName()); + } + + List requestedIdentifiers = ((RequestUnsubscribeTIC) request).getData(); + + Optional> ticIdentifiers = Optional.ofNullable(requestedIdentifiers); + + if (ticIdentifiers.isPresent()) { + for (TICIdentifier identifier : ticIdentifiers.get()) { + try { + this.ticCore.unsubscribe(identifier, client); + try { + response = + new ResponseUnsubscribeTIC( + LocalDateTime.now(), TIC2WebSocketEndPointErrorCode.NO_ERROR.value(), null); + } catch (Exception e) { + this.logger.error(e.getMessage(), e); + } + } catch (TICCoreException e) { + response = + this.createErrorResponse( + request.getName(), + TIC2WebSocketEndPointErrorCode.UNSUBSCRIPTION_FAIL, + e.getMessage()); + } + } + } else { + this.ticCore.unsubscribe(client); + try { + response = + new ResponseUnsubscribeTIC( + LocalDateTime.now(), TIC2WebSocketEndPointErrorCode.NO_ERROR.value(), null); + } catch (Exception e) { + this.logger.error(e.getMessage(), e); + } + } + + return response; + } + + /** + * Creates a generic error response for a given request name and error code. + * + * @param name the name of the request + * @param code the error code + * @param message the error message + * @return the error response + */ + private Response createErrorResponse( + String name, TIC2WebSocketEndPointErrorCode code, String message) { + try { + return new ResponseError(name, LocalDateTime.now(), code.value(), message); + } catch (Exception e) { + this.logger.error(e.getMessage(), e); + return null; + } + } +} diff --git a/src/main/java/tic/stream/TICStream.java b/src/main/java/tic/stream/TICStream.java new file mode 100644 index 0000000..a676cfe --- /dev/null +++ b/src/main/java/tic/stream/TICStream.java @@ -0,0 +1,259 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.stream; + +import java.util.Collection; +import java.util.Objects; +import java.util.concurrent.CountDownLatch; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import tic.frame.TICFrame; +import tic.frame.TICMode; +import tic.frame.codec.TICFrameCodec; +import tic.frame.codec.TICFrameSummarizedCodec; +import tic.io.serialport.SerialPortDescriptor; +import tic.io.serialport.SerialPortFinder; +import tic.io.serialport.SerialPortFinderBase; +import tic.stream.configuration.TICStreamConfiguration; +import tic.stream.configuration.TICStreamConfigurationLoader; +import tic.stream.identifier.TICStreamIdentifier; +import tic.stream.identifier.TICStreamIdentifierType; +import tic.util.task.Task; +import tic.util.task.TaskBase; +import tic.util.task.TaskPeriodicWithSubscribers; + +public class TICStream extends TaskPeriodicWithSubscribers { + + private static final Logger logger = LogManager.getLogger(TICStream.class); + + private final TICStreamConfiguration configuration; + private final SerialPortFinder portFinder; + + private final int timeoutMillis; + private TICStreamModeDetector streamModeDetector; + private TICMode currentMode; + private TICStreamReader streamReader; + private TICFrame lastFrame; + + public static void main(String[] args) { + if (args.length != 1) { + System.err.println("Usage: java tic.stream.TICStream "); + System.exit(1); + } + + String configPath = args[0]; + + try { + TICStreamConfiguration configuration = TICStreamConfigurationLoader.load(configPath); + TICStream stream = new TICStream(configuration); + CountDownLatch shutdownLatch = new CountDownLatch(1); + + stream.subscribe( + new TICStreamListener() { + @Override + public void onFrame(TICFrame frame) { + + try { + logger.debug( + "TIC stream frame:\n" + + TICFrameSummarizedCodec.getInstance().encodeToJsonString(frame) + + "\n"); + } catch (Exception e) { + logger.error("Failed to encode TIC frame to JSON: " + e.getMessage()); + } + } + + @Override + public void onError(String error) { + logger.error("TIC stream error: " + error); + } + }); + + Runtime.getRuntime() + .addShutdownHook( + new Thread( + () -> { + stream.stop(); + shutdownLatch.countDown(); + })); + + logger.info("Starting TIC stream with configuration " + configPath); + logger.info("Press CTRL-C to stop."); + stream.start(); + shutdownLatch.await(); + } catch (Exception exception) { + logger.error("Failed to start TIC stream: " + exception.getMessage()); + System.exit(1); + } + } + + public TICStream(TICStreamConfiguration configuration) { + this(configuration, SerialPortFinderBase.getInstance()); + } + + public TICStream(TICStreamConfiguration configuration, SerialPortFinder portFinder) { + this.configuration = Objects.requireNonNull(configuration, "configuration must not be null"); + this.portFinder = Objects.requireNonNull(portFinder, "portFinder must not be null"); + this.timeoutMillis = configuration.getTimeout() * 1000; + this.initializeStreamReader(); + this.initializeStreamModeDetector(); + } + + private void initializeStreamReader() { + String portName = this.resolvePortName(); + int baudrate = this.resolveBaudrate(this.configuration.getTicMode()); + if (this.streamReader != null) { + try { + this.streamReader.close(); + } catch (Exception e) { + logger.warn("Failed to close existing TIC stream reader: {}", e.getMessage()); + } + } + this.streamReader = new TICStreamReader(portName, baudrate, timeoutMillis); + + if (this.streamModeDetector == null) { + this.initializeStreamModeDetector(); + } else { + this.streamModeDetector.setStreamReader(this.streamReader); + } + } + + private void initializeStreamModeDetector() { + if (this.streamReader == null) { + throw new IllegalStateException("TIC stream reader is not initialized"); + } + this.streamModeDetector = new TICStreamModeDetector(this.currentMode, this.streamReader); + } + + // Synchronous + public TICFrame getNextFrame() { + byte[] ticFrameAsByte = this.streamReader.read(); + if (ticFrameAsByte == null) { + return null; + } + TICFrame ticFrame = TICFrameCodec.decode(ticFrameAsByte); + return ticFrame; + } + + // Asynchronous + public TICFrame getLastFrame() { + return this.lastFrame; + } + + @Override + protected void process() { + if (this.streamReader == null) { + throw new IllegalStateException("TIC stream reader is not initialized"); + } + + if (this.currentMode == null) { + TICMode newMode = this.streamModeDetector.autoDetectMode(); + if (newMode != null && newMode != this.currentMode) { + logger.info("TIC mode detected: {}", newMode); + } + if (newMode == null) { + this.onReadTimeout(); + return; + } + this.currentMode = newMode; + this.initializeStreamReader(); + } + + try { + TICFrame ticFrame = this.getNextFrame(); + + if (ticFrame == null) { + this.onReadTimeout(); + } else { + this.notifyOnDataRead(ticFrame); + } + this.lastFrame = ticFrame; + } catch (Exception e) { + this.notifyOnErrorDetected("TIC read failed: " + e.getMessage()); + } + } + + private void notifyOnDataRead(TICFrame ticFrame) { + Collection subscribers = this.getSubscribers(); + for (TICStreamListener subscriber : subscribers) { + Task task = + new TaskBase() { + @Override + public void process() { + subscriber.onFrame(ticFrame); + } + }; + task.start(); + } + } + + private void notifyOnErrorDetected(String message) { + Collection subscribers = this.getSubscribers(); + for (TICStreamListener subscriber : subscribers) { + Task task = + new TaskBase() { + @Override + public void process() { + subscriber.onError(message); + } + }; + task.start(); + } + } + + protected void onReadTimeout() { + this.notifyOnErrorDetected("TIC read timeout"); + try { + this.streamReader.reset(); + } catch (Exception e) { + } + + this.currentMode = null; + } + + private int resolveBaudrate(TICMode mode) { + if (mode == TICMode.HISTORIC) { + return 1200; + } + return 9600; // Default for STANDARD and AUTO + } + + private String resolvePortName() { + TICStreamIdentifier identifier = this.configuration.getIdentifier(); + if (identifier == null) { + throw new IllegalStateException("No TIC stream identifier configured"); + } + + SerialPortDescriptor descriptor = null; + if (identifier.getType() == TICStreamIdentifierType.PORT_ID) { + descriptor = this.portFinder.findByPortId(identifier.getPortId()); + if (descriptor == null) { + throw new IllegalStateException( + "Serial port with id " + identifier.getPortId() + " not found"); + } + } else if (identifier.getType() == TICStreamIdentifierType.PORT_NAME) { + String configuredName = identifier.getPortName(); + if (configuredName == null || configuredName.isEmpty()) { + throw new IllegalStateException("Serial port name is not configured"); + } + descriptor = this.portFinder.findByPortName(configuredName); + if (descriptor == null) { + logger.warn( + "Serial port {} not found via discovery, attempting to open directly", configuredName); + return configuredName; + } + } else { + throw new IllegalStateException("Unsupported identifier type " + identifier.getType()); + } + + if (descriptor.portName() == null || descriptor.portName().isEmpty()) { + throw new IllegalStateException("Resolved descriptor lacks a port name"); + } + return descriptor.portName(); + } +} diff --git a/src/main/java/tic/stream/TICStreamListener.java b/src/main/java/tic/stream/TICStreamListener.java new file mode 100644 index 0000000..caf59c3 --- /dev/null +++ b/src/main/java/tic/stream/TICStreamListener.java @@ -0,0 +1,28 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.stream; + +import tic.frame.TICFrame; +import tic.util.task.Subscriber; + +public interface TICStreamListener extends Subscriber { + /** + * Notify when a new TIC frame is received + * + * @param frame the frame received + */ + public void onFrame(TICFrame frame); + + /** + * Notify when an error occurs during TIC stream reading + * + * @param error the error detected + */ + public void onError(String error); + +} diff --git a/src/main/java/tic/stream/TICStreamModeDetector.java b/src/main/java/tic/stream/TICStreamModeDetector.java new file mode 100644 index 0000000..0f72a0e --- /dev/null +++ b/src/main/java/tic/stream/TICStreamModeDetector.java @@ -0,0 +1,105 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.stream; + +import java.util.Arrays; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import tic.frame.TICMode; +import tic.frame.delimiter.TICStartPattern; + +public class TICStreamModeDetector { + private static final Logger logger = LogManager.getLogger(TICStreamModeDetector.class); + private TICMode selectedMode; + private TICMode currentMode; + private TICStreamReader streamReader; + + public TICStreamModeDetector(TICMode ticMode, TICStreamReader streamReader) { + this.selectedMode = ticMode; + this.streamReader = streamReader; + } + + /** + * Updates the stream reader reference so auto-detection keeps using the active reader after a + * reconnect/reset. + */ + public void setStreamReader(TICStreamReader streamReader) { + this.streamReader = streamReader; + } + + /** + * Gets the current TIC mode being used by the channel. Returns the detected mode if available, + * otherwise returns the selected mode from configuration. + * + * @return the current TIC mode (HISTORIC, STANDARD, or AUTO) + */ + public TICMode getMode() { + return (this.getCurrentMode() != null) ? this.getCurrentMode() : this.getSelectedMode(); + } + + /** + * Gets the TIC mode selected in the channel configuration. + * + * @return the selected TIC mode from configuration + */ + public TICMode getSelectedMode() { + return this.selectedMode; + } + + /** + * Gets the currently detected TIC mode during operation. This may differ from the selected mode + * if auto-detection is enabled. + * + * @return the currently detected TIC mode, or null if not yet detected + */ + public TICMode getCurrentMode() { + return this.currentMode; + } + + public TICMode autoDetectMode() { + if (this.selectedMode == TICMode.STANDARD || this.selectedMode == TICMode.HISTORIC) { + this.currentMode = this.selectedMode; + return this.currentMode; + } + logger.debug("Auto detecting TIC Mode"); + try { + byte[] ticFrame = this.streamReader.read(); + + for (TICMode ticMode : TICMode.values()) { + if (ticMode != TICMode.AUTO) { + if (this.checkMode(ticMode, ticFrame)) { + logger.debug("TIC Mode " + ticMode + " detected"); + this.currentMode = ticMode; + return this.currentMode; + } + } + } + + logger.debug("TIC Mode not detected"); + return null; + } catch (Exception e) { + logger.error("Error during TIC mode detection: " + e.getMessage(), e); + } + return null; + } + + private boolean checkMode(TICMode ticMode, byte[] ticFrame) { + if (ticFrame == null || ticFrame.length <= TICStartPattern.length()) { + return false; + } + + byte[] expectedStart = this.getExpectedStartBytes(ticMode); + byte[] ticFrameStart = Arrays.copyOf(ticFrame, TICStartPattern.length()); + + return Arrays.equals(ticFrameStart, expectedStart); + } + + private byte[] getExpectedStartBytes(TICMode ticMode) { + return TICStartPattern.getValueFromMode(ticMode); + } +} diff --git a/src/main/java/tic/stream/TICStreamReader.java b/src/main/java/tic/stream/TICStreamReader.java new file mode 100644 index 0000000..0827f65 --- /dev/null +++ b/src/main/java/tic/stream/TICStreamReader.java @@ -0,0 +1,243 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.stream; + +import jssc.SerialPort; +import jssc.SerialPortException; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import tic.frame.TICFrame; +import tic.frame.codec.TICFrameCodec; +import tic.frame.codec.TICFrameSummarizedCodec; +import tic.frame.delimiter.TICFrameDelimiter; +import tic.util.time.Time; + +public class TICStreamReader { + + private static final Logger logger = LogManager.getLogger(TICStreamReader.class); + private String portName; + private SerialPort serialPort; + private int timeoutMillis; + private int baudrate; + private int pollingPeriod; + + /** Polling period in milliseconds for data reception */ + private static final int RECEIVE_DATA_POLLING_PERIOD = 100; + + private static final int DATA_BITS = 7; + private static final int STOP_BITS = SerialPort.STOPBITS_1; + private static final int PARITY = SerialPort.PARITY_EVEN; + + public TICStreamReader(String portName, int baudrate, int timeoutMillis) { + this.portName = portName; + this.baudrate = baudrate; + this.pollingPeriod = RECEIVE_DATA_POLLING_PERIOD; + this.timeoutMillis = timeoutMillis; + } + + /** + * Small CLI helper that opens a TIC stream with inline configuration and prints the first + * received frame to the console. + * + *

Usage: {@code java tic.stream.TICStreamReader } + */ + public static void main(String[] args) { + if (args.length < 2) { + System.err.println("Usage: java tic.stream.TICStreamReader "); + System.exit(1); + } + + String portName = args[0]; + + int baudrate; + try { + baudrate = Integer.parseInt(args[1]); + } catch (NumberFormatException exception) { + System.err.println("Invalid baudrate value: " + args[1]); + System.exit(1); + return; + } + int timeout = 10000; + + TICStreamReader streamReader = new TICStreamReader(portName, baudrate, timeout); + + System.out.println( + "Listening TIC stream on PORT_NAME=" + portName + " at baudrate=" + baudrate); + try { + byte[] frameBuffer = streamReader.read(); + if (frameBuffer == null) { + System.err.println("No TIC frame received within timeout (" + timeout + "s)"); + System.exit(3); + } else { + TICFrame frame = TICFrameCodec.decode(frameBuffer); + String jsonFrame = TICFrameSummarizedCodec.getInstance().encodeToJsonString(frame); + System.out.println("TIC frame read:\n" + jsonFrame); + System.exit(0); + } + } catch (Exception exception) { + System.err.println("Error while reading TIC frame: " + exception.getMessage()); + exception.printStackTrace(System.err); + System.exit(2); + } finally { + try { + streamReader.close(); + } catch (Exception closeException) { + System.err.println("Warning: failed to close stream: " + closeException.getMessage()); + } + } + } + + public byte[] read() { + long beginTime = System.currentTimeMillis(); + long elapsedTime = 0; + boolean startFrameFound = false; + StringBuffer buffer = new StringBuffer(); + + while (hasRemainingTime(elapsedTime)) { + Character nextByte = readNextByteIfAvailable(); + if (nextByte != null) { + if (!startFrameFound) { + if (isStartDelimiter(nextByte)) { + startFrameFound = true; + buffer.append(nextByte); + } + } else { + buffer.append(nextByte); + if (isEndDelimiter(nextByte)) { + return buffer.toString().getBytes(); + } + } + } + elapsedTime = System.currentTimeMillis() - beginTime; + } + + return null; + } + + private boolean hasRemainingTime(long elapsedTime) { + return this.timeoutMillis == 0 || elapsedTime < this.timeoutMillis; + } + + private Character readNextByteIfAvailable() { + try { + if (this.available() <= 0) { + Time.sleep(this.pollingPeriod); + return null; + } + } catch (Exception e) { + return null; + } + + byte[] chunk = this.read(1); + if (chunk.length == 0) { + return null; + } + + return (char) chunk[0]; + } + + private boolean isStartDelimiter(char value) { + return value == TICFrameDelimiter.BEGIN.getValue(); + } + + private boolean isEndDelimiter(char value) { + return value == TICFrameDelimiter.END.getValue(); + } + + /** Reads the specified number of bytes from the serial port input buffer. */ + private synchronized byte[] read(int byteCount) { + if (byteCount <= 0) { + throw new IllegalArgumentException("byteCount must be strictly positive"); + } + this.open(); + try { + byte[] data = this.serialPort.readBytes(byteCount); + return (data != null) ? data : new byte[0]; + } catch (SerialPortException exception) { + throw new IllegalStateException("Cannot read serial port", exception); + } + } + + /** Returns the number of bytes available to read from the serial port input buffer. */ + private synchronized int available() { + this.open(); + try { + return this.serialPort.getInputBufferBytesCount(); + } catch (SerialPortException exception) { + throw new IllegalStateException("Cannot query input buffer size", exception); + } + } + + /** Flushes the serial port input and output buffers. */ + private synchronized void flush() { + this.open(); + try { + int mask = + SerialPort.PURGE_RXCLEAR + | SerialPort.PURGE_RXABORT + | SerialPort.PURGE_TXCLEAR + | SerialPort.PURGE_TXABORT; + this.serialPort.purgePort(mask); + } catch (SerialPortException exception) { + throw new IllegalStateException("Cannot flush serial port", exception); + } + } + + /** Opens the serial port if needed and returns the handler. */ + private synchronized void open() { + if (this.isOpened()) { + return; + } + + if (this.serialPort == null) { + this.serialPort = new SerialPort(this.portName); + } + + try { + this.serialPort.openPort(); + this.serialPort.setParams(this.baudrate, DATA_BITS, STOP_BITS, PARITY); + this.serialPort.setFlowControlMode(SerialPort.FLOWCONTROL_NONE); + + logger.info("Opened TIC serial port {}", this.serialPort.getPortName()); + } catch (SerialPortException exception) { + throw new IllegalStateException( + "Failed to open serial port " + this.serialPort.getPortName(), exception); + } + } + + /** Closes the serial port if opened. */ + public synchronized void close() { + if (this.serialPort == null) { + return; + } + try { + if (this.serialPort.isOpened()) { + this.serialPort.closePort(); + logger.debug("Closed serial port {}", this.serialPort.getPortName()); + } + } catch (SerialPortException exception) { + throw new IllegalStateException("Cannot close serial port", exception); + } finally { + this.serialPort = null; + } + } + + protected void reset() { + this.close(); + this.open(); + try { + this.flush(); + } catch (Exception e) { + } + } + + /** Indicates whether the serial port is currently opened. */ + private synchronized boolean isOpened() { + return this.serialPort != null && this.serialPort.isOpened(); + } +} diff --git a/src/main/java/tic/stream/configuration/TICStreamConfiguration.java b/src/main/java/tic/stream/configuration/TICStreamConfiguration.java new file mode 100644 index 0000000..26e5c7e --- /dev/null +++ b/src/main/java/tic/stream/configuration/TICStreamConfiguration.java @@ -0,0 +1,97 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.stream.configuration; + +import tic.frame.TICMode; +import tic.stream.identifier.TICStreamIdentifier; + +/** + * Configuration class for TIC stream, including TIC mode, identifier, and timeout. + * + * @author Enedis Smarties team + */ +public class TICStreamConfiguration { + + public static final TICMode DEFAULT_TIC_MODE = TICMode.AUTO; + public static final int DEFAULT_TIMEOUT = 10; + + private TICMode ticMode; + private TICStreamIdentifier identifier; + private int timeout; + + /** + * Constructs a TICStreamConfiguration with the specified parameters. + * + * @param ticMode the TIC mode (STANDARD, HISTORIC, or AUTO) + */ + public TICStreamConfiguration(TICMode ticMode, TICStreamIdentifier identifier, int timeout) { + this.setTicMode(ticMode); + this.setIdentifier(identifier); + this.setTimeout(timeout); + } + + /** + * Returns the configured TIC mode for this stream. + * + * @return the TIC mode (STANDARD, HISTORIC, or AUTO) + */ + public TICMode getTicMode() { + return this.ticMode; + } + + /** + * Returns the TIC stream identifier. + * + * @return the TIC stream identifier + */ + public TICStreamIdentifier getIdentifier() { + return this.identifier; + } + + /** + * Returns the timeout value for the TIC stream. + * + * @return the timeout value in seconds + */ + public int getTimeout() { + return this.timeout; + } + + private void setTicMode(TICMode ticMode) { + checkTicMode(ticMode); + this.ticMode = ticMode; + } + + private void setIdentifier(TICStreamIdentifier identifier) { + checkIdentifier(identifier); + this.identifier = identifier; + } + + private void setTimeout(int timeout) { + checkTimeout(timeout); + this.timeout = timeout; + } + + private void checkTicMode(TICMode ticMode) { + if (ticMode == null) { + throw new IllegalArgumentException("TIC mode cannot be null"); + } + } + + private void checkIdentifier(TICStreamIdentifier identifier) { + if (identifier == null) { + throw new IllegalArgumentException("TIC stream identifier cannot be null"); + } + } + + private void checkTimeout(int timeout) { + if (timeout <= 0) { + throw new IllegalArgumentException("Timeout must be a positive integer"); + } + } +} diff --git a/src/main/java/tic/stream/configuration/TICStreamConfigurationLoader.java b/src/main/java/tic/stream/configuration/TICStreamConfigurationLoader.java new file mode 100644 index 0000000..fd7dbda --- /dev/null +++ b/src/main/java/tic/stream/configuration/TICStreamConfigurationLoader.java @@ -0,0 +1,82 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.stream.configuration; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import org.json.JSONException; +import org.json.JSONObject; +import org.json.JSONTokener; +import tic.frame.TICMode; +import tic.stream.identifier.SerialPortId; +import tic.stream.identifier.SerialPortName; +import tic.stream.identifier.TICStreamIdentifier; +import tic.stream.identifier.TICStreamIdentifierType; + +public final class TICStreamConfigurationLoader { + + private TICStreamConfigurationLoader() {} + + /** + * Load TIC stream configuration from a JSON file. + * + * @param filepath the path to the configuration file + * @return the loaded TIC stream configuration + * @throws IllegalStateException if there is an error loading or parsing the configuration + */ + public static TICStreamConfiguration load(String filepath) { + try { + String json = readFileAsString(filepath); + JSONObject rootObject = new JSONObject(new JSONTokener(json)); + + TICMode ticMode = parseTicMode(rootObject); + int timeout = parseTimeout(rootObject); + TICStreamIdentifier identifier = parseIdentifier(rootObject); + + return new TICStreamConfiguration(ticMode, identifier, timeout); + } catch (NullPointerException | IOException | JSONException exception) { + throw new IllegalStateException("Unable to load TIC stream configuration", exception); + } + } + + private static final String readFileAsString(String filepath) throws IOException { + Path path = Paths.get(filepath); + return new String(Files.readAllBytes(path)); + } + + private static TICMode parseTicMode(JSONObject root) { + String modeValue = root.optString("ticMode", TICStreamConfiguration.DEFAULT_TIC_MODE.name()); + return TICMode.valueOf(modeValue.toUpperCase()); + } + + private static int parseTimeout(JSONObject root) { + int timeout = root.optInt("timeout", TICStreamConfiguration.DEFAULT_TIMEOUT); + if (timeout <= 0) { + throw new IllegalArgumentException("Timeout must be a positive integer"); + } + return timeout; + } + + private static TICStreamIdentifier parseIdentifier(JSONObject root) { + JSONObject identifierObject = root.optJSONObject("identifier"); + if (identifierObject == null) { + throw new IllegalArgumentException("TIC stream identifier is required"); + } + String typeValue = identifierObject.optString("type"); + String value = identifierObject.optString("value"); + if (typeValue.equalsIgnoreCase(TICStreamIdentifierType.PORT_NAME.name())) { + return new TICStreamIdentifier(new SerialPortName(value)); + } else if (typeValue.equalsIgnoreCase(TICStreamIdentifierType.PORT_ID.name())) { + return new TICStreamIdentifier(new SerialPortId(value)); + } else { + throw new IllegalArgumentException("Invalid TIC stream identifier type: " + typeValue); + } + } +} diff --git a/src/main/java/tic/stream/identifier/SerialPortId.java b/src/main/java/tic/stream/identifier/SerialPortId.java new file mode 100644 index 0000000..0a2f4f3 --- /dev/null +++ b/src/main/java/tic/stream/identifier/SerialPortId.java @@ -0,0 +1,30 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.stream.identifier; + +/** + * Class representing a serial port identifier by its ID. + */ +public class SerialPortId { + private String portId; + + public SerialPortId(String portId) { + this.setPortId(portId); + } + + public String getPortId() { + return portId; + } + + private void setPortId(String portId) { + if (portId == null) { + throw new IllegalArgumentException("Port ID cannot be null"); + } + this.portId = portId; + } +} diff --git a/src/main/java/tic/stream/identifier/SerialPortName.java b/src/main/java/tic/stream/identifier/SerialPortName.java new file mode 100644 index 0000000..d6b4dad --- /dev/null +++ b/src/main/java/tic/stream/identifier/SerialPortName.java @@ -0,0 +1,30 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.stream.identifier; + +/** + * Class representing a serial port identified by its name. + */ +public class SerialPortName { + private String portName; + + public SerialPortName(String portName) { + this.setPortName(portName); + } + + public String getPortName() { + return portName; + } + + private void setPortName(String portName) { + if (portName == null) { + throw new IllegalArgumentException("Port name cannot be null"); + } + this.portName = portName; + } +} diff --git a/src/main/java/tic/stream/identifier/TICStreamIdentifier.java b/src/main/java/tic/stream/identifier/TICStreamIdentifier.java new file mode 100644 index 0000000..cb7a6f6 --- /dev/null +++ b/src/main/java/tic/stream/identifier/TICStreamIdentifier.java @@ -0,0 +1,57 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.stream.identifier; + +/** Class representing a TIC stream identifier, which can be either by name or by ID. */ +public class TICStreamIdentifier { + private SerialPortName portName; + private SerialPortId portId; + private TICStreamIdentifierType type; + + public TICStreamIdentifier(SerialPortName portName) { + this.type = TICStreamIdentifierType.PORT_NAME; + this.setPortName(portName); + } + + public TICStreamIdentifier(SerialPortId portId) { + this.type = TICStreamIdentifierType.PORT_ID; + this.setPortId(portId); + } + + public String getPortName() { + return this.portName.getPortName(); + } + + public String getPortId() { + return this.portId.getPortId(); + } + + public TICStreamIdentifierType getType() { + return this.type; + } + + private void setPortName(SerialPortName portName) { + if (this.type == TICStreamIdentifierType.PORT_ID) { + throw new IllegalStateException("Cannot set port name when identifier type is PORT_ID"); + } + if (portName == null) { + throw new IllegalArgumentException("Port name cannot be null"); + } + this.portName = portName; + } + + private void setPortId(SerialPortId portId) { + if (this.type == TICStreamIdentifierType.PORT_NAME) { + throw new IllegalStateException("Cannot set port ID when identifier type is PORT_NAME"); + } + if (portId == null) { + throw new IllegalArgumentException("Port ID cannot be null"); + } + this.portId = portId; + } +} diff --git a/src/main/java/tic/stream/identifier/TICStreamIdentifierType.java b/src/main/java/tic/stream/identifier/TICStreamIdentifierType.java new file mode 100644 index 0000000..a0ce232 --- /dev/null +++ b/src/main/java/tic/stream/identifier/TICStreamIdentifierType.java @@ -0,0 +1,22 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.stream.identifier; + +/** + * Enumeration representing the types of TIC stream identifiers. + * + *

This enum defines the different ways to identify a serial port, such as by its name or ID. + * + * @author Enedis Smarties team + */ +public enum TICStreamIdentifierType { + /** Identifier type for the serial port name. */ + PORT_NAME, + /** Identifier type for the serial port ID. */ + PORT_ID; +} diff --git a/src/main/java/tic/util/ValueChecker.java b/src/main/java/tic/util/ValueChecker.java new file mode 100644 index 0000000..c0b0e0b --- /dev/null +++ b/src/main/java/tic/util/ValueChecker.java @@ -0,0 +1,69 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.util; + +/** + * Utility class for validating values such as numbers and strings. + * + *

This class provides methods to validate numerical ranges and string properties, throwing + * exceptions for invalid inputs. It is useful for ensuring data integrity in various contexts. + * + *

Common use cases include: + * + *

    + *
  • Validating numerical inputs against specified ranges + *
  • Checking for null or empty strings + *
  • Ensuring data consistency before processing + *
+ * + * @author Enedis Smarties team + */ +public class ValueChecker { + + public static Number validateNumber(Number value, String key, boolean allowNull) { + if (value == null) { + if (!allowNull) { + throw new IllegalArgumentException("Value '" + key + "' cannot be null"); + } + return null; + } + return value; + } + + public static Number validateNumber( + Number value, String key, int min, int max, boolean allowNull) { + if (value == null) { + if (!allowNull) { + throw new IllegalArgumentException("Value '" + key + "' cannot be null"); + } + return null; + } + if (value.doubleValue() < min || value.doubleValue() > max) { + throw new IllegalArgumentException( + "Value '" + key + "' must be in range [" + min + "-" + max + "], but got: " + value); + } + return value; + } + + public static String validateString( + String value, String key, boolean allowNull, boolean allowEmpty) { + if (value == null && allowNull) { + return null; + } + + if (value == null && !allowNull) { + throw new IllegalArgumentException("Value '" + key + "' cannot be null"); + } + + if (!allowEmpty && value.isEmpty()) { + throw new IllegalArgumentException("Value '" + key + "' cannot be empty"); + } + + return value; + } +} diff --git a/src/main/java/enedis/lab/util/task/Subscriber.java b/src/main/java/tic/util/codec/Codec.java similarity index 60% rename from src/main/java/enedis/lab/util/task/Subscriber.java rename to src/main/java/tic/util/codec/Codec.java index 253daec..048010f 100644 --- a/src/main/java/enedis/lab/util/task/Subscriber.java +++ b/src/main/java/tic/util/codec/Codec.java @@ -1,16 +1,14 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.util.task; - -/** - * Subscriber interface - */ -public interface Subscriber -{ - -} +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.util.codec; + +public interface Codec { + T2 encode(T1 object) throws Exception; + + T1 decode(T2 object) throws Exception; +} diff --git a/src/main/java/enedis/lab/util/message/MessageType.java b/src/main/java/tic/util/codec/JsonArrayCodec.java similarity index 53% rename from src/main/java/enedis/lab/util/message/MessageType.java rename to src/main/java/tic/util/codec/JsonArrayCodec.java index 6441f34..fe6cd73 100644 --- a/src/main/java/enedis/lab/util/message/MessageType.java +++ b/src/main/java/tic/util/codec/JsonArrayCodec.java @@ -1,21 +1,14 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.util.message; - -/** - * Message type - */ -public enum MessageType -{ - /** Event */ - EVENT, - /** Request */ - REQUEST, - /** Response */ - RESPONSE; -} +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.util.codec; + +public interface JsonArrayCodec { + Object encodeToJsonArray(T object) throws Exception; + + T decodeFromJsonArray(Object jsonArray) throws Exception; +} diff --git a/src/main/java/tic/util/codec/JsonObjectCodec.java b/src/main/java/tic/util/codec/JsonObjectCodec.java new file mode 100644 index 0000000..605f726 --- /dev/null +++ b/src/main/java/tic/util/codec/JsonObjectCodec.java @@ -0,0 +1,14 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.util.codec; + +public interface JsonObjectCodec { + Object encodeToJsonObject(T object) throws Exception; + + T decodeFromJsonObject(Object jsonObject) throws Exception; +} diff --git a/src/main/java/tic/util/codec/JsonStringCodec.java b/src/main/java/tic/util/codec/JsonStringCodec.java new file mode 100644 index 0000000..3f9c4be --- /dev/null +++ b/src/main/java/tic/util/codec/JsonStringCodec.java @@ -0,0 +1,24 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.util.codec; + +public interface JsonStringCodec { + int DEFAULT_INDENT = 2; + + default String encodeToJsonString(T object) throws Exception { + return encodeToJsonString(object, DEFAULT_INDENT); + } + + default T decodeFromJsonString(String jsonString) throws Exception { + return decodeFromJsonString(jsonString, DEFAULT_INDENT); + } + + String encodeToJsonString(T object, int indentFactor) throws Exception; + + T decodeFromJsonString(String jsonString, int indentFactor) throws Exception; +} diff --git a/src/main/java/tic/util/message/Event.java b/src/main/java/tic/util/message/Event.java new file mode 100644 index 0000000..87c5692 --- /dev/null +++ b/src/main/java/tic/util/message/Event.java @@ -0,0 +1,61 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.util.message; + +import java.time.LocalDateTime; + +/** + * Abstract base class for event messages. + * + *

This class represents event messages. It provides support for event-specific fields such as + * date/time and enforces the accepted message type. Subclasses can define additional event data and + * behavior. + * + *

Common use cases include: + * + *

    + *
  • Representing system or application events + *
  • Handling event notifications in the message pipeline + *
  • Extending for custom event types + *
+ * + * @author Enedis Smarties team + * @see Message + */ +public abstract class Event extends Message { + private LocalDateTime dateTime; + + /** + * Constructor setting parameters to specific values + * + * @param name + * @param dateTime + */ + public Event(String name, LocalDateTime dateTime) { + super(MessageType.EVENT, name); + this.setDateTime(dateTime); + } + + /** + * Get date time + * + * @return the date time + */ + public LocalDateTime getDateTime() { + return this.dateTime; + } + + /** + * Set date time + * + * @param dateTime + */ + public void setDateTime(LocalDateTime dateTime) { + this.dateTime = dateTime; + } +} diff --git a/src/main/java/tic/util/message/Message.java b/src/main/java/tic/util/message/Message.java new file mode 100644 index 0000000..3384b96 --- /dev/null +++ b/src/main/java/tic/util/message/Message.java @@ -0,0 +1,76 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.util.message; + +/** + * Base class for all messages. + * + *

This class provides the core structure for messages, including type and name fields. It can be + * extended for specific message types such as requests, responses, and events. + * + *

Common use cases include: + * + *

    + *
  • Representing generic messages in the communication pipeline + *
  • Providing a base for request, response, and event messages + *
  • Supporting extensible message structures + *
+ * + * @author Enedis Smarties team + */ +public class Message { + private MessageType type; + private String name; + + /** + * Constructor setting parameters to specific values + * + * @param type + * @param name + */ + public Message(MessageType type, String name) { + this.setType(type); + this.setName(name); + } + + /** + * Get type + * + * @return the type + */ + public MessageType getType() { + return this.type; + } + + /** + * Get name + * + * @return the name + */ + public String getName() { + return this.name; + } + + /** + * Set type + * + * @param type + */ + public void setType(MessageType type) { + this.type = type; + } + + /** + * Set name + * + * @param name + */ + public void setName(String name) { + this.name = name; + } +} diff --git a/src/main/java/tic/util/message/MessageType.java b/src/main/java/tic/util/message/MessageType.java new file mode 100644 index 0000000..d1f8831 --- /dev/null +++ b/src/main/java/tic/util/message/MessageType.java @@ -0,0 +1,31 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.util.message; + +/** + * Enumeration of message types. + * + *

This enum defines the supported message types, including events, requests, and responses. It + * is used to categorize messages and control their processing in the communication pipeline. + * + *

    + *
  • {@link #EVENT} - Event messages + *
  • {@link #REQUEST} - Request messages + *
  • {@link #RESPONSE} - Response messages + *
+ * + * @author Enedis Smarties team + */ +public enum MessageType { + /** Event */ + EVENT, + /** Request */ + REQUEST, + /** Response */ + RESPONSE; +} diff --git a/src/main/java/tic/util/message/Request.java b/src/main/java/tic/util/message/Request.java new file mode 100644 index 0000000..ddfc154 --- /dev/null +++ b/src/main/java/tic/util/message/Request.java @@ -0,0 +1,37 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.util.message; + +/** + * Abstract base class for request messages. + * + *

This class represents request messages. It enforces the accepted message type and provides + * support for request-specific fields. Subclasses can define additional request data and behavior. + * + *

Common use cases include: + * + *

    + *
  • Representing client requests for data or actions + *
  • Handling request validation and processing + *
  • Extending for custom request types + *
+ * + * @author Enedis Smarties team + * @see Message + */ +public abstract class Request extends Message { + + /** + * Constructor setting parameters to specific values + * + * @param name + */ + public Request(String name) { + super(MessageType.REQUEST, name); + } +} diff --git a/src/main/java/tic/util/message/Response.java b/src/main/java/tic/util/message/Response.java new file mode 100644 index 0000000..9abd34b --- /dev/null +++ b/src/main/java/tic/util/message/Response.java @@ -0,0 +1,105 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.util.message; + +import java.time.LocalDateTime; + +/** + * Abstract base class for response messages. + * + *

This class represents response messages. It provides support for response-specific fields such + * as date/time, error code, and error message, and enforces the accepted message type. Subclasses + * can define additional response data and behavior. + * + *

Common use cases include: + * + *

    + *
  • Representing server responses to client requests + *
  • Handling error reporting and status information + *
  • Extending for custom response types + *
+ * + * @author Enedis Smarties team + * @see Message + */ +public abstract class Response extends Message { + private LocalDateTime dateTime; + private Number errorCode; + private String errorMessage; + + /** + * Constructor setting parameters to specific values + * + * @param name + * @param dateTime + * @param errorCode + * @param errorMessage + */ + public Response( + String name, LocalDateTime dateTime, Number errorCode, String errorMessage) { + super(MessageType.RESPONSE, name); + + this.setDateTime(dateTime); + this.setErrorCode(errorCode); + this.setErrorMessage(errorMessage); + } + + /** + * Get date time + * + * @return the date time + */ + public LocalDateTime getDateTime() { + return this.dateTime; + } + + /** + * Get error code + * + * @return the error code + */ + public Number getErrorCode() { + return this.errorCode; + } + + /** + * Get error message + * + * @return the error message + */ + public String getErrorMessage() { + return this.errorMessage; + } + + /** + * Set date time + * + * @param dateTime + */ + public void setDateTime(LocalDateTime dateTime) { + this.dateTime = dateTime; + } + + /** + * Set error code + * + * @param errorCode + */ + public void setErrorCode(Number errorCode) { + this.errorCode = errorCode; + } + + /** + * Set error message + * + * @param errorMessage + */ + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } +} diff --git a/src/main/java/tic/util/message/ResponseWithData.java b/src/main/java/tic/util/message/ResponseWithData.java new file mode 100644 index 0000000..b393331 --- /dev/null +++ b/src/main/java/tic/util/message/ResponseWithData.java @@ -0,0 +1,42 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.util.message; + +import java.time.LocalDateTime; + +public abstract class ResponseWithData extends Response { + + /** + * Constructor setting parameters to specific values + * + * @param name + * @param dateTime + * @param errorCode + * @param errorMessage + * @param data + */ + public ResponseWithData( + String name, LocalDateTime dateTime, Number errorCode, String errorMessage, T data) { + super(name, dateTime, errorCode, errorMessage); + this.setData(data); + } + + /** + * Get data + * + * @return the data + */ + public abstract T getData(); + + /** + * Set data + * + * @param data + */ + public abstract void setData(T data); +} diff --git a/src/main/java/tic/util/message/codec/EventJsonEncoder.java b/src/main/java/tic/util/message/codec/EventJsonEncoder.java new file mode 100644 index 0000000..b6cb118 --- /dev/null +++ b/src/main/java/tic/util/message/codec/EventJsonEncoder.java @@ -0,0 +1,63 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.util.message.codec; + +import org.json.JSONObject; +import tic.core.TICCoreError; +import tic.core.TICCoreFrame; +import tic.core.codec.TICIdentifierCodec; +import tic.frame.codec.TICFrameSummarizedCodec; +import tic.service.message.EventOnError; +import tic.service.message.EventOnTICData; +import tic.util.message.Event; + +public class EventJsonEncoder { + private static TICIdentifierCodec ticIdentifierCodec = TICIdentifierCodec.getInstance(); + private static TICFrameSummarizedCodec ticFrameSummarizedCodec = TICFrameSummarizedCodec.getInstance(); + + private EventJsonEncoder() {} + + public static JSONObject encode(Event message, JSONObject jsonMessage) { + jsonMessage.put("datetime", message.getDateTime().toString()); + + switch (message.getName()) { + case EventOnError.NAME: + return encodeEventOnError((EventOnError) message, jsonMessage); + case EventOnTICData.NAME: + return encodeEventOnTICData((EventOnTICData) message, jsonMessage); + default: + return jsonMessage; + } + } + + private static JSONObject encodeEventOnError(EventOnError message, JSONObject jsonMessage) { + TICCoreError error = message.getData(); + jsonMessage.put("identifier", ticIdentifierCodec.encodeToJsonObject(error.getIdentifier())); + jsonMessage.put("errorCode", error.getErrorCode()); + jsonMessage.put("errorMessage", error.getErrorMessage()); + try { + jsonMessage.put("frame", ticFrameSummarizedCodec.encodeToJsonObject(error.getFrame())); + } catch (Exception e) { + jsonMessage.put("frame", JSONObject.NULL); + } + return jsonMessage; + } + + private static JSONObject encodeEventOnTICData(EventOnTICData message, JSONObject jsonMessage) { + TICCoreFrame frame = message.getData(); + jsonMessage.put("identifier", ticIdentifierCodec.encodeToJsonObject(frame.getIdentifier())); + jsonMessage.put("mode", frame.getMode().toString()); + jsonMessage.put("captureDateTime", frame.getCaptureDateTime().toString()); + try { + jsonMessage.put("frame", ticFrameSummarizedCodec.encodeToJsonObject(frame.getFrame())); + } catch (Exception e) { + jsonMessage.put("frame", JSONObject.NULL); + } + return jsonMessage; + } +} diff --git a/src/main/java/tic/util/message/codec/MessageJsonCodec.java b/src/main/java/tic/util/message/codec/MessageJsonCodec.java new file mode 100644 index 0000000..13e3781 --- /dev/null +++ b/src/main/java/tic/util/message/codec/MessageJsonCodec.java @@ -0,0 +1,100 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.util.message.codec; + +import org.json.JSONObject; +import tic.util.codec.JsonObjectCodec; +import tic.util.codec.JsonStringCodec; +import tic.util.message.Event; +import tic.util.message.Message; +import tic.util.message.Request; +import tic.util.message.Response; +import tic.util.message.exception.MessageException; +import tic.util.message.exception.MessageInvalidFormatException; +import tic.util.message.exception.UnsupportedMessageException; + +/** + * Codec for encoding and decoding Message objects to and from JSON format. + * + *

This codec supports serialization of various Message types, including Event, Request, and + * Response, into JSON objects and strings. It also handles deserialization from JSON back into the + * appropriate Message subclass based on the message name and type. + * + *

Usage examples: + * + *

    + *
  • Encoding a Message to a JSON string for transmission or storage + *
  • Decoding a JSON string received from a network or file into a Message object + *
  • Handling different Message types with specific encoding/decoding logic + *
+ * + * @author Enedis Smarties team + */ +public class MessageJsonCodec implements JsonObjectCodec, JsonStringCodec { + + private static MessageJsonCodec instance = null; + + public static MessageJsonCodec getInstance() { + if (instance == null) { + return new MessageJsonCodec(); + } + return instance; + } + + private MessageJsonCodec() {} + + @Override + public String encodeToJsonString(Message object, int indentFactor) throws Exception { + JSONObject jsonObject = encodeToJsonObject(object); + return jsonObject.toString(indentFactor); + } + + @Override + public Message decodeFromJsonString(String jsonString, int indentFactor) throws Exception { + if (jsonString == null || jsonString.isEmpty()) { + throw new MessageInvalidFormatException("Input JSON string is null or empty"); + } + + JSONObject jsonObject = null; + + try { + jsonObject = new JSONObject(jsonString); + } catch (Exception e) { + throw new MessageInvalidFormatException("Input is not a valid JSON string", e); + } + + return decodeFromJsonObject(jsonObject); + } + + @Override + public JSONObject encodeToJsonObject(Message message) { + JSONObject jsonMessage = new JSONObject(); + jsonMessage.put("name", message.getName()); + jsonMessage.put("type", message.getType().toString()); + + switch (message.getType()) { + case EVENT: + return EventJsonEncoder.encode((Event) message, jsonMessage); + case REQUEST: + return RequestJsonEncoder.encode((Request) message, jsonMessage); + case RESPONSE: + return ResponseJsonEncoder.encode((Response) message, jsonMessage); + default: + return jsonMessage; + } + } + + @Override + public Message decodeFromJsonObject(Object object) throws MessageException { + try { + return RequestJsonDecoder.decode(object); + } catch (Exception e) { + throw new UnsupportedMessageException("Failed to decode Message from JSON object", e); + } + } +} diff --git a/src/main/java/tic/util/message/codec/RequestJsonDecoder.java b/src/main/java/tic/util/message/codec/RequestJsonDecoder.java new file mode 100644 index 0000000..9a5d3a2 --- /dev/null +++ b/src/main/java/tic/util/message/codec/RequestJsonDecoder.java @@ -0,0 +1,127 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.util.message.codec; + +import java.util.Collections; +import java.util.List; +import org.json.JSONArray; +import org.json.JSONObject; +import tic.core.TICIdentifier; +import tic.core.codec.TICIdentifierCodec; +import tic.service.message.RequestGetAvailableTICs; +import tic.service.message.RequestGetModemsInfo; +import tic.service.message.RequestReadTIC; +import tic.service.message.RequestSubscribeTIC; +import tic.service.message.RequestUnsubscribeTIC; +import tic.util.message.Message; +import tic.util.message.MessageType; +import tic.util.message.exception.MessageException; +import tic.util.message.exception.MessageInvalidContentException; +import tic.util.message.exception.MessageInvalidFormatException; +import tic.util.message.exception.MessageInvalidTypeException; +import tic.util.message.exception.MessageKeyNameDoesntExistException; + +public class RequestJsonDecoder { + + private RequestJsonDecoder() {} + + public static Message decode(Object object) throws Exception { + if (object == null || object instanceof JSONObject == false) { + throw new MessageInvalidFormatException("Input is not a valid JSON object"); + } + + JSONObject jsonObject = (JSONObject) object; + + if (!jsonObject.has("name") || !jsonObject.has("type")) { + throw new MessageInvalidContentException( + "JSON object missing required fields 'name' or 'type'"); + } + + String type = jsonObject.getString("type"); + if (!type.equals(MessageType.REQUEST.name())) { + throw new MessageInvalidTypeException("Invalid message type: " + type); + } + + Message message; + + String name = jsonObject.getString("name"); + switch (name) { + case RequestGetAvailableTICs.NAME: + message = decodeGetAvailableTICs(jsonObject); + break; + case RequestGetModemsInfo.NAME: + message = decodeGetModemsInfo(jsonObject); + break; + case RequestReadTIC.NAME: + message = decodeReadTIC(jsonObject); + break; + case RequestSubscribeTIC.NAME: + message = decodeSubscribeTIC(jsonObject); + break; + case RequestUnsubscribeTIC.NAME: + message = decodeUnsubscribeTIC(jsonObject); + break; + default: + throw new MessageKeyNameDoesntExistException("Unsupported request message name: " + name); + } + return message; + } + + private static Message decodeGetAvailableTICs(JSONObject jsonObject) { + return new RequestGetAvailableTICs(); + } + + private static Message decodeGetModemsInfo(JSONObject jsonObject) { + return new RequestGetModemsInfo(); + } + + private static Message decodeReadTIC(JSONObject jsonObject) throws MessageException { + if (!jsonObject.has("data")) { + throw new MessageInvalidContentException( + "JSON object missing required field 'data' for ReadTIC request"); + } + JSONObject dataObject = jsonObject.getJSONObject("data"); + return new RequestReadTIC(TICIdentifierCodec.getInstance().decodeFromJsonObject(dataObject)); + } + + private static Message decodeSubscribeTIC(JSONObject jsonObject) throws MessageException { + return new RequestSubscribeTIC(decodeOptionalTICIdentifierList(jsonObject)); + } + + private static Message decodeUnsubscribeTIC(JSONObject jsonObject) throws MessageException { + return new RequestUnsubscribeTIC(decodeOptionalTICIdentifierList(jsonObject)); + } + + private static List decodeOptionalTICIdentifierList(JSONObject jsonObject) + throws MessageException { + if (jsonObject == null || !jsonObject.has("data") || jsonObject.isNull("data")) { + return null; + } + + Object dataValue = jsonObject.opt("data"); + if (dataValue == null || dataValue == JSONObject.NULL) { + return null; + } + + try { + if (dataValue instanceof JSONArray) { + return TICIdentifierCodec.getInstance().decodeFromJsonArray(dataValue); + } + if (dataValue instanceof JSONObject) { + TICIdentifier identifier = TICIdentifierCodec.getInstance().decodeFromJsonObject(dataValue); + return Collections.singletonList(identifier); + } + } catch (IllegalArgumentException e) { + throw new MessageInvalidFormatException("Invalid 'data' field: " + e.getMessage(), e); + } + + throw new MessageInvalidFormatException( + "Invalid 'data' field: expected an array of TICIdentifier or a single TICIdentifier" + + " object"); + } +} diff --git a/src/main/java/tic/util/message/codec/RequestJsonEncoder.java b/src/main/java/tic/util/message/codec/RequestJsonEncoder.java new file mode 100644 index 0000000..68b27df --- /dev/null +++ b/src/main/java/tic/util/message/codec/RequestJsonEncoder.java @@ -0,0 +1,60 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.util.message.codec; + +import org.json.JSONObject; +import tic.core.TICIdentifier; +import tic.core.codec.TICIdentifierCodec; +import tic.service.message.RequestGetAvailableTICs; +import tic.service.message.RequestGetModemsInfo; +import tic.service.message.RequestReadTIC; +import tic.service.message.RequestSubscribeTIC; +import tic.service.message.RequestUnsubscribeTIC; +import tic.util.message.Request; + +public class RequestJsonEncoder { + + private static TICIdentifierCodec ticIdentifierCodec = TICIdentifierCodec.getInstance(); + + private RequestJsonEncoder() {} + + public static JSONObject encode(Request message, JSONObject jsonMessage) { + switch (message.getName()) { + case RequestGetAvailableTICs.NAME: + return jsonMessage; + case RequestGetModemsInfo.NAME: + return jsonMessage; + case RequestReadTIC.NAME: + return encodeReadTICRequest((RequestReadTIC) message, jsonMessage); + case RequestSubscribeTIC.NAME: + return encodeSubscribeTICRequest((RequestSubscribeTIC) message, jsonMessage); + case RequestUnsubscribeTIC.NAME: + return encodeUnsubscribeTICRequest((RequestUnsubscribeTIC) message, jsonMessage); + default: + return jsonMessage; + } + } + + private static JSONObject encodeReadTICRequest(RequestReadTIC message, JSONObject jsonMessage) { + TICIdentifier identifier = message.getData(); + jsonMessage.put("data", ticIdentifierCodec.encodeToJsonObject(identifier)); + return jsonMessage; + } + + private static JSONObject encodeSubscribeTICRequest( + RequestSubscribeTIC message, JSONObject jsonMessage) { + jsonMessage.put("data", ticIdentifierCodec.encodeToJsonArray(message.getData())); + return jsonMessage; + } + + private static JSONObject encodeUnsubscribeTICRequest( + RequestUnsubscribeTIC message, JSONObject jsonMessage) { + jsonMessage.put("data", ticIdentifierCodec.encodeToJsonArray(message.getData())); + return jsonMessage; + } +} diff --git a/src/main/java/tic/util/message/codec/ResponseJsonEncoder.java b/src/main/java/tic/util/message/codec/ResponseJsonEncoder.java new file mode 100644 index 0000000..0aa87ec --- /dev/null +++ b/src/main/java/tic/util/message/codec/ResponseJsonEncoder.java @@ -0,0 +1,82 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.util.message.codec; + +import org.json.JSONObject; +import tic.core.codec.TICCoreFrameCodec; +import tic.core.codec.TICIdentifierCodec; +import tic.io.modem.ModemJsonCodec; +import tic.service.message.ResponseGetAvailableTICs; +import tic.service.message.ResponseGetModemsInfo; +import tic.service.message.ResponseReadTIC; +import tic.service.message.ResponseSubscribeTIC; +import tic.service.message.ResponseUnsubscribeTIC; +import tic.util.message.Response; + +public class ResponseJsonEncoder { + + private static TICIdentifierCodec ticIdentifierCodec = TICIdentifierCodec.getInstance(); + + private ResponseJsonEncoder() {} + + public static JSONObject encode(Response message, JSONObject jsonMessage) { + jsonMessage.put("datetime", message.getDateTime().toString()); + jsonMessage.put("errorCode", message.getErrorCode()); + jsonMessage.put("errorMessage", message.getErrorMessage()); + + switch (message.getName()) { + case ResponseGetAvailableTICs.NAME: + if (message instanceof ResponseGetAvailableTICs) { + return encodeGetAvailableTICsResponse((ResponseGetAvailableTICs) message, jsonMessage); + } + return jsonMessage; + case ResponseGetModemsInfo.NAME: + if (message instanceof ResponseGetModemsInfo) { + return encodeGetModemsInfoResponse((ResponseGetModemsInfo) message, jsonMessage); + } + return jsonMessage; + case ResponseReadTIC.NAME: + if (message instanceof ResponseReadTIC) { + return encodeReadTICResponse((ResponseReadTIC) message, jsonMessage); + } + return jsonMessage; + case ResponseSubscribeTIC.NAME: + return jsonMessage; + case ResponseUnsubscribeTIC.NAME: + return jsonMessage; + default: + return jsonMessage; + } + } + + private static JSONObject encodeGetAvailableTICsResponse( + ResponseGetAvailableTICs message, JSONObject jsonMessage) { + jsonMessage.put("data", ticIdentifierCodec.encodeToJsonArray(message.getData())); + return jsonMessage; + } + + private static JSONObject encodeGetModemsInfoResponse( + ResponseGetModemsInfo message, JSONObject jsonMessage) { + try { + jsonMessage.put("data", ModemJsonCodec.getInstance().encodeToJsonArray(message.getData())); + } catch (Exception e) { + jsonMessage.put("data", JSONObject.NULL); + } + return jsonMessage; + } + + private static JSONObject encodeReadTICResponse(ResponseReadTIC message, JSONObject jsonMessage) { + try { + jsonMessage.put( + "data", TICCoreFrameCodec.getInstance().encodeToJsonObject(message.getData())); + } catch (Exception e) { + jsonMessage.put("data", JSONObject.NULL); + } + return jsonMessage; + } +} diff --git a/src/main/java/tic/util/message/exception/MessageException.java b/src/main/java/tic/util/message/exception/MessageException.java new file mode 100644 index 0000000..4561d2c --- /dev/null +++ b/src/main/java/tic/util/message/exception/MessageException.java @@ -0,0 +1,77 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.util.message.exception; + +/** + * Exception for signaling errors during message processing in the TIC2WebSocket framework. + * + *

This exception serves as the base class for all message-related errors encountered while + * parsing, validating, or handling messages. It enables robust error reporting and propagation + * throughout the message handling pipeline. + * + *

Common use cases include: + * + *

    + *
  • Reporting invalid message formats + *
  • Handling missing or unsupported message types + *
  • Signaling errors in message content or structure + *
  • Chaining underlying exceptions for debugging + *
+ * + * @author Enedis Smarties team + */ +public class MessageException extends Exception { + + private static final long serialVersionUID = -2263755971102386572L; + + /** + * Creates a new MessageException with no detail message. + * + *

This constructor is typically used when no specific error information is available. + */ + public MessageException() { + super(); + } + + /** + * Creates a new MessageException with a detail message and underlying cause. + * + *

This constructor is used when both a descriptive error message and the original cause of the + * error are available, providing complete context for debugging. + * + * @param message the detail message explaining the error + * @param cause the underlying exception that caused this error + */ + public MessageException(String message, Throwable cause) { + super(message, cause); + } + + /** + * Creates a new MessageException with a detail message. + * + *

This constructor is used when a descriptive error message is available but there is no + * underlying cause to chain. + * + * @param message the detail message explaining the error + */ + public MessageException(String message) { + super(message); + } + + /** + * Creates a new MessageException with an underlying cause. + * + *

This constructor is used when the original cause is known but no additional descriptive + * message is needed beyond what the cause provides. + * + * @param cause the underlying exception that caused this error + */ + public MessageException(Throwable cause) { + super(cause); + } +} diff --git a/src/main/java/tic/util/message/exception/MessageInvalidContentException.java b/src/main/java/tic/util/message/exception/MessageInvalidContentException.java new file mode 100644 index 0000000..f957cca --- /dev/null +++ b/src/main/java/tic/util/message/exception/MessageInvalidContentException.java @@ -0,0 +1,77 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.util.message.exception; + +/** + * Exception indicating that a message contains invalid or unexpected content. + * + *

This exception is thrown when the content of a message does not conform to the expected + * structure, contains invalid values, or fails validation during parsing or processing. It is part + * of the message exception hierarchy used to signal specific errors in communication. + * + *

Common use cases include: + * + *

    + *
  • Detecting missing or malformed fields in a message + *
  • Reporting invalid data values or types + *
  • Handling content validation failures + *
  • Chaining underlying exceptions for debugging + *
+ * + * @author Enedis Smarties team + */ +public class MessageInvalidContentException extends MessageException { + + private static final long serialVersionUID = -2263755971102386572L; + + /** + * Creates a new MessageInvalidContentException with no detail message. + * + *

This constructor is typically used when no specific error information is available. + */ + public MessageInvalidContentException() { + super(); + } + + /** + * Creates a new MessageInvalidContentException with a detail message and underlying cause. + * + *

This constructor is used when both a descriptive error message and the original cause of the + * error are available, providing complete context for debugging. + * + * @param message the detail message explaining the error + * @param cause the underlying exception that caused this error + */ + public MessageInvalidContentException(String message, Throwable cause) { + super(message, cause); + } + + /** + * Creates a new MessageInvalidContentException with a detail message. + * + *

This constructor is used when a descriptive error message is available but there is no + * underlying cause to chain. + * + * @param message the detail message explaining the error + */ + public MessageInvalidContentException(String message) { + super(message); + } + + /** + * Creates a new MessageInvalidContentException with an underlying cause. + * + *

This constructor is used when the original cause is known but no additional descriptive + * message is needed beyond what the cause provides. + * + * @param cause the underlying exception that caused this error + */ + public MessageInvalidContentException(Throwable cause) { + super(cause); + } +} diff --git a/src/main/java/tic/util/message/exception/MessageInvalidFormatException.java b/src/main/java/tic/util/message/exception/MessageInvalidFormatException.java new file mode 100644 index 0000000..c87bf0b --- /dev/null +++ b/src/main/java/tic/util/message/exception/MessageInvalidFormatException.java @@ -0,0 +1,77 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.util.message.exception; + +/** + * Exception indicating that a message has an invalid format. + * + *

This exception is thrown when a message fails to conform to the expected format, such as + * incorrect JSON structure, missing required fields, or syntactic errors during parsing. It is part + * of the message exception hierarchy used to signal specific errors in communication. + * + *

Common use cases include: + * + *

    + *
  • Detecting malformed or corrupted messages + *
  • Reporting missing or unexpected fields + *
  • Handling parsing failures due to format errors + *
  • Chaining underlying exceptions for debugging + *
+ * + * @author Enedis Smarties team + */ +public class MessageInvalidFormatException extends MessageException { + + private static final long serialVersionUID = -2263755971102386572L; + + /** + * Creates a new MessageInvalidFormatException with no detail message. + * + *

This constructor is typically used when no specific error information is available. + */ + public MessageInvalidFormatException() { + super(); + } + + /** + * Creates a new MessageInvalidFormatException with a detail message and underlying cause. + * + *

This constructor is used when both a descriptive error message and the original cause of the + * error are available, providing complete context for debugging. + * + * @param message the detail message explaining the error + * @param cause the underlying exception that caused this error + */ + public MessageInvalidFormatException(String message, Throwable cause) { + super(message, cause); + } + + /** + * Creates a new MessageInvalidFormatException with a detail message. + * + *

This constructor is used when a descriptive error message is available but there is no + * underlying cause to chain. + * + * @param message the detail message explaining the error + */ + public MessageInvalidFormatException(String message) { + super(message); + } + + /** + * Creates a new MessageInvalidFormatException with an underlying cause. + * + *

This constructor is used when the original cause is known but no additional descriptive + * message is needed beyond what the cause provides. + * + * @param cause the underlying exception that caused this error + */ + public MessageInvalidFormatException(Throwable cause) { + super(cause); + } +} diff --git a/src/main/java/tic/util/message/exception/MessageInvalidTypeException.java b/src/main/java/tic/util/message/exception/MessageInvalidTypeException.java new file mode 100644 index 0000000..cdae0d3 --- /dev/null +++ b/src/main/java/tic/util/message/exception/MessageInvalidTypeException.java @@ -0,0 +1,77 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.util.message.exception; + +/** + * Exception indicating that a message has an invalid or unsupported type. + * + *

This exception is thrown when a message specifies a type that is not recognized, not + * supported, or does not match the expected types during parsing or processing. It is part of the + * message exception hierarchy used to signal specific errors in communication. + * + *

Common use cases include: + * + *

    + *
  • Detecting unknown or unsupported message types + *
  • Reporting type mismatches in message definitions + *
  • Handling validation failures due to type errors + *
  • Chaining underlying exceptions for debugging + *
+ * + * @author Enedis Smarties team + */ +public class MessageInvalidTypeException extends MessageException { + + private static final long serialVersionUID = -2263755971102386572L; + + /** + * Creates a new MessageInvalidTypeException with no detail message. + * + *

This constructor is typically used when no specific error information is available. + */ + public MessageInvalidTypeException() { + super(); + } + + /** + * Creates a new MessageInvalidTypeException with a detail message and underlying cause. + * + *

This constructor is used when both a descriptive error message and the original cause of the + * error are available, providing complete context for debugging. + * + * @param message the detail message explaining the error + * @param cause the underlying exception that caused this error + */ + public MessageInvalidTypeException(String message, Throwable cause) { + super(message, cause); + } + + /** + * Creates a new MessageInvalidTypeException with a detail message. + * + *

This constructor is used when a descriptive error message is available but there is no + * underlying cause to chain. + * + * @param message the detail message explaining the error + */ + public MessageInvalidTypeException(String message) { + super(message); + } + + /** + * Creates a new MessageInvalidTypeException with an underlying cause. + * + *

This constructor is used when the original cause is known but no additional descriptive + * message is needed beyond what the cause provides. + * + * @param cause the underlying exception that caused this error + */ + public MessageInvalidTypeException(Throwable cause) { + super(cause); + } +} diff --git a/src/main/java/tic/util/message/exception/MessageKeyNameDoesntExistException.java b/src/main/java/tic/util/message/exception/MessageKeyNameDoesntExistException.java new file mode 100644 index 0000000..f005023 --- /dev/null +++ b/src/main/java/tic/util/message/exception/MessageKeyNameDoesntExistException.java @@ -0,0 +1,77 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.util.message.exception; + +/** + * Exception indicating that a required message key name does not exist. + * + *

This exception is thrown when a message references a key name that is missing, undefined, or + * not recognized during parsing or processing. It is part of the message exception hierarchy used + * to signal specific errors in communication. + * + *

Common use cases include: + * + *

    + *
  • Detecting missing key names in message definitions + *
  • Reporting undefined or unrecognized keys + *
  • Handling validation failures due to absent keys + *
  • Chaining underlying exceptions for debugging + *
+ * + * @author Enedis Smarties team + */ +public class MessageKeyNameDoesntExistException extends MessageException { + + private static final long serialVersionUID = -2263755971102386572L; + + /** + * Creates a new MessageKeyNameDoesntExistException with no detail message. + * + *

This constructor is typically used when no specific error information is available. + */ + public MessageKeyNameDoesntExistException() { + super(); + } + + /** + * Creates a new MessageKeyNameDoesntExistException with a detail message and underlying cause. + * + *

This constructor is used when both a descriptive error message and the original cause of the + * error are available, providing complete context for debugging. + * + * @param message the detail message explaining the error + * @param cause the underlying exception that caused this error + */ + public MessageKeyNameDoesntExistException(String message, Throwable cause) { + super(message, cause); + } + + /** + * Creates a new MessageKeyNameDoesntExistException with a detail message. + * + *

This constructor is used when a descriptive error message is available but there is no + * underlying cause to chain. + * + * @param message the detail message explaining the error + */ + public MessageKeyNameDoesntExistException(String message) { + super(message); + } + + /** + * Creates a new MessageKeyNameDoesntExistException with an underlying cause. + * + *

This constructor is used when the original cause is known but no additional descriptive + * message is needed beyond what the cause provides. + * + * @param cause the underlying exception that caused this error + */ + public MessageKeyNameDoesntExistException(Throwable cause) { + super(cause); + } +} diff --git a/src/main/java/tic/util/message/exception/MessageKeyTypeDoesntExistException.java b/src/main/java/tic/util/message/exception/MessageKeyTypeDoesntExistException.java new file mode 100644 index 0000000..104d014 --- /dev/null +++ b/src/main/java/tic/util/message/exception/MessageKeyTypeDoesntExistException.java @@ -0,0 +1,77 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.util.message.exception; + +/** + * Exception indicating that a required message key type does not exist. + * + *

This exception is thrown when a message references a key type that is missing, undefined, or + * not recognized during parsing or processing. It is part of the message exception hierarchy used + * to signal specific errors in communication. + * + *

Common use cases include: + * + *

    + *
  • Detecting missing key types in message definitions + *
  • Reporting undefined or unrecognized key types + *
  • Handling validation failures due to absent key types + *
  • Chaining underlying exceptions for debugging + *
+ * + * @author Enedis Smarties team + */ +public class MessageKeyTypeDoesntExistException extends MessageException { + + private static final long serialVersionUID = -2263755971102386572L; + + /** + * Creates a new MessageKeyTypeDoesntExistException with no detail message. + * + *

This constructor is typically used when no specific error information is available. + */ + public MessageKeyTypeDoesntExistException() { + super(); + } + + /** + * Creates a new MessageKeyTypeDoesntExistException with a detail message and underlying cause. + * + *

This constructor is used when both a descriptive error message and the original cause of the + * error are available, providing complete context for debugging. + * + * @param message the detail message explaining the error + * @param cause the underlying exception that caused this error + */ + public MessageKeyTypeDoesntExistException(String message, Throwable cause) { + super(message, cause); + } + + /** + * Creates a new MessageKeyTypeDoesntExistException with a detail message. + * + *

This constructor is used when a descriptive error message is available but there is no + * underlying cause to chain. + * + * @param message the detail message explaining the error + */ + public MessageKeyTypeDoesntExistException(String message) { + super(message); + } + + /** + * Creates a new MessageKeyTypeDoesntExistException with an underlying cause. + * + *

This constructor is used when the original cause is known but no additional descriptive + * message is needed beyond what the cause provides. + * + * @param cause the underlying exception that caused this error + */ + public MessageKeyTypeDoesntExistException(Throwable cause) { + super(cause); + } +} diff --git a/src/main/java/tic/util/message/exception/UnsupportedMessageException.java b/src/main/java/tic/util/message/exception/UnsupportedMessageException.java new file mode 100644 index 0000000..1cfd985 --- /dev/null +++ b/src/main/java/tic/util/message/exception/UnsupportedMessageException.java @@ -0,0 +1,77 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.util.message.exception; + +/** + * Exception indicating that a message type or operation is unsupported. + * + *

This exception is thrown when a message specifies a type, operation, or feature that is not + * supported by the current implementation. It is part of the message exception hierarchy used to + * signal specific errors in communication. + * + *

Common use cases include: + * + *

    + *
  • Detecting unsupported message types or operations + *
  • Reporting attempts to use unimplemented features + *
  • Handling validation failures due to unsupported requests + *
  • Chaining underlying exceptions for debugging + *
+ * + * @author Enedis Smarties team + */ +public class UnsupportedMessageException extends MessageException { + + private static final long serialVersionUID = -2263755971102386572L; + + /** + * Creates a new UnsupportedMessageException with no detail message. + * + *

This constructor is typically used when no specific error information is available. + */ + public UnsupportedMessageException() { + super(); + } + + /** + * Creates a new UnsupportedMessageException with a detail message and underlying cause. + * + *

This constructor is used when both a descriptive error message and the original cause of the + * error are available, providing complete context for debugging. + * + * @param message the detail message explaining the error + * @param cause the underlying exception that caused this error + */ + public UnsupportedMessageException(String message, Throwable cause) { + super(message, cause); + } + + /** + * Creates a new UnsupportedMessageException with a detail message. + * + *

This constructor is used when a descriptive error message is available but there is no + * underlying cause to chain. + * + * @param message the detail message explaining the error + */ + public UnsupportedMessageException(String message) { + super(message); + } + + /** + * Creates a new UnsupportedMessageException with an underlying cause. + * + *

This constructor is used when the original cause is known but no additional descriptive + * message is needed beyond what the cause provides. + * + * @param cause the underlying exception that caused this error + */ + public UnsupportedMessageException(Throwable cause) { + super(cause); + } +} diff --git a/src/main/java/tic/util/task/FilteredNotifier.java b/src/main/java/tic/util/task/FilteredNotifier.java new file mode 100644 index 0000000..30422a7 --- /dev/null +++ b/src/main/java/tic/util/task/FilteredNotifier.java @@ -0,0 +1,106 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.util.task; + +import java.util.Collection; +import java.util.function.Predicate; + +/** + * Interface for managing filtered notifications to subscribers. + * + *

This interface defines methods for subscribing, unsubscribing, and querying subscribers with + * associated filters. It supports flexible event delivery and observer patterns. + * + *

Common use cases include: + * + *

    + *
  • Selective event delivery based on filters + *
  • Managing filtered lists of subscribers + *
  • Supporting custom notification logic + *
+ * + * @param the filter type + * @param the subscriber type + */ +public interface FilteredNotifier extends Notifier { + /** + * Add a subscriber with filter + * + * @param filter the filter used for subscription + * @param listener the subscriber reference + * @throws Exception on subscription failure + */ + public void subscribe(F filter, T listener) throws Exception; + + /** + * Remove a subscriber with filter + * + * @param filter the filter used for subscription + * @param listener the subscriber reference + * @throws Exception if filter or listener not found + */ + public void unsubscribe(F filter, T listener) throws Exception; + + /** + * Check if the given filter has a given subscriber + * + * @param filter the filter used for subscription + * @param listener the subscriber reference + * @return true if the given subscriber exists + */ + public boolean hasSubscriber(F filter, T listener); + + /** + * Get subscribers associated with filter + * + * @param filter the filter used for subscription + * @return The subscribers collection + */ + public Collection getSubscribers(F filter); + + /** + * Get subscribers including global and/or filters + * + * @param includeGlobal indicates if includes global subscribers + * @param includeFilter indicates if includes filters subscribers + * @return The subscribers collection + */ + public Collection getSubscribers(boolean includeGlobal, boolean includeFilter); + + /** + * Get subscribers associated with predicate filter + * + * @param predicate the predicate used to test with filters used for subscription + * @param includeGlobal indicates if includes global subscribers + * @return The subscribers collection + */ + public Collection getSubscribers(Predicate predicate, boolean includeGlobal); + + /** + * Check if the given filter has been set + * + * @param filter the filter used for subscription + * @return true if the given filter exists + */ + public boolean hasFilter(F filter); + + /** + * Get filters + * + * @return The filters collection + */ + public Collection getFilters(); + + /** + * Get filters associated with listener + * + * @param listener the subscriber reference + * @return The filters collection + */ + public Collection getFilters(T listener); +} diff --git a/src/main/java/tic/util/task/FilteredNotifierBase.java b/src/main/java/tic/util/task/FilteredNotifierBase.java new file mode 100644 index 0000000..8c6670c --- /dev/null +++ b/src/main/java/tic/util/task/FilteredNotifierBase.java @@ -0,0 +1,218 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.util.task; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArraySet; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; +import java.util.function.Predicate; + +/** + * Generic base implementation for managing filtered notifications to subscribers. + * + *

This class provides mechanisms for subscribing, unsubscribing, and querying subscribers with + * associated filters. It supports both filtered and unfiltered (global) subscriptions, enabling + * flexible event delivery and observer patterns. + * + *

Common use cases include: + * + *

    + *
  • Delivering events to subscribers that match specific filters + *
  • Supporting selective notification in observer patterns + *
  • Extending for custom filtering logic + *
+ * + * @param the filter type + * @param the subscriber type + */ +public class FilteredNotifierBase implements FilteredNotifier { + protected Map> subscribersFiltered; + private Lock subscribersFilteredLock = new ReentrantLock(); + protected Collection subscribersUnfiltered; + private Lock subscribersUnfilteredLock = new ReentrantLock(); + + /** Default constructor */ + public FilteredNotifierBase() { + super(); + this.subscribersFiltered = new ConcurrentHashMap>(); + this.subscribersUnfiltered = new CopyOnWriteArraySet(); + } + + @Override + public void subscribe(T listener) { + if (listener == null) { + return; + } + this.subscribersUnfilteredLock.lock(); + this.subscribersUnfiltered.add(listener); + this.subscribersUnfilteredLock.unlock(); + } + + @Override + public void unsubscribe(T listener) { + if (listener == null) { + return; + } + for (F filter : this.getFilters()) { + this.unsubscribe(filter, listener); + } + this.subscribersUnfilteredLock.lock(); + this.subscribersUnfiltered.remove(listener); + this.subscribersUnfilteredLock.unlock(); + } + + @Override + public boolean hasSubscriber(T listener) { + for (F filter : this.getFilters()) { + if (this.hasSubscriber(filter, listener)) { + return true; + } + } + + this.subscribersUnfilteredLock.lock(); + boolean hasSubscriber = this.subscribersUnfiltered.contains(listener); + this.subscribersUnfilteredLock.unlock(); + + return hasSubscriber; + } + + @Override + public Collection getSubscribers() { + return this.getSubscribers(true, true); + } + + @Override + public void subscribe(F filter, T listener) { + if (filter == null || listener == null) { + return; + } + Collection subscribers; + if (this.hasFilter(filter)) { + subscribers = this.getSubscribers(filter); + if (!subscribers.contains(listener)) { + subscribers.add(listener); + } + } else { + subscribers = new HashSet(); + subscribers.add(listener); + } + this.subscribersFilteredLock.lock(); + this.subscribersFiltered.put(filter, subscribers); + this.subscribersFilteredLock.unlock(); + } + + @Override + public void unsubscribe(F filter, T listener) { + if (filter == null || listener == null) { + return; + } + Collection subscribers = this.getSubscribers(filter); + if (subscribers.contains(listener)) { + subscribers.remove(listener); + if (subscribers.size() == 0) { + this.subscribersFilteredLock.lock(); + this.subscribersFiltered.remove(filter); + this.subscribersFilteredLock.unlock(); + } + } + } + + @Override + public boolean hasSubscriber(F filter, T listener) { + Collection subscribers = this.getSubscribers(filter); + + return subscribers.contains(listener); + } + + @Override + public Collection getSubscribers(F filter) { + this.subscribersFilteredLock.lock(); + Collection subscribersFiltered = + (this.hasFilter(filter)) ? this.subscribersFiltered.get(filter) : new HashSet(); + this.subscribersFilteredLock.unlock(); + + return subscribersFiltered; + } + + @Override + public Collection getSubscribers(boolean includeGlobal, boolean includeFilter) { + Collection subscribers = new HashSet(); + + if (includeFilter) { + for (F filter : this.getFilters()) { + Collection filterSubscribers = this.getSubscribers(filter); + subscribers.addAll(filterSubscribers); + } + } + if (includeGlobal) { + this.subscribersUnfilteredLock.lock(); + subscribers.addAll(this.subscribersUnfiltered); + this.subscribersUnfilteredLock.unlock(); + } + + return subscribers; + } + + @Override + public Collection getSubscribers(Predicate predicate, boolean includeGlobal) { + Collection subscribers = new HashSet(); + + if (predicate != null) { + this.subscribersFilteredLock.lock(); + for (F filter : this.subscribersFiltered.keySet()) { + if (predicate.test(filter)) { + subscribers.addAll(this.subscribersFiltered.get(filter)); + } + } + this.subscribersFilteredLock.unlock(); + } + if (includeGlobal) { + this.subscribersUnfilteredLock.lock(); + subscribers.addAll(this.subscribersUnfiltered); + this.subscribersUnfilteredLock.unlock(); + } + + return subscribers; + } + + @Override + public boolean hasFilter(F filter) { + this.subscribersFilteredLock.lock(); + boolean hasFilter = (filter != null) ? this.subscribersFiltered.containsKey(filter) : false; + this.subscribersFilteredLock.unlock(); + + return hasFilter; + } + + @Override + public Collection getFilters() { + this.subscribersFilteredLock.lock(); + Collection subscribersFiltered = this.subscribersFiltered.keySet(); + this.subscribersFilteredLock.unlock(); + + return subscribersFiltered; + } + + @Override + public Collection getFilters(T listener) { + Collection filters = new HashSet(); + + for (F filter : this.getFilters()) { + Collection subscribers = this.getSubscribers(filter); + if (subscribers.contains(listener)) { + filters.add(filter); + } + } + + return filters; + } +} diff --git a/src/main/java/tic/util/task/Notifier.java b/src/main/java/tic/util/task/Notifier.java new file mode 100644 index 0000000..21e3894 --- /dev/null +++ b/src/main/java/tic/util/task/Notifier.java @@ -0,0 +1,58 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.util.task; + +import java.util.Collection; + +/** + * Interface for managing subscribers and sending notifications. + * + *

This interface defines methods for adding, removing, and querying subscribers, as well as + * retrieving the current set of subscribers. It is used as a generic contract for event-driven and + * observer patterns. + * + *

Common use cases include: + * + *

    + *
  • Managing lists of listeners or observers + *
  • Sending notifications to registered subscribers + *
  • Supporting event-driven architectures + *
+ * + * @param the subscriber type + */ +public interface Notifier { + /** + * Add a subscriber + * + * @param subscriber + */ + public void subscribe(T subscriber); + + /** + * Remove a subscriber + * + * @param subscriber + */ + public void unsubscribe(T subscriber); + + /** + * Check if the given subscriber has been added + * + * @param subscriber + * @return true if the given subscriber has been added + */ + public boolean hasSubscriber(T subscriber); + + /** + * Get subscribers + * + * @return The subscribers collection + */ + public Collection getSubscribers(); +} diff --git a/src/main/java/tic/util/task/NotifierBase.java b/src/main/java/tic/util/task/NotifierBase.java new file mode 100644 index 0000000..1a761ed --- /dev/null +++ b/src/main/java/tic/util/task/NotifierBase.java @@ -0,0 +1,62 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.util.task; + +import java.util.Collection; +import java.util.Set; +import java.util.concurrent.CopyOnWriteArraySet; + +/** + * Generic base implementation for managing subscribers and sending notifications. + * + *

This class provides mechanisms for adding, removing, and querying subscribers. It is used as a + * foundation for event-driven and observer patterns, supporting flexible notification delivery. + * + *

Common use cases include: + * + *

    + *
  • Managing lists of listeners or observers + *
  • Sending notifications to registered subscribers + *
  • Extending for custom notification logic + *
+ * + * @param the subscriber type + */ +public class NotifierBase implements Notifier { + protected Set subscribers; + + /** Default constructor */ + public NotifierBase() { + super(); + this.subscribers = new CopyOnWriteArraySet(); + } + + @Override + public void subscribe(T listener) { + if (listener != null && !this.subscribers.contains(listener)) { + this.subscribers.add(listener); + } + } + + @Override + public void unsubscribe(T listener) { + if (listener != null && this.subscribers.contains(listener)) { + this.subscribers.remove(listener); + } + } + + @Override + public boolean hasSubscriber(T listener) { + return this.subscribers.contains(listener); + } + + @Override + public Collection getSubscribers() { + return this.subscribers; + } +} diff --git a/src/main/java/tic/util/task/Subscriber.java b/src/main/java/tic/util/task/Subscriber.java new file mode 100644 index 0000000..0aa0af2 --- /dev/null +++ b/src/main/java/tic/util/task/Subscriber.java @@ -0,0 +1,16 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.util.task; + +/** + * Interface representing a generic event subscriber. + * + *

This interface is used as a contract for objects that can receive notifications or events from + * a notifier. It is commonly used in observer and event-driven patterns. + */ +public interface Subscriber {} diff --git a/src/main/java/tic/util/task/Task.java b/src/main/java/tic/util/task/Task.java new file mode 100644 index 0000000..fe592d7 --- /dev/null +++ b/src/main/java/tic/util/task/Task.java @@ -0,0 +1,30 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.util.task; + +/** + * Interface representing a generic asynchronous task. + * + *

This interface defines the contract for executing tasks, typically in a concurrent or + * event-driven environment. Implementations may represent background jobs, scheduled actions, or + * event handlers. + */ +public interface Task { + /** Start task */ + public void start(); + + /** Stop task */ + public void stop(); + + /** + * Get the task running state + * + * @return true if the task running + */ + public boolean isRunning(); +} diff --git a/src/main/java/tic/util/task/TaskBase.java b/src/main/java/tic/util/task/TaskBase.java new file mode 100644 index 0000000..ca7417c --- /dev/null +++ b/src/main/java/tic/util/task/TaskBase.java @@ -0,0 +1,113 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.util.task; + +import java.util.concurrent.atomic.AtomicBoolean; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +/** + * Abstract base class representing a generic asynchronous task. + * + *

This class provides a foundation for implementing tasks that can be executed asynchronously, + * typically in concurrent or event-driven environments. + */ +public abstract class TaskBase implements Task, Runnable { + private AtomicBoolean stopRequired; + private Thread task; + protected static Logger logger = LogManager.getLogger(); + + /** Default constructor */ + public TaskBase() { + super(); + this.stopRequired = new AtomicBoolean(); + } + + @Override + public void start() { + if (this.task == null || !this.task.isAlive()) { + this.stopRequired.set(false); + this.task = new Thread(this); + this.task.start(); + } + } + + @Override + public void stop() { + try { + if (this.task != null && this.task.isAlive()) { + this.stopRequired.set(true); + if (this.task != Thread.currentThread()) { + this.task.join(); + } + } + } catch (InterruptedException exception) { + logger.error("Stop task interrupted", exception); + } + } + + @Override + public final boolean isRunning() { + return this.task == null ? false : this.task.isAlive(); + } + + @Override + public void run() { + this.runOnStart(); + this.runProcess(); + this.runOnTerminate(); + } + + protected final boolean isStopRequired() { + return this.stopRequired.get(); + } + + protected final void runOnStart() { + try { + this.onStart(); + } catch (Exception exception) { + logger.error("Task on start aborted", exception); + this.runOnError(exception); + } + } + + protected final void runProcess() { + try { + this.process(); + } catch (Exception exception) { + logger.error("Task process aborted", exception); + this.runOnError(exception); + } + } + + protected final void runOnTerminate() { + try { + this.onTerminate(); + } catch (Exception exception) { + logger.error("Task on terminate aborted", exception); + this.runOnError(exception); + } + } + + protected final void runOnError(Exception exception) { + try { + this.onError(exception); + } catch (Exception onErrorException) { + logger.error("Task on error aborted", exception); + } + } + + /** Task core process method */ + protected abstract void process(); + + protected void onStart() {} + + protected void onTerminate() {} + + protected void onError(Exception exception) {} +} diff --git a/src/main/java/tic/util/task/TaskPeriodic.java b/src/main/java/tic/util/task/TaskPeriodic.java new file mode 100644 index 0000000..5431365 --- /dev/null +++ b/src/main/java/tic/util/task/TaskPeriodic.java @@ -0,0 +1,83 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.util.task; + +import java.util.concurrent.atomic.AtomicLong; +import tic.util.time.Time; + +/** + * Abstract class representing a generic periodic asynchronous task. + * + *

This class provides functionality for executing tasks at regular intervals, typically used for + * background operations or scheduled actions. + */ +public abstract class TaskPeriodic extends TaskBase { + /** Default period (in milliseconds) used to execute process */ + public static final long DEFAULT_PERIOD = 1000; + + private AtomicLong period = new AtomicLong(); + + /** + * Constructor with default parameter + * + * @see #DEFAULT_PERIOD + */ + public TaskPeriodic() { + super(); + this.setPeriod(DEFAULT_PERIOD); + } + + /** + * Constructor with polling period + * + * @param period the period (in milliseconds) used to execute process + */ + public TaskPeriodic(long period) { + super(); + this.setPeriod(period); + } + + @Override + public void run() { + this.runOnStart(); + while (!this.isStopRequired()) { + this.runProcess(); + if (this.isStopRequired()) { + break; + } + this.waitPeriod(); + } + this.runOnTerminate(); + } + + /** + * Get polling period + * + * @return The period (in milliseconds) used to execute process + */ + public long getPeriod() { + return this.period.get(); + } + + /** + * Set the polling period + * + * @param period the period (in milliseconds) used to execute process + * @throws IllegalArgumentException if period <= 0 + */ + public void setPeriod(long period) { + if (period <= 0) { + throw new IllegalArgumentException("Cannot set period " + period + " : must be > 0"); + } + this.period.set(period); + } + + private void waitPeriod() { + Time.sleep(this.getPeriod()); + } +} diff --git a/src/main/java/tic/util/task/TaskPeriodicWithSubscribers.java b/src/main/java/tic/util/task/TaskPeriodicWithSubscribers.java new file mode 100644 index 0000000..0446c26 --- /dev/null +++ b/src/main/java/tic/util/task/TaskPeriodicWithSubscribers.java @@ -0,0 +1,59 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.util.task; + +import java.util.Collection; + +/** + * Abstract class representing a generic periodic asynchronous task with subscriber notification. + * + *

This class provides functionality for executing tasks at regular intervals and notifying + * registered subscribers of events or results. + * + * @param the subscriber type + */ +public abstract class TaskPeriodicWithSubscribers extends TaskPeriodic + implements Notifier { + protected Notifier notifier; + + /** Default constructor */ + public TaskPeriodicWithSubscribers() { + super(); + this.notifier = new NotifierBase(); + } + + /** + * Constructor setting period + * + * @param period the period in milliseconds + */ + public TaskPeriodicWithSubscribers(long period) { + super(period); + this.notifier = new NotifierBase(); + } + + @Override + public void subscribe(T listener) { + this.notifier.subscribe(listener); + } + + @Override + public void unsubscribe(T listener) { + this.notifier.unsubscribe(listener); + } + + @Override + public boolean hasSubscriber(T listener) { + return this.notifier.hasSubscriber(listener); + } + + @Override + public Collection getSubscribers() { + return this.notifier.getSubscribers(); + } +} diff --git a/src/main/java/tic/util/time/Time.java b/src/main/java/tic/util/time/Time.java new file mode 100644 index 0000000..3a8e848 --- /dev/null +++ b/src/main/java/tic/util/time/Time.java @@ -0,0 +1,112 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.util.time; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; + +/** + * Utility class providing time-related constants and helper methods. + * + *

This class offers constants for time units and static methods for sleeping, formatting + * timestamps, and decorating messages with timestamps. It is designed for general-purpose time + * management and formatting. + * + *

Common use cases include: + * + *

    + *
  • Sleeping for a specified duration + *
  • Formatting timestamps as date/time strings + *
  • Decorating log messages with current date/time + *
+ * + * @author Enedis Smarties team + */ +public abstract class Time { + /** Millisecond */ + public static final int MILLISECOND = 1; + + /** Second */ + public static final int SECOND = 1000 * MILLISECOND; + + /** Minute */ + public static final int MINUTE = 60 * SECOND; + + /** Hour */ + public static final int HOUR = 60 * MINUTE; + + /** Day */ + public static final int DAY = 24 * HOUR; + + /* Default format for displaying the date/time */ + private static final String DFLT_DATETIME_FORMAT = "yyyy/MM/dd HH:mm:ss.SSS"; + + /** + * Wait the given duration in millisecond + * + * @param duration + */ + public static void sleep(long duration) { + if (duration <= 0L) { + return; + } + try { + Thread.sleep(duration); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + /** + * Convert date/time from long number (since an origin) to a string in the default format + * + * @param timestamp a long number (of milliseconds since January 1, 1970, 00:00:00 GMT) + * @return the time/date string in the default format + */ + public static String timestampToDateTimeStr(long timestamp) { + return timestampToDateTimeStr(timestamp, DFLT_DATETIME_FORMAT); + } + + /** + * Convert date/time from long number to a string in the specified format + * + * @param timestamp a long number (of milliseconds since January 1, 1970, 00:00:00 GMT) + * @param dateTimeFormatStr the format specified + * @return the time/date string in the specified format + */ + public static String timestampToDateTimeStr(long timestamp, String dateTimeFormatStr) { + DateFormat dateFormat = new SimpleDateFormat(dateTimeFormatStr); + Date date = new Date(timestamp); + return dateFormat.format(date); + } + + /** + * Timestamp a message with the current DateTime + * + * @param msg + * @return the message decorated with current DateTime + */ + public static String timestamp(String msg) { + return timestamp(msg, DFLT_DATETIME_FORMAT); + } + + /** + * Timestamp a message with the current DateTime + * + * @param msg + * @param dateTimeFormat + * @return the message decorated with current DateTime + */ + public static String timestamp(String msg, String dateTimeFormat) { + DateFormat dateFormat = new SimpleDateFormat(dateTimeFormat); + Date date = new Date(); + String text = dateFormat.format(date) + " : " + msg; + return text; + } +} diff --git a/src/main/resources/config/TICStreamConfiguration.json b/src/main/resources/config/TICStreamConfiguration.json new file mode 100644 index 0000000..6285b65 --- /dev/null +++ b/src/main/resources/config/TICStreamConfiguration.json @@ -0,0 +1,8 @@ +{ + "ticMode": "AUTO", + "timeout": 10, + "identifier": { + "type": "PORT_NAME", + "value": "COM1" + } +} diff --git a/src/main/resources/log4j2-debug.xml b/src/main/resources/log4j2-debug.xml index 8ad49b1..6b398ff 100644 --- a/src/main/resources/log4j2-debug.xml +++ b/src/main/resources/log4j2-debug.xml @@ -10,35 +10,35 @@ SPDX-License-Identifier: Apache-2.0 - ${sys:logDir:-var/log} - ${sys:logFile:-TIC2WebSocket} + ${sys:logDir:-var/log} + ${sys:logFile:-TIC2WebSocket} - + - + - - - - - - + + + + + + - - - - + + + + - + diff --git a/src/main/resources/log4j2-error.xml b/src/main/resources/log4j2-error.xml index 6b7a9c5..fc52ab6 100644 --- a/src/main/resources/log4j2-error.xml +++ b/src/main/resources/log4j2-error.xml @@ -10,35 +10,35 @@ SPDX-License-Identifier: Apache-2.0 - ${sys:logDir:-var/log} - ${sys:logFile:-TIC2WebSocket} + ${sys:logDir:-var/log} + ${sys:logFile:-TIC2WebSocket} - + - + - - - - - - + + + + + + - - - - + + + + - + diff --git a/src/main/resources/log4j2-fatal.xml b/src/main/resources/log4j2-fatal.xml index 6a936cd..0de1921 100644 --- a/src/main/resources/log4j2-fatal.xml +++ b/src/main/resources/log4j2-fatal.xml @@ -10,35 +10,35 @@ SPDX-License-Identifier: Apache-2.0 - ${sys:logDir:-var/log} - ${sys:logFile:-TIC2WebSocket} + ${sys:logDir:-var/log} + ${sys:logFile:-TIC2WebSocket} - + - + - - - - - - + + + + + + - - - - + + + + - + diff --git a/src/main/resources/log4j2-info.xml b/src/main/resources/log4j2-info.xml index 8a0f971..4e3b7cf 100644 --- a/src/main/resources/log4j2-info.xml +++ b/src/main/resources/log4j2-info.xml @@ -10,35 +10,35 @@ SPDX-License-Identifier: Apache-2.0 - ${sys:logDir:-var/log} - ${sys:logFile:-TIC2WebSocket} + ${sys:logDir:-var/log} + ${sys:logFile:-TIC2WebSocket} - + - + - - - - - - + + + + + + - - - - + + + + - + diff --git a/src/main/resources/log4j2-off.xml b/src/main/resources/log4j2-off.xml index 539ef56..12d4296 100644 --- a/src/main/resources/log4j2-off.xml +++ b/src/main/resources/log4j2-off.xml @@ -10,35 +10,35 @@ SPDX-License-Identifier: Apache-2.0 - ${sys:logDir:-var/log} - ${sys:logFile:-TIC2WebSocket} + ${sys:logDir:-var/log} + ${sys:logFile:-TIC2WebSocket} - + - + - - - - - - + + + + + + - - - - + + + + - + diff --git a/src/main/resources/log4j2-trace.xml b/src/main/resources/log4j2-trace.xml index f0324fe..7c6680d 100644 --- a/src/main/resources/log4j2-trace.xml +++ b/src/main/resources/log4j2-trace.xml @@ -10,35 +10,35 @@ SPDX-License-Identifier: Apache-2.0 - ${sys:logDir:-var/log} - ${sys:logFile:-TIC2WebSocket} + ${sys:logDir:-var/log} + ${sys:logFile:-TIC2WebSocket} - + - + - - - - - - + + + + + + - - - - + + + + - + diff --git a/src/main/resources/log4j2-warn.xml b/src/main/resources/log4j2-warn.xml index 8d42e66..ea7fbb9 100644 --- a/src/main/resources/log4j2-warn.xml +++ b/src/main/resources/log4j2-warn.xml @@ -10,35 +10,35 @@ SPDX-License-Identifier: Apache-2.0 - ${sys:logDir:-var/log} - ${sys:logFile:-TIC2WebSocket} + ${sys:logDir:-var/log} + ${sys:logFile:-TIC2WebSocket} - + - + - - - - - - + + + + + + - - - - + + + + - + diff --git a/src/main/scripts/SerialPortPlugNotifier.bat b/src/main/scripts/SerialPortPlugNotifier.bat deleted file mode 100644 index 78d1907..0000000 --- a/src/main/scripts/SerialPortPlugNotifier.bat +++ /dev/null @@ -1,14 +0,0 @@ -REM Copyright (C) 2025 Enedis Smarties team -REM -REM SPDX-FileContributor: Jehan BOUSCH -REM SPDX-FileContributor: Mathieu SABARTHES -REM -REM SPDX-License-Identifier: Apache-2.0 - -@echo off - -REM Get script directory -set SCRIPT_DIRECTORY=%~dp0 - -REM Run executable -java -cp "%SCRIPT_DIRECTORY%/lib/*" enedis.lab.io.serialport.SerialPortPlugNotifier %* \ No newline at end of file diff --git a/src/main/scripts/SerialPortPlugNotifier.sh b/src/main/scripts/SerialPortPlugNotifier.sh deleted file mode 100644 index 7617085..0000000 --- a/src/main/scripts/SerialPortPlugNotifier.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/bash - -# Copyright (C) 2025 Enedis Smarties team -# -# SPDX-FileContributor: Jehan BOUSCH -# SPDX-FileContributor: Mathieu SABARTHES -# -# SPDX-License-Identifier: Apache-2.0 - -# Get script directory -SCRIPT_DIRECTORY=$(dirname "$0") - -# Run executable -java -cp "$SCRIPT_DIRECTORY/lib/*" enedis.lab.io.serialport.SerialPortPlugNotifier $* \ No newline at end of file diff --git a/src/main/scripts/TIC2WebSocket.bat b/src/main/scripts/TIC2WebSocket.bat deleted file mode 100644 index f5316e0..0000000 --- a/src/main/scripts/TIC2WebSocket.bat +++ /dev/null @@ -1,14 +0,0 @@ -REM Copyright (C) 2025 Enedis Smarties team -REM -REM SPDX-FileContributor: Jehan BOUSCH -REM SPDX-FileContributor: Mathieu SABARTHES -REM -REM SPDX-License-Identifier: Apache-2.0 - -@echo off - -REM Get script directory -set SCRIPT_DIRECTORY=%~dp0 - -REM Run executable -java -DlogDir="%SCRIPT_DIRECTORY%var\log" -DconfigFile="%SCRIPT_DIRECTORY%var\config\TIC2WebSocketConfiguration.json" -cp "%SCRIPT_DIRECTORY%/lib/*" enedis.tic.service.TIC2WebSocketApplication %* \ No newline at end of file diff --git a/src/main/scripts/TIC2WebSocket.sh b/src/main/scripts/TIC2WebSocket.sh deleted file mode 100644 index d69dc26..0000000 --- a/src/main/scripts/TIC2WebSocket.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/bash - -# Copyright (C) 2025 Enedis Smarties team -# -# SPDX-FileContributor: Jehan BOUSCH -# SPDX-FileContributor: Mathieu SABARTHES -# -# SPDX-License-Identifier: Apache-2.0 - -# Get script directory -SCRIPT_DIRECTORY=$(dirname $(realpath "$0")) - -# Run executable -java -DlogDir="$SCRIPT_DIRECTORY/var/log" -DconfigFile="$SCRIPT_DIRECTORY/var/config/TIC2WebSocketConfiguration.json" -cp "$SCRIPT_DIRECTORY/lib/*" enedis.tic.service.TIC2WebSocketApplication $* \ No newline at end of file diff --git a/src/main/scripts/TIC2WebSocket_remote_debug.sh b/src/main/scripts/TIC2WebSocket_remote_debug.sh deleted file mode 100644 index 5ca9c68..0000000 --- a/src/main/scripts/TIC2WebSocket_remote_debug.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/bash - -# Copyright (C) 2025 Enedis Smarties team -# -# SPDX-FileContributor: Jehan BOUSCH -# SPDX-FileContributor: Mathieu SABARTHES -# -# SPDX-License-Identifier: Apache-2.0 - -# Get script directory -SCRIPT_DIRECTORY=$(dirname "$0") - -# Run executable -java -Xdebug -Xrunjdwp:transport=dt_socket,server=y,address=0.0.0.0:8000 -DlogDir="$SCRIPT_DIRECTORY/var/log" -DconfigDir="$SCRIPT_DIRECTORY/var/config" -cp "$SCRIPT_DIRECTORY/lib/*" tic.service.app.TIC2WebSocketApplication $* \ No newline at end of file diff --git a/src/main/scripts/TICPortPlugNotifier.bat b/src/main/scripts/TICPortPlugNotifier.bat deleted file mode 100644 index 3121547..0000000 --- a/src/main/scripts/TICPortPlugNotifier.bat +++ /dev/null @@ -1,14 +0,0 @@ -REM Copyright (C) 2025 Enedis Smarties team -REM -REM SPDX-FileContributor: Jehan BOUSCH -REM SPDX-FileContributor: Mathieu SABARTHES -REM -REM SPDX-License-Identifier: Apache-2.0 - -@echo off - -REM Get script directory -set SCRIPT_DIRECTORY=%~dp0 - -REM Run executable -java -cp "%SCRIPT_DIRECTORY%/lib/*" enedis.lab.io.tic.TICPortPlugNotifier %* \ No newline at end of file diff --git a/src/main/scripts/TICPortPlugNotifier.sh b/src/main/scripts/TICPortPlugNotifier.sh deleted file mode 100644 index 2747dce..0000000 --- a/src/main/scripts/TICPortPlugNotifier.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/bash - -# Copyright (C) 2025 Enedis Smarties team -# -# SPDX-FileContributor: Jehan BOUSCH -# SPDX-FileContributor: Mathieu SABARTHES -# -# SPDX-License-Identifier: Apache-2.0 - -# Get script directory -SCRIPT_DIRECTORY=$(dirname "$0") - -# Run executable -java -cp "$SCRIPT_DIRECTORY/lib/*" enedis.lab.io.tic.TICPortPlugNotifier $* \ No newline at end of file diff --git a/src/main/scripts/debug/TIC2WebSocket_remote_debug.sh b/src/main/scripts/debug/TIC2WebSocket_remote_debug.sh new file mode 100644 index 0000000..69643b1 --- /dev/null +++ b/src/main/scripts/debug/TIC2WebSocket_remote_debug.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +# Copyright (C) 2025 Enedis Smarties team +# +# SPDX-FileContributor: Jehan BOUSCH +# SPDX-FileContributor: Mathieu SABARTHES +# +# SPDX-License-Identifier: Apache-2.0 + +# Get script directory +SCRIPT_DIRECTORY=$(dirname $(realpath "$0")) + +# Get distribution root directory (parent of script directory) +ROOT_DIRECTORY=$(realpath "$SCRIPT_DIRECTORY/..") + +# Define app directory +APP_DIRECTORY="$ROOT_DIRECTORY/app" + +# Define log directory and config file +LOG_DIRECTORY="$APP_DIRECTORY/var/log" +CONFIG_FILE="$APP_DIRECTORY/var/config/TIC2WebSocketConfiguration.json" +CLASSPATH="$APP_DIRECTORY/lib/*" +MAIN_CLASS=tic.service.TIC2WebSocketApplication + +# Run executable +java -Xdebug -Xrunjdwp:transport=dt_socket,server=y,address=0.0.0.0:8000 -DlogDir="$LOG_DIRECTORY" -DconfigFile="$CONFIG_FILE" -cp "$CLASSPATH" $MAIN_CLASS $* \ No newline at end of file diff --git a/src/main/scripts/diagnostic/ModemFinder.bat b/src/main/scripts/diagnostic/ModemFinder.bat new file mode 100644 index 0000000..4efa621 --- /dev/null +++ b/src/main/scripts/diagnostic/ModemFinder.bat @@ -0,0 +1,24 @@ +REM Copyright (C) 2025 Enedis Smarties team +REM +REM SPDX-FileContributor: Jehan BOUSCH +REM SPDX-FileContributor: Mathieu SABARTHES +REM +REM SPDX-License-Identifier: Apache-2.0 + +@echo off + +REM Get script directory +set SCRIPT_DIRECTORY=%~dp0 + +REM Get distribution root directory (parent of script directory) +for %%I in ("%SCRIPT_DIRECTORY%..") do set ROOT_DIRECTORY=%%~fI\ + +REM Define app directory +set APP_DIRECTORY=%ROOT_DIRECTORY%app\ + +REM Define classpath and main class +set CLASSPATH=%APP_DIRECTORY%lib\* +set MAIN_CLASS=tic.diagnostic.modem.ModemFinderApp + +REM Run executable +java -cp "%CLASSPATH%" %MAIN_CLASS% %* diff --git a/src/main/scripts/diagnostic/ModemFinder.sh b/src/main/scripts/diagnostic/ModemFinder.sh new file mode 100644 index 0000000..010b075 --- /dev/null +++ b/src/main/scripts/diagnostic/ModemFinder.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +# Copyright (C) 2025 Enedis Smarties team +# +# SPDX-FileContributor: Jehan BOUSCH +# SPDX-FileContributor: Mathieu SABARTHES +# +# SPDX-License-Identifier: Apache-2.0 + +# Get script directory +SCRIPT_DIRECTORY=$(dirname $(realpath "$0")) + +# Get distribution root directory (parent of script directory) +ROOT_DIRECTORY=$(realpath "$SCRIPT_DIRECTORY/..") + +# Define app directory +APP_DIRECTORY="$ROOT_DIRECTORY/app" + +# Define classpath and main class +CLASSPATH="$APP_DIRECTORY/lib/*" +MAIN_CLASS=tic.diagnostic.modem.ModemFinderApp + +# Run executable +java -cp "$CLASSPATH" $MAIN_CLASS $* diff --git a/src/main/scripts/diagnostic/ModemPlugNotifier.bat b/src/main/scripts/diagnostic/ModemPlugNotifier.bat new file mode 100644 index 0000000..b1c95d6 --- /dev/null +++ b/src/main/scripts/diagnostic/ModemPlugNotifier.bat @@ -0,0 +1,24 @@ +REM Copyright (C) 2025 Enedis Smarties team +REM +REM SPDX-FileContributor: Jehan BOUSCH +REM SPDX-FileContributor: Mathieu SABARTHES +REM +REM SPDX-License-Identifier: Apache-2.0 + +@echo off + +REM Get script directory +set SCRIPT_DIRECTORY=%~dp0 + +REM Get distribution root directory (parent of script directory) +for %%I in ("%SCRIPT_DIRECTORY%..") do set ROOT_DIRECTORY=%%~fI\ + +REM Define app directory +set APP_DIRECTORY=%ROOT_DIRECTORY%app\ + +REM Define classpath and main class +set CLASSPATH=%APP_DIRECTORY%lib\* +set MAIN_CLASS=tic.diagnostic.modem.ModemPlugNotifierApp + +REM Run executable +java -cp "%CLASSPATH%" %MAIN_CLASS% %* \ No newline at end of file diff --git a/src/main/scripts/diagnostic/ModemPlugNotifier.sh b/src/main/scripts/diagnostic/ModemPlugNotifier.sh new file mode 100644 index 0000000..e6cc87f --- /dev/null +++ b/src/main/scripts/diagnostic/ModemPlugNotifier.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +# Copyright (C) 2025 Enedis Smarties team +# +# SPDX-FileContributor: Jehan BOUSCH +# SPDX-FileContributor: Mathieu SABARTHES +# +# SPDX-License-Identifier: Apache-2.0 + +# Get script directory +SCRIPT_DIRECTORY=$(dirname $(realpath "$0")) + +# Get distribution root directory (parent of script directory) +ROOT_DIRECTORY=$(realpath "$SCRIPT_DIRECTORY/..") + +# Define app directory +APP_DIRECTORY="$ROOT_DIRECTORY/app" + +# Define classpath and main class +CLASSPATH="$APP_DIRECTORY/lib/*" +MAIN_CLASS=tic.diagnostic.modem.ModemPlugNotifierApp + +# Run executable +java -cp "$CLASSPATH" $MAIN_CLASS $* \ No newline at end of file diff --git a/src/main/scripts/diagnostic/SerialPortFinder.bat b/src/main/scripts/diagnostic/SerialPortFinder.bat new file mode 100644 index 0000000..c22930e --- /dev/null +++ b/src/main/scripts/diagnostic/SerialPortFinder.bat @@ -0,0 +1,24 @@ +REM Copyright (C) 2025 Enedis Smarties team +REM +REM SPDX-FileContributor: Jehan BOUSCH +REM SPDX-FileContributor: Mathieu SABARTHES +REM +REM SPDX-License-Identifier: Apache-2.0 + +@echo off + +REM Get script directory +set SCRIPT_DIRECTORY=%~dp0 + +REM Get distribution root directory (parent of script directory) +for %%I in ("%SCRIPT_DIRECTORY%..") do set ROOT_DIRECTORY=%%~fI\ + +REM Define app directory +set APP_DIRECTORY=%ROOT_DIRECTORY%app\ + +REM Define classpath and main class +set CLASSPATH=%APP_DIRECTORY%lib\* +set MAIN_CLASS=tic.diagnostic.serialport.SerialPortFinderApp + +REM Run executable +java -cp "%CLASSPATH%" %MAIN_CLASS% %* \ No newline at end of file diff --git a/src/main/scripts/diagnostic/SerialPortFinder.sh b/src/main/scripts/diagnostic/SerialPortFinder.sh new file mode 100644 index 0000000..e8b7bd6 --- /dev/null +++ b/src/main/scripts/diagnostic/SerialPortFinder.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +# Copyright (C) 2025 Enedis Smarties team +# +# SPDX-FileContributor: Jehan BOUSCH +# SPDX-FileContributor: Mathieu SABARTHES +# +# SPDX-License-Identifier: Apache-2.0 + +# Get script directory +SCRIPT_DIRECTORY=$(dirname $(realpath "$0")) + +# Get distribution root directory (parent of script directory) +ROOT_DIRECTORY=$(realpath "$SCRIPT_DIRECTORY/..") + +# Define app directory +APP_DIRECTORY="$ROOT_DIRECTORY/app" + +# Define classpath and main class +CLASSPATH="$APP_DIRECTORY/lib/*" +MAIN_CLASS=tic.diagnostic.serialport.SerialPortFinderApp + +# Run executable +java -cp "$CLASSPATH" $MAIN_CLASS $* \ No newline at end of file diff --git a/src/main/scripts/diagnostic/TICCore.bat b/src/main/scripts/diagnostic/TICCore.bat new file mode 100644 index 0000000..ad270ea --- /dev/null +++ b/src/main/scripts/diagnostic/TICCore.bat @@ -0,0 +1,24 @@ +REM Copyright (C) 2025 Enedis Smarties team +REM +REM SPDX-FileContributor: Jehan BOUSCH +REM SPDX-FileContributor: Mathieu SABARTHES +REM +REM SPDX-License-Identifier: Apache-2.0 + +@echo off + +REM Get script directory +set SCRIPT_DIRECTORY=%~dp0 + +REM Get distribution root directory (parent of script directory) +for %%I in ("%SCRIPT_DIRECTORY%..") do set ROOT_DIRECTORY=%%~fI\ + +REM Define app directory +set APP_DIRECTORY=%ROOT_DIRECTORY%app\ + +REM Define classpath and main class +set CLASSPATH=%APP_DIRECTORY%lib\* +set MAIN_CLASS=tic.diagnostic.core.TICCoreApp + +REM Run executable +java -cp "%CLASSPATH%" %MAIN_CLASS% %* diff --git a/src/main/scripts/diagnostic/TICCore.sh b/src/main/scripts/diagnostic/TICCore.sh new file mode 100644 index 0000000..abc5cad --- /dev/null +++ b/src/main/scripts/diagnostic/TICCore.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +# Copyright (C) 2025 Enedis Smarties team +# +# SPDX-FileContributor: Jehan BOUSCH +# SPDX-FileContributor: Mathieu SABARTHES +# +# SPDX-License-Identifier: Apache-2.0 + +# Get script directory +SCRIPT_DIRECTORY=$(dirname $(realpath "$0")) + +# Get distribution root directory (parent of script directory) +ROOT_DIRECTORY=$(realpath "$SCRIPT_DIRECTORY/..") + +# Define app directory +APP_DIRECTORY="$ROOT_DIRECTORY/app" + +# Define classpath and main class +CLASSPATH="$APP_DIRECTORY/lib/*" +MAIN_CLASS=tic.diagnostic.core.TICCoreApp + +# Run executable +java -cp "$CLASSPATH" $MAIN_CLASS $* diff --git a/src/main/scripts/TICPortDump.bat b/src/main/scripts/diagnostic/TICPortDump.bat similarity index 96% rename from src/main/scripts/TICPortDump.bat rename to src/main/scripts/diagnostic/TICPortDump.bat index e3519bd..bd424bd 100644 --- a/src/main/scripts/TICPortDump.bat +++ b/src/main/scripts/diagnostic/TICPortDump.bat @@ -1,16 +1,16 @@ -REM Copyright (C) 2025 Enedis Smarties team -REM -REM SPDX-FileContributor: Jehan BOUSCH -REM SPDX-FileContributor: Mathieu SABARTHES -REM -REM SPDX-License-Identifier: Apache-2.0 - -@echo off - -REM Get script directory -set SCRIPT_DIRECTORY=%~dp0 -REM Get script name -set SCRIPT_NAME=%~n0 - -REM Run powershell script +REM Copyright (C) 2025 Enedis Smarties team +REM +REM SPDX-FileContributor: Jehan BOUSCH +REM SPDX-FileContributor: Mathieu SABARTHES +REM +REM SPDX-License-Identifier: Apache-2.0 + +@echo off + +REM Get script directory +set SCRIPT_DIRECTORY=%~dp0 +REM Get script name +set SCRIPT_NAME=%~n0 + +REM Run powershell script powershell -File %SCRIPT_DIRECTORY%/%SCRIPT_NAME%.ps1 %* \ No newline at end of file diff --git a/src/main/scripts/TICPortDump.ps1 b/src/main/scripts/diagnostic/TICPortDump.ps1 similarity index 95% rename from src/main/scripts/TICPortDump.ps1 rename to src/main/scripts/diagnostic/TICPortDump.ps1 index 6b6eb87..5a330c2 100644 --- a/src/main/scripts/TICPortDump.ps1 +++ b/src/main/scripts/diagnostic/TICPortDump.ps1 @@ -1,42 +1,42 @@ -# Copyright (C) 2025 Enedis Smarties team -# -# SPDX-FileContributor: Jehan BOUSCH -# SPDX-FileContributor: Mathieu SABARTHES -# -# SPDX-License-Identifier: Apache-2.0 - -if($args.count -lt 1) -{ - Write-Error 'Usage: ' + $MyInvocation.MyCommand.Name + ' portName [ticMode]' -ErrorAction Stop -} -$portName = $args[0] -if($args.count -lt 2) -{ - $ticMode = "STANDARD" -} -else -{ - $ticMode = $args[1] -} - -if($ticMode -eq "STANDARD") -{ - $baudrate = 9600 -} -elseif($ticMode -eq "HISTORIC") -{ - $baudrate = 1200 -} -else -{ - Write-Error 'The tic mode "' + $ticMode + '" is unknown (only "STANDARD" or "HISTORIC" is allowed)!' -ErrorAction Stop -} - -$port = new-Object System.IO.Ports.SerialPort $portName,$baudrate,Even,7,one -$port.open() -while($port.IsOpen) -{ - $line = $port.ReadLine() - Write-Output $line -} +# Copyright (C) 2025 Enedis Smarties team +# +# SPDX-FileContributor: Jehan BOUSCH +# SPDX-FileContributor: Mathieu SABARTHES +# +# SPDX-License-Identifier: Apache-2.0 + +if($args.count -lt 1) +{ + Write-Error 'Usage: ' + $MyInvocation.MyCommand.Name + ' portName [ticMode]' -ErrorAction Stop +} +$portName = $args[0] +if($args.count -lt 2) +{ + $ticMode = "STANDARD" +} +else +{ + $ticMode = $args[1] +} + +if($ticMode -eq "STANDARD") +{ + $baudrate = 9600 +} +elseif($ticMode -eq "HISTORIC") +{ + $baudrate = 1200 +} +else +{ + Write-Error 'The tic mode "' + $ticMode + '" is unknown (only "STANDARD" or "HISTORIC" is allowed)!' -ErrorAction Stop +} + +$port = new-Object System.IO.Ports.SerialPort $portName,$baudrate,Even,7,one +$port.open() +while($port.IsOpen) +{ + $line = $port.ReadLine() + Write-Output $line +} $port.close() \ No newline at end of file diff --git a/src/main/scripts/TICPortDump.sh b/src/main/scripts/diagnostic/TICPortDump.sh similarity index 100% rename from src/main/scripts/TICPortDump.sh rename to src/main/scripts/diagnostic/TICPortDump.sh diff --git a/src/main/scripts/diagnostic/UsbPortFinder.bat b/src/main/scripts/diagnostic/UsbPortFinder.bat new file mode 100644 index 0000000..e4f41ca --- /dev/null +++ b/src/main/scripts/diagnostic/UsbPortFinder.bat @@ -0,0 +1,24 @@ +REM Copyright (C) 2025 Enedis Smarties team +REM +REM SPDX-FileContributor: Jehan BOUSCH +REM SPDX-FileContributor: Mathieu SABARTHES +REM +REM SPDX-License-Identifier: Apache-2.0 + +@echo off + +REM Get script directory +set SCRIPT_DIRECTORY=%~dp0 + +REM Get distribution root directory (parent of script directory) +for %%I in ("%SCRIPT_DIRECTORY%..") do set ROOT_DIRECTORY=%%~fI\ + +REM Define app directory +set APP_DIRECTORY=%ROOT_DIRECTORY%app\ + +REM Define classpath and main class +set CLASSPATH=%APP_DIRECTORY%lib\* +set MAIN_CLASS=tic.diagnostic.usb.UsbPortFinderApp + +REM Run executable +java -cp "%CLASSPATH%" %MAIN_CLASS% %* diff --git a/src/main/scripts/diagnostic/UsbPortFinder.sh b/src/main/scripts/diagnostic/UsbPortFinder.sh new file mode 100644 index 0000000..211b899 --- /dev/null +++ b/src/main/scripts/diagnostic/UsbPortFinder.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +# Copyright (C) 2025 Enedis Smarties team +# +# SPDX-FileContributor: Jehan BOUSCH +# SPDX-FileContributor: Mathieu SABARTHES +# +# SPDX-License-Identifier: Apache-2.0 + +# Get script directory +SCRIPT_DIRECTORY=$(dirname $(realpath "$0")) + +# Get distribution root directory (parent of script directory) +ROOT_DIRECTORY=$(realpath "$SCRIPT_DIRECTORY/..") + +# Define app directory +APP_DIRECTORY="$ROOT_DIRECTORY/app" + +# Define classpath and main class +CLASSPATH="$APP_DIRECTORY/lib/*" +MAIN_CLASS=tic.diagnostic.usb.UsbPortFinderApp + +# Run executable +java -cp "$CLASSPATH" $MAIN_CLASS $* diff --git a/src/main/scripts/launcher/TIC2WebSocket.bat b/src/main/scripts/launcher/TIC2WebSocket.bat new file mode 100644 index 0000000..0dae77c --- /dev/null +++ b/src/main/scripts/launcher/TIC2WebSocket.bat @@ -0,0 +1,23 @@ +REM Copyright (C) 2025 Enedis Smarties team +REM +REM SPDX-FileContributor: Jehan BOUSCH +REM SPDX-FileContributor: Mathieu SABARTHES +REM +REM SPDX-License-Identifier: Apache-2.0 + +@echo off + +REM Get script directory +set SCRIPT_DIRECTORY=%~dp0 + +REM App directory is the script directory +set APP_DIRECTORY=%SCRIPT_DIRECTORY% + +REM Define log directory and config file +set LOG_DIRECTORY=%APP_DIRECTORY%var\log +set CONFIG_FILE=%APP_DIRECTORY%var\config\TIC2WebSocketConfiguration.json +set CLASSPATH=%APP_DIRECTORY%lib\* +set MAIN_CLASS=tic.service.TIC2WebSocketApplication + +REM Run executable +java -DlogDir="%LOG_DIRECTORY%" -DconfigFile="%CONFIG_FILE%" -cp "%CLASSPATH%" %MAIN_CLASS% %* \ No newline at end of file diff --git a/src/main/scripts/launcher/TIC2WebSocket.sh b/src/main/scripts/launcher/TIC2WebSocket.sh new file mode 100644 index 0000000..187665e --- /dev/null +++ b/src/main/scripts/launcher/TIC2WebSocket.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +# Copyright (C) 2025 Enedis Smarties team +# +# SPDX-FileContributor: Jehan BOUSCH +# SPDX-FileContributor: Mathieu SABARTHES +# +# SPDX-License-Identifier: Apache-2.0 + +# Get script directory +SCRIPT_DIRECTORY=$(dirname $(realpath "$0")) + +# App directory is the script directory +APP_DIRECTORY="$SCRIPT_DIRECTORY" + +# Define log directory and config file +LOG_DIRECTORY="$APP_DIRECTORY/var/log" +CONFIG_FILE="$APP_DIRECTORY/var/config/TIC2WebSocketConfiguration.json" +CLASSPATH="$APP_DIRECTORY/lib/*" +MAIN_CLASS=tic.service.TIC2WebSocketApplication + +# Run executable +java -DlogDir="$LOG_DIRECTORY" -DconfigFile="$CONFIG_FILE" -cp "$CLASSPATH" $MAIN_CLASS $* \ No newline at end of file diff --git a/src/main/scripts/setup_TIC2WebSocket.sh b/src/main/scripts/setup_TIC2WebSocket.sh deleted file mode 100644 index 6a34c31..0000000 --- a/src/main/scripts/setup_TIC2WebSocket.sh +++ /dev/null @@ -1,92 +0,0 @@ -#!/bin/bash - -# Copyright (C) 2025 Enedis Smarties team -# -# SPDX-FileContributor: Jehan BOUSCH -# SPDX-FileContributor: Mathieu SABARTHES -# -# SPDX-License-Identifier: Apache-2.0 - -############################################ VARIABLES ############################################ - -TIC2WebSocket_DIR=$(dirname "${BASH_SOURCE[0]}") -TIC2WebSocket_SCRIPT="${BASH_SOURCE[0]}" -TIC2WebSocket_PACKAGE="$TIC2WebSocket_DIR"/TIC2WebSocket-0.0-bin.zip -TIC2WebSocket_INSTALLDIR=/Applications/TIC2WebSocket - -############################################ FUNCTIONS ############################################ - -function TIC2WebSocket_install() -{ - sudo mkdir -p "$TIC2WebSocket_INSTALLDIR" - sudo unzip "$TIC2WebSocket_PACKAGE" -d "$TIC2WebSocket_INSTALLDIR" - sudo chmod -R 777 "$TIC2WebSocket_INSTALLDIR" -} - -function TIC2WebSocket_uninstall() -{ - sudo rm -Rf "$TIC2WebSocket_INSTALLDIR" -} - -function TIC2WebSocket_isInstalled() -{ - "$TIC2WebSocket_INSTALLDIR"/TIC2WebSocket.sh --version > /dev/null 2>&1 - if [ $? != 0 ]; then - echo false - return 0 - fi - echo true -} - -############################################## MAIN ############################################### - -option="$1" - -case "$option" in - install) - - if [ $(TIC2WebSocket_isInstalled) == "true" ]; then - echo "TIC2WebSocket already installed" - else - echo "Install TIC2WebSocket" - TIC2WebSocket_install - fi - ;; - - uninstall) - - if [ $(TIC2WebSocket_isInstalled) == "true" ]; then - echo "Uninstall TIC2WebSocket" - TIC2WebSocket_uninstall - else - echo "TIC2WebSocket already uninstalled" - fi - ;; - - reinstall) - - if [ $(TIC2WebSocket_isInstalled) == "true" ]; then - echo "Remove TIC2WebSocket" - TIC2WebSocket_uninstall - fi - echo "Install TIC2WebSocket" - TIC2WebSocket_install - ;; - - status) - - if [ $(TIC2WebSocket_isInstalled) == "true" ]; then - echo "TIC2WebSocket installed" - else - echo "TIC2WebSocket not installed" - fi - ;; - - *) - if [ "$option" != "" ]; then - echo "Usage: $(basename "$TIC2WebSocket_SCRIPT") {install|uninstallreinstall|status}" - exit 1 - fi - ;; - -esac diff --git a/src/test/java/enedis/lab/io/PortFinderMock.java b/src/test/java/enedis/lab/io/PortFinderMock.java deleted file mode 100644 index 4fb9c13..0000000 --- a/src/test/java/enedis/lab/io/PortFinderMock.java +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.io; - -import java.util.ArrayList; -import java.util.List; - -import enedis.lab.mock.FunctionCall; -import enedis.lab.types.DataArrayList; -import enedis.lab.types.DataList; - -@SuppressWarnings("javadoc") -public class PortFinderMock implements PortFinder -{ - public List findAllCalls = new ArrayList(); - public DataList descriptorList = new DataArrayList(); - - public PortFinderMock() - { - this.descriptorList = new DataArrayList(); - } - - @Override - public DataList findAll() - { - this.findAllCalls.add(new FunctionCall()); - return this.getDescriptors(); - } - - public DataList getDescriptors() - { - DataList descriptors = new DataArrayList(); - - synchronized (this.descriptorList) - { - descriptors.addAll(this.descriptorList); - } - - return descriptors; - } - - public DataList setDescriptors(DataList descriptors) - { - synchronized (this.descriptorList) - { - this.descriptorList.clear(); - this.descriptorList.addAll(descriptors); - } - - return descriptors; - } - - public void addDescriptor(T descriptor) - { - synchronized (this.descriptorList) - { - this.descriptorList.add(descriptor); - } - } - - public void removeDescriptor(T descriptor) - { - synchronized (this.descriptorList) - { - this.descriptorList.remove(descriptor); - } - } -} diff --git a/src/test/java/enedis/lab/io/tic/TICPortFinderMock.java b/src/test/java/enedis/lab/io/tic/TICPortFinderMock.java deleted file mode 100644 index 225f8f4..0000000 --- a/src/test/java/enedis/lab/io/tic/TICPortFinderMock.java +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.io.tic; - -import enedis.lab.io.PortFinderMock; -import enedis.lab.types.DataArrayList; -import enedis.lab.types.DataList; - -@SuppressWarnings("javadoc") -public class TICPortFinderMock extends PortFinderMock implements TICPortFinder -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - public DataList nativeDescriptorList = new DataArrayList(); - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - public TICPortFinderMock() - { - super(); - } - - public TICPortFinderMock(TICPortDescriptor... descriptors) - { - this.setDescriptors(DataArrayList.asList(descriptors)); - } - - @Override - public TICPortDescriptor findNative(String portName) - { - for (TICPortDescriptor descriptor : this.nativeDescriptorList) - { - if (descriptor.getPortName() == null && portName == null) - { - return descriptor; - } - if (descriptor.getPortName().equals(portName)) - { - return descriptor; - } - } - - return null; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// interfaceName - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -} diff --git a/src/test/java/enedis/lab/mock/FunctionCall.java b/src/test/java/enedis/lab/mock/FunctionCall.java deleted file mode 100644 index 6a5ba81..0000000 --- a/src/test/java/enedis/lab/mock/FunctionCall.java +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.lab.mock; - -@SuppressWarnings("javadoc") -public class FunctionCall -{ - public long captureTime; - - public FunctionCall() - { - super(); - this.captureTime = System.nanoTime(); - } - - public FunctionCall(long captureTime) - { - super(); - this.captureTime = captureTime; - } -} diff --git a/src/test/java/enedis/tic/core/TICCoreBaseTest.java b/src/test/java/enedis/tic/core/TICCoreBaseTest.java deleted file mode 100644 index f8d7fff..0000000 --- a/src/test/java/enedis/tic/core/TICCoreBaseTest.java +++ /dev/null @@ -1,498 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.tic.core; - -import java.time.LocalDateTime; -import java.util.List; - -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -import enedis.lab.io.tic.TICModemType; -import enedis.lab.io.tic.TICPortDescriptor; -import enedis.lab.io.tic.TICPortFinderMock; -import enedis.lab.mock.FunctionCall; -import enedis.lab.protocol.tic.TICMode; -import enedis.lab.types.DataDictionaryException; -import enedis.lab.types.datadictionary.DataDictionaryBase; -import enedis.lab.util.time.Time; -import enedis.lab.util.task.Task; - -@SuppressWarnings("javadoc") -public class TICCoreBaseTest -{ - private static final int NOTIFICATION_TIMEOUT = 1000; - - private TICPortFinderMock ticPortFinder; - private long plugNotifierPeriod; - private TICCoreBase ticCore; - - @Before - public void startTICCore() throws TICCoreException - { - this.ticPortFinder = new TICPortFinderMock(); - this.plugNotifierPeriod = 50; - this.ticCore = new TICCoreBase(this.ticPortFinder, this.plugNotifierPeriod, TICCoreStreamMock.class, TICMode.AUTO, null); - - this.ticCore.start(); - this.waitTaskRunning(this.ticCore); - } - - @After - public void stopTICCore() throws TICCoreException - { - this.ticCore.stop(); - TICCoreStreamMock.streams.clear(); - } - - @Test - public void test_getAvailableTICs() throws TICCoreException, DataDictionaryException - { - List availableTICs = this.ticCore.getAvailableTICs(); - Assert.assertNotNull(availableTICs); - Assert.assertEquals(0, availableTICs.size()); - - TICPortDescriptor descriptor1 = new TICPortDescriptor("1", "COM3", null, null, null, null, TICModemType.MICHAUD); - TICPortDescriptor descriptor2 = new TICPortDescriptor("2", "COM4", null, null, null, null, TICModemType.TELEINFO); - this.plugModem(descriptor1); - this.plugModem(descriptor2); - - availableTICs = this.ticCore.getAvailableTICs(); - Assert.assertNotNull(availableTICs); - Assert.assertEquals(2, availableTICs.size()); - Assert.assertTrue(availableTICs.contains(new TICIdentifier("1", "COM3", null))); - Assert.assertTrue(availableTICs.contains(new TICIdentifier("2", "COM4", null))); - - this.unplugModem(descriptor2); - - availableTICs = this.ticCore.getAvailableTICs(); - Assert.assertNotNull(availableTICs); - Assert.assertEquals(1, availableTICs.size()); - Assert.assertTrue(availableTICs.contains(new TICIdentifier("1", "COM3", null))); - } - - @Test - public void test_getModemsInfo() throws TICCoreException, DataDictionaryException - { - List modemsInfo = this.ticCore.getModemsInfo(); - Assert.assertNotNull(modemsInfo); - Assert.assertEquals(0, modemsInfo.size()); - - TICPortDescriptor descriptor1 = new TICPortDescriptor(null, "COM3", null, null, null, null, TICModemType.MICHAUD); - TICPortDescriptor descriptor2 = new TICPortDescriptor(null, "COM4", null, null, null, null, TICModemType.TELEINFO); - this.plugModem(descriptor1); - this.plugModem(descriptor2); - - modemsInfo = this.ticCore.getModemsInfo(); - Assert.assertNotNull(modemsInfo); - Assert.assertEquals(2, modemsInfo.size()); - Assert.assertTrue(modemsInfo.contains(descriptor1)); - Assert.assertTrue(modemsInfo.contains(descriptor2)); - - this.unplugModem(descriptor2); - modemsInfo = this.ticCore.getModemsInfo(); - Assert.assertNotNull(modemsInfo); - Assert.assertEquals(1, modemsInfo.size()); - Assert.assertTrue(modemsInfo.contains(descriptor1)); - } - - @Test - public void test_readNextFrame_ok() throws TICCoreException, DataDictionaryException - { - TICIdentifier identifier = this.plugModem(new TICPortDescriptor("1", "COM3", null, null, null, null, TICModemType.MICHAUD)); - Assert.assertEquals(1, TICCoreStreamMock.streams.size()); - TICCoreStreamMock stream = TICCoreStreamMock.streams.get(0); - Assert.assertEquals(identifier, stream.getIdentifier()); - - TICCoreReadNextFrameTask task = new TICCoreReadNextFrameTask(this.ticCore, identifier); - task.start(); - this.waitTaskRunning(task); - this.waitReadNextFrameSubsbription(); - TICCoreFrame frame = this.createFrame(identifier, TICMode.STANDARD, LocalDateTime.of(2020, 3, 3, 12, 59, 30, 0)); - stream.notifyOnData(frame); - this.waitTaskTerminated(task); - Assert.assertNull(task.exception); - Assert.assertNotNull(task.frame); - Assert.assertTrue(task.frame == frame); - } - - @Test - public void test_readNextFrame_error_OTHER_REASON() throws TICCoreException, DataDictionaryException - { - TICIdentifier identifier = this.plugModem(new TICPortDescriptor("1", "COM3", null, null, null, null, TICModemType.MICHAUD)); - Assert.assertEquals(1, TICCoreStreamMock.streams.size()); - TICCoreStreamMock stream = TICCoreStreamMock.streams.get(0); - Assert.assertEquals(identifier, stream.getIdentifier()); - - TICCoreReadNextFrameTask task = new TICCoreReadNextFrameTask(this.ticCore, identifier); - task.start(); - this.waitTaskRunning(task); - this.waitReadNextFrameSubsbription(); - TICCoreError error = new TICCoreError(identifier, TICCoreErrorCode.OTHER_REASON.getCode(), "Cannot read stream"); - stream.notifyOnError(error); - this.waitTaskTerminated(task); - Assert.assertNull(task.frame); - Assert.assertNotNull(task.exception); - Assert.assertTrue(task.exception instanceof TICCoreException); - TICCoreException exception = (TICCoreException) task.exception; - Assert.assertEquals(error.getErrorCode(), exception.getErrorCode()); - Assert.assertEquals(error.getErrorMessage(), exception.getErrorInfo()); - } - - @Test - public void test_readNextFrame_error_STREAM_IDENTIFIER_NOT_FOUND() throws TICCoreException, DataDictionaryException - { - TICIdentifier identifier = this.plugModem(new TICPortDescriptor("1", "COM3", null, null, null, null, TICModemType.MICHAUD)); - Assert.assertEquals(1, TICCoreStreamMock.streams.size()); - TICCoreStreamMock stream = TICCoreStreamMock.streams.get(0); - Assert.assertEquals(identifier, stream.getIdentifier()); - - TICCoreReadNextFrameTask task = new TICCoreReadNextFrameTask(this.ticCore, new TICIdentifier("2", "COM3", null)); - task.start(); - this.waitTaskRunning(task); - this.waitTaskTerminated(task); - Assert.assertNull(task.frame); - Assert.assertNotNull(task.exception); - Assert.assertTrue(task.exception instanceof TICCoreException); - TICCoreException exception = (TICCoreException) task.exception; - Assert.assertEquals(TICCoreErrorCode.STREAM_IDENTIFIER_NOT_FOUND.getCode(), exception.getErrorCode()); - } - - @Test - public void test_readNextFrame_timeout() throws TICCoreException, DataDictionaryException - { - TICIdentifier identifier = this.plugModem(new TICPortDescriptor("1", "COM3", null, null, null, null, TICModemType.MICHAUD)); - Assert.assertEquals(1, TICCoreStreamMock.streams.size()); - TICCoreStreamMock stream = TICCoreStreamMock.streams.get(0); - Assert.assertEquals(identifier, stream.getIdentifier()); - - TICCoreReadNextFrameTask task = new TICCoreReadNextFrameTask(this.ticCore, identifier, 200); - task.start(); - this.waitTaskRunning(task); - this.waitReadNextFrameSubsbription(); - this.waitTaskTerminated(task); - Assert.assertNull(task.frame); - Assert.assertNotNull(task.exception); - Assert.assertTrue(task.exception instanceof TICCoreException); - TICCoreException exception = (TICCoreException) task.exception; - Assert.assertEquals(TICCoreErrorCode.DATA_READ_TIMEOUT.getCode(), exception.getErrorCode()); - } - - @Test - public void test_subscribe_any() throws TICCoreException, DataDictionaryException - { - TICCoreSubscriberMock subscriber = new TICCoreSubscriberMock(); - this.ticCore.subscribe(subscriber); - } - - @Test - public void test_unsubscribe_any() throws TICCoreException, DataDictionaryException - { - TICCoreSubscriberMock subscriber = new TICCoreSubscriberMock(); - this.ticCore.subscribe(subscriber); - this.ticCore.unsubscribe(subscriber); - } - - @Test - public void test_subscribe_withIdentifier_ok() throws TICCoreException, DataDictionaryException - { - TICIdentifier identifier = this.plugModem(new TICPortDescriptor("1", "COM3", null, null, null, null, TICModemType.MICHAUD)); - - TICCoreSubscriberMock subscriber = new TICCoreSubscriberMock(); - this.ticCore.subscribe(identifier, subscriber); - } - - @Test - public void test_unsubscribe_withIdentifier_ok() throws TICCoreException, DataDictionaryException - { - TICIdentifier identifier = this.plugModem(new TICPortDescriptor("1", "COM3", null, null, null, null, TICModemType.MICHAUD)); - - TICCoreSubscriberMock subscriber = new TICCoreSubscriberMock(); - this.ticCore.subscribe(identifier, subscriber); - this.ticCore.unsubscribe(identifier, subscriber); - } - - @Test - public void test_subscribe_withIdentifier_notFound() throws TICCoreException, DataDictionaryException - { - this.plugModem(new TICPortDescriptor("1", "COM3", null, null, null, null, TICModemType.MICHAUD)); - - TICCoreSubscriberMock subscriber = new TICCoreSubscriberMock(); - TICIdentifier identifier = new TICIdentifier(null, "COM4", null); - try - { - this.ticCore.subscribe(identifier, subscriber); - Assert.fail("Subscribe should have trhown an exception since stream identifier does not match !"); - } - catch (Exception e) - { - Assert.assertTrue(e instanceof TICCoreException); - TICCoreException exception = (TICCoreException) e; - Assert.assertEquals(TICCoreErrorCode.STREAM_IDENTIFIER_NOT_FOUND.getCode(), exception.getErrorCode()); - } - } - - @Test - public void test_onError_whenUnplugModem() throws TICCoreException, DataDictionaryException - { - TICPortDescriptor descriptor1 = new TICPortDescriptor("1", "COM3", null, null, null, null, TICModemType.MICHAUD); - TICPortDescriptor descriptor2 = new TICPortDescriptor("2", "COM4", null, null, null, null, TICModemType.TELEINFO); - TICIdentifier identifier1 = this.plugModem(descriptor1); - TICIdentifier identifier2 = this.plugModem(descriptor2); - - TICCoreSubscriberMock subscriber1 = new TICCoreSubscriberMock(); - TICCoreSubscriberMock subscriber2 = new TICCoreSubscriberMock(); - TICCoreSubscriberMock subscriber3 = new TICCoreSubscriberMock(); - TICCoreSubscriberMock subscriber4 = new TICCoreSubscriberMock(); - TICCoreSubscriberMock subscriber5 = new TICCoreSubscriberMock(); - this.ticCore.subscribe(subscriber1); - this.ticCore.subscribe(identifier1, subscriber2); - this.ticCore.subscribe(identifier1, subscriber3); - this.ticCore.subscribe(identifier2, subscriber4); - this.ticCore.subscribe(identifier2, subscriber5); - - this.unplugModem(descriptor1); - this.waitSubscriberNotification(subscriber1.onErrorCalls, 1); - Assert.assertEquals(1, subscriber1.onErrorCalls.size()); - Assert.assertEquals(TICCoreErrorCode.STREAM_UNPLUGGED.getCode(), subscriber1.onErrorCalls.get(0).error.getErrorCode()); - this.waitSubscriberNotification(subscriber2.onErrorCalls, 1); - Assert.assertEquals(1, subscriber2.onErrorCalls.size()); - Assert.assertEquals(TICCoreErrorCode.STREAM_UNPLUGGED.getCode(), subscriber2.onErrorCalls.get(0).error.getErrorCode()); - this.waitSubscriberNotification(subscriber3.onErrorCalls, 1); - Assert.assertEquals(1, subscriber3.onErrorCalls.size()); - Assert.assertEquals(TICCoreErrorCode.STREAM_UNPLUGGED.getCode(), subscriber3.onErrorCalls.get(0).error.getErrorCode()); - Assert.assertEquals(0, subscriber4.onErrorCalls.size()); - Assert.assertEquals(0, subscriber5.onErrorCalls.size()); - - this.unplugModem(descriptor2); - this.waitSubscriberNotification(subscriber4.onErrorCalls, 1); - Assert.assertEquals(1, subscriber4.onErrorCalls.size()); - Assert.assertEquals(TICCoreErrorCode.STREAM_UNPLUGGED.getCode(), subscriber4.onErrorCalls.get(0).error.getErrorCode()); - this.waitSubscriberNotification(subscriber5.onErrorCalls, 1); - Assert.assertEquals(1, subscriber5.onErrorCalls.size()); - Assert.assertEquals(TICCoreErrorCode.STREAM_UNPLUGGED.getCode(), subscriber5.onErrorCalls.get(0).error.getErrorCode()); - this.waitSubscriberNotification(subscriber1.onErrorCalls, 1); - Assert.assertEquals(2, subscriber1.onErrorCalls.size()); - Assert.assertEquals(TICCoreErrorCode.STREAM_UNPLUGGED.getCode(), subscriber1.onErrorCalls.get(1).error.getErrorCode()); - Assert.assertEquals(1, subscriber2.onErrorCalls.size()); - Assert.assertEquals(1, subscriber3.onErrorCalls.size()); - } - - @Test - public void test_onData_any() throws TICCoreException, DataDictionaryException - { - TICCoreSubscriberMock subscriber = new TICCoreSubscriberMock(); - this.ticCore.subscribe(subscriber); - - this.plugModem(new TICPortDescriptor("1", "COM3", null, null, null, null, TICModemType.MICHAUD)); - Assert.assertEquals(1, TICCoreStreamMock.streams.size()); - TICCoreStreamMock stream1 = TICCoreStreamMock.streams.get(0); - TICCoreFrame frame1 = this.createFrame(stream1.getIdentifier(), TICMode.STANDARD, LocalDateTime.of(2020, 3, 3, 12, 59, 30, 0)); - stream1.notifyOnData(frame1); - this.waitSubscriberNotification(subscriber.onDataCalls, 1); - Assert.assertEquals(1, subscriber.onDataCalls.size()); - Assert.assertTrue(frame1 == subscriber.onDataCalls.get(0).frame); - - this.plugModem(new TICPortDescriptor("2", "COM4", null, null, null, null, TICModemType.TELEINFO)); - TICCoreStreamMock stream2 = TICCoreStreamMock.streams.get(1); - TICCoreFrame frame2 = this.createFrame(stream2.getIdentifier(), TICMode.HISTORIC, LocalDateTime.of(2017, 2, 14, 9, 37, 12, 0)); - stream2.notifyOnData(frame2); - this.waitSubscriberNotification(subscriber.onDataCalls, 2); - Assert.assertEquals(2, subscriber.onDataCalls.size()); - Assert.assertTrue(frame1 == subscriber.onDataCalls.get(0).frame); - Assert.assertTrue(frame2 == subscriber.onDataCalls.get(1).frame); - } - - @Test - public void test_onData_withIdentifier() throws TICCoreException, DataDictionaryException - { - TICIdentifier identifier = this.plugModem(new TICPortDescriptor("1", "COM3", null, null, null, null, TICModemType.MICHAUD)); - TICCoreSubscriberMock subscriber = new TICCoreSubscriberMock(); - this.ticCore.subscribe(identifier, subscriber); - - Assert.assertEquals(1, TICCoreStreamMock.streams.size()); - TICCoreStreamMock stream1 = TICCoreStreamMock.streams.get(0); - TICCoreFrame frame1 = this.createFrame(stream1.getIdentifier(), TICMode.STANDARD, LocalDateTime.of(2020, 3, 3, 12, 59, 30, 0)); - stream1.notifyOnData(frame1); - this.waitSubscriberNotification(subscriber.onDataCalls, 1); - Assert.assertEquals(1, subscriber.onDataCalls.size()); - Assert.assertTrue(frame1 == subscriber.onDataCalls.get(0).frame); - - this.plugModem(new TICPortDescriptor("2", "COM4", null, null, null, null, TICModemType.MICHAUD)); - TICCoreStreamMock stream2 = TICCoreStreamMock.streams.get(1); - TICCoreFrame frame2 = this.createFrame(stream2.getIdentifier(), TICMode.HISTORIC, LocalDateTime.of(2017, 2, 14, 9, 37, 12, 0)); - stream2.notifyOnData(frame2); - this.waitSubscriberNotification(subscriber.onDataCalls, 1); - Assert.assertEquals(1, subscriber.onDataCalls.size()); - Assert.assertTrue(frame1 == subscriber.onDataCalls.get(0).frame); - } - - @Test - public void test_onError_any() throws TICCoreException, DataDictionaryException - { - TICCoreSubscriberMock subscriber = new TICCoreSubscriberMock(); - this.ticCore.subscribe(subscriber); - - this.plugModem(new TICPortDescriptor("1", "COM3", null, null, null, null, TICModemType.MICHAUD)); - Assert.assertEquals(1, TICCoreStreamMock.streams.size()); - TICCoreStreamMock stream1 = TICCoreStreamMock.streams.get(0); - TICCoreError error1 = new TICCoreError(stream1.getIdentifier(), TICCoreErrorCode.OTHER_REASON.getCode(), "Cannot read stream"); - stream1.notifyOnError(error1); - this.waitSubscriberNotification(subscriber.onErrorCalls, 1); - Assert.assertEquals(1, subscriber.onErrorCalls.size()); - Assert.assertTrue(error1 == subscriber.onErrorCalls.get(0).error); - - this.plugModem(new TICPortDescriptor("2", "COM4", null, null, null, null, TICModemType.TELEINFO)); - TICCoreStreamMock stream2 = TICCoreStreamMock.streams.get(1); - TICCoreError error2 = new TICCoreError(stream2.getIdentifier(), TICCoreErrorCode.OTHER_REASON.getCode(), "Error reading stream COM4"); - stream2.notifyOnError(error2); - this.waitSubscriberNotification(subscriber.onErrorCalls, 2); - Assert.assertEquals(2, subscriber.onErrorCalls.size()); - Assert.assertTrue(error1 == subscriber.onErrorCalls.get(0).error); - Assert.assertTrue(error2 == subscriber.onErrorCalls.get(1).error); - } - - @Test - public void test_onError_withIdentifier() throws TICCoreException, DataDictionaryException - { - TICIdentifier identifier = this.plugModem(new TICPortDescriptor("1", "COM3", null, null, null, null, TICModemType.MICHAUD)); - - TICCoreSubscriberMock subscriber = new TICCoreSubscriberMock(); - this.ticCore.subscribe(identifier, subscriber); - - Assert.assertEquals(1, TICCoreStreamMock.streams.size()); - TICCoreStreamMock stream1 = TICCoreStreamMock.streams.get(0); - TICCoreError error1 = new TICCoreError(stream1.getIdentifier(), TICCoreErrorCode.OTHER_REASON.getCode(), "Cannot read stream"); - stream1.notifyOnError(error1); - this.waitSubscriberNotification(subscriber.onErrorCalls, 1); - Assert.assertEquals(1, subscriber.onErrorCalls.size()); - Assert.assertTrue(error1 == subscriber.onErrorCalls.get(0).error); - - this.plugModem(new TICPortDescriptor("2", "COM4", null, null, null, null, TICModemType.TELEINFO)); - TICCoreStreamMock stream2 = TICCoreStreamMock.streams.get(1); - TICCoreError error2 = new TICCoreError(stream2.getIdentifier(), TICCoreErrorCode.OTHER_REASON.getCode(), "Error reading stream COM4"); - stream2.notifyOnError(error2); - this.waitSubscriberNotification(subscriber.onErrorCalls, 1); - Assert.assertEquals(1, subscriber.onErrorCalls.size()); - Assert.assertTrue(error1 == subscriber.onErrorCalls.get(0).error); - } - - @Test - public void test_getIdentifiers() throws TICCoreException, DataDictionaryException - { - TICIdentifier identifier1 = this.plugModem(new TICPortDescriptor("1", "COM3", null, null, null, null, TICModemType.MICHAUD)); - TICIdentifier identifier2 = this.plugModem(new TICPortDescriptor("2", "COM4", null, null, null, null, TICModemType.TELEINFO)); - - TICCoreSubscriberMock subscriber1 = new TICCoreSubscriberMock(); - TICCoreSubscriberMock subscriber2 = new TICCoreSubscriberMock(); - TICCoreSubscriberMock subscriber3 = new TICCoreSubscriberMock(); - - this.ticCore.subscribe(subscriber1); - List indentifierList1 = this.ticCore.getIndentifiers(subscriber1); - Assert.assertNotNull(indentifierList1); - Assert.assertEquals(2, indentifierList1.size()); - Assert.assertTrue(indentifierList1.contains(identifier1)); - Assert.assertTrue(indentifierList1.contains(identifier2)); - - this.ticCore.subscribe(identifier1, subscriber2); - List indentifierList2 = this.ticCore.getIndentifiers(subscriber2); - Assert.assertNotNull(indentifierList2); - Assert.assertEquals(1, indentifierList2.size()); - Assert.assertTrue(indentifierList2.contains(identifier1)); - - this.ticCore.subscribe(identifier2, subscriber3); - List indentifierList3 = this.ticCore.getIndentifiers(subscriber3); - Assert.assertNotNull(indentifierList3); - Assert.assertEquals(1, indentifierList3.size()); - Assert.assertTrue(indentifierList3.contains(identifier2)); - - this.ticCore.unsubscribe(subscriber1); - indentifierList1 = this.ticCore.getIndentifiers(subscriber1); - Assert.assertNotNull(indentifierList1); - Assert.assertEquals(0, indentifierList1.size()); - - this.ticCore.unsubscribe(identifier1, subscriber2); - indentifierList2 = this.ticCore.getIndentifiers(subscriber2); - Assert.assertNotNull(indentifierList2); - Assert.assertEquals(0, indentifierList2.size()); - - this.ticCore.unsubscribe(identifier2, subscriber3); - indentifierList3 = this.ticCore.getIndentifiers(subscriber3); - Assert.assertNotNull(indentifierList3); - Assert.assertEquals(0, indentifierList3.size()); - } - - private TICIdentifier plugModem(TICPortDescriptor descriptor) throws DataDictionaryException - { - this.ticPortFinder.addDescriptor(descriptor); - this.waitPlugNotifierUpdate(); - - return new TICIdentifier(descriptor.getPortId(), descriptor.getPortName(), null); - } - - private void unplugModem(TICPortDescriptor descriptor) - { - this.ticPortFinder.removeDescriptor(descriptor); - this.waitPlugNotifierUpdate(); - } - - private TICCoreFrame createFrame(TICIdentifier identifier, TICMode mode, LocalDateTime localDateTime) throws DataDictionaryException - { - DataDictionaryBase content = new DataDictionaryBase(); - if (mode == TICMode.STANDARD) - { - content.set("ADSC", identifier.getSerialNumber()); - } - else - { - content.set("ADCO", identifier.getSerialNumber()); - } - TICCoreFrame frame = new TICCoreFrame(identifier, mode, localDateTime, content); - - return frame; - } - - private void waitPlugNotifierUpdate() - { - Time.sleep(2 * this.plugNotifierPeriod); - } - - private void waitTaskRunning(Task task) - { - while (!task.isRunning()) - { - Time.sleep(50); - } - } - - private void waitTaskTerminated(Task task) - { - while (task.isRunning()) - { - Time.sleep(50); - } - } - - private void waitReadNextFrameSubsbription() - { - Time.sleep(100); - } - - private void waitSubscriberNotification(List onCalls, int expectedSize) - { - long begin = System.nanoTime(); - long elapsed = 0; - while (onCalls.size() < expectedSize && elapsed < NOTIFICATION_TIMEOUT) - { - Time.sleep(50); - elapsed = (System.nanoTime() - begin) / 1000000; - } - } -} diff --git a/src/test/java/enedis/tic/core/TICCoreReadNextFrameTask.java b/src/test/java/enedis/tic/core/TICCoreReadNextFrameTask.java deleted file mode 100644 index d31601d..0000000 --- a/src/test/java/enedis/tic/core/TICCoreReadNextFrameTask.java +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.tic.core; - -import enedis.lab.util.task.TaskBase; - -public class TICCoreReadNextFrameTask extends TaskBase -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - public TICCore ticCore; - public TICIdentifier identifier; - public TICCoreFrame frame; - public Exception exception; - public int timeout; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - public TICCoreReadNextFrameTask(TICCore ticCore, TICIdentifier identifier) - { - this(ticCore, identifier, -1); - } - - public TICCoreReadNextFrameTask(TICCore ticCore, TICIdentifier identifier, int timeout) - { - super(); - this.ticCore = ticCore; - this.identifier = identifier; - this.timeout = timeout; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// TaskBase - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - protected void process() - { - try - { - if (this.timeout > 0) - { - this.frame = this.ticCore.readNextFrame(this.identifier, this.timeout); - } - else - { - this.frame = this.ticCore.readNextFrame(this.identifier); - } - } - catch (Exception exception) - { - this.exception = exception; - } - - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -} diff --git a/src/test/java/enedis/tic/core/TICCoreStreamMock.java b/src/test/java/enedis/tic/core/TICCoreStreamMock.java deleted file mode 100644 index 4606620..0000000 --- a/src/test/java/enedis/tic/core/TICCoreStreamMock.java +++ /dev/null @@ -1,167 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.tic.core; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashSet; -import java.util.List; - -import enedis.lab.protocol.tic.TICMode; -import enedis.lab.types.DataDictionaryException; - -public class TICCoreStreamMock implements TICCoreStream -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - public static List streams = new ArrayList(); - public Collection subscribers; - public boolean running; - public TICIdentifier identifier; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - public TICCoreStreamMock(String portId, String portName, TICMode mode) throws DataDictionaryException - { - super(); - this.subscribers = new HashSet(); - this.running = false; - this.identifier = new TICIdentifier(portId, portName, null); - streams.add(this); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// TICCoreStream - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public TICIdentifier getIdentifier() - { - return this.identifier; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// Task - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public boolean isRunning() - { - return this.running; - } - - @Override - public void start() - { - this.running = true; - } - - @Override - public void stop() - { - this.running = false; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// Notifier - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public Collection getSubscribers() - { - return this.subscribers; - } - - @Override - public boolean hasSubscriber(TICCoreSubscriber subscriber) - { - return this.subscribers.contains(subscriber); - } - - @Override - public void subscribe(TICCoreSubscriber subscriber) - { - this.subscribers.add(subscriber); - } - - @Override - public void unsubscribe(TICCoreSubscriber subscriber) - { - this.subscribers.remove(subscriber); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - public void notifyOnData(TICCoreFrame frame) - { - for (TICCoreSubscriber subscriber : this.subscribers) - { - subscriber.onData(frame); - } - } - - public void notifyOnError(TICCoreError error) - { - for (TICCoreSubscriber subscriber : this.subscribers) - { - subscriber.onError(error); - } - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -} diff --git a/src/test/java/enedis/tic/core/TICCoreSubscriberMock.java b/src/test/java/enedis/tic/core/TICCoreSubscriberMock.java deleted file mode 100644 index c826a11..0000000 --- a/src/test/java/enedis/tic/core/TICCoreSubscriberMock.java +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.tic.core; - -import java.util.ArrayList; -import java.util.List; - -public class TICCoreSubscriberMock implements TICCoreSubscriber -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - public List onDataCalls = new ArrayList(); - public List onErrorCalls = new ArrayList(); - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// TICCoreSubscriber - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public void onData(TICCoreFrame frame) - { - this.onDataCalls.add(new TICCoreSubscriberOnDataCall(frame)); - } - - @Override - public void onError(TICCoreError error) - { - this.onErrorCalls.add(new TICCoreSubscriberOnErrorCall(error)); - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -} diff --git a/src/test/java/enedis/tic/core/TICCoreSubscriberOnDataCall.java b/src/test/java/enedis/tic/core/TICCoreSubscriberOnDataCall.java deleted file mode 100644 index 55555a2..0000000 --- a/src/test/java/enedis/tic/core/TICCoreSubscriberOnDataCall.java +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.tic.core; - -import enedis.lab.mock.FunctionCall; - -@SuppressWarnings("javadoc") -public class TICCoreSubscriberOnDataCall extends FunctionCall -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - public TICCoreFrame frame; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - public TICCoreSubscriberOnDataCall(TICCoreFrame frame) - { - super(); - this.frame = frame; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// interfaceName - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -} diff --git a/src/test/java/enedis/tic/core/TICCoreSubscriberOnErrorCall.java b/src/test/java/enedis/tic/core/TICCoreSubscriberOnErrorCall.java deleted file mode 100644 index 862a016..0000000 --- a/src/test/java/enedis/tic/core/TICCoreSubscriberOnErrorCall.java +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.tic.core; - -import enedis.lab.mock.FunctionCall; - -@SuppressWarnings("javadoc") -public class TICCoreSubscriberOnErrorCall extends FunctionCall -{ - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTANTS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// TYPES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// STATIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// ATTRIBUTES - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - public TICCoreError error; - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// CONSTRUCTORS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - public TICCoreSubscriberOnErrorCall(TICCoreError error) - { - super(); - this.error = error; - } - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// INTERFACE - /// interfaceName - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PUBLIC METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PROTECTED METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// PRIVATE METHODS - /// - /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -} diff --git a/src/test/java/enedis/tic/core/TICIdentifierTest.java b/src/test/java/enedis/tic/core/TICIdentifierTest.java deleted file mode 100644 index af522a6..0000000 --- a/src/test/java/enedis/tic/core/TICIdentifierTest.java +++ /dev/null @@ -1,187 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.tic.core; - -import org.junit.Assert; -import org.junit.Test; - -import enedis.lab.types.DataDictionaryException; - -public class TICIdentifierTest -{ - @Test - public void test_constructor_full() throws DataDictionaryException - { - TICIdentifier identifier = new TICIdentifier("{1-1}", "COM3", "021976551632"); - - Assert.assertEquals("{1-1}", identifier.getPortId()); - Assert.assertEquals("COM3", identifier.getPortName()); - Assert.assertEquals("021976551632", identifier.getSerialNumber()); - } - - @Test - public void test_constructor_onlyPortId() throws DataDictionaryException - { - TICIdentifier identifier = new TICIdentifier("{1-1}", null, null); - - Assert.assertEquals("{1-1}", identifier.getPortId()); - Assert.assertNull(identifier.getPortName()); - Assert.assertNull(identifier.getSerialNumber()); - } - - @Test - public void test_constructor_onlyPortName() throws DataDictionaryException - { - TICIdentifier identifier = new TICIdentifier(null, "COM3", null); - - Assert.assertNull(identifier.getPortId()); - Assert.assertEquals("COM3", identifier.getPortName()); - Assert.assertNull(identifier.getSerialNumber()); - } - - @Test - public void test_constructor_onlySerialNumber() throws DataDictionaryException - { - TICIdentifier identifier = new TICIdentifier(null, null, "021976551632"); - - Assert.assertNull(identifier.getPortId()); - Assert.assertNull(identifier.getPortName()); - Assert.assertEquals("021976551632", identifier.getSerialNumber()); - } - - @Test(expected = DataDictionaryException.class) - public void test_constructor_empty() throws DataDictionaryException - { - new TICIdentifier(null, null, null); - } - - @Test - public void test_setPortId_null_notEmpty() throws DataDictionaryException - { - TICIdentifier identifier = new TICIdentifier("{1-1}", null, "021976551632"); - - Assert.assertEquals("{1-1}", identifier.getPortId()); - identifier.setPortId(null); - Assert.assertNull(identifier.getPortId()); - } - - @Test(expected = DataDictionaryException.class) - public void test_setPortId_null_empty() throws DataDictionaryException - { - TICIdentifier identifier = new TICIdentifier("{1-1}", null, null); - - Assert.assertEquals("{1-1}", identifier.getPortId()); - identifier.setPortId(null); - } - - @Test - public void test_setPortName_null_notEmpty() throws DataDictionaryException - { - TICIdentifier identifier = new TICIdentifier(null, "COM3", "021976551632"); - - Assert.assertEquals("COM3", identifier.getPortName()); - identifier.setPortName(null); - Assert.assertNull(identifier.getPortName()); - } - - @Test(expected = DataDictionaryException.class) - public void test_setPortName_null_empty() throws DataDictionaryException - { - TICIdentifier identifier = new TICIdentifier(null, "COM3", null); - - Assert.assertEquals("COM3", identifier.getPortName()); - identifier.setPortName(null); - } - - @Test - public void test_setSerialNumber_null_notEmpty() throws DataDictionaryException - { - TICIdentifier identifier = new TICIdentifier(null, "COM3", "021976551632"); - - Assert.assertEquals("021976551632", identifier.getSerialNumber()); - identifier.setSerialNumber(null); - Assert.assertNull(identifier.getSerialNumber()); - } - - @Test(expected = DataDictionaryException.class) - public void test_setSerialNumber_null_empty() throws DataDictionaryException - { - TICIdentifier identifier = new TICIdentifier(null, null, "021976551632"); - - Assert.assertEquals("021976551632", identifier.getSerialNumber()); - identifier.setSerialNumber(null); - } - - @Test - public void test_matches_null() throws DataDictionaryException - { - TICIdentifier identifier = new TICIdentifier(null, null, "021976551632"); - - Assert.assertFalse(identifier.matches(null)); - } - - @Test - public void test_matches_same_serialNumber() throws DataDictionaryException - { - TICIdentifier identifier1 = new TICIdentifier("{1-1}", "COM3", "021976551632"); - TICIdentifier identifier2 = new TICIdentifier("{1-2}", "COM4", "021976551632"); - - Assert.assertTrue(identifier1.matches(identifier2)); - } - - @Test - public void test_matches_different_serialNumber() throws DataDictionaryException - { - TICIdentifier identifier1 = new TICIdentifier("{1-1}", "COM3", "021976551632"); - TICIdentifier identifier2 = new TICIdentifier("{1-1}", "COM3", "021976551638"); - - Assert.assertFalse(identifier1.matches(identifier2)); - } - - @Test - public void test_matches_same_portId() throws DataDictionaryException - { - TICIdentifier identifier1 = new TICIdentifier("{1-1}", "COM3", "021976551632"); - TICIdentifier identifier2 = new TICIdentifier("{1-1}", "COM4", "021976551633"); - TICIdentifier identifier3 = new TICIdentifier("{1-1}", "COM5", null); - - Assert.assertTrue(identifier1.matches(identifier3)); - Assert.assertFalse(identifier1.matches(identifier2)); - } - - @Test - public void test_matches_different_portId() throws DataDictionaryException - { - TICIdentifier identifier1 = new TICIdentifier("{1-1}", null, null); - TICIdentifier identifier2 = new TICIdentifier("{1-7}", null, null); - - Assert.assertFalse(identifier1.matches(identifier2)); - } - - @Test - public void test_matches_same_portName() throws DataDictionaryException - { - TICIdentifier identifier1 = new TICIdentifier("{1-1}", "COM3", "021976551632"); - TICIdentifier identifier2 = new TICIdentifier("{1-2}", "COM3", "021976551633"); - TICIdentifier identifier3 = new TICIdentifier("{1-3}", "COM3", null); - TICIdentifier identifier4 = new TICIdentifier(null, "COM3", null); - - Assert.assertTrue(identifier1.matches(identifier4)); - Assert.assertFalse(identifier1.matches(identifier3)); - Assert.assertFalse(identifier1.matches(identifier2)); - } - - @Test - public void test_matches_different_portName() throws DataDictionaryException - { - TICIdentifier identifier1 = new TICIdentifier(null, "COM3", null); - TICIdentifier identifier2 = new TICIdentifier(null, "COM8", null); - - Assert.assertFalse(identifier1.matches(identifier2)); - } -} diff --git a/src/test/java/enedis/tic/service/message/TIC2WebSocketEventFactoryTest.java b/src/test/java/enedis/tic/service/message/TIC2WebSocketEventFactoryTest.java deleted file mode 100644 index 2974e57..0000000 --- a/src/test/java/enedis/tic/service/message/TIC2WebSocketEventFactoryTest.java +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.tic.service.message; - -import org.junit.Assert; -import org.junit.Test; - -import enedis.lab.util.message.Message; -import enedis.lab.util.message.MessageType; -import enedis.lab.util.message.exception.MessageInvalidContentException; -import enedis.lab.util.message.exception.MessageInvalidFormatException; -import enedis.lab.util.message.exception.MessageInvalidTypeException; -import enedis.lab.util.message.exception.MessageKeyNameDoesntExistException; -import enedis.lab.util.message.exception.MessageKeyTypeDoesntExistException; -import enedis.lab.util.message.exception.UnsupportedMessageException; -import enedis.tic.service.message.factory.TIC2WebSocketEventFactory; - -@SuppressWarnings("javadoc") -public class TIC2WebSocketEventFactoryTest -{ - @Test - public void testGetMessage_EventOnTICData() throws MessageInvalidFormatException, MessageKeyTypeDoesntExistException, MessageKeyNameDoesntExistException, - MessageInvalidTypeException, UnsupportedMessageException, MessageInvalidContentException - { - TIC2WebSocketEventFactory factory = new TIC2WebSocketEventFactory(); - - String text = "{\"type\":\"" + MessageType.EVENT.name() + "\",\"name\":\"" + EventOnTICData.NAME - + "\",\"dateTime\":\"01/01/2000 00:00:00\",\"data\":{\"captureDateTime\":\"01/01/2000 00:00:00\",\"mode\":\"STANDARD\",\"identifier\":{\"serialNumber\":\"010203040506\"},\"content\":{\"URMS\":230}}}"; - - Message message = factory.getMessage(text, EventOnTICData.NAME); - - Assert.assertNotNull(message); - Assert.assertTrue(message instanceof EventOnTICData); - - EventOnTICData event = (EventOnTICData) message; - - Assert.assertEquals(MessageType.EVENT, event.getType()); - Assert.assertEquals(EventOnTICData.NAME, event.getName()); - Assert.assertNotNull(event.getData()); - - Message messageDecoded = factory.getMessage(event.toString(), EventOnTICData.NAME); - Assert.assertNotNull(message); - Assert.assertTrue(messageDecoded.equals(event)); - } - - @Test - public void testGetMessage_EventOnError() throws MessageInvalidFormatException, MessageKeyTypeDoesntExistException, MessageKeyNameDoesntExistException, - MessageInvalidTypeException, UnsupportedMessageException, MessageInvalidContentException - { - TIC2WebSocketEventFactory factory = new TIC2WebSocketEventFactory(); - - String text = "{\"type\":\"" + MessageType.EVENT.name() + "\",\"name\":\"" + EventOnError.NAME - + "\",\"dateTime\":\"01/01/2000 00:00:00\",\"data\":{\"errorCode\":\"-1\",\"errorMessage\":\"une erreur\",\"identifier\":{\"serialNumber\":\"010203040506\"}}}"; - - Message message = factory.getMessage(text, EventOnError.NAME); - - Assert.assertNotNull(message); - Assert.assertTrue(message instanceof EventOnError); - - EventOnError event = (EventOnError) message; - - Assert.assertEquals(MessageType.EVENT, event.getType()); - Assert.assertEquals(EventOnError.NAME, event.getName()); - Assert.assertNotNull(event.getData()); - - Message messageDecoded = factory.getMessage(event.toString(), EventOnError.NAME); - Assert.assertNotNull(message); - Assert.assertTrue(messageDecoded.equals(event)); - } -} diff --git a/src/test/java/enedis/tic/service/message/TIC2WebSocketMessageFactoryTest.java b/src/test/java/enedis/tic/service/message/TIC2WebSocketMessageFactoryTest.java deleted file mode 100644 index 0431191..0000000 --- a/src/test/java/enedis/tic/service/message/TIC2WebSocketMessageFactoryTest.java +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.tic.service.message; - -import org.junit.Test; - -import enedis.lab.util.message.MessageType; -import enedis.lab.util.message.exception.MessageInvalidContentException; -import enedis.lab.util.message.exception.MessageInvalidFormatException; -import enedis.lab.util.message.exception.MessageInvalidTypeException; -import enedis.lab.util.message.exception.MessageKeyNameDoesntExistException; -import enedis.lab.util.message.exception.MessageKeyTypeDoesntExistException; -import enedis.lab.util.message.exception.UnsupportedMessageException; -import enedis.tic.service.message.factory.TIC2WebSocketMessageFactory; - -@SuppressWarnings("javadoc") -public class TIC2WebSocketMessageFactoryTest -{ - @Test(expected = UnsupportedMessageException.class) - public void testGetMessage_UnsupportedRequest() throws MessageInvalidFormatException, MessageKeyTypeDoesntExistException, MessageKeyNameDoesntExistException, - MessageInvalidTypeException, UnsupportedMessageException, MessageInvalidContentException - { - TIC2WebSocketMessageFactory factory = new TIC2WebSocketMessageFactory(); - - String text = "{\"type\":\"" + MessageType.REQUEST.name() + "\",\"name\":\"coucou\"}"; - - factory.getMessage(text); - } -} diff --git a/src/test/java/enedis/tic/service/message/TIC2WebSocketRequestFactoryTest.java b/src/test/java/enedis/tic/service/message/TIC2WebSocketRequestFactoryTest.java deleted file mode 100644 index 2ddd38c..0000000 --- a/src/test/java/enedis/tic/service/message/TIC2WebSocketRequestFactoryTest.java +++ /dev/null @@ -1,239 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.tic.service.message; - -import org.junit.Assert; -import org.junit.Test; - -import enedis.lab.util.message.Message; -import enedis.lab.util.message.MessageType; -import enedis.lab.util.message.exception.MessageInvalidContentException; -import enedis.lab.util.message.exception.MessageInvalidFormatException; -import enedis.lab.util.message.exception.MessageInvalidTypeException; -import enedis.lab.util.message.exception.MessageKeyNameDoesntExistException; -import enedis.lab.util.message.exception.MessageKeyTypeDoesntExistException; -import enedis.lab.util.message.exception.UnsupportedMessageException; -import enedis.tic.service.message.factory.TIC2WebSocketRequestFactory; - -@SuppressWarnings("javadoc") -public class TIC2WebSocketRequestFactoryTest -{ - @Test - public void testGetMessage_RequestGetAvailableTics() throws MessageInvalidFormatException, MessageKeyTypeDoesntExistException, MessageKeyNameDoesntExistException, - MessageInvalidTypeException, UnsupportedMessageException, MessageInvalidContentException - { - TIC2WebSocketRequestFactory factory = new TIC2WebSocketRequestFactory(); - - String text = "{\"type\":\"" + MessageType.REQUEST.name() + "\",\"name\":\"" + RequestGetAvailableTICs.NAME + "\"}"; - - Message message = factory.getMessage(text, RequestGetAvailableTICs.NAME); - - Assert.assertNotNull(message); - Assert.assertTrue(message instanceof RequestGetAvailableTICs); - - RequestGetAvailableTICs request = (RequestGetAvailableTICs) message; - - Assert.assertEquals(MessageType.REQUEST, request.getType()); - Assert.assertEquals(RequestGetAvailableTICs.NAME, request.getName()); - - Message messageDecoded = factory.getMessage(request.toString(), RequestGetAvailableTICs.NAME); - Assert.assertNotNull(message); - Assert.assertTrue(messageDecoded.equals(request)); - } - - @Test - public void testGetMessage_RequestGetModemsInfo() throws MessageInvalidFormatException, MessageKeyTypeDoesntExistException, MessageKeyNameDoesntExistException, - MessageInvalidTypeException, UnsupportedMessageException, MessageInvalidContentException - { - TIC2WebSocketRequestFactory factory = new TIC2WebSocketRequestFactory(); - - String text = "{\"type\":\"" + MessageType.REQUEST.name() + "\",\"name\":\"" + RequestGetModemsInfo.NAME + "\"}"; - - Message message = factory.getMessage(text, RequestGetModemsInfo.NAME); - - Assert.assertNotNull(message); - Assert.assertTrue(message instanceof RequestGetModemsInfo); - - RequestGetModemsInfo request = (RequestGetModemsInfo) message; - - Assert.assertEquals(MessageType.REQUEST, request.getType()); - Assert.assertEquals(RequestGetModemsInfo.NAME, request.getName()); - - Message messageDecoded = factory.getMessage(request.toString(), RequestGetModemsInfo.NAME); - Assert.assertNotNull(message); - Assert.assertTrue(messageDecoded.equals(request)); - } - - @Test - public void testGetMessage_RequestReadTIC() throws MessageInvalidFormatException, MessageKeyTypeDoesntExistException, MessageKeyNameDoesntExistException, - MessageInvalidTypeException, UnsupportedMessageException, MessageInvalidContentException - { - TIC2WebSocketRequestFactory factory = new TIC2WebSocketRequestFactory(); - - String text = "{\"type\":\"" + MessageType.REQUEST.name() + "\",\"name\":\"" + RequestReadTIC.NAME + "\",\"data\":{\"serialNumber\":\"010203040506\"}}"; - - Message message = factory.getMessage(text, RequestReadTIC.NAME); - - Assert.assertNotNull(message); - Assert.assertTrue(message instanceof RequestReadTIC); - - RequestReadTIC request = (RequestReadTIC) message; - - Assert.assertEquals(MessageType.REQUEST, request.getType()); - Assert.assertEquals(RequestReadTIC.NAME, request.getName()); - Assert.assertNotNull(request.getData()); - - Message messageDecoded = factory.getMessage(request.toString(), RequestReadTIC.NAME); - Assert.assertNotNull(message); - Assert.assertTrue(messageDecoded.equals(request)); - } - - @Test - public void testGetMessage_RequestSubscribeTIC_allTIC() throws MessageInvalidFormatException, MessageKeyTypeDoesntExistException, MessageKeyNameDoesntExistException, - MessageInvalidTypeException, UnsupportedMessageException, MessageInvalidContentException - { - TIC2WebSocketRequestFactory factory = new TIC2WebSocketRequestFactory(); - - String text = "{\"type\":\"" + MessageType.REQUEST.name() + "\",\"name\":\"" + RequestSubscribeTIC.NAME + "\"}"; - - Message message = factory.getMessage(text, RequestSubscribeTIC.NAME); - - Assert.assertNotNull(message); - Assert.assertTrue(message instanceof RequestSubscribeTIC); - - RequestSubscribeTIC request = (RequestSubscribeTIC) message; - - Assert.assertEquals(MessageType.REQUEST, request.getType()); - Assert.assertEquals(RequestSubscribeTIC.NAME, request.getName()); - - Message messageDecoded = factory.getMessage(request.toString(), RequestSubscribeTIC.NAME); - Assert.assertNotNull(message); - Assert.assertTrue(messageDecoded.equals(request)); - } - - @Test - public void testGetMessage_RequestSubscribeTIC_oneTIC() throws MessageInvalidFormatException, MessageKeyTypeDoesntExistException, MessageKeyNameDoesntExistException, - MessageInvalidTypeException, UnsupportedMessageException, MessageInvalidContentException - { - TIC2WebSocketRequestFactory factory = new TIC2WebSocketRequestFactory(); - - String text = "{\"type\":\"" + MessageType.REQUEST.name() + "\",\"name\":\"" + RequestSubscribeTIC.NAME + "\",\"data\":{\"serialNumber\":\"010203040506\"}}"; - - Message message = factory.getMessage(text, RequestSubscribeTIC.NAME); - - Assert.assertNotNull(message); - Assert.assertTrue(message instanceof RequestSubscribeTIC); - - RequestSubscribeTIC request = (RequestSubscribeTIC) message; - - Assert.assertEquals(MessageType.REQUEST, request.getType()); - Assert.assertEquals(RequestSubscribeTIC.NAME, request.getName()); - Assert.assertNotNull(request.getData()); - - Message messageDecoded = factory.getMessage(request.toString(), RequestSubscribeTIC.NAME); - Assert.assertNotNull(message); - Assert.assertTrue(messageDecoded.equals(request)); - } - - @Test - public void testGetMessage_RequestSubscribeTIC_severalTIC() throws MessageInvalidFormatException, MessageKeyTypeDoesntExistException, MessageKeyNameDoesntExistException, - MessageInvalidTypeException, UnsupportedMessageException, MessageInvalidContentException - { - TIC2WebSocketRequestFactory factory = new TIC2WebSocketRequestFactory(); - - String text = "{\"type\":\"" + MessageType.REQUEST.name() + "\",\"name\":\"" + RequestSubscribeTIC.NAME - + "\",\"data\":[{\"serialNumber\":\"010203040506\"},{\"portId\":\"1-1\"}]}"; - - Message message = factory.getMessage(text, RequestSubscribeTIC.NAME); - - Assert.assertNotNull(message); - Assert.assertTrue(message instanceof RequestSubscribeTIC); - - RequestSubscribeTIC request = (RequestSubscribeTIC) message; - - Assert.assertEquals(MessageType.REQUEST, request.getType()); - Assert.assertEquals(RequestSubscribeTIC.NAME, request.getName()); - Assert.assertNotNull(request.getData()); - - Message messageDecoded = factory.getMessage(request.toString(), RequestSubscribeTIC.NAME); - Assert.assertNotNull(message); - Assert.assertTrue(messageDecoded.equals(request)); - } - - @Test - public void testGetMessage_RequestUnsubscribeTIC_allTIC() throws MessageInvalidFormatException, MessageKeyTypeDoesntExistException, MessageKeyNameDoesntExistException, - MessageInvalidTypeException, UnsupportedMessageException, MessageInvalidContentException - { - TIC2WebSocketRequestFactory factory = new TIC2WebSocketRequestFactory(); - - String text = "{\"type\":\"" + MessageType.REQUEST.name() + "\",\"name\":\"" + RequestUnsubscribeTIC.NAME + "\"}"; - - Message message = factory.getMessage(text, RequestUnsubscribeTIC.NAME); - - Assert.assertNotNull(message); - Assert.assertTrue(message instanceof RequestUnsubscribeTIC); - - RequestUnsubscribeTIC request = (RequestUnsubscribeTIC) message; - - Assert.assertEquals(MessageType.REQUEST, request.getType()); - Assert.assertEquals(RequestUnsubscribeTIC.NAME, request.getName()); - - Message messageDecoded = factory.getMessage(request.toString(), RequestUnsubscribeTIC.NAME); - Assert.assertNotNull(message); - Assert.assertTrue(messageDecoded.equals(request)); - } - - @Test - public void testGetMessage_RequestUnsubscribeTIC_oneTIC() throws MessageInvalidFormatException, MessageKeyTypeDoesntExistException, MessageKeyNameDoesntExistException, - MessageInvalidTypeException, UnsupportedMessageException, MessageInvalidContentException - { - TIC2WebSocketRequestFactory factory = new TIC2WebSocketRequestFactory(); - - String text = "{\"type\":\"" + MessageType.REQUEST.name() + "\",\"name\":\"" + RequestUnsubscribeTIC.NAME + "\",\"data\":{\"serialNumber\":\"010203040506\"}}"; - - Message message = factory.getMessage(text, RequestUnsubscribeTIC.NAME); - - Assert.assertNotNull(message); - Assert.assertTrue(message instanceof RequestUnsubscribeTIC); - - RequestUnsubscribeTIC request = (RequestUnsubscribeTIC) message; - - Assert.assertEquals(MessageType.REQUEST, request.getType()); - Assert.assertEquals(RequestUnsubscribeTIC.NAME, request.getName()); - Assert.assertNotNull(request.getData()); - - Message messageDecoded = factory.getMessage(request.toString(), RequestUnsubscribeTIC.NAME); - Assert.assertNotNull(message); - Assert.assertTrue(messageDecoded.equals(request)); - } - - @Test - public void testGetMessage_RequestUnsubscribeTIC_severalTIC() throws MessageInvalidFormatException, MessageKeyTypeDoesntExistException, MessageKeyNameDoesntExistException, - MessageInvalidTypeException, UnsupportedMessageException, MessageInvalidContentException - { - TIC2WebSocketRequestFactory factory = new TIC2WebSocketRequestFactory(); - - String text = "{\"type\":\"" + MessageType.REQUEST.name() + "\",\"name\":\"" + RequestUnsubscribeTIC.NAME - + "\",\"data\":[{\"serialNumber\":\"010203040506\"},{\"portId\":\"1-1\"}]}"; - - Message message = factory.getMessage(text, RequestUnsubscribeTIC.NAME); - - Assert.assertNotNull(message); - Assert.assertTrue(message instanceof RequestUnsubscribeTIC); - - RequestUnsubscribeTIC request = (RequestUnsubscribeTIC) message; - - Assert.assertEquals(MessageType.REQUEST, request.getType()); - Assert.assertEquals(RequestUnsubscribeTIC.NAME, request.getName()); - Assert.assertNotNull(request.getData()); - - Message messageDecoded = factory.getMessage(request.toString(), RequestUnsubscribeTIC.NAME); - Assert.assertNotNull(message); - Assert.assertTrue(messageDecoded.equals(request)); - } -} diff --git a/src/test/java/enedis/tic/service/message/TIC2WebSocketResponseFactoryTest.java b/src/test/java/enedis/tic/service/message/TIC2WebSocketResponseFactoryTest.java deleted file mode 100644 index dc8068e..0000000 --- a/src/test/java/enedis/tic/service/message/TIC2WebSocketResponseFactoryTest.java +++ /dev/null @@ -1,161 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.tic.service.message; - -import org.junit.Assert; -import org.junit.Test; - -import enedis.lab.util.message.Message; -import enedis.lab.util.message.MessageType; -import enedis.lab.util.message.exception.MessageInvalidContentException; -import enedis.lab.util.message.exception.MessageInvalidFormatException; -import enedis.lab.util.message.exception.MessageInvalidTypeException; -import enedis.lab.util.message.exception.MessageKeyNameDoesntExistException; -import enedis.lab.util.message.exception.MessageKeyTypeDoesntExistException; -import enedis.lab.util.message.exception.UnsupportedMessageException; -import enedis.tic.service.message.factory.TIC2WebSocketResponseFactory; - -@SuppressWarnings("javadoc") -public class TIC2WebSocketResponseFactoryTest -{ - @Test - public void testGetMessage_ResponseGetAvailableTics() throws MessageInvalidFormatException, MessageKeyTypeDoesntExistException, MessageKeyNameDoesntExistException, - MessageInvalidTypeException, UnsupportedMessageException, MessageInvalidContentException - { - TIC2WebSocketResponseFactory factory = new TIC2WebSocketResponseFactory(); - - String text = "{\"type\":\"" + MessageType.RESPONSE.name() + "\",\"name\":\"" + ResponseGetAvailableTICs.NAME - + "\",\"dateTime\":\"01/01/2000 00:00:00\",\"errorCode\":0,\"data\":[{\"serialNumber\":\"010203040506\"}]}"; - - Message message = factory.getMessage(text, ResponseGetAvailableTICs.NAME); - - Assert.assertNotNull(message); - Assert.assertTrue(message instanceof ResponseGetAvailableTICs); - - ResponseGetAvailableTICs response = (ResponseGetAvailableTICs) message; - - Assert.assertEquals(MessageType.RESPONSE, response.getType()); - Assert.assertEquals(ResponseGetAvailableTICs.NAME, response.getName()); - Assert.assertNotNull(response.getDateTime()); - Assert.assertEquals(0, response.getErrorCode().intValue()); - Assert.assertNull(response.getErrorMessage()); - Assert.assertNotNull(response.getData()); - - Message messageDecoded = factory.getMessage(response.toString(), ResponseGetAvailableTICs.NAME); - Assert.assertNotNull(message); - Assert.assertTrue(messageDecoded.equals(response)); - } - - @Test - public void testGetMessage_ResponseGetModemsInfo() throws MessageInvalidFormatException, MessageKeyTypeDoesntExistException, MessageKeyNameDoesntExistException, - MessageInvalidTypeException, UnsupportedMessageException, MessageInvalidContentException - { - TIC2WebSocketResponseFactory factory = new TIC2WebSocketResponseFactory(); - - String text = "{\"type\":\"" + MessageType.RESPONSE.name() + "\",\"name\":\"" + ResponseGetModemsInfo.NAME - + "\",\"dateTime\":\"01/01/2000 00:00:00\",\"errorCode\":0,\"errorMessage\":\"error\"}"; - - Message message = factory.getMessage(text, ResponseGetModemsInfo.NAME); - - Assert.assertNotNull(message); - Assert.assertTrue(message instanceof ResponseGetModemsInfo); - - ResponseGetModemsInfo response = (ResponseGetModemsInfo) message; - - Assert.assertEquals(MessageType.RESPONSE, response.getType()); - Assert.assertEquals(ResponseGetModemsInfo.NAME, response.getName()); - Assert.assertNotNull(response.getDateTime()); - Assert.assertEquals(0, response.getErrorCode().intValue()); - Assert.assertEquals("error", response.getErrorMessage()); - Assert.assertNull(response.getData()); - - Message messageDecoded = factory.getMessage(response.toString(), ResponseGetModemsInfo.NAME); - Assert.assertNotNull(message); - Assert.assertTrue(messageDecoded.equals(response)); - } - - @Test - public void testGetMessage_ResponseReadTIC() throws MessageInvalidFormatException, MessageKeyTypeDoesntExistException, MessageKeyNameDoesntExistException, - MessageInvalidTypeException, UnsupportedMessageException, MessageInvalidContentException - { - TIC2WebSocketResponseFactory factory = new TIC2WebSocketResponseFactory(); - - String text = "{\"type\":\"" + MessageType.RESPONSE.name() + "\",\"name\":\"" + ResponseReadTIC.NAME - + "\",\"dateTime\":\"01/01/2000 00:00:00\",\"errorCode\":0,\"data\":{\"captureDateTime\":\"01/01/2000 00:00:00\",\"mode\":\"STANDARD\",\"identifier\":{\"serialNumber\":\"010203040506\"},\"content\":{\"URMS\":230}}}"; - - Message message = factory.getMessage(text, ResponseReadTIC.NAME); - - Assert.assertNotNull(message); - Assert.assertTrue(message instanceof ResponseReadTIC); - - ResponseReadTIC response = (ResponseReadTIC) message; - - Assert.assertEquals(MessageType.RESPONSE, response.getType()); - Assert.assertEquals(ResponseReadTIC.NAME, response.getName()); - Assert.assertNotNull(response.getDateTime()); - Assert.assertEquals(0, response.getErrorCode().intValue()); - Assert.assertNull(response.getErrorMessage()); - Assert.assertNotNull(response.getData()); - - Message messageDecoded = factory.getMessage(response.toString(), ResponseReadTIC.NAME); - Assert.assertNotNull(message); - Assert.assertTrue(messageDecoded.equals(response)); - } - - @Test - public void testGetMessage_ResponseSubscribeTIC() throws MessageInvalidFormatException, MessageKeyTypeDoesntExistException, MessageKeyNameDoesntExistException, - MessageInvalidTypeException, UnsupportedMessageException, MessageInvalidContentException - { - TIC2WebSocketResponseFactory factory = new TIC2WebSocketResponseFactory(); - - String text = "{\"type\":\"" + MessageType.RESPONSE.name() + "\",\"name\":\"" + ResponseSubscribeTIC.NAME + "\",\"dateTime\":\"01/01/2000 00:00:00\",\"errorCode\":0}"; - - Message message = factory.getMessage(text, ResponseSubscribeTIC.NAME); - - Assert.assertNotNull(message); - Assert.assertTrue(message instanceof ResponseSubscribeTIC); - - ResponseSubscribeTIC response = (ResponseSubscribeTIC) message; - - Assert.assertEquals(MessageType.RESPONSE, response.getType()); - Assert.assertEquals(ResponseSubscribeTIC.NAME, response.getName()); - Assert.assertNotNull(response.getDateTime()); - Assert.assertEquals(0, response.getErrorCode().intValue()); - Assert.assertNull(response.getErrorMessage()); - - Message messageDecoded = factory.getMessage(response.toString(), ResponseSubscribeTIC.NAME); - Assert.assertNotNull(message); - Assert.assertTrue(messageDecoded.equals(response)); - } - - @Test - public void testGetMessage_ResponseUnsubscribeTIC_allTIC() throws MessageInvalidFormatException, MessageKeyTypeDoesntExistException, MessageKeyNameDoesntExistException, - MessageInvalidTypeException, UnsupportedMessageException, MessageInvalidContentException - { - TIC2WebSocketResponseFactory factory = new TIC2WebSocketResponseFactory(); - - String text = "{\"type\":\"" + MessageType.RESPONSE.name() + "\",\"name\":\"" + ResponseUnsubscribeTIC.NAME + "\",\"dateTime\":\"01/01/2000 00:00:00\",\"errorCode\":0}"; - - Message message = factory.getMessage(text, ResponseUnsubscribeTIC.NAME); - - Assert.assertNotNull(message); - Assert.assertTrue(message instanceof ResponseUnsubscribeTIC); - - ResponseUnsubscribeTIC response = (ResponseUnsubscribeTIC) message; - - Assert.assertEquals(MessageType.RESPONSE, response.getType()); - Assert.assertEquals(ResponseUnsubscribeTIC.NAME, response.getName()); - Assert.assertNotNull(response.getDateTime()); - Assert.assertEquals(0, response.getErrorCode().intValue()); - Assert.assertNull(response.getErrorMessage()); - - Message messageDecoded = factory.getMessage(response.toString(), ResponseUnsubscribeTIC.NAME); - Assert.assertNotNull(message); - Assert.assertTrue(messageDecoded.equals(response)); - } -} diff --git a/src/test/java/enedis/tic/service/netty/TIC2WebSocketServerTest.java b/src/test/java/enedis/tic/service/netty/TIC2WebSocketServerTest.java deleted file mode 100644 index 948283a..0000000 --- a/src/test/java/enedis/tic/service/netty/TIC2WebSocketServerTest.java +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (C) 2025 Enedis Smarties team -// -// SPDX-FileContributor: Jehan BOUSCH -// SPDX-FileContributor: Mathieu SABARTHES -// -// SPDX-License-Identifier: Apache-2.0 - -package enedis.tic.service.netty; - -import org.junit.Test; -import static org.junit.Assert.*; - -import enedis.tic.service.client.TIC2WebSocketClientPool; -import enedis.tic.service.client.TIC2WebSocketClientPoolBase; -import enedis.tic.service.requesthandler.TIC2WebSocketRequestHandler; -import enedis.tic.service.requesthandler.TIC2WebSocketRequestHandlerBase; -import enedis.tic.core.TICCoreBase; -import enedis.lab.protocol.tic.TICMode; -import java.util.Arrays; - -/** - * Test for TIC2WebSocketServer - */ -public class TIC2WebSocketServerTest -{ - @Test - public void testServerInstantiation() - { - // Create mock dependencies - TIC2WebSocketClientPool clientPool = new TIC2WebSocketClientPoolBase(); - TIC2WebSocketRequestHandler requestHandler = new TIC2WebSocketRequestHandlerBase( - new TICCoreBase(TICMode.HISTORIC, Arrays.asList("COM1"))); - - // Test server creation - TIC2WebSocketServer server = new TIC2WebSocketServer("localhost", 8080, clientPool, requestHandler); - - assertNotNull("Server should not be null", server); - } -} diff --git a/src/test/java/tic/ResourceLoader.java b/src/test/java/tic/ResourceLoader.java new file mode 100644 index 0000000..c0bb646 --- /dev/null +++ b/src/test/java/tic/ResourceLoader.java @@ -0,0 +1,50 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +public class ResourceLoader { + + private ResourceLoader() {} + + public static String getFilePath(String resourcePath) throws URISyntaxException { + Path path = getPath(resourcePath); + + return path.toString(); + } + + public static String readString(String resourcePath) throws IOException, URISyntaxException { + return new String(readAllBytes(resourcePath)); + } + + public static byte[] readAllBytes(String resourcePath) throws IOException, URISyntaxException { + Path path = getPath(resourcePath); + + return Files.readAllBytes(path); + } + + public static Path getPath(String resourcePath) throws URISyntaxException { + URL url = ResourceLoader.class.getResource(resourcePath); + + if (url == null) { + throw new IllegalArgumentException("Resource not found: " + resourcePath); + } + + URI uri = url.toURI(); + Path path = Paths.get(uri); + + return path; + } +} diff --git a/src/test/java/tic/core/TICCoreBaseTest.java b/src/test/java/tic/core/TICCoreBaseTest.java new file mode 100644 index 0000000..d5c1869 --- /dev/null +++ b/src/test/java/tic/core/TICCoreBaseTest.java @@ -0,0 +1,788 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.core; + +import java.time.LocalDateTime; +import java.util.List; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import tic.frame.TICFrame; +import tic.frame.TICMode; +import tic.frame.group.TICGroup; +import tic.io.modem.ModemDescriptor; +import tic.io.modem.ModemFinderMock; +import tic.io.modem.ModemType; +import tic.mock.FunctionCall; +import tic.util.task.Task; +import tic.util.time.Time; + +@SuppressWarnings("javadoc") +public class TICCoreBaseTest { + private static final int NOTIFICATION_TIMEOUT = 1000; + + private ModemFinderMock ticPortFinder; + private long plugNotifierPeriod; + private TICCoreBase ticCore; + + @Before + public void startTICCore() throws TICCoreException { + this.ticPortFinder = new ModemFinderMock(); + this.plugNotifierPeriod = 50; + this.ticCore = + new TICCoreBase( + this.ticPortFinder, + this.plugNotifierPeriod, + TICMode.AUTO, + null); + + this.ticCore.start(); + this.waitTaskRunning(this.ticCore); + } + + @After + public void stopTICCore() throws TICCoreException { + this.ticCore.stop(); + TICCoreStreamMock.streams.clear(); + } + + @Test + public void test_getAvailableTICs_empty() { + // Given + List availableTICs; + + // When + availableTICs = this.ticCore.getAvailableTICs(); + + // Then + Assert.assertNotNull(availableTICs); + Assert.assertEquals(0, availableTICs.size()); + } + + // @Test + public void test_getAvailableTICs_plug() throws TICCoreException { + // Given + List availableTICs; + ModemDescriptor descriptor1 = + new ModemDescriptor.Builder<>() + .portId("1") + .portName("COM3") + .modemType(ModemType.MICHAUD) + .build(); + ModemDescriptor descriptor2 = + new ModemDescriptor.Builder<>() + .portId("2") + .portName("COM4") + .modemType(ModemType.TELEINFO) + .build(); + this.plugModem(descriptor1); + this.plugModem(descriptor2); + + // When + availableTICs = this.ticCore.getAvailableTICs(); + + // Then + Assert.assertNotNull(availableTICs); + Assert.assertEquals(2, availableTICs.size()); + Assert.assertTrue(availableTICs.contains(new TICIdentifier.Builder().portId("1").portName("COM3").build())); + Assert.assertTrue(availableTICs.contains(new TICIdentifier.Builder().portId("2").portName("COM4").build())); + } + + // @Test + public void test_getAvailableTICs_unplug() throws TICCoreException { + // Given + List availableTICs; + ModemDescriptor descriptor1 = + new ModemDescriptor.Builder<>() + .portId("1") + .portName("COM3") + .modemType(ModemType.MICHAUD) + .build(); + ModemDescriptor descriptor2 = + new ModemDescriptor.Builder<>() + .portId("2") + .portName("COM4") + .modemType(ModemType.TELEINFO) + .build(); + this.plugModem(descriptor1); + this.plugModem(descriptor2); + + // When + this.unplugModem(descriptor1); + availableTICs = this.ticCore.getAvailableTICs(); + + // Then + Assert.assertNotNull(availableTICs); + Assert.assertEquals(1, availableTICs.size()); + Assert.assertTrue(availableTICs.contains(new TICIdentifier.Builder().portId("2").portName("COM4").build())); + } + + @Test + public void test_getModemsInfo_empty() { + // Given + List modemsInfo; + + // When + modemsInfo = this.ticCore.getModemsInfo(); + + // Then + Assert.assertNotNull(modemsInfo); + Assert.assertEquals(0, modemsInfo.size()); + } + + // @Test + public void test_getModemsInfo_plug() throws TICCoreException { + // Given + List modemsInfo; + ModemDescriptor descriptor1 = + new ModemDescriptor.Builder<>() + .portId("1") + .portName("COM3") + .modemType(ModemType.MICHAUD) + .build(); + ModemDescriptor descriptor2 = + new ModemDescriptor.Builder<>() + .portId("2") + .portName("COM4") + .modemType(ModemType.TELEINFO) + .build(); + this.plugModem(descriptor1); + this.plugModem(descriptor2); + + // When + modemsInfo = this.ticCore.getModemsInfo(); + + // Then + Assert.assertNotNull(modemsInfo); + Assert.assertEquals(2, modemsInfo.size()); + Assert.assertTrue(modemsInfo.contains(descriptor1)); + Assert.assertTrue(modemsInfo.contains(descriptor2)); + } + + // @Test + public void test_getModemsInfo_unplug() throws TICCoreException { + // Given + List modemsInfo; + ModemDescriptor descriptor1 = + new ModemDescriptor.Builder<>() + .portId("1") + .portName("COM3") + .modemType(ModemType.MICHAUD) + .build(); + ModemDescriptor descriptor2 = + new ModemDescriptor.Builder<>() + .portId("2") + .portName("COM4") + .modemType(ModemType.TELEINFO) + .build(); + this.plugModem(descriptor1); + this.plugModem(descriptor2); + + // When + this.unplugModem(descriptor1); + modemsInfo = this.ticCore.getModemsInfo(); + + // Then + Assert.assertNotNull(modemsInfo); + Assert.assertEquals(1, modemsInfo.size()); + Assert.assertTrue(modemsInfo.contains(descriptor2)); + } + + // @Test + public void test_readNextFrame_ok() throws TICCoreException { + // Given + TICIdentifier identifier = + this.plugModem( + new ModemDescriptor.Builder<>() + .portId("1") + .portName("COM3") + .modemType(ModemType.MICHAUD) + .build()); + TICCoreStreamMock stream = TICCoreStreamMock.streams.get(0); + TICCoreReadNextFrameTask task = new TICCoreReadNextFrameTask(this.ticCore, identifier); + task.start(); + this.waitTaskRunning(task); + this.waitReadNextFrameSubscription(); + TICCoreFrame frame = + this.createFrame(identifier, TICMode.STANDARD, LocalDateTime.of(2020, 3, 3, 12, 59, 30, 0)); + + // When + stream.notifyOnData(frame); + this.waitTaskTerminated(task); + + // Then + Assert.assertNull(task.exception); + Assert.assertNotNull(task.frame); + Assert.assertTrue(task.frame == frame); + } + + // @Test + public void test_readNextFrame_error_OTHER_REASON() throws TICCoreException { + // Given + TICIdentifier identifier = + this.plugModem( + new ModemDescriptor.Builder<>() + .portId("1") + .portName("COM3") + .modemType(ModemType.MICHAUD) + .build()); + TICCoreStreamMock stream = TICCoreStreamMock.streams.get(0); + TICCoreReadNextFrameTask task = new TICCoreReadNextFrameTask(this.ticCore, identifier); + TICCoreError error = + new TICCoreError(identifier, TICCoreErrorCode.OTHER_REASON.getCode(), "Cannot read stream"); + + task.start(); + this.waitTaskRunning(task); + this.waitReadNextFrameSubscription(); + + // When + stream.notifyOnError(error); + this.waitTaskTerminated(task); + + // Then + Assert.assertNull(task.frame); + Assert.assertNotNull(task.exception); + Assert.assertTrue(task.exception instanceof TICCoreException); + TICCoreException exception = (TICCoreException) task.exception; + Assert.assertEquals(error.getErrorCode(), exception.getErrorCode()); + Assert.assertEquals(error.getErrorMessage(), exception.getErrorInfo()); + } + + // @Test + public void test_readNextFrame_error_STREAM_IDENTIFIER_NOT_FOUND() throws TICCoreException { + // Given + this.plugModem( + new ModemDescriptor.Builder<>() + .portId("1") + .portName("COM3") + .modemType(ModemType.MICHAUD) + .build()); + TICCoreReadNextFrameTask task = + new TICCoreReadNextFrameTask(this.ticCore, new TICIdentifier.Builder().portId("2").portName("COM3").build()); + + // When + task.start(); + this.waitTaskRunning(task); + this.waitTaskTerminated(task); + + // Then + Assert.assertNull(task.frame); + Assert.assertNotNull(task.exception); + Assert.assertTrue(task.exception instanceof TICCoreException); + TICCoreException exception = (TICCoreException) task.exception; + Assert.assertEquals( + TICCoreErrorCode.STREAM_IDENTIFIER_NOT_FOUND.getCode(), exception.getErrorCode()); + } + + // @Test + public void test_readNextFrame_timeout() throws TICCoreException { + // Given + TICIdentifier identifier = + this.plugModem( + new ModemDescriptor.Builder<>() + .portId("1") + .portName("COM3") + .modemType(ModemType.MICHAUD) + .build()); + TICCoreReadNextFrameTask task = new TICCoreReadNextFrameTask(this.ticCore, identifier, 200); + + // When + task.start(); + this.waitTaskRunning(task); + this.waitReadNextFrameSubscription(); + this.waitTaskTerminated(task); + + // Then + Assert.assertNull(task.frame); + Assert.assertNotNull(task.exception); + Assert.assertTrue(task.exception instanceof TICCoreException); + TICCoreException exception = (TICCoreException) task.exception; + Assert.assertEquals(TICCoreErrorCode.DATA_READ_TIMEOUT.getCode(), exception.getErrorCode()); + } + + @Test + public void test_subscribe_any() { + // Given + Exception exception = null; + TICCoreSubscriberMock subscriber = new TICCoreSubscriberMock(); + + // When + try { + this.ticCore.subscribe(subscriber); + } catch (Exception e) { + exception = e; + } + + // Then + Assert.assertNull(exception); + } + + @Test + public void test_unsubscribe_any() { + // Given + Exception exception = null; + TICCoreSubscriberMock subscriber = new TICCoreSubscriberMock(); + this.ticCore.subscribe(subscriber); + + // When + try { + this.ticCore.unsubscribe(subscriber); + } catch (Exception e) { + exception = e; + } + + // Then + Assert.assertNull(exception); + } + + // @Test + public void test_subscribe_withIdentifier_ok() { + // Given + Exception exception = null; + ModemDescriptor descriptor = + new ModemDescriptor.Builder<>() + .portId("1") + .portName("COM3") + .modemType(ModemType.MICHAUD) + .build(); + TICCoreSubscriberMock subscriber = new TICCoreSubscriberMock(); + TICIdentifier identifier; + + // When + try { + identifier = this.plugModem(descriptor); + this.ticCore.subscribe(identifier, subscriber); + } catch (Exception e) { + exception = e; + } + + // Then + Assert.assertNull(exception); + } + + // @Test + public void test_unsubscribe_withIdentifier_ok() { + // Given + Exception exception = null; + ModemDescriptor descriptor = + new ModemDescriptor.Builder<>() + .portId("1") + .portName("COM3") + .modemType(ModemType.MICHAUD) + .build(); + TICCoreSubscriberMock subscriber = new TICCoreSubscriberMock(); + TICIdentifier identifier; + + // When + try { + identifier = this.plugModem(descriptor); + this.ticCore.subscribe(identifier, subscriber); + this.ticCore.unsubscribe(identifier, subscriber); + } catch (Exception e) { + exception = e; + } + + // Then + Assert.assertNull(exception); + } + + // @Test + public void test_subscribe_withIdentifier_notFound() throws TICCoreException { + // Given + Exception exception = null; + this.plugModem( + new ModemDescriptor.Builder<>() + .portId("1") + .portName("COM3") + .modemType(ModemType.MICHAUD) + .build()); + TICCoreSubscriberMock subscriber = new TICCoreSubscriberMock(); + TICIdentifier identifier = new TICIdentifier.Builder().portName("COM4").build(); + + // When + try { + this.ticCore.subscribe(identifier, subscriber); + Assert.fail( + "Subscribe should have thrown an exception since stream identifier does not match !"); + } catch (Exception e) { + exception = e; + } + + // Then + Assert.assertTrue(exception instanceof TICCoreException); + TICCoreException ticCoreException = (TICCoreException) exception; + Assert.assertEquals( + TICCoreErrorCode.STREAM_IDENTIFIER_NOT_FOUND.getCode(), ticCoreException.getErrorCode()); + } + + // @Test + public void test_onError_whenUnplugModem() throws TICCoreException { + // Given + ModemDescriptor descriptor1 = + new ModemDescriptor.Builder<>() + .portId("1") + .portName("COM3") + .modemType(ModemType.MICHAUD) + .build(); + ModemDescriptor descriptor2 = + new ModemDescriptor.Builder<>() + .portId("2") + .portName("COM4") + .modemType(ModemType.TELEINFO) + .build(); + TICIdentifier identifier1 = this.plugModem(descriptor1); + TICIdentifier identifier2 = this.plugModem(descriptor2); + TICCoreSubscriberMock subscriber1 = new TICCoreSubscriberMock(); + TICCoreSubscriberMock subscriber2 = new TICCoreSubscriberMock(); + TICCoreSubscriberMock subscriber3 = new TICCoreSubscriberMock(); + TICCoreSubscriberMock subscriber4 = new TICCoreSubscriberMock(); + TICCoreSubscriberMock subscriber5 = new TICCoreSubscriberMock(); + this.ticCore.subscribe(subscriber1); + this.ticCore.subscribe(identifier1, subscriber2); + this.ticCore.subscribe(identifier1, subscriber3); + this.ticCore.subscribe(identifier2, subscriber4); + this.ticCore.subscribe(identifier2, subscriber5); + + // When + this.unplugModem(descriptor1); + + // Then + this.waitSubscriberNotification(subscriber1.onErrorCalls, 1); + Assert.assertEquals(1, subscriber1.onErrorCalls.size()); + Assert.assertEquals( + TICCoreErrorCode.STREAM_UNPLUGGED.getCode(), + subscriber1.onErrorCalls.get(0).error.getErrorCode()); + this.waitSubscriberNotification(subscriber2.onErrorCalls, 1); + Assert.assertEquals(1, subscriber2.onErrorCalls.size()); + Assert.assertEquals( + TICCoreErrorCode.STREAM_UNPLUGGED.getCode(), + subscriber2.onErrorCalls.get(0).error.getErrorCode()); + this.waitSubscriberNotification(subscriber3.onErrorCalls, 1); + Assert.assertEquals(1, subscriber3.onErrorCalls.size()); + Assert.assertEquals( + TICCoreErrorCode.STREAM_UNPLUGGED.getCode(), + subscriber3.onErrorCalls.get(0).error.getErrorCode()); + Assert.assertEquals(0, subscriber4.onErrorCalls.size()); + Assert.assertEquals(0, subscriber5.onErrorCalls.size()); + + // When + this.unplugModem(descriptor2); + + // Then + this.waitSubscriberNotification(subscriber4.onErrorCalls, 1); + Assert.assertEquals(1, subscriber4.onErrorCalls.size()); + Assert.assertEquals( + TICCoreErrorCode.STREAM_UNPLUGGED.getCode(), + subscriber4.onErrorCalls.get(0).error.getErrorCode()); + this.waitSubscriberNotification(subscriber5.onErrorCalls, 1); + Assert.assertEquals(1, subscriber5.onErrorCalls.size()); + Assert.assertEquals( + TICCoreErrorCode.STREAM_UNPLUGGED.getCode(), + subscriber5.onErrorCalls.get(0).error.getErrorCode()); + this.waitSubscriberNotification(subscriber1.onErrorCalls, 1); + Assert.assertEquals(2, subscriber1.onErrorCalls.size()); + Assert.assertEquals( + TICCoreErrorCode.STREAM_UNPLUGGED.getCode(), + subscriber1.onErrorCalls.get(1).error.getErrorCode()); + Assert.assertEquals(1, subscriber2.onErrorCalls.size()); + Assert.assertEquals(1, subscriber3.onErrorCalls.size()); + } + + // @Test + public void test_onData_any_oneModem() throws TICCoreException { + // Given + TICCoreSubscriberMock subscriber = new TICCoreSubscriberMock(); + this.ticCore.subscribe(subscriber); + this.plugModem( + new ModemDescriptor.Builder<>() + .portId("1") + .portName("COM3") + .modemType(ModemType.MICHAUD) + .build()); + TICCoreStreamMock stream1 = TICCoreStreamMock.streams.get(0); + TICCoreFrame frame1 = + this.createFrame( + stream1.getIdentifier(), TICMode.STANDARD, LocalDateTime.of(2020, 3, 3, 12, 59, 30, 0)); + + // When + stream1.notifyOnData(frame1); + this.waitSubscriberNotification(subscriber.onDataCalls, 1); + + // Then + Assert.assertEquals(1, subscriber.onDataCalls.size()); + Assert.assertTrue(frame1 == subscriber.onDataCalls.get(0).frame); + } + + // @Test + public void test_onData_any_twoModems() throws TICCoreException { + // Given + TICCoreSubscriberMock subscriber = new TICCoreSubscriberMock(); + this.ticCore.subscribe(subscriber); + this.plugModem( + new ModemDescriptor.Builder<>() + .portId("1") + .portName("COM3") + .modemType(ModemType.MICHAUD) + .build()); + this.plugModem( + new ModemDescriptor.Builder<>() + .portId("2") + .portName("COM4") + .modemType(ModemType.TELEINFO) + .build()); + TICCoreStreamMock stream1 = TICCoreStreamMock.streams.get(0); + TICCoreStreamMock stream2 = TICCoreStreamMock.streams.get(1); + TICCoreFrame frame1 = + this.createFrame( + stream1.getIdentifier(), TICMode.STANDARD, LocalDateTime.of(2020, 3, 3, 12, 59, 30, 0)); + TICCoreFrame frame2 = + this.createFrame( + stream2.getIdentifier(), TICMode.HISTORIC, LocalDateTime.of(2017, 2, 14, 9, 37, 12, 0)); + + // When + stream1.notifyOnData(frame1); + this.waitSubscriberNotification(subscriber.onDataCalls, 1); + stream2.notifyOnData(frame2); + this.waitSubscriberNotification(subscriber.onDataCalls, 2); + + // Then + Assert.assertEquals(2, subscriber.onDataCalls.size()); + Assert.assertTrue(frame1 == subscriber.onDataCalls.get(0).frame); + Assert.assertTrue(frame2 == subscriber.onDataCalls.get(1).frame); + } + + // @Test + public void test_onData_withIdentifier_oneModem() throws TICCoreException { + // Given + TICIdentifier identifier = + this.plugModem( + new ModemDescriptor.Builder<>() + .portId("1") + .portName("COM3") + .modemType(ModemType.MICHAUD) + .build()); + TICCoreSubscriberMock subscriber = new TICCoreSubscriberMock(); + this.ticCore.subscribe(identifier, subscriber); + TICCoreStreamMock stream1 = TICCoreStreamMock.streams.get(0); + TICCoreFrame frame1 = + this.createFrame( + stream1.getIdentifier(), TICMode.STANDARD, LocalDateTime.of(2020, 3, 3, 12, 59, 30, 0)); + + // When + stream1.notifyOnData(frame1); + this.waitSubscriberNotification(subscriber.onDataCalls, 1); + + // Then + Assert.assertEquals(1, subscriber.onDataCalls.size()); + Assert.assertTrue(frame1 == subscriber.onDataCalls.get(0).frame); + } + + // @Test + public void test_onData_withIdentifier_twoModems() throws TICCoreException { + // Given + TICIdentifier identifier = + this.plugModem( + new ModemDescriptor.Builder<>() + .portId("1") + .portName("COM3") + .modemType(ModemType.MICHAUD) + .build()); + this.plugModem( + new ModemDescriptor.Builder<>() + .portId("2") + .portName("COM4") + .modemType(ModemType.TELEINFO) + .build()); + + TICCoreSubscriberMock subscriber = new TICCoreSubscriberMock(); + this.ticCore.subscribe(identifier, subscriber); + TICCoreStreamMock stream1 = TICCoreStreamMock.streams.get(0); + TICCoreStreamMock stream2 = TICCoreStreamMock.streams.get(1); + TICCoreFrame frame1 = + this.createFrame( + stream1.getIdentifier(), TICMode.STANDARD, LocalDateTime.of(2020, 3, 3, 12, 59, 30, 0)); + TICCoreFrame frame2 = + this.createFrame( + stream2.getIdentifier(), TICMode.HISTORIC, LocalDateTime.of(2017, 2, 14, 9, 37, 12, 0)); + + // When + stream1.notifyOnData(frame1); + this.waitSubscriberNotification(subscriber.onDataCalls, 1); + stream2.notifyOnData(frame2); + this.waitSubscriberNotification(subscriber.onDataCalls, 1); + + // Then + Assert.assertEquals(1, subscriber.onDataCalls.size()); + Assert.assertTrue(frame1 == subscriber.onDataCalls.get(0).frame); + } + + // @Test + public void test_onError_any() throws TICCoreException { + // Given + TICCoreSubscriberMock subscriber = new TICCoreSubscriberMock(); + this.ticCore.subscribe(subscriber); + this.plugModem( + new ModemDescriptor.Builder<>() + .portId("1") + .portName("COM3") + .modemType(ModemType.MICHAUD) + .build()); + TICCoreStreamMock stream1 = TICCoreStreamMock.streams.get(0); + TICCoreError error1 = + new TICCoreError( + stream1.getIdentifier(), TICCoreErrorCode.OTHER_REASON.getCode(), "Cannot read stream"); + + // When + stream1.notifyOnError(error1); + this.waitSubscriberNotification(subscriber.onErrorCalls, 1); + + // Then + Assert.assertEquals(1, subscriber.onErrorCalls.size()); + Assert.assertTrue(error1 == subscriber.onErrorCalls.get(0).error); + } + + // @Test + public void test_onError_withIdentifier() throws TICCoreException { + // Given + TICIdentifier identifier = + this.plugModem( + new ModemDescriptor.Builder<>() + .portId("1") + .portName("COM3") + .modemType(ModemType.MICHAUD) + .build()); + TICCoreSubscriberMock subscriber = new TICCoreSubscriberMock(); + this.ticCore.subscribe(identifier, subscriber); + TICCoreStreamMock stream1 = TICCoreStreamMock.streams.get(0); + TICCoreError error1 = + new TICCoreError( + stream1.getIdentifier(), TICCoreErrorCode.OTHER_REASON.getCode(), "Cannot read stream"); + + // When + stream1.notifyOnError(error1); + this.waitSubscriberNotification(subscriber.onErrorCalls, 1); + + // Then + Assert.assertEquals(1, subscriber.onErrorCalls.size()); + Assert.assertTrue(error1 == subscriber.onErrorCalls.get(0).error); + } + + // @Test + public void test_getIdentifiers() throws TICCoreException { + // Given + TICIdentifier identifier1 = + this.plugModem( + new ModemDescriptor.Builder<>() + .portId("1") + .portName("COM3") + .modemType(ModemType.MICHAUD) + .build()); + TICIdentifier identifier2 = + this.plugModem( + new ModemDescriptor.Builder<>() + .portId("2") + .portName("COM4") + .modemType(ModemType.TELEINFO) + .build()); + + TICCoreSubscriberMock subscriber1 = new TICCoreSubscriberMock(); + TICCoreSubscriberMock subscriber2 = new TICCoreSubscriberMock(); + TICCoreSubscriberMock subscriber3 = new TICCoreSubscriberMock(); + List indentifierList1_subscribed; + List indentifierList2_subscribed; + List indentifierList3_subscribed; + List indentifierList1_unsubscribed; + List indentifierList2_unsubscribed; + List indentifierList3_unsubscribed; + + // When + this.ticCore.subscribe(subscriber1); + indentifierList1_subscribed = this.ticCore.getIndentifiers(subscriber1); + this.ticCore.subscribe(identifier1, subscriber2); + indentifierList2_subscribed = this.ticCore.getIndentifiers(subscriber2); + this.ticCore.subscribe(identifier2, subscriber3); + indentifierList3_subscribed = this.ticCore.getIndentifiers(subscriber3); + this.ticCore.unsubscribe(subscriber1); + indentifierList1_unsubscribed = this.ticCore.getIndentifiers(subscriber1); + this.ticCore.unsubscribe(identifier1, subscriber2); + indentifierList2_unsubscribed = this.ticCore.getIndentifiers(subscriber2); + this.ticCore.unsubscribe(identifier2, subscriber3); + indentifierList3_unsubscribed = this.ticCore.getIndentifiers(subscriber3); + + // Then + Assert.assertNotNull(indentifierList1_subscribed); + Assert.assertEquals(2, indentifierList1_subscribed.size()); + Assert.assertTrue(indentifierList1_subscribed.contains(identifier1)); + Assert.assertTrue(indentifierList1_subscribed.contains(identifier2)); + Assert.assertNotNull(indentifierList2_subscribed); + Assert.assertEquals(1, indentifierList2_subscribed.size()); + Assert.assertTrue(indentifierList2_subscribed.contains(identifier1)); + Assert.assertNotNull(indentifierList3_subscribed); + Assert.assertEquals(1, indentifierList3_subscribed.size()); + Assert.assertTrue(indentifierList3_subscribed.contains(identifier2)); + Assert.assertNotNull(indentifierList1_unsubscribed); + Assert.assertEquals(0, indentifierList1_unsubscribed.size()); + Assert.assertNotNull(indentifierList2_unsubscribed); + Assert.assertEquals(0, indentifierList2_unsubscribed.size()); + Assert.assertNotNull(indentifierList3_unsubscribed); + Assert.assertEquals(0, indentifierList3_unsubscribed.size()); + } + + private TICIdentifier plugModem(ModemDescriptor descriptor) { + this.ticPortFinder.addDescriptor(descriptor); + this.waitPlugNotifierUpdate(); + + return new TICIdentifier.Builder().portId(descriptor.portId()).portName(descriptor.portName()).build(); + } + + private void unplugModem(ModemDescriptor descriptor) { + this.ticPortFinder.removeDescriptor(descriptor); + this.waitPlugNotifierUpdate(); + } + + private TICCoreFrame createFrame( + TICIdentifier identifier, TICMode mode, LocalDateTime localDateTime) { + TICFrame content = new TICFrame(mode); + if (mode == TICMode.STANDARD) { + content.addGroup(new TICGroup("ADSC", identifier.getSerialNumber())); + } else { + content.addGroup(new TICGroup("ADCO", identifier.getSerialNumber())); + } + return new TICCoreFrame(identifier, mode, localDateTime, content); + } + + private void waitPlugNotifierUpdate() { + Time.sleep(2 * this.plugNotifierPeriod); + } + + private void waitTaskRunning(Task task) { + while (!task.isRunning()) { + Time.sleep(50); + } + } + + private void waitTaskTerminated(Task task) { + while (task.isRunning()) { + Time.sleep(50); + } + } + + private void waitReadNextFrameSubscription() { + Time.sleep(100); + } + + private void waitSubscriberNotification(List onCalls, int expectedSize) { + long begin = System.nanoTime(); + long elapsed = 0; + while (onCalls.size() < expectedSize && elapsed < NOTIFICATION_TIMEOUT) { + Time.sleep(50); + elapsed = (System.nanoTime() - begin) / 1000000; + } + } +} diff --git a/src/test/java/tic/core/TICCoreReadNextFrameTask.java b/src/test/java/tic/core/TICCoreReadNextFrameTask.java new file mode 100644 index 0000000..362dadb --- /dev/null +++ b/src/test/java/tic/core/TICCoreReadNextFrameTask.java @@ -0,0 +1,42 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.core; + +import tic.util.task.TaskBase; + +public class TICCoreReadNextFrameTask extends TaskBase { + public TICCore ticCore; + public TICIdentifier identifier; + public TICCoreFrame frame; + public Exception exception; + public int timeout; + + public TICCoreReadNextFrameTask(TICCore ticCore, TICIdentifier identifier) { + this(ticCore, identifier, -1); + } + + public TICCoreReadNextFrameTask(TICCore ticCore, TICIdentifier identifier, int timeout) { + super(); + this.ticCore = ticCore; + this.identifier = identifier; + this.timeout = timeout; + } + + @Override + protected void process() { + try { + if (this.timeout > 0) { + this.frame = this.ticCore.readNextFrame(this.identifier, this.timeout); + } else { + this.frame = this.ticCore.readNextFrame(this.identifier); + } + } catch (Exception exception) { + this.exception = exception; + } + } +} diff --git a/src/test/java/tic/core/TICCoreStreamMock.java b/src/test/java/tic/core/TICCoreStreamMock.java new file mode 100644 index 0000000..aea3345 --- /dev/null +++ b/src/test/java/tic/core/TICCoreStreamMock.java @@ -0,0 +1,82 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.core; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import tic.frame.TICMode; +import tic.io.modem.ModemFinder; + +public class TICCoreStreamMock implements TICCoreStream { + public static List streams = new ArrayList(); + public Collection subscribers; + public boolean running; + public TICIdentifier identifier; + + public TICCoreStreamMock(String portId, String portName, TICMode mode, ModemFinder finder) { + super(); + this.subscribers = new HashSet(); + this.running = false; + this.identifier = new TICIdentifier.Builder().portId(portId).portName(portName).build(); + streams.add(this); + } + + @Override + public TICIdentifier getIdentifier() { + return this.identifier; + } + + @Override + public boolean isRunning() { + return this.running; + } + + @Override + public void start() { + this.running = true; + } + + @Override + public void stop() { + this.running = false; + } + + @Override + public Collection getSubscribers() { + return this.subscribers; + } + + @Override + public boolean hasSubscriber(TICCoreSubscriber subscriber) { + return this.subscribers.contains(subscriber); + } + + @Override + public void subscribe(TICCoreSubscriber subscriber) { + this.subscribers.add(subscriber); + } + + @Override + public void unsubscribe(TICCoreSubscriber subscriber) { + this.subscribers.remove(subscriber); + } + + public void notifyOnData(TICCoreFrame frame) { + for (TICCoreSubscriber subscriber : this.subscribers) { + subscriber.onData(frame); + } + } + + public void notifyOnError(TICCoreError error) { + for (TICCoreSubscriber subscriber : this.subscribers) { + subscriber.onError(error); + } + } +} diff --git a/src/test/java/tic/core/TICCoreSubscriberMock.java b/src/test/java/tic/core/TICCoreSubscriberMock.java new file mode 100644 index 0000000..630cc4c --- /dev/null +++ b/src/test/java/tic/core/TICCoreSubscriberMock.java @@ -0,0 +1,33 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.core; + +import java.util.ArrayList; +import java.util.List; + +@SuppressWarnings("javadoc") +public class TICCoreSubscriberMock implements TICCoreSubscriber { + public List onDataCalls; + public List onErrorCalls; + + public TICCoreSubscriberMock() { + super(); + this.onDataCalls = new ArrayList(); + this.onErrorCalls = new ArrayList(); + } + + @Override + public void onData(TICCoreFrame frame) { + this.onDataCalls.add(new TICCoreSubscriberOnDataCall(frame)); + } + + @Override + public void onError(TICCoreError error) { + this.onErrorCalls.add(new TICCoreSubscriberOnErrorCall(error)); + } +} diff --git a/src/test/java/tic/core/TICCoreSubscriberOnDataCall.java b/src/test/java/tic/core/TICCoreSubscriberOnDataCall.java new file mode 100644 index 0000000..f5f8609 --- /dev/null +++ b/src/test/java/tic/core/TICCoreSubscriberOnDataCall.java @@ -0,0 +1,20 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.core; + +import tic.mock.FunctionCall; + +@SuppressWarnings("javadoc") +public class TICCoreSubscriberOnDataCall extends FunctionCall { + public TICCoreFrame frame; + + public TICCoreSubscriberOnDataCall(TICCoreFrame frame) { + super(); + this.frame = frame; + } +} diff --git a/src/test/java/tic/core/TICCoreSubscriberOnErrorCall.java b/src/test/java/tic/core/TICCoreSubscriberOnErrorCall.java new file mode 100644 index 0000000..4228fd8 --- /dev/null +++ b/src/test/java/tic/core/TICCoreSubscriberOnErrorCall.java @@ -0,0 +1,20 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.core; + +import tic.mock.FunctionCall; + +@SuppressWarnings("javadoc") +public class TICCoreSubscriberOnErrorCall extends FunctionCall { + public TICCoreError error; + + public TICCoreSubscriberOnErrorCall(TICCoreError error) { + super(); + this.error = error; + } +} diff --git a/src/test/java/tic/core/TICIdentifierTest.java b/src/test/java/tic/core/TICIdentifierTest.java new file mode 100644 index 0000000..51b9921 --- /dev/null +++ b/src/test/java/tic/core/TICIdentifierTest.java @@ -0,0 +1,114 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.core; + +import org.junit.Assert; +import org.junit.Test; + +public class TICIdentifierTest { + @Test + public void test_constructor_full() { + TICIdentifier identifier = new TICIdentifier.Builder().portId("{1-1}").portName("COM3").serialNumber("021976551632").build(); + + Assert.assertEquals("{1-1}", identifier.getPortId()); + Assert.assertEquals("COM3", identifier.getPortName()); + Assert.assertEquals("021976551632", identifier.getSerialNumber()); + } + + @Test + public void test_constructor_onlyPortId() { + TICIdentifier identifier = new TICIdentifier.Builder().portId("{1-1}").build(); + + Assert.assertEquals("{1-1}", identifier.getPortId()); + Assert.assertNull(identifier.getPortName()); + Assert.assertNull(identifier.getSerialNumber()); + } + + @Test + public void test_constructor_onlyPortName() { + TICIdentifier identifier = new TICIdentifier.Builder().portName("COM3").build(); + + Assert.assertNull(identifier.getPortId()); + Assert.assertEquals("COM3", identifier.getPortName()); + Assert.assertNull(identifier.getSerialNumber()); + } + + @Test + public void test_constructor_onlySerialNumber() { + TICIdentifier identifier = new TICIdentifier.Builder().serialNumber("021976551632").build(); + + Assert.assertNull(identifier.getPortId()); + Assert.assertNull(identifier.getPortName()); + Assert.assertEquals("021976551632", identifier.getSerialNumber()); + } + + @Test(expected = IllegalArgumentException.class) + public void test_constructor_empty() { + new TICIdentifier.Builder().build(); + } + + @Test + public void test_matches_null() { + TICIdentifier identifier = new TICIdentifier.Builder().serialNumber("021976551632").build(); + Assert.assertFalse(identifier.matches(null)); + } + + @Test + public void test_matches_same_serialNumber() { + TICIdentifier identifier1 = new TICIdentifier.Builder().portId("{1-1}").portName("COM3").serialNumber("021976551632").build(); + TICIdentifier identifier2 = new TICIdentifier.Builder().portId("{1-2}").portName("COM4").serialNumber("021976551632").build(); + + Assert.assertTrue(identifier1.matches(identifier2)); + } + + @Test + public void test_matches_different_serialNumber() { + TICIdentifier identifier1 = new TICIdentifier.Builder().portId("{1-1}").portName("COM3").serialNumber("021976551632").build(); + TICIdentifier identifier2 = new TICIdentifier.Builder().portId("{1-1}").portName("COM3").serialNumber("021976551638").build(); + + Assert.assertFalse(identifier1.matches(identifier2)); + } + + @Test + public void test_matches_same_portId() { + TICIdentifier identifier1 = new TICIdentifier.Builder().portId("{1-1}").portName("COM3").serialNumber("021976551632").build(); + TICIdentifier identifier2 = new TICIdentifier.Builder().portId("{1-1}").portName("COM4").serialNumber("021976551633").build(); + TICIdentifier identifier3 = new TICIdentifier.Builder().portId("{1-1}").portName("COM5").build(); + + Assert.assertTrue(identifier1.matches(identifier3)); + Assert.assertFalse(identifier1.matches(identifier2)); + } + + @Test + public void test_matches_different_portId() { + TICIdentifier identifier1 = new TICIdentifier.Builder().portId("{1-1}").build(); + TICIdentifier identifier2 = new TICIdentifier.Builder().portId("{1-7}").build(); + + Assert.assertFalse(identifier1.matches(identifier2)); + } + + @Test + public void test_matches_same_portName() { + TICIdentifier identifier1 = new TICIdentifier.Builder().portId("{1-1}").portName("COM3").serialNumber("021976551632").build(); + TICIdentifier identifier2 = new TICIdentifier.Builder().portId("{1-2}").portName("COM3").serialNumber("021976551633").build(); + TICIdentifier identifier3 = new TICIdentifier.Builder().portId("{1-3}").portName("COM3").build(); + TICIdentifier identifier4 = new TICIdentifier.Builder().portName("COM3").build(); + + Assert.assertTrue(identifier1.matches(identifier4)); + Assert.assertFalse(identifier1.matches(identifier3)); + Assert.assertFalse(identifier1.matches(identifier2)); + } + + @Test + public void test_matches_different_portName() { + TICIdentifier identifier1 = new TICIdentifier.Builder().portName("COM3").build(); + TICIdentifier identifier2 = new TICIdentifier.Builder().portName("COM8").build(); + + Assert.assertFalse(identifier1.matches(identifier2)); + } +} diff --git a/src/test/java/tic/frame/TICFrameTest.java b/src/test/java/tic/frame/TICFrameTest.java new file mode 100644 index 0000000..f95bd53 --- /dev/null +++ b/src/test/java/tic/frame/TICFrameTest.java @@ -0,0 +1,326 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.frame; + +import java.util.Arrays; +import java.util.List; +import org.junit.Assert; +import org.junit.Test; +import tic.frame.group.TICGroup; + +public class TICFrameTest { + + @Test + public void test_constructor_historic_mode() { + // Given + TICMode mode = TICMode.HISTORIC; + + // When + TICFrame frame = new TICFrame(mode); + + // Then + Assert.assertEquals("TIC frame mode mismatch", TICMode.HISTORIC, frame.getMode()); + Assert.assertEquals("TIC frame group list size mismatch", 0, frame.getGroupList().size()); + } + + @Test + public void test_constructor_standard_mode() { + // Given + TICMode mode = TICMode.STANDARD; + + // When + TICFrame frame = new TICFrame(mode); + + // Then + Assert.assertEquals("TIC frame mode mismatch", TICMode.STANDARD, frame.getMode()); + Assert.assertEquals("TIC frame group list size mismatch", 0, frame.getGroupList().size()); + } + + @Test + public void test_constructor_null_mode() { + // Given + TICMode mode = null; + + // When + IllegalArgumentException exception = + Assert.assertThrows(IllegalArgumentException.class, () -> new TICFrame(mode)); + + // Then + Assert.assertEquals("TICFrame mode must not be null", exception.getMessage()); + } + + @Test + public void test_constructor_auto_mode() { + // Given + TICMode mode = TICMode.AUTO; + + // When + IllegalArgumentException exception = + Assert.assertThrows(IllegalArgumentException.class, () -> new TICFrame(mode)); + + // Then + Assert.assertEquals("TICFrame cannot be created with AUTO mode", exception.getMessage()); + } + + @Test + public void test_addGroup() { + // Given + TICFrame frame = new TICFrame(TICMode.HISTORIC); + List groups = + Arrays.asList( + new TICGroup("ADCO", "812164417227"), + new TICGroup("OPTARIF", "BASE"), + new TICGroup("ISOUSC", "15"), + new TICGroup("BASE", "000000104"), + new TICGroup("PTEC", "TH.."), + new TICGroup("IINST", "000"), + new TICGroup("IMAX", "000"), + new TICGroup("PAPP", "00000"), + new TICGroup("MOTDETAT", "000000")); + + // When + groups.forEach(group -> frame.addGroup(group)); + + // Then + Assert.assertEquals("TIC frame group list size mismatch", 9, frame.getGroupList().size()); + Assert.assertEquals( + "TIC frame group n°1 mismatch", + new TICGroup("ADCO", "812164417227"), + frame.getGroupList().get(0)); + Assert.assertEquals( + "TIC frame group n°2 mismatch", + new TICGroup("OPTARIF", "BASE"), + frame.getGroupList().get(1)); + Assert.assertEquals( + "TIC frame group n°3 mismatch", new TICGroup("ISOUSC", "15"), frame.getGroupList().get(2)); + Assert.assertEquals( + "TIC frame group n°4 mismatch", + new TICGroup("BASE", "000000104"), + frame.getGroupList().get(3)); + Assert.assertEquals( + "TIC frame group n°5 mismatch", new TICGroup("PTEC", "TH.."), frame.getGroupList().get(4)); + Assert.assertEquals( + "TIC frame group n°6 mismatch", new TICGroup("IINST", "000"), frame.getGroupList().get(5)); + Assert.assertEquals( + "TIC frame group n°7 mismatch", new TICGroup("IMAX", "000"), frame.getGroupList().get(6)); + Assert.assertEquals( + "TIC frame group n°8 mismatch", new TICGroup("PAPP", "00000"), frame.getGroupList().get(7)); + Assert.assertEquals( + "TIC frame group n°9 mismatch", + new TICGroup("MOTDETAT", "000000"), + frame.getGroupList().get(8)); + } + + @Test + public void test_getGroup_match() { + // Given + TICFrame frame = new TICFrame(TICMode.HISTORIC); + TICGroup targetGroup = new TICGroup("IINST", "000"); + List groups = + Arrays.asList( + new TICGroup("ADCO", "812164417227"), + new TICGroup("OPTARIF", "BASE"), + new TICGroup("ISOUSC", "15"), + new TICGroup("BASE", "000000104"), + new TICGroup("PTEC", "TH.."), + targetGroup, + new TICGroup("IMAX", "000"), + new TICGroup("PAPP", "00000"), + new TICGroup("MOTDETAT", "000000")); + + groups.forEach(group -> frame.addGroup(group)); + + // When + TICGroup retrievedGroup = frame.getGroup("IINST"); + + // Then + Assert.assertEquals("TIC frame getGroup mismatch", targetGroup, retrievedGroup); + } + + @Test + public void test_getGroup_null() { + // Given + TICFrame frame = new TICFrame(TICMode.HISTORIC); + List groups = + Arrays.asList( + new TICGroup("ADCO", "812164417227"), + new TICGroup("OPTARIF", "BASE"), + new TICGroup("ISOUSC", "15"), + new TICGroup("BASE", "000000104"), + new TICGroup("PTEC", "TH.."), + new TICGroup("IINST", "000"), + new TICGroup("IMAX", "000"), + new TICGroup("PAPP", "00000"), + new TICGroup("MOTDETAT", "000000")); + + groups.forEach(group -> frame.addGroup(group)); + + // When + TICGroup retrievedGroup = frame.getGroup("IINSTI"); + + // Then + Assert.assertEquals("TIC frame getGroup should not match", null, retrievedGroup); + } + + @Test + public void test_hasInvalidGroup_no_invalid_group() { + // Given + TICFrame frame = new TICFrame(TICMode.HISTORIC); + List groups = + Arrays.asList( + new TICGroup("ADCO", "812164417227"), + new TICGroup("OPTARIF", "BASE"), + new TICGroup("ISOUSC", "15"), + new TICGroup("BASE", "000000104"), + new TICGroup("PTEC", "TH.."), + new TICGroup("IINST", "000"), + new TICGroup("IMAX", "000"), + new TICGroup("PAPP", "00000"), + new TICGroup("MOTDETAT", "000000")); + groups.forEach(group -> frame.addGroup(group)); + + // When + boolean hasInvalidGroup = frame.hasInvalidGroup(); + + // Then + Assert.assertEquals("TIC frame has invalid group mismatch", false, hasInvalidGroup); + } + + @Test + public void test_hasInvalidGroup_single_invalid_group() { + // Given + TICFrame frame = new TICFrame(TICMode.HISTORIC); + List groups = + Arrays.asList( + new TICGroup("ADCO", "812164417227"), + new TICGroup("OPTARIF", "BASE", false), + new TICGroup("ISOUSC", "15"), + new TICGroup("BASE", "000000104"), + new TICGroup("PTEC", "TH.."), + new TICGroup("IINST", "000"), + new TICGroup("IMAX", "000"), + new TICGroup("PAPP", "00000"), + new TICGroup("MOTDETAT", "000000")); + groups.forEach(group -> frame.addGroup(group)); + + // When + boolean hasInvalidGroup = frame.hasInvalidGroup(); + + // Then + Assert.assertEquals("TIC frame has invalid group mismatch", true, hasInvalidGroup); + } + + @Test + public void test_hasInvalidGroup_multiple_invalid_groups() { + // Given + TICFrame frame = new TICFrame(TICMode.HISTORIC); + List groups = + Arrays.asList( + new TICGroup("ADCO", "812164417227"), + new TICGroup("OPTARIF", "BASE", false), + new TICGroup("ISOUSC", "15"), + new TICGroup("BASE", "000000104", false), + new TICGroup("PTEC", "TH.."), + new TICGroup("IINST", "000"), + new TICGroup("IMAX", "000"), + new TICGroup("PAPP", "00000"), + new TICGroup("MOTDETAT", "000000")); + groups.forEach(group -> frame.addGroup(group)); + + // When + boolean hasInvalidGroup = frame.hasInvalidGroup(); + + // Then + Assert.assertEquals("TIC frame has invalid group mismatch", true, hasInvalidGroup); + } + + @Test + public void test_containsGroupLabel_match() { + // Given + TICFrame frame = new TICFrame(TICMode.HISTORIC); + TICGroup targetGroup = new TICGroup("IINST", "000"); + List groups = + Arrays.asList( + new TICGroup("ADCO", "812164417227"), + new TICGroup("OPTARIF", "BASE"), + new TICGroup("ISOUSC", "15"), + new TICGroup("BASE", "000000104"), + new TICGroup("PTEC", "TH.."), + targetGroup, + new TICGroup("IMAX", "000"), + new TICGroup("PAPP", "00000"), + new TICGroup("MOTDETAT", "000000")); + + groups.forEach(group -> frame.addGroup(group)); + + // When + boolean containsGroup = frame.containsGroupLabel("IINST"); + + // Then + Assert.assertEquals("TIC frame containsGroupLabel mismatch", true, containsGroup); + } + + @Test + public void test_containsGroupLabel_mismatch() { + // Given + TICFrame frame = new TICFrame(TICMode.HISTORIC); + TICGroup targetGroup = new TICGroup("IINST", "000"); + List groups = + Arrays.asList( + new TICGroup("ADCO", "812164417227"), + new TICGroup("OPTARIF", "BASE"), + new TICGroup("ISOUSC", "15"), + new TICGroup("BASE", "000000104"), + new TICGroup("PTEC", "TH.."), + targetGroup, + new TICGroup("IMAX", "000"), + new TICGroup("PAPP", "00000"), + new TICGroup("MOTDETAT", "000000")); + + groups.forEach(group -> frame.addGroup(group)); + + // When + boolean containsGroup = frame.containsGroupLabel("IINSTI"); + + // Then + Assert.assertEquals("TIC frame containsGroupLabel mismatch", false, containsGroup); + } + + @Test + public void test_toString() { + // Given + TICFrame frame = new TICFrame(TICMode.HISTORIC); + List groups = + Arrays.asList( + new TICGroup("ADCO", "812164417227"), + new TICGroup("OPTARIF", "BASE", false), + new TICGroup("ISOUSC", "15"), + new TICGroup("BASE", "000000104", false), + new TICGroup("PTEC", "TH.."), + new TICGroup("IINST", "000"), + new TICGroup("IMAX", "000"), + new TICGroup("PAPP", "00000"), + new TICGroup("MOTDETAT", "000000")); + + groups.forEach(group -> frame.addGroup(group)); + + // When + String text = frame.toString(); + + // Then + Assert.assertEquals( + "TIC frame string unexpected", + "mode=HISTORIC, groupList=[(label=ADCO, value=812164417227, isValid=true), (label=OPTARIF," + + " value=BASE, isValid=false), (label=ISOUSC, value=15, isValid=true), (label=BASE," + + " value=000000104, isValid=false), (label=PTEC, value=TH.., isValid=true)," + + " (label=IINST, value=000, isValid=true), (label=IMAX, value=000, isValid=true)," + + " (label=PAPP, value=00000, isValid=true), (label=MOTDETAT, value=000000," + + " isValid=true)]", + text); + } +} diff --git a/src/test/java/tic/frame/TICModeDetectorTest.java b/src/test/java/tic/frame/TICModeDetectorTest.java new file mode 100644 index 0000000..7f3abd6 --- /dev/null +++ b/src/test/java/tic/frame/TICModeDetectorTest.java @@ -0,0 +1,134 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.frame; + +import org.junit.Assert; +import org.junit.Test; + +public class TICModeDetectorTest { + + @Test + public void test_findModeFromFrameBuffer_historic() { + // Given + String frameBuffer = "\u0002\nADCO 031664001115 3\r\u0003"; + + // When + TICMode mode = TICModeDetector.findModeFromFrameBuffer(frameBuffer.getBytes()); + + // Then + Assert.assertEquals("TIC frame mode mismatch", TICMode.HISTORIC, mode); + } + + @Test + public void test_findModeFromFrameBuffer_standard() { + // Given + String frameBuffer = "\u0002\nADSC\t031664001115\t)\r\u0003"; + + // When + TICMode mode = TICModeDetector.findModeFromFrameBuffer(frameBuffer.getBytes()); + + // Then + Assert.assertEquals("TIC frame mode mismatch", TICMode.STANDARD, mode); + } + + @Test + public void test_findModeFromFrameBuffer_unknown_mode() { + // Given + String frameBuffer = "\u0002\nADSC\0031664001115\0)\r\u0003"; + + // When + TICMode mode = TICModeDetector.findModeFromFrameBuffer(frameBuffer.getBytes()); + + // Then + Assert.assertEquals("TIC frame mode mismatch", null, mode); + } + + @Test + public void test_findModeFromFrameBuffer_null_buffer() { + // Given + byte[] frameBuffer = null; + + // When + IllegalArgumentException exception = + Assert.assertThrows( + IllegalArgumentException.class, + () -> TICModeDetector.findModeFromFrameBuffer(frameBuffer)); + + // Then + Assert.assertEquals( + "Tic frame buffer is null, unable to determine TIC Mode!", exception.getMessage()); + } + + @Test + public void test_findModeFromFrameBuffer_buffer_length_too_short() { + // Given + String frameBuffer = "\u0002\nADSC"; + + // When + IllegalArgumentException exception = + Assert.assertThrows( + IllegalArgumentException.class, + () -> TICModeDetector.findModeFromFrameBuffer(frameBuffer.getBytes())); + + // Then + Assert.assertEquals( + "Tic frame buffer 0x020A41445343 too short to determine TIC Mode!", exception.getMessage()); + } + + @Test + public void test_findModeFromGroupBuffer_historic() { + // Given + String groupBuffer = "\nADCO 031664001115 3\r"; + + // When + TICMode mode = TICModeDetector.findModeFromGroupBuffer(groupBuffer.getBytes()); + + // Then + Assert.assertEquals("TIC group mode mismatch", TICMode.HISTORIC, mode); + } + + @Test + public void test_findModeFromGroupBuffer_standard() { + // Given + String groupBuffer = "\nADSC\t031664001115\t)\r"; + + // When + TICMode mode = TICModeDetector.findModeFromGroupBuffer(groupBuffer.getBytes()); + + // Then + Assert.assertEquals("TIC group mode mismatch", TICMode.STANDARD, mode); + } + + @Test + public void test_findModeFromGroupBuffer_unknown_mode() { + // Given + String groupBuffer = "\nADSC\0031664001115\0)\r"; + + // When + TICMode mode = TICModeDetector.findModeFromGroupBuffer(groupBuffer.getBytes()); + + // Then + Assert.assertEquals("TIC group mode mismatch", null, mode); + } + + @Test + public void test_findModeFromGroupBuffer_null_buffer() { + // Given + byte[] groupBuffer = null; + + // When + IllegalArgumentException exception = + Assert.assertThrows( + IllegalArgumentException.class, + () -> TICModeDetector.findModeFromGroupBuffer(groupBuffer)); + + // Then + Assert.assertEquals( + "Tic group buffer is null, unable to determine TIC Mode!", exception.getMessage()); + } +} diff --git a/src/test/java/tic/frame/checksum/TICChecksumOffsetTest.java b/src/test/java/tic/frame/checksum/TICChecksumOffsetTest.java new file mode 100644 index 0000000..977ca1b --- /dev/null +++ b/src/test/java/tic/frame/checksum/TICChecksumOffsetTest.java @@ -0,0 +1,200 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.frame.checksum; + +import org.junit.Assert; +import org.junit.Test; +import tic.frame.TICMode; + +public class TICChecksumOffsetTest { + @Test + public void test_getOffsetBegin() { + // When + int offsetBegin = TICChecksumOffset.getOffsetBegin(); + + // Then + Assert.assertEquals(1, offsetBegin); + } + + @Test + public void test_getOffsetEnd_historic() { + // Given + byte[] groupBuffer = "\nADCO 031664001115 3\r".getBytes(); + + // When + int offsetEnd = TICChecksumOffset.getOffsetEnd(groupBuffer, TICMode.HISTORIC); + + // Then + Assert.assertEquals(18, offsetEnd); + } + + @Test + public void test_getOffsetEnd_standard() { + // Given + byte[] groupBuffer = "\nADSC\t031664001115\t)\r".getBytes(); + + // When + int offsetEnd = TICChecksumOffset.getOffsetEnd(groupBuffer, TICMode.STANDARD); + + // Then + Assert.assertEquals(19, offsetEnd); + } + + @Test + public void test_getOffsetEnd_without_mode() { + // Given + byte[] groupBuffer = "\nADSC\t031664001115\t)\r".getBytes(); + + // When + int offsetEnd = TICChecksumOffset.getOffsetEnd(groupBuffer); + + // Then + Assert.assertEquals(19, offsetEnd); + } + + @Test + public void test_getOffsetEnd_auto_with_historic() { + // Given + byte[] groupBuffer = "\nADCO 031664001115 3\r".getBytes(); + + // When + int offsetEnd = TICChecksumOffset.getOffsetEnd(groupBuffer, TICMode.AUTO); + + // Then + Assert.assertEquals(18, offsetEnd); + } + + @Test + public void test_getOffsetEnd_auto_with_standard() { + // Given + byte[] groupBuffer = "\nADSC\t031664001115\t)\r".getBytes(); + + // When + int offsetEnd = TICChecksumOffset.getOffsetEnd(groupBuffer, TICMode.AUTO); + + // Then + Assert.assertEquals(19, offsetEnd); + } + + @Test + public void test_getOffsetEnd_with_nullBuffer() { + // When + NullPointerException exception = + Assert.assertThrows( + NullPointerException.class, + () -> TICChecksumOffset.getOffsetEnd(null, TICMode.STANDARD)); + + // Then + Assert.assertEquals("groupBuffer must not be null", exception.getMessage()); + } + + @Test + public void test_getOffsetEnd_with_nullMode() { + // Given + byte[] groupBuffer = "\nADSC\t031664001115\t)\r".getBytes(); + + // When + IllegalArgumentException exception = + Assert.assertThrows( + IllegalArgumentException.class, + () -> TICChecksumOffset.getOffsetEnd(groupBuffer, null)); + + // Then + Assert.assertEquals("mode must not be null", exception.getMessage()); + } + + @Test + public void test_getOffsetEnd_with_invalidMode() { + // Given + byte[] groupBuffer = "\nADSC\n031664001115\n)\r".getBytes(); + + // When + IllegalArgumentException exception = + Assert.assertThrows( + IllegalArgumentException.class, + () -> TICChecksumOffset.getOffsetEnd(groupBuffer, TICMode.AUTO)); + + // Then + Assert.assertEquals("Unable to determine TIC mode from group buffer", exception.getMessage()); + } + + @Test + public void test_checkBufferOffsets_with_invalidOffsetBegin() { + // Given + byte[] groupBuffer = "\nADSC\t031664001115\t)\r".getBytes(); + int offsetBegin = -1; + int offsetEnd = 5; + + // When + IllegalArgumentException exception = + Assert.assertThrows( + IllegalArgumentException.class, + () -> TICChecksumOffset.checkBufferOffsets(groupBuffer, offsetBegin, offsetEnd)); + + // Then + Assert.assertEquals( + "Invalid offsetBegin for checksum computation (must be positive)", exception.getMessage()); + } + + @Test + public void test_checkBufferOffsets_with_invalidOffsetEnd() { + // Given + byte[] groupBuffer = "\nADSC\t031664001115\t)\r".getBytes(); + int offsetBegin = 1; + int offsetEnd = groupBuffer.length + 1; + + // When + IllegalArgumentException exception = + Assert.assertThrows( + IllegalArgumentException.class, + () -> TICChecksumOffset.checkBufferOffsets(groupBuffer, offsetBegin, offsetEnd)); + + // Then + Assert.assertEquals( + "Invalid offsetEnd for checksum computation (must be lower than data length)", + exception.getMessage()); + } + + @Test + public void test_checkBufferOffsets_with_invalidOffsetRange() { + // Given + byte[] groupBuffer = "\nADSC\t031664001115\t)\r".getBytes(); + int offsetBegin = 5; + int offsetEnd = 3; + + // When + IllegalArgumentException exception = + Assert.assertThrows( + IllegalArgumentException.class, + () -> TICChecksumOffset.checkBufferOffsets(groupBuffer, offsetBegin, offsetEnd)); + + // Then + Assert.assertEquals( + "Invalid offset range for checksum computation (offsetBegin must be lower than offsetEnd)", + exception.getMessage()); + } + + @Test + public void test_checkBufferOffsets_with_invalidLength() { + // Given + byte[] groupBuffer = "\nADSC\t05\t)\r".getBytes(); + int offsetBegin = 0; + int offsetEnd = 11; + + // When + IllegalArgumentException exception = + Assert.assertThrows( + IllegalArgumentException.class, + () -> TICChecksumOffset.checkBufferOffsets(groupBuffer, offsetBegin, offsetEnd)); + + // Then + Assert.assertEquals( + "Invalid length for checksum computation (length must be lower than data length)", + exception.getMessage()); + } +} diff --git a/src/test/java/tic/frame/checksum/TICChecksumTest.java b/src/test/java/tic/frame/checksum/TICChecksumTest.java new file mode 100644 index 0000000..d48cf94 --- /dev/null +++ b/src/test/java/tic/frame/checksum/TICChecksumTest.java @@ -0,0 +1,140 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.frame.checksum; + +import org.junit.Assert; +import org.junit.Test; +import tic.frame.TICMode; + +public class TICChecksumTest { + + @Test + public void test_verifyChecksum_valid_historic() { + // Given + byte[] groupBuffer = "\nADCO 031664001115 3\r".getBytes(); + + // When + boolean isValid = TICChecksum.verifyChecksum(groupBuffer, TICMode.HISTORIC); + + // Then + Assert.assertTrue(isValid); + } + + @Test + public void test_verifyChecksum_valid_standard() { + // Given + byte[] groupBuffer = "\nADSC\t031664001115\t)\r".getBytes(); + + // When + boolean isValid = TICChecksum.verifyChecksum(groupBuffer, TICMode.STANDARD); + + // Then + Assert.assertTrue(isValid); + } + + @Test + public void test_verifyChecksum_valid_auto_with_historic() { + // Given + byte[] groupBuffer = "\nADCO 031664001115 3\r".getBytes(); + + // When + boolean isValid = TICChecksum.verifyChecksum(groupBuffer, TICMode.AUTO); + + // Then + Assert.assertTrue(isValid); + } + + @Test + public void test_verifyChecksum_valid_auto_with_standard() { + // Given + byte[] groupBuffer = "\nADSC\t031664001115\t)\r".getBytes(); + + // When + boolean isValid = TICChecksum.verifyChecksum(groupBuffer, TICMode.AUTO); + + // Then + Assert.assertTrue(isValid); + } + + @Test + public void test_verifyChecksum_invalid_historic() { + // Given + byte[] groupBuffer = "\nADCO 031664001115 4\r".getBytes(); + + // When + boolean isValid = TICChecksum.verifyChecksum(groupBuffer, TICMode.HISTORIC); + + // Then + Assert.assertFalse(isValid); + } + + @Test + public void test_verifyChecksum_invalid_standard() { + // Given + byte[] groupBuffer = "\nADSC\t031664001115\t*\r".getBytes(); + + // When + boolean isValid = TICChecksum.verifyChecksum(groupBuffer, TICMode.STANDARD); + + // Then + Assert.assertFalse(isValid); + } + + @Test + public void test_verifyChecksum_invalid_auto_with_historic() { + // Given + byte[] groupBuffer = "\nADCO 031664001115 4\r".getBytes(); + + // When + boolean isValid = TICChecksum.verifyChecksum(groupBuffer, TICMode.AUTO); + + // Then + Assert.assertFalse(isValid); + } + + @Test + public void test_verifyChecksum_invalid_auto_with_standard() { + // Given + byte[] groupBuffer = "\nADSC\t031664001115\t*\r".getBytes(); + + // When + boolean isValid = TICChecksum.verifyChecksum(groupBuffer, TICMode.AUTO); + + // Then + Assert.assertFalse(isValid); + } + + @Test + public void test_verifyChecksum_historic_with_tooShortBuffer() { + // Given: only DATA, missing separator/checksum payload + byte[] groupBuffer = "\nA\r".getBytes(); + + // When + IllegalArgumentException exception = + Assert.assertThrows( + IllegalArgumentException.class, + () -> TICChecksum.verifyChecksum(groupBuffer, TICMode.HISTORIC)); + + // Then + Assert.assertTrue(exception.getMessage().contains("offset range")); + } + + @Test + public void test_verifyChecksum_standard_with_tooShortBuffer() { + // Given: truncated group without checksum and carriage return + byte[] groupBuffer = "\n".getBytes(); + + // When + IllegalArgumentException exception = + Assert.assertThrows( + IllegalArgumentException.class, + () -> TICChecksum.verifyChecksum(groupBuffer, TICMode.STANDARD)); + // Then + Assert.assertTrue(exception.getMessage().contains("offset range")); + } +} diff --git a/src/test/java/tic/frame/codec/TICFrameCodecTest.java b/src/test/java/tic/frame/codec/TICFrameCodecTest.java new file mode 100644 index 0000000..0097689 --- /dev/null +++ b/src/test/java/tic/frame/codec/TICFrameCodecTest.java @@ -0,0 +1,295 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.frame.codec; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.util.Arrays; +import org.junit.Assert; +import org.junit.Test; +import tic.ResourceLoader; +import tic.frame.TICFrame; +import tic.frame.TICMode; +import tic.frame.group.TICGroup; + +public class TICFrameCodecTest { + + @Test + public void test_decode_historic() throws IOException, URISyntaxException { + // Given + byte[] frameBuffer = ResourceLoader.readAllBytes("/tic/frame/codec/ticFrameHistoric.txt"); + + // When + TICFrame frame = TICFrameCodec.decode(frameBuffer); + + // Then + Assert.assertEquals(TICMode.HISTORIC, frame.getMode()); + Arrays.asList( + new TICGroup("ADCO", "812164417227"), + new TICGroup("OPTARIF", "BASE"), + new TICGroup("ISOUSC", "15"), + new TICGroup("BASE", "000000104"), + new TICGroup("PTEC", "TH.."), + new TICGroup("IINST", "000"), + new TICGroup("IMAX", "000"), + new TICGroup("PAPP", "00000"), + new TICGroup("MOTDETAT", "000000")) + .forEach( + expectedGroup -> { + Assert.assertTrue( + "Expected group " + expectedGroup + " not found in frame groups", + frame.getGroupList().contains(expectedGroup)); + }); + } + + @Test + public void test_decode_standard() throws IOException, URISyntaxException { + // Given + byte[] frameBuffer = ResourceLoader.readAllBytes("/tic/frame/codec/ticFrameStandard.txt"); + + // When + TICFrame frame = TICFrameCodec.decode(frameBuffer); + + // Then + Assert.assertEquals(TICMode.STANDARD, frame.getMode()); + Arrays.asList( + new TICGroup("ADSC", "031664001115"), + new TICGroup("VTIC", "02"), + new TICGroup("DATE", "E170915101601\t"), + new TICGroup("NGTF", "H PLEINE/CREUSE "), + new TICGroup("LTARF", "INDEX INACTIF 2 "), + new TICGroup("EAST", "000000000"), + new TICGroup("EASF01", "000000000"), + new TICGroup("EASF02", "000000000"), + new TICGroup("EASF03", "000000000"), + new TICGroup("EASF04", "000000000"), + new TICGroup("EASF05", "000000000"), + new TICGroup("EASF06", "000000000"), + new TICGroup("EASF07", "000000000"), + new TICGroup("EASF08", "000000000"), + new TICGroup("EASF09", "000000000"), + new TICGroup("EASF10", "000000000"), + new TICGroup("EASD01", "000000000"), + new TICGroup("EASD02", "000000000"), + new TICGroup("EASD03", "000000000"), + new TICGroup("EASD04", "000000000"), + new TICGroup("IRMS1", "000"), + new TICGroup("URMS1", "230"), + new TICGroup("PREF", "03"), + new TICGroup("PCOUP", "02"), + new TICGroup("SINSTS", "00000"), + new TICGroup("SMAXSN", "E170915100926\t00000"), + new TICGroup("SMAXSN-1", "E170913000000\t00000"), + new TICGroup("CCASN", "E170913113000\t00000"), + new TICGroup("CCASN-1", "E170913110000\t00000"), + new TICGroup("UMOY1", "E170915101500\t230"), + new TICGroup("STGE", "000A4411"), + new TICGroup("MSG1", "PAS DE MESSAGE "), + new TICGroup("PRM", "00000000000000"), + new TICGroup("RELAIS", "000"), + new TICGroup("NTARF", "02"), + new TICGroup("NJOURF", "00"), + new TICGroup("NJOURF+1", "00"), + new TICGroup( + "PJOURF+1", + "00008002 0100C001 06008002 1230C001 15308002 NONUTILE NONUTILE NONUTILE NONUTILE" + + " NONUTILE NONUTILE")) + .forEach( + expectedGroup -> { + Assert.assertTrue( + "Expected group " + expectedGroup + " not found in frame groups", + frame.getGroupList().contains(expectedGroup)); + }); + } + + @Test + public void test_encode_historic() throws IOException, URISyntaxException { + // Given + TICFrame frame = new TICFrame(TICMode.HISTORIC); + Arrays.asList( + new TICGroup("ADCO", "812164417227"), + new TICGroup("OPTARIF", "BASE"), + new TICGroup("ISOUSC", "15"), + new TICGroup("BASE", "000000104"), + new TICGroup("PTEC", "TH.."), + new TICGroup("IINST", "000"), + new TICGroup("IMAX", "000"), + new TICGroup("PAPP", "00000"), + new TICGroup("MOTDETAT", "000000")) + .forEach( + group -> { + frame.addGroup(group); + }); + + // When + byte[] encodedFrameBuffer = TICFrameCodec.encode(frame); + + // Then + byte[] expectedFrameBuffer = + ResourceLoader.readAllBytes("/tic/frame/codec/ticFrameHistoric.txt"); + Assert.assertArrayEquals(expectedFrameBuffer, encodedFrameBuffer); + } + + @Test + public void test_encode_standard() throws IOException, URISyntaxException { + // Given + TICFrame frame = new TICFrame(TICMode.STANDARD); + Arrays.asList( + new TICGroup("ADSC", "031664001115"), + new TICGroup("VTIC", "02"), + new TICGroup("DATE", "E170915101601\t"), + new TICGroup("NGTF", "H PLEINE/CREUSE "), + new TICGroup("LTARF", "INDEX INACTIF 2 "), + new TICGroup("EAST", "000000000"), + new TICGroup("EASF01", "000000000"), + new TICGroup("EASF02", "000000000"), + new TICGroup("EASF03", "000000000"), + new TICGroup("EASF04", "000000000"), + new TICGroup("EASF05", "000000000"), + new TICGroup("EASF06", "000000000"), + new TICGroup("EASF07", "000000000"), + new TICGroup("EASF08", "000000000"), + new TICGroup("EASF09", "000000000"), + new TICGroup("EASF10", "000000000"), + new TICGroup("EASD01", "000000000"), + new TICGroup("EASD02", "000000000"), + new TICGroup("EASD03", "000000000"), + new TICGroup("EASD04", "000000000"), + new TICGroup("IRMS1", "000"), + new TICGroup("URMS1", "230"), + new TICGroup("PREF", "03"), + new TICGroup("PCOUP", "02", false), + new TICGroup("SINSTS", "00000"), + new TICGroup("SMAXSN", "E170915100926\t00000"), + new TICGroup("SMAXSN-1", "E170913000000\t00000"), + new TICGroup("CCASN", "E170913113000\t00000"), + new TICGroup("CCASN-1", "E170913110000\t00000"), + new TICGroup("UMOY1", "E170915101500\t230"), + new TICGroup("STGE", "000A4411"), + new TICGroup("MSG1", "PAS DE MESSAGE "), + new TICGroup("PRM", "00000000000000"), + new TICGroup("RELAIS", "000"), + new TICGroup("NTARF", "02"), + new TICGroup("NJOURF", "00"), + new TICGroup("NJOURF+1", "00"), + new TICGroup( + "PJOURF+1", + "00008002 0100C001 06008002 1230C001 15308002 NONUTILE NONUTILE NONUTILE NONUTILE" + + " NONUTILE NONUTILE")) + .forEach( + group -> { + frame.addGroup(group); + }); + + // When + byte[] encodedFrameBuffer = TICFrameCodec.encode(frame); + + // Then + byte[] expectedFrameBuffer = + ResourceLoader.readAllBytes("/tic/frame/codec/ticFrameStandard_PCOUP_Invalid.txt"); + Assert.assertArrayEquals(expectedFrameBuffer, encodedFrameBuffer); + } + + @Test + public void test_encode_with_nullFrame() { + // Given + TICFrame frame = null; + + // When + IllegalArgumentException exception = + Assert.assertThrows(IllegalArgumentException.class, () -> TICFrameCodec.encode(frame)); + + // Then + Assert.assertEquals("frame cannot be null", exception.getMessage()); + } + + @Test + public void test_decode_with_nullBuffer() { + // Given + byte[] frameBuffer = null; + + // When + IllegalArgumentException exception = + Assert.assertThrows( + IllegalArgumentException.class, () -> TICFrameCodec.decode(frameBuffer)); + + // Then + Assert.assertEquals("frameBuffer cannot be null", exception.getMessage()); + } + + @Test + public void test_decode_with_invalidLength() { + // Given + byte[] frameBuffer = new byte[3]; + + // When + IllegalArgumentException exception = + Assert.assertThrows( + IllegalArgumentException.class, () -> TICFrameCodec.decode(frameBuffer)); + + // Then + Assert.assertEquals("frameBuffer length must be >= 4 bytes", exception.getMessage()); + } + + @Test + public void test_decode_with_invalidBegin() { + // Given + byte[] frameBuffer = new byte[] {0x00, 0x01, 0x02, 0x03}; + + // When + IllegalArgumentException exception = + Assert.assertThrows( + IllegalArgumentException.class, () -> TICFrameCodec.decode(frameBuffer)); + + // Then + Assert.assertEquals("frameBuffer begin must be 2", exception.getMessage()); + } + + @Test + public void test_decode_with_invalidEnd() { + // Given + byte[] frameBuffer = new byte[] {0x02, 0x0A, 0x0D, 0x00}; + + // When + IllegalArgumentException exception = + Assert.assertThrows( + IllegalArgumentException.class, () -> TICFrameCodec.decode(frameBuffer)); + + // Then + Assert.assertEquals("frameBuffer end must be 3", exception.getMessage()); + } + + @Test + public void test_decode_with_bufferTooShort_for_modeDetection() { + // Given + byte[] frameBuffer = new byte[] {0x02, 0x0A, 'A', 0x0D, 0x03}; + + // When + IllegalArgumentException exception = + Assert.assertThrows( + IllegalArgumentException.class, () -> TICFrameCodec.decode(frameBuffer)); + + // Then + Assert.assertEquals( + "Tic frame buffer 0x020A410D03 too short to determine TIC Mode!", exception.getMessage()); + } + + @Test + public void test_decode_with_invalidBuffer_for_modeDetection() { + // Given + byte[] frameBuffer = new byte[] {0x02, 0x0A, 'A', 'D', 'C', 'C', 0x0D, 0x03}; + + // When + IllegalArgumentException exception = + Assert.assertThrows( + IllegalArgumentException.class, () -> TICFrameCodec.decode(frameBuffer)); + + // Then + Assert.assertEquals("Unable to determine TIC Mode from frame buffer!", exception.getMessage()); + } +} diff --git a/src/test/java/tic/frame/codec/TICFrameJsonEncoderTest.java b/src/test/java/tic/frame/codec/TICFrameJsonEncoderTest.java new file mode 100644 index 0000000..4ea7866 --- /dev/null +++ b/src/test/java/tic/frame/codec/TICFrameJsonEncoderTest.java @@ -0,0 +1,177 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.frame.codec; + +import static org.junit.Assert.assertNull; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.util.Arrays; +import java.util.List; + +import org.json.JSONException; +import org.junit.Test; +import org.skyscreamer.jsonassert.JSONAssert; +import tic.ResourceLoader; +import tic.frame.TICFrame; +import tic.frame.TICMode; +import tic.frame.group.TICGroup; + +public class TICFrameJsonEncoderTest { + + static List HISTORIC_GROUPS; + static List STANDARD_GROUPS; + + static { + HISTORIC_GROUPS = + Arrays.asList( + new TICGroup("ADCO", "812164417227"), + new TICGroup("OPTARIF", "BASE"), + new TICGroup("ISOUSC", "15"), + new TICGroup("BASE", "000000104"), + new TICGroup("PTEC", "TH.."), + new TICGroup("IINST", "000"), + new TICGroup("IMAX", "000"), + new TICGroup("PAPP", "00000"), + new TICGroup("MOTDETAT", "000000", false)); + + STANDARD_GROUPS = + Arrays.asList( + new TICGroup("ADSC", "031664001115"), + new TICGroup("VTIC", "02"), + new TICGroup("DATE", "E170915101601\t"), + new TICGroup("NGTF", "H PLEINE/CREUSE "), + new TICGroup("LTARF", "INDEX INACTIF 2 "), + new TICGroup("EAST", "000000000"), + new TICGroup("EASF01", "000000000"), + new TICGroup("EASF02", "000000000"), + new TICGroup("EASF03", "000000000"), + new TICGroup("EASF04", "000000000"), + new TICGroup("EASF05", "000000000"), + new TICGroup("EASF06", "000000000"), + new TICGroup("EASF07", "000000000"), + new TICGroup("EASF08", "000000000"), + new TICGroup("EASF09", "000000000"), + new TICGroup("EASF10", "000000000"), + new TICGroup("EASD01", "000000000"), + new TICGroup("EASD02", "000000000"), + new TICGroup("EASD03", "000000000"), + new TICGroup("EASD04", "000000000"), + new TICGroup("IRMS1", "000"), + new TICGroup("URMS1", "230"), + new TICGroup("PREF", "03"), + new TICGroup("PCOUP", "02", false), + new TICGroup("SINSTS", "00000"), + new TICGroup("SMAXSN", "E170915100926\t00000"), + new TICGroup("SMAXSN-1", "E170913000000\t00000"), + new TICGroup("CCASN", "E170913113000\t00000"), + new TICGroup("CCASN-1", "E170913110000\t00000"), + new TICGroup("UMOY1", "E170915101500\t230"), + new TICGroup("STGE", "000A4411"), + new TICGroup("MSG1", "PAS DE MESSAGE "), + new TICGroup("PRM", "00000000000000"), + new TICGroup("RELAIS", "000"), + new TICGroup("NTARF", "02"), + new TICGroup("NJOURF", "00"), + new TICGroup("NJOURF+1", "00"), + new TICGroup( + "PJOURF+1", + "00008002 0100C001 06008002 1230C001 15308002 NONUTILE NONUTILE NONUTILE NONUTILE" + + " NONUTILE NONUTILE")); + } + + @Test + public void test_encode_full_details() throws IOException, URISyntaxException, JSONException { + // Given + TICFrame frame = new TICFrame(TICMode.HISTORIC); + HISTORIC_GROUPS.forEach(group -> frame.addGroup(group)); + String actualJsonText = null; + Exception exception = null; + + // When + try { + actualJsonText = TICFrameDetailledCodec.getInstance().encodeToJsonString(frame); + } catch (Exception e) { + exception = e; + } + + // Then + assertNull("Exception should not be thrown during encoding", exception); + String expectedJsonText = + ResourceLoader.readString("/tic/frame/codec/ticFrameHistoric_full_details.json"); + JSONAssert.assertEquals(expectedJsonText, actualJsonText, false); + } + + @Test + public void test_encode_summarized() throws IOException, URISyntaxException, JSONException { + // Given + TICFrame frame = new TICFrame(TICMode.STANDARD); + STANDARD_GROUPS.forEach(group -> frame.addGroup(group)); + String actualJsonText = null; + Exception exception = null; + + // When + try { + actualJsonText = TICFrameSummarizedCodec.getInstance().encodeToJsonString(frame); + } catch (Exception e) { + exception = e; + } + + // Then + assertNull("Exception should not be thrown during encoding", exception); + String expectedJsonText = + ResourceLoader.readString("/tic/frame/codec/ticFrameStandard_summarized.json"); + JSONAssert.assertEquals(expectedJsonText, actualJsonText, false); + } + + @Test + public void test_encode_full_details_negative_indent() + throws IOException, URISyntaxException, JSONException { + // Given + TICFrame frame = new TICFrame(TICMode.HISTORIC); + HISTORIC_GROUPS.forEach(group -> frame.addGroup(group)); + String actualJsonText = null; + Exception exception = null; + + // When + try { + actualJsonText = TICFrameDetailledCodec.getInstance().encodeToJsonString(frame, -1); + } catch (Exception e) { + exception = e; + } + + // Then + assertNull("Exception should not be thrown during encoding", exception); + String expectedJsonText = + ResourceLoader.readString("/tic/frame/codec/ticFrameHistoric_full_details.json"); + JSONAssert.assertEquals(expectedJsonText, actualJsonText, false); + } + + @Test + public void test_encode_summarized_negative_indent() + throws IOException, URISyntaxException, JSONException { + // Given + TICFrame frame = new TICFrame(TICMode.STANDARD); + STANDARD_GROUPS.forEach(group -> frame.addGroup(group)); + String actualJsonText = null; + Exception exception = null; + + // When + try { + actualJsonText = TICFrameSummarizedCodec.getInstance().encodeToJsonString(frame, -1); + } catch (Exception e) { + exception = e; + } + + // Then + assertNull("Exception should not be thrown during encoding", exception); + String expectedJsonText = + ResourceLoader.readString("/tic/frame/codec/ticFrameStandard_summarized.json"); + JSONAssert.assertEquals(expectedJsonText, actualJsonText, false); + } +} diff --git a/src/test/java/tic/frame/delimiter/TICFrameDelimiterTest.java b/src/test/java/tic/frame/delimiter/TICFrameDelimiterTest.java new file mode 100644 index 0000000..a0972a4 --- /dev/null +++ b/src/test/java/tic/frame/delimiter/TICFrameDelimiterTest.java @@ -0,0 +1,36 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.frame.delimiter; + +import org.junit.Assert; +import org.junit.Test; + +public class TICFrameDelimiterTest { + + @Test + public void test_value_begin() { + // Given + + // When + byte begin = TICFrameDelimiter.BEGIN.getValue(); + + // Then + Assert.assertEquals("TIC frame begin invalid", 0x02, begin); + } + + @Test + public void test_value_end() { + // Given + + // When + byte end = TICFrameDelimiter.END.getValue(); + + // Then + Assert.assertEquals("TIC frame end invalid", 0x03, end); + } +} diff --git a/src/test/java/tic/frame/delimiter/TICGroupDelimiterTest.java b/src/test/java/tic/frame/delimiter/TICGroupDelimiterTest.java new file mode 100644 index 0000000..ef60bc7 --- /dev/null +++ b/src/test/java/tic/frame/delimiter/TICGroupDelimiterTest.java @@ -0,0 +1,35 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.frame.delimiter; + +import org.junit.Assert; +import org.junit.Test; + +public class TICGroupDelimiterTest { + @Test + public void test_value_begin() { + // Given + + // When + byte begin = TICGroupDelimiter.BEGIN.getValue(); + + // Then + Assert.assertEquals("TIC group begin invalid", '\n', begin); + } + + @Test + public void test_value_end() { + // Given + + // When + byte end = TICGroupDelimiter.END.getValue(); + + // Then + Assert.assertEquals("TIC group end invalid", '\r', end); + } +} diff --git a/src/test/java/tic/frame/delimiter/TICSeparatorTest.java b/src/test/java/tic/frame/delimiter/TICSeparatorTest.java new file mode 100644 index 0000000..babf3e1 --- /dev/null +++ b/src/test/java/tic/frame/delimiter/TICSeparatorTest.java @@ -0,0 +1,86 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.frame.delimiter; + +import org.junit.Assert; +import org.junit.Test; +import tic.frame.TICMode; + +public class TICSeparatorTest { + + @Test + public void test_value_historic() { + // Given + + // When + byte separator = TICSeparator.HISTORIC.getValue(); + + // Then + Assert.assertEquals("Historic TIC separator invalid", ' ', separator); + } + + @Test + public void test_value_standard() { + // Given + + // When + byte separator = TICSeparator.STANDARD.getValue(); + // Then + Assert.assertEquals("Standard TIC separator invalid", '\t', separator); + } + + @Test + public void test_value_from_historic_value() { + // Given + TICMode mode = TICMode.HISTORIC; + + // When + byte separator = TICSeparator.getValueFromMode(mode); + // Then + Assert.assertEquals("Historic TIC separator invalid", ' ', separator); + } + + @Test + public void test_value_from_standard_value() { + // Given + TICMode mode = TICMode.STANDARD; + + // When + byte separator = TICSeparator.getValueFromMode(mode); + // Then + Assert.assertEquals("Standard TIC separator invalid", '\t', separator); + } + + @Test + public void test_value_from_null_mode() { + // Given + TICMode mode = null; + + // When + IllegalArgumentException exception = + Assert.assertThrows( + IllegalArgumentException.class, () -> TICSeparator.getValueFromMode(mode)); + + // Then + Assert.assertEquals("cannot get separator value from null mode", exception.getMessage()); + } + + @Test + public void test_value_from_invalid_mode() { + // Given + TICMode mode = TICMode.AUTO; + + // When + IllegalArgumentException exception = + Assert.assertThrows( + IllegalArgumentException.class, () -> TICSeparator.getValueFromMode(mode)); + + // Then + Assert.assertEquals("cannot get separator value from AUTO mode", exception.getMessage()); + } +} diff --git a/src/test/java/tic/frame/delimiter/TICStartPatternTest.java b/src/test/java/tic/frame/delimiter/TICStartPatternTest.java new file mode 100644 index 0000000..dd71f70 --- /dev/null +++ b/src/test/java/tic/frame/delimiter/TICStartPatternTest.java @@ -0,0 +1,112 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.frame.delimiter; + +import org.junit.Assert; +import org.junit.Test; +import tic.frame.TICMode; + +public class TICStartPatternTest { + + @Test + public void test_historic() { + // Given + + // When + byte[] actualBytes = TICStartPattern.HISTORIC.getValue(); + + // Then + Assert.assertArrayEquals( + "Historic TIC start pattern invalid", + new byte[] {2, '\n', 'A', 'D', 'C', 'O', ' '}, + actualBytes); + } + + @Test + public void test_standard() { + // Given + + // When + byte[] actualBytes = TICStartPattern.STANDARD.getValue(); + + // Then + Assert.assertArrayEquals( + "Standard TIC start pattern invalid", + new byte[] {2, '\n', 'A', 'D', 'S', 'C', '\t'}, + actualBytes); + } + + @Test + public void test_length() { + // Given + + // When + int actualLength = TICStartPattern.length(); + + // Then + Assert.assertEquals("TIC start pattern length invalid", 7, actualLength); + } + + @Test + public void test_value_from_historic_value() { + // Given + TICMode mode = TICMode.HISTORIC; + + // When + byte[] actualBytes = TICStartPattern.getValueFromMode(mode); + + // Then + Assert.assertArrayEquals( + "Historic TIC start pattern invalid", + new byte[] {2, '\n', 'A', 'D', 'C', 'O', ' '}, + actualBytes); + } + + @Test + public void test_value_from_standard_value() { + // Given + TICMode mode = TICMode.STANDARD; + + // When + byte[] actualBytes = TICStartPattern.getValueFromMode(mode); + + // Then + Assert.assertArrayEquals( + "Standard TIC start pattern invalid", + new byte[] {2, '\n', 'A', 'D', 'S', 'C', '\t'}, + actualBytes); + } + + @Test + public void test_value_from_null_mode() { + // Given + TICMode mode = null; + + // When + IllegalArgumentException exception = + Assert.assertThrows( + IllegalArgumentException.class, () -> TICStartPattern.getValueFromMode(mode)); + + // Then + Assert.assertEquals("cannot get start pattern value from null mode", exception.getMessage()); + } + + @Test + public void test_value_from_invalid_mode() { + // Given + TICMode mode = TICMode.AUTO; + + // When + IllegalArgumentException exception = + Assert.assertThrows( + IllegalArgumentException.class, () -> TICStartPattern.getValueFromMode(mode)); + + // Then + Assert.assertEquals("cannot get start pattern value from AUTO mode", exception.getMessage()); + } +} diff --git a/src/test/java/tic/frame/group/TICGroupTest.java b/src/test/java/tic/frame/group/TICGroupTest.java new file mode 100644 index 0000000..5531422 --- /dev/null +++ b/src/test/java/tic/frame/group/TICGroupTest.java @@ -0,0 +1,222 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.frame.group; + +import org.junit.Assert; +import org.junit.Test; + +import tic.frame.TICMode; + +public class TICGroupTest { + @Test + public void test_default_constructor() { + // Given + + // When + TICGroup group = new TICGroup("ADCO", "12345"); + + // Then + Assert.assertEquals("TIC group label mismatch", "ADCO", group.getLabel()); + Assert.assertEquals("TIC group value mismatch", "12345", group.getValue()); + Assert.assertEquals("TIC group isValid mismatch", true, group.isValid()); + } + + @Test + public void test_full_constructor() { + // Given + + // When + TICGroup group = new TICGroup("ADSC", "156FE", false); + + // Then + Assert.assertEquals("TIC group label mismatch", "ADSC", group.getLabel()); + Assert.assertEquals("TIC group value mismatch", "156FE", group.getValue()); + Assert.assertEquals("TIC group isValid mismatch", false, group.isValid()); + } + + @Test + public void test_equals_identical() { + // Given + TICGroup group = new TICGroup("ADSC", "156FE", false); + + // When + boolean matches = group.equals(group); + + // Then + Assert.assertEquals("TIC group first mismatch itself", true, matches); + } + + @Test + public void test_equals_match() { + // Given + TICGroup firstGroup = new TICGroup("ADSC", "156FE", false); + TICGroup secondGroup = new TICGroup("ADSC", "156FE", false); + + // When + boolean firstMatchesSecond = firstGroup.equals(secondGroup); + boolean secondMatchesFirst = secondGroup.equals(firstGroup); + + // Then + Assert.assertEquals("TIC group first mismatch second", true, firstMatchesSecond); + Assert.assertEquals("TIC group second mismatch first", true, secondMatchesFirst); + } + + @Test + public void test_equals_label_mismatch() { + // Given + TICGroup firstGroup = new TICGroup("ADSC", "156FE", false); + TICGroup secondGroup = new TICGroup("ADCO", "156FE", false); + + // When + boolean firstMatchesSecond = firstGroup.equals(secondGroup); + boolean secondMatchesFirst = secondGroup.equals(firstGroup); + + // Then + Assert.assertEquals("TIC group first should not match second", false, firstMatchesSecond); + Assert.assertEquals("TIC group second should not match first", false, secondMatchesFirst); + } + + @Test + public void test_equals_value_mismatch() { + // Given + TICGroup firstGroup = new TICGroup("ADSC", "156FE", false); + TICGroup secondGroup = new TICGroup("ADSC", "156FF", false); + + // When + boolean firstMatchesSecond = firstGroup.equals(secondGroup); + boolean secondMatchesFirst = secondGroup.equals(firstGroup); + + // Then + Assert.assertEquals("TIC group first should not match second", false, firstMatchesSecond); + Assert.assertEquals("TIC group second should not match first", false, secondMatchesFirst); + } + + @Test + public void test_equals_isValid_mismatch() { + // Given + TICGroup firstGroup = new TICGroup("ADSC", "156FE", false); + TICGroup secondGroup = new TICGroup("ADSC", "156FE", true); + + // When + boolean firstMatchesSecond = firstGroup.equals(secondGroup); + boolean secondMatchesFirst = secondGroup.equals(firstGroup); + + // Then + Assert.assertEquals("TIC group first should not match second", false, firstMatchesSecond); + Assert.assertEquals("TIC group second should not match first", false, secondMatchesFirst); + } + + @Test + public void test_equals_label_and_value_mismatch() { + // Given + TICGroup firstGroup = new TICGroup("ADCO", "156FE", false); + TICGroup secondGroup = new TICGroup("ADSC", "156FF", false); + + // When + boolean firstMatchesSecond = firstGroup.equals(secondGroup); + boolean secondMatchesFirst = secondGroup.equals(firstGroup); + + // Then + Assert.assertEquals("TIC group first should not match second", false, firstMatchesSecond); + Assert.assertEquals("TIC group second should not match first", false, secondMatchesFirst); + } + + @Test + public void test_equals_label_and_isValid_mismatch() { + // Given + TICGroup firstGroup = new TICGroup("ADCO", "156FF", true); + TICGroup secondGroup = new TICGroup("ADSC", "156FF", false); + + // When + boolean firstMatchesSecond = firstGroup.equals(secondGroup); + boolean secondMatchesFirst = secondGroup.equals(firstGroup); + + // Then + Assert.assertEquals("TIC group first should not match second", false, firstMatchesSecond); + Assert.assertEquals("TIC group second should not match first", false, secondMatchesFirst); + } + + @Test + public void test_equals_value_and_isValid_mismatch() { + // Given + TICGroup firstGroup = new TICGroup("ADCO", "156FF", true); + TICGroup secondGroup = new TICGroup("ADCO", "156FE", false); + + // When + boolean firstMatchesSecond = firstGroup.equals(secondGroup); + boolean secondMatchesFirst = secondGroup.equals(firstGroup); + + // Then + Assert.assertEquals("TIC group first should not match second", false, firstMatchesSecond); + Assert.assertEquals("TIC group second should not match first", false, secondMatchesFirst); + } + + @Test + public void test_equals_full_mismatch() { + // Given + TICGroup firstGroup = new TICGroup("ADSC", "156FF", true); + TICGroup secondGroup = new TICGroup("ADCO", "156FE", false); + + // When + boolean firstMatchesSecond = firstGroup.equals(secondGroup); + boolean secondMatchesFirst = secondGroup.equals(firstGroup); + + // Then + Assert.assertEquals("TIC group first should not match second", false, firstMatchesSecond); + Assert.assertEquals("TIC group second should not match first", false, secondMatchesFirst); + } + + @Test + public void test_equals_null() { + // Given + TICGroup group = new TICGroup("ADSC", "156FE", false); + + // When + boolean matches = group.equals(null); + + // Then + Assert.assertEquals("TIC group match null", false, matches); + } + + @Test + public void test_equals_other_class() { + // Given + TICGroup group = new TICGroup("ADSC", "156FE", false); + + // When + boolean matches = group.equals((Object) TICMode.HISTORIC); + + // Then + Assert.assertEquals("TIC group match other class", false, matches); + } + + @Test + public void test_hashCode() { + // Given + TICGroup group = new TICGroup("ADSC", "156FE", false); + + // When + int hashCode = group.hashCode(); + + // Then + Assert.assertEquals("TIC group hash code unexpected", 48891225, hashCode); + } + + @Test + public void test_toString() { + // Given + TICGroup group = new TICGroup("ADSC", "156FE", false); + + // When + String text = group.toString(); + + // Then + Assert.assertEquals( + "TIC group string unexpected", "(label=ADSC, value=156FE, isValid=false)", text); + } +} diff --git a/src/test/java/tic/io/PortFinderMock.java b/src/test/java/tic/io/PortFinderMock.java new file mode 100644 index 0000000..af6c2da --- /dev/null +++ b/src/test/java/tic/io/PortFinderMock.java @@ -0,0 +1,57 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.io; + +import java.util.ArrayList; +import java.util.List; +import tic.mock.FunctionCall; + +@SuppressWarnings("javadoc") +public class PortFinderMock implements PortFinder { + public List findAllCalls = new ArrayList<>(); + public List descriptorList = new ArrayList<>(); + + public PortFinderMock() {} + + @Override + public List findAll() { + this.findAllCalls.add(new FunctionCall()); + return this.getDescriptors(); + } + + public List getDescriptors() { + List descriptors = new ArrayList<>(); + + synchronized (this.descriptorList) { + descriptors.addAll(this.descriptorList); + } + + return descriptors; + } + + public List setDescriptors(List descriptors) { + synchronized (this.descriptorList) { + this.descriptorList.clear(); + this.descriptorList.addAll(descriptors); + } + + return descriptors; + } + + public void addDescriptor(T descriptor) { + synchronized (this.descriptorList) { + this.descriptorList.add(descriptor); + } + } + + public void removeDescriptor(T descriptor) { + synchronized (this.descriptorList) { + this.descriptorList.remove(descriptor); + } + } +} diff --git a/src/test/java/tic/io/modem/ModemDescriptorTest.java b/src/test/java/tic/io/modem/ModemDescriptorTest.java new file mode 100644 index 0000000..21b89fe --- /dev/null +++ b/src/test/java/tic/io/modem/ModemDescriptorTest.java @@ -0,0 +1,515 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.io.modem; + +import org.junit.Assert; +import org.junit.Test; +import tic.frame.TICMode; +import tic.io.serialport.SerialPortDescriptor; +import tic.io.usb.UsbPortDescriptor; + +public class ModemDescriptorTest { + + @Test + public void test_instance_with_all_parameters() { + // Given + ModemDescriptor.Builder builder = + new ModemDescriptor.Builder<>() + .portId("ABCD1") + .portName("/dev/ttyUSB0") + .description("USB Serial Port") + .productId((short) 0x6001) + .vendorId((short) 0x0403) + .productName("test_product") + .manufacturer("test_manufacturer") + .serialNumber("SN123") + .modemType(ModemType.MICHAUD); + // When + ModemDescriptor descriptor = builder.build(); + + // Then + Assert.assertEquals("ABCD1", descriptor.portId()); + Assert.assertEquals("/dev/ttyUSB0", descriptor.portName()); + Assert.assertEquals("USB Serial Port", descriptor.description()); + Assert.assertEquals(Short.valueOf((short) 0x6001), descriptor.productId()); + Assert.assertEquals(Short.valueOf((short) 0x0403), descriptor.vendorId()); + Assert.assertEquals("test_product", descriptor.productName()); + Assert.assertEquals("test_manufacturer", descriptor.manufacturer()); + Assert.assertEquals("SN123", descriptor.serialNumber()); + Assert.assertEquals(ModemType.MICHAUD, descriptor.modemType()); + } + + @Test + public void test_copy_with_SerialPortDesciptor() { + // Given + SerialPortDescriptor serialDescriptor = + new SerialPortDescriptor.Builder<>() + .portId("ABCD1") + .portName("/dev/ttyUSB0") + .description("USB Serial Port") + .productId((short) 1) + .vendorId((short) 2) + .productName("test_product") + .manufacturer("test_manufacturer") + .serialNumber("SN123") + .build(); + // When + ModemDescriptor modemDescriptor = + new ModemDescriptor.Builder<>().copy(serialDescriptor).build(); + + // Then + Assert.assertEquals("ABCD1", modemDescriptor.portId()); + Assert.assertEquals("/dev/ttyUSB0", modemDescriptor.portName()); + Assert.assertEquals("USB Serial Port", modemDescriptor.description()); + Assert.assertEquals(Short.valueOf((short) 1), modemDescriptor.productId()); + Assert.assertEquals(Short.valueOf((short) 2), modemDescriptor.vendorId()); + Assert.assertEquals("test_product", modemDescriptor.productName()); + Assert.assertEquals("test_manufacturer", modemDescriptor.manufacturer()); + Assert.assertEquals("SN123", modemDescriptor.serialNumber()); + Assert.assertEquals(null, modemDescriptor.modemType()); + } + + @Test + public void test_copy_with_UsbPortDescriptor() { + // Given + UsbPortDescriptor usbPortDescriptor = + new UsbPortDescriptor.Builder() + .bcdDevice((short) 1) + .bcdUSB((short) 2) + .bDescriptorType((byte) 3) + .bDeviceClass((byte) 4) + .bDeviceProtocol((byte) 5) + .bDeviceSubClass((byte) 6) + .bLength((byte) 7) + .bMaxPacketSize0((byte) 8) + .bNumConfigurations((byte) 9) + .idProduct((short) 10) + .idVendor((short) 11) + .iManufacturer((byte) 12) + .iProduct((byte) 13) + .iSerialNumber((byte) 14) + .manufacturer("test_manufacturer") + .product("test_product") + .serialNumber("SN123") + .build(); + // When + ModemDescriptor modemDescriptor = + new ModemDescriptor.Builder<>().copy(usbPortDescriptor).build(); + + // Then + Assert.assertEquals(null, modemDescriptor.portId()); + Assert.assertEquals(null, modemDescriptor.portName()); + Assert.assertEquals(null, modemDescriptor.description()); + Assert.assertEquals(Short.valueOf((short) 10), modemDescriptor.productId()); + Assert.assertEquals(Short.valueOf((short) 11), modemDescriptor.vendorId()); + Assert.assertEquals("test_product", modemDescriptor.productName()); + Assert.assertEquals("test_manufacturer", modemDescriptor.manufacturer()); + Assert.assertEquals("SN123", modemDescriptor.serialNumber()); + Assert.assertEquals(null, modemDescriptor.modemType()); + } + + @Test + public void test_instance_with_null_productId() { + // Given + ModemDescriptor.Builder builder = + new ModemDescriptor.Builder<>() + .portId("ABCD1") + .portName("/dev/ttyUSB0") + .description("USB Serial Port") + .productId(null) + .vendorId((short) 0x0403) + .productName("test_product") + .manufacturer("test_manufacturer") + .serialNumber("SN123") + .modemType(ModemType.MICHAUD); + // When + ModemDescriptor descriptor = builder.build(); + + // Then + Assert.assertEquals("ABCD1", descriptor.portId()); + Assert.assertEquals("/dev/ttyUSB0", descriptor.portName()); + Assert.assertEquals("USB Serial Port", descriptor.description()); + Assert.assertEquals(Short.valueOf((short) 0x6001), descriptor.productId()); + Assert.assertEquals(Short.valueOf((short) 0x0403), descriptor.vendorId()); + Assert.assertEquals("test_product", descriptor.productName()); + Assert.assertEquals("test_manufacturer", descriptor.manufacturer()); + Assert.assertEquals("SN123", descriptor.serialNumber()); + Assert.assertEquals(ModemType.MICHAUD, descriptor.modemType()); + } + + @Test + public void test_instance_with_null_vendorId() { + // Given + ModemDescriptor.Builder builder = + new ModemDescriptor.Builder<>() + .portId("ABCD1") + .portName("/dev/ttyUSB0") + .description("USB Serial Port") + .productId((short) 0x6001) + .vendorId(null) + .productName("test_product") + .manufacturer("test_manufacturer") + .serialNumber("SN123") + .modemType(ModemType.MICHAUD); + // When + ModemDescriptor descriptor = builder.build(); + + // Then + Assert.assertEquals("ABCD1", descriptor.portId()); + Assert.assertEquals("/dev/ttyUSB0", descriptor.portName()); + Assert.assertEquals("USB Serial Port", descriptor.description()); + Assert.assertEquals(Short.valueOf((short) 0x6001), descriptor.productId()); + Assert.assertEquals(Short.valueOf((short) 0x0403), descriptor.vendorId()); + Assert.assertEquals("test_product", descriptor.productName()); + Assert.assertEquals("test_manufacturer", descriptor.manufacturer()); + Assert.assertEquals("SN123", descriptor.serialNumber()); + Assert.assertEquals(ModemType.MICHAUD, descriptor.modemType()); + } + + @Test + public void test_instance_with_null_modemType() { + // Given + ModemDescriptor.Builder builder = + new ModemDescriptor.Builder<>() + .portId("ABCD1") + .portName("/dev/ttyUSB0") + .description("USB Serial Port") + .productId((short) 0x6001) + .vendorId((short) 0x0403) + .productName("test_product") + .manufacturer("test_manufacturer") + .serialNumber("SN123") + .modemType(null); + // When + ModemDescriptor descriptor = builder.build(); + + // Then + Assert.assertEquals("ABCD1", descriptor.portId()); + Assert.assertEquals("/dev/ttyUSB0", descriptor.portName()); + Assert.assertEquals("USB Serial Port", descriptor.description()); + Assert.assertEquals(null, descriptor.productId()); + Assert.assertEquals(null, descriptor.vendorId()); + Assert.assertEquals("test_product", descriptor.productName()); + Assert.assertEquals("test_manufacturer", descriptor.manufacturer()); + Assert.assertEquals("SN123", descriptor.serialNumber()); + Assert.assertEquals(null, descriptor.modemType()); + } + + @Test + public void test_instance_with_missing_productId() { + // Given + ModemDescriptor.Builder builder = + new ModemDescriptor.Builder<>() + .portId("ABCD1") + .portName("/dev/ttyUSB0") + .description("USB Serial Port") + .vendorId((short) 0x0403) + .productName("test_product") + .manufacturer("test_manufacturer") + .serialNumber("SN123") + .modemType(ModemType.MICHAUD); + // When + ModemDescriptor descriptor = builder.build(); + + // Then + Assert.assertEquals("ABCD1", descriptor.portId()); + Assert.assertEquals("/dev/ttyUSB0", descriptor.portName()); + Assert.assertEquals("USB Serial Port", descriptor.description()); + Assert.assertEquals(Short.valueOf((short) 0x6001), descriptor.productId()); + Assert.assertEquals(Short.valueOf((short) 0x0403), descriptor.vendorId()); + Assert.assertEquals("test_product", descriptor.productName()); + Assert.assertEquals("test_manufacturer", descriptor.manufacturer()); + Assert.assertEquals("SN123", descriptor.serialNumber()); + Assert.assertEquals(ModemType.MICHAUD, descriptor.modemType()); + } + + @Test + public void test_instance_with_missing_vendorId() { + // Given + ModemDescriptor.Builder builder = + new ModemDescriptor.Builder<>() + .portId("ABCD1") + .portName("/dev/ttyUSB0") + .description("USB Serial Port") + .productId((short) 0x6001) + .productName("test_product") + .manufacturer("test_manufacturer") + .serialNumber("SN123") + .modemType(ModemType.MICHAUD); + // When + ModemDescriptor descriptor = builder.build(); + + // Then + Assert.assertEquals("ABCD1", descriptor.portId()); + Assert.assertEquals("/dev/ttyUSB0", descriptor.portName()); + Assert.assertEquals("USB Serial Port", descriptor.description()); + Assert.assertEquals(Short.valueOf((short) 0x6001), descriptor.productId()); + Assert.assertEquals(Short.valueOf((short) 0x0403), descriptor.vendorId()); + Assert.assertEquals("test_product", descriptor.productName()); + Assert.assertEquals("test_manufacturer", descriptor.manufacturer()); + Assert.assertEquals("SN123", descriptor.serialNumber()); + Assert.assertEquals(ModemType.MICHAUD, descriptor.modemType()); + } + + @Test + public void test_instance_with_missing_modemType() { + // Given + ModemDescriptor.Builder builder = + new ModemDescriptor.Builder<>() + .portId("ABCD1") + .portName("/dev/ttyUSB0") + .description("USB Serial Port") + .productId((short) 1) + .vendorId((short) 2) + .productName("test_product") + .manufacturer("test_manufacturer") + .serialNumber("SN123"); + // When + ModemDescriptor descriptor = builder.build(); + + // Then + Assert.assertEquals("ABCD1", descriptor.portId()); + Assert.assertEquals("/dev/ttyUSB0", descriptor.portName()); + Assert.assertEquals("USB Serial Port", descriptor.description()); + Assert.assertEquals(Short.valueOf((short) 1), descriptor.productId()); + Assert.assertEquals(Short.valueOf((short) 2), descriptor.vendorId()); + Assert.assertEquals("test_product", descriptor.productName()); + Assert.assertEquals("test_manufacturer", descriptor.manufacturer()); + Assert.assertEquals("SN123", descriptor.serialNumber()); + Assert.assertEquals(null, descriptor.modemType()); + } + + @Test + public void test_instance_with_modemType_and_null_productId() { + // Given + ModemDescriptor.Builder builder = + new ModemDescriptor.Builder<>() + .portId("ABCD1") + .portName("/dev/ttyUSB0") + .description("USB Serial Port") + .modemType(ModemType.MICHAUD) + .productId(null) + .vendorId((short) 0x0403) + .productName("test_product") + .manufacturer("test_manufacturer") + .serialNumber("SN123"); + ; + // When + IllegalArgumentException exception = + Assert.assertThrows(IllegalArgumentException.class, () -> builder.build()); + + // Then + Assert.assertEquals( + "Modem type is specified while productId is not provided", exception.getMessage()); + } + + @Test + public void test_instance_with_modemType_and_null_vendorId() { + // Given + ModemDescriptor.Builder builder = + new ModemDescriptor.Builder<>() + .portId("ABCD1") + .portName("/dev/ttyUSB0") + .description("USB Serial Port") + .modemType(ModemType.MICHAUD) + .productId((short) 0x6001) + .vendorId(null) + .productName("test_product") + .manufacturer("test_manufacturer") + .serialNumber("SN123"); + ; + // When + IllegalArgumentException exception = + Assert.assertThrows(IllegalArgumentException.class, () -> builder.build()); + + // Then + Assert.assertEquals( + "Modem type is specified while vendorId is not provided", exception.getMessage()); + } + + @Test + public void test_instance_with_modemType_and_inconsistent_productId() { + // Given + ModemDescriptor.Builder builder = + new ModemDescriptor.Builder<>() + .portId("ABCD1") + .portName("/dev/ttyUSB0") + .description("USB Serial Port") + .modemType(ModemType.MICHAUD) + .productId((short) 0x6015) + .vendorId((short) 0x0403) + .productName("test_product") + .manufacturer("test_manufacturer") + .serialNumber("SN123"); + ; + // When + IllegalArgumentException exception = + Assert.assertThrows(IllegalArgumentException.class, () -> builder.build()); + + // Then + Assert.assertEquals("Modem type is inconsistent with the productId", exception.getMessage()); + } + + @Test + public void test_instance_with_modemType_and_inconsistent_vendorId() { + // Given + ModemDescriptor.Builder builder = + new ModemDescriptor.Builder<>() + .portId("ABCD1") + .portName("/dev/ttyUSB0") + .description("USB Serial Port") + .modemType(ModemType.MICHAUD) + .productId((short) 0x6001) + .vendorId((short) 0x0430) + .productName("test_product") + .manufacturer("test_manufacturer") + .serialNumber("SN123"); + ; + // When + IllegalArgumentException exception = + Assert.assertThrows(IllegalArgumentException.class, () -> builder.build()); + + // Then + Assert.assertEquals("Modem type is inconsistent with the vendorId", exception.getMessage()); + } + + @Test + public void test_equals_with_same_instance() { + // Given + ModemDescriptor descriptor = + new ModemDescriptor.Builder<>() + .portId("ABCD1") + .portName("/dev/ttyUSB0") + .description("USB Serial Port") + .productName("test_product") + .manufacturer("test_manufacturer") + .serialNumber("SN123") + .modemType(ModemType.MICHAUD) + .build(); + // When + boolean match = descriptor.equals(descriptor); + + // Then + Assert.assertEquals(true, match); + } + + @Test + public void test_equals_with_identical_object() { + // Given + ModemDescriptor descriptor = + new ModemDescriptor.Builder<>() + .portId("ABCD1") + .portName("/dev/ttyUSB0") + .description("USB Serial Port") + .productName("test_product") + .manufacturer("test_manufacturer") + .serialNumber("SN123") + .modemType(ModemType.MICHAUD) + .build(); + + ModemDescriptor otherDescriptor = + new ModemDescriptor.Builder<>() + .portId("ABCD1") + .portName("/dev/ttyUSB0") + .description("USB Serial Port") + .productName("test_product") + .manufacturer("test_manufacturer") + .serialNumber("SN123") + .modemType(ModemType.MICHAUD) + .build(); + // When + boolean match = descriptor.equals(otherDescriptor); + + // Then + Assert.assertEquals(true, match); + } + + @Test + public void test_equals_with_different_object_type() { + // Given + ModemDescriptor descriptor = + new ModemDescriptor.Builder<>() + .portId("ABCD1") + .portName("/dev/ttyUSB0") + .description("USB Serial Port") + .productName("test_product") + .manufacturer("test_manufacturer") + .serialNumber("SN123") + .modemType(ModemType.MICHAUD) + .build(); + + // When + boolean match = descriptor.equals((Object) TICMode.HISTORIC); + + // Then + Assert.assertEquals(false, match); + } + + @Test + public void test_equals_with_different_modemType() { + // Given + ModemDescriptor descriptor = + new ModemDescriptor.Builder<>() + .portId("ABCD1") + .portName("/dev/ttyUSB0") + .description("USB Serial Port") + .productName("test_product") + .manufacturer("test_manufacturer") + .serialNumber("SN123") + .modemType(ModemType.MICHAUD) + .build(); + + ModemDescriptor otherDescriptor = + new ModemDescriptor.Builder<>() + .portId("ABCD1") + .portName("/dev/ttyUSB0") + .description("USB Serial Port") + .productName("test_product") + .manufacturer("test_manufacturer") + .serialNumber("SN1234") + .modemType(ModemType.TELEINFO) + .build(); + // When + boolean match = descriptor.equals(otherDescriptor); + + // Then + Assert.assertEquals(false, match); + } + + @Test + public void test_hashCode() { + // Given + ModemDescriptor descriptor = + new ModemDescriptor.Builder<>() + .portId("ABCD1") + .portName("/dev/ttyUSB0") + .description("USB Serial Port") + .productName("test_product") + .manufacturer("test_manufacturer") + .serialNumber("SN123") + .modemType(ModemType.MICHAUD) + .build(); + ModemDescriptor sameDescriptor = + new ModemDescriptor.Builder<>() + .portId("ABCD1") + .portName("/dev/ttyUSB0") + .description("USB Serial Port") + .productName("test_product") + .manufacturer("test_manufacturer") + .serialNumber("SN123") + .modemType(ModemType.MICHAUD) + .build(); + + // When + int hashCode = descriptor.hashCode(); + int sameHashCode = sameDescriptor.hashCode(); + + // Then + Assert.assertEquals(sameHashCode, hashCode); + } +} diff --git a/src/test/java/tic/io/modem/ModemFinderMock.java b/src/test/java/tic/io/modem/ModemFinderMock.java new file mode 100644 index 0000000..f562577 --- /dev/null +++ b/src/test/java/tic/io/modem/ModemFinderMock.java @@ -0,0 +1,52 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.io.modem; + +import tic.io.PortFinderMock; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** Test utility that mimics a {@link ModemFinder} with in-memory descriptors. */ +public class ModemFinderMock extends PortFinderMock implements ModemFinder { + private final List nativeDescriptorList = new ArrayList<>(); + + public ModemFinderMock() { + super(); + } + + public ModemFinderMock(ModemDescriptor... descriptors) { + super(); + if (descriptors != null) { + this.setDescriptors(Arrays.asList(descriptors)); + } + } + + @Override + public ModemDescriptor findNative(String portName) { + for (ModemDescriptor descriptor : this.nativeDescriptorList) { + if (descriptor.portName() == null && portName == null) { + return descriptor; + } + if (descriptor.portName() != null && descriptor.portName().equals(portName)) { + return descriptor; + } + } + return null; + } + + public void addNativeDescriptor(ModemDescriptor descriptor) { + if (descriptor != null) { + this.nativeDescriptorList.add(descriptor); + } + } + + public void removeNativeDescriptor(ModemDescriptor descriptor) { + this.nativeDescriptorList.remove(descriptor); + } +} diff --git a/src/test/java/tic/io/modem/ModemJsonEncoderTest.java b/src/test/java/tic/io/modem/ModemJsonEncoderTest.java new file mode 100644 index 0000000..de36105 --- /dev/null +++ b/src/test/java/tic/io/modem/ModemJsonEncoderTest.java @@ -0,0 +1,96 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.io.modem; + +import java.util.List; +import org.junit.Test; +import org.skyscreamer.jsonassert.JSONAssert; +import tic.ResourceLoader; + +public class ModemJsonEncoderTest { + + @Test + public void test_encode_AllFields() throws Exception { + // Given + ModemDescriptor descriptor = + new ModemDescriptor.Builder<>() + .portId("ABCD1") + .portName("COM7") + .description("USB Serial Port") + .productName("test_product") + .manufacturer("test_manufacturer") + .serialNumber("SN123") + .modemType(ModemType.MICHAUD) + .build(); + + // When + String actualJsonText = + ModemJsonCodec.getInstance() + .encodeToJsonObject(descriptor).toString(); + + // Then + String expectedJsonText = ResourceLoader.readString("/tic/io/modem/AllFields.json"); + JSONAssert.assertEquals(expectedJsonText, actualJsonText, false); + } + + @Test + public void test_encode_Descriptor() throws Exception { + // Given + ModemDescriptor descriptor = + new ModemDescriptor.Builder<>() + .portId("ABCD1") + .portName("COM7") + .description("USB Serial Port") + .productName("test_product") + .manufacturer("test_manufacturer") + .serialNumber("SN123") + .modemType(ModemType.MICHAUD) + .build(); + + // When + String actualJsonText = ModemJsonCodec.getInstance().encodeToJsonString(descriptor); + + // Then + String expectedJsonText = ResourceLoader.readString("/tic/io/modem/Descriptor.json"); + JSONAssert.assertEquals(expectedJsonText, actualJsonText, false); + } + + @Test + public void encodeShouldHandleNullModemType() throws Exception { + // Given + ModemDescriptor descriptor = + new ModemDescriptor.Builder<>() + .portName("COM8") + .productId((short) 1234) + .vendorId((short) 5678) + .build(); + + // When + String actualJsonText = + ModemJsonCodec.getInstance() + .encodeToJsonString(descriptor); + + // Then + String expectedJsonText = ResourceLoader.readString("/tic/io/modem/NullModemType.json"); + JSONAssert.assertEquals(expectedJsonText, actualJsonText, false); + } + + @Test + public void encodeHandlesNullList() throws Exception { + // Given + List descriptors = null; + + // When + String actualJsonText = + ModemJsonCodec.getInstance().encodeToJsonArray(descriptors).toString(); + + // Then + String expectedJsonText = ResourceLoader.readString("/tic/io/modem/NullList.json"); + JSONAssert.assertEquals(expectedJsonText, actualJsonText, false); + } +} diff --git a/src/test/java/tic/io/serialport/SerialPortDescriptorTest.java b/src/test/java/tic/io/serialport/SerialPortDescriptorTest.java new file mode 100644 index 0000000..4498ec8 --- /dev/null +++ b/src/test/java/tic/io/serialport/SerialPortDescriptorTest.java @@ -0,0 +1,879 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.io.serialport; + +import org.junit.Assert; +import org.junit.Test; +import tic.frame.TICMode; + +public class SerialPortDescriptorTest { + + @Test + public void test_instance_with_all_parameters() { + // Given + SerialPortDescriptor descriptor = createStandardDescriptor(); + + // When + + // Then + Assert.assertEquals("ABCD1", descriptor.portId()); + Assert.assertEquals("/dev/ttyUSB0", descriptor.portName()); + Assert.assertEquals("USB Serial Port", descriptor.description()); + Assert.assertEquals(Short.valueOf((short) 1), descriptor.productId()); + Assert.assertEquals(Short.valueOf((short) 2), descriptor.vendorId()); + Assert.assertEquals("test_product", descriptor.productName()); + Assert.assertEquals("test_manufacturer", descriptor.manufacturer()); + Assert.assertEquals("SN123", descriptor.serialNumber()); + } + + @Test + public void test_instance_with_null_portId() { + // Given + SerialPortDescriptor.Builder builder = + new SerialPortDescriptor.Builder<>() + .portId(null) + .portName("/dev/ttyUSB0") + .description("USB Serial Port") + .productId((short) 1) + .vendorId((short) 2) + .productName("test_product") + .manufacturer("test_manufacturer") + .serialNumber("SN123"); + // When + SerialPortDescriptor descriptor = builder.build(); + + // Then + Assert.assertEquals(null, descriptor.portId()); + Assert.assertEquals("/dev/ttyUSB0", descriptor.portName()); + Assert.assertEquals("USB Serial Port", descriptor.description()); + Assert.assertEquals(Short.valueOf((short) 1), descriptor.productId()); + Assert.assertEquals(Short.valueOf((short) 2), descriptor.vendorId()); + Assert.assertEquals("test_product", descriptor.productName()); + Assert.assertEquals("test_manufacturer", descriptor.manufacturer()); + Assert.assertEquals("SN123", descriptor.serialNumber()); + } + + @Test + public void test_instance_with_null_portName() { + // Given + SerialPortDescriptor.Builder builder = + new SerialPortDescriptor.Builder<>() + .portId("ABCD1") + .portName(null) + .description("USB Serial Port") + .productId((short) 1) + .vendorId((short) 2) + .productName("test_product") + .manufacturer("test_manufacturer") + .serialNumber("SN123"); + // When + SerialPortDescriptor descriptor = builder.build(); + + // Then + Assert.assertEquals("ABCD1", descriptor.portId()); + Assert.assertEquals(null, descriptor.portName()); + Assert.assertEquals("USB Serial Port", descriptor.description()); + Assert.assertEquals(Short.valueOf((short) 1), descriptor.productId()); + Assert.assertEquals(Short.valueOf((short) 2), descriptor.vendorId()); + Assert.assertEquals("test_product", descriptor.productName()); + Assert.assertEquals("test_manufacturer", descriptor.manufacturer()); + Assert.assertEquals("SN123", descriptor.serialNumber()); + } + + @Test + public void test_instance_with_null_description() { + // Given + SerialPortDescriptor.Builder builder = + new SerialPortDescriptor.Builder<>() + .portId("ABCD1") + .portName("/dev/ttyUSB0") + .description(null) + .productId((short) 1) + .vendorId((short) 2) + .productName("test_product") + .manufacturer("test_manufacturer") + .serialNumber("SN123"); + // When + SerialPortDescriptor descriptor = builder.build(); + + // Then + Assert.assertEquals("ABCD1", descriptor.portId()); + Assert.assertEquals("/dev/ttyUSB0", descriptor.portName()); + Assert.assertEquals(null, descriptor.description()); + Assert.assertEquals(Short.valueOf((short) 1), descriptor.productId()); + Assert.assertEquals(Short.valueOf((short) 2), descriptor.vendorId()); + Assert.assertEquals("test_product", descriptor.productName()); + Assert.assertEquals("test_manufacturer", descriptor.manufacturer()); + Assert.assertEquals("SN123", descriptor.serialNumber()); + } + + @Test + public void test_instance_with_null_productId() { + // Given + SerialPortDescriptor.Builder builder = + new SerialPortDescriptor.Builder<>() + .portId("ABCD1") + .portName("/dev/ttyUSB0") + .description("USB Serial Port") + .productId(null) + .vendorId((short) 2) + .productName("test_product") + .manufacturer("test_manufacturer") + .serialNumber("SN123"); + // When + SerialPortDescriptor descriptor = builder.build(); + + // Then + Assert.assertEquals("ABCD1", descriptor.portId()); + Assert.assertEquals("/dev/ttyUSB0", descriptor.portName()); + Assert.assertEquals("USB Serial Port", descriptor.description()); + Assert.assertEquals(null, descriptor.productId()); + Assert.assertEquals(Short.valueOf((short) 2), descriptor.vendorId()); + Assert.assertEquals("test_product", descriptor.productName()); + Assert.assertEquals("test_manufacturer", descriptor.manufacturer()); + Assert.assertEquals("SN123", descriptor.serialNumber()); + } + + @Test + public void test_instance_with_null_vendorId() { + // Given + SerialPortDescriptor.Builder builder = + new SerialPortDescriptor.Builder<>() + .portId("ABCD1") + .portName("/dev/ttyUSB0") + .description("USB Serial Port") + .productId((short) 1) + .vendorId(null) + .productName("test_product") + .manufacturer("test_manufacturer") + .serialNumber("SN123"); + // When + SerialPortDescriptor descriptor = builder.build(); + + // Then + Assert.assertEquals("ABCD1", descriptor.portId()); + Assert.assertEquals("/dev/ttyUSB0", descriptor.portName()); + Assert.assertEquals("USB Serial Port", descriptor.description()); + Assert.assertEquals(Short.valueOf((short) 1), descriptor.productId()); + Assert.assertEquals(null, descriptor.vendorId()); + Assert.assertEquals("test_product", descriptor.productName()); + Assert.assertEquals("test_manufacturer", descriptor.manufacturer()); + Assert.assertEquals("SN123", descriptor.serialNumber()); + } + + @Test + public void test_instance_with_null_productName() { + // Given + SerialPortDescriptor.Builder builder = + new SerialPortDescriptor.Builder<>() + .portId("ABCD1") + .portName("/dev/ttyUSB0") + .description("USB Serial Port") + .productId((short) 1) + .vendorId((short) 2) + .productName(null) + .manufacturer("test_manufacturer") + .serialNumber("SN123"); + // When + SerialPortDescriptor descriptor = builder.build(); + + // Then + Assert.assertEquals("ABCD1", descriptor.portId()); + Assert.assertEquals("/dev/ttyUSB0", descriptor.portName()); + Assert.assertEquals("USB Serial Port", descriptor.description()); + Assert.assertEquals(Short.valueOf((short) 1), descriptor.productId()); + Assert.assertEquals(Short.valueOf((short) 2), descriptor.vendorId()); + Assert.assertEquals(null, descriptor.productName()); + Assert.assertEquals("test_manufacturer", descriptor.manufacturer()); + Assert.assertEquals("SN123", descriptor.serialNumber()); + } + + @Test + public void test_instance_with_null_manufacturer() { + // Given + SerialPortDescriptor.Builder builder = + new SerialPortDescriptor.Builder<>() + .portId("ABCD1") + .portName("/dev/ttyUSB0") + .description("USB Serial Port") + .productId((short) 1) + .vendorId((short) 2) + .productName("test_product") + .manufacturer(null) + .serialNumber("SN123"); + // When + SerialPortDescriptor descriptor = builder.build(); + + // Then + Assert.assertEquals("ABCD1", descriptor.portId()); + Assert.assertEquals("/dev/ttyUSB0", descriptor.portName()); + Assert.assertEquals("USB Serial Port", descriptor.description()); + Assert.assertEquals(Short.valueOf((short) 1), descriptor.productId()); + Assert.assertEquals(Short.valueOf((short) 2), descriptor.vendorId()); + Assert.assertEquals("test_product", descriptor.productName()); + Assert.assertEquals(null, descriptor.manufacturer()); + Assert.assertEquals("SN123", descriptor.serialNumber()); + } + + @Test + public void test_instance_with_null_serialNumber() { + // Given + SerialPortDescriptor.Builder builder = + new SerialPortDescriptor.Builder<>() + .portId("ABCD1") + .portName("/dev/ttyUSB0") + .description("USB Serial Port") + .productId((short) 1) + .vendorId((short) 2) + .productName("test_product") + .manufacturer("test_manufacturer") + .serialNumber(null); + // When + SerialPortDescriptor descriptor = builder.build(); + + // Then + Assert.assertEquals("ABCD1", descriptor.portId()); + Assert.assertEquals("/dev/ttyUSB0", descriptor.portName()); + Assert.assertEquals("USB Serial Port", descriptor.description()); + Assert.assertEquals(Short.valueOf((short) 1), descriptor.productId()); + Assert.assertEquals(Short.valueOf((short) 2), descriptor.vendorId()); + Assert.assertEquals("test_product", descriptor.productName()); + Assert.assertEquals("test_manufacturer", descriptor.manufacturer()); + Assert.assertEquals(null, descriptor.serialNumber()); + } + + @Test + public void test_instance_with_missing_portId() { + // Given + SerialPortDescriptor.Builder builder = + new SerialPortDescriptor.Builder<>() + .portName("/dev/ttyUSB0") + .description("USB Serial Port") + .productId((short) 1) + .vendorId((short) 2) + .productName("test_product") + .manufacturer("test_manufacturer") + .serialNumber("SN123"); + // When + SerialPortDescriptor descriptor = builder.build(); + + // Then + Assert.assertEquals(null, descriptor.portId()); + Assert.assertEquals("/dev/ttyUSB0", descriptor.portName()); + Assert.assertEquals("USB Serial Port", descriptor.description()); + Assert.assertEquals(Short.valueOf((short) 1), descriptor.productId()); + Assert.assertEquals(Short.valueOf((short) 2), descriptor.vendorId()); + Assert.assertEquals("test_product", descriptor.productName()); + Assert.assertEquals("test_manufacturer", descriptor.manufacturer()); + Assert.assertEquals("SN123", descriptor.serialNumber()); + } + + @Test + public void test_instance_with_missing_portName() { + // Given + SerialPortDescriptor.Builder builder = + new SerialPortDescriptor.Builder<>() + .portId("ABCD1") + .description("USB Serial Port") + .productId((short) 1) + .vendorId((short) 2) + .productName("test_product") + .manufacturer("test_manufacturer") + .serialNumber("SN123"); + // When + SerialPortDescriptor descriptor = builder.build(); + + // Then + Assert.assertEquals("ABCD1", descriptor.portId()); + Assert.assertEquals(null, descriptor.portName()); + Assert.assertEquals("USB Serial Port", descriptor.description()); + Assert.assertEquals(Short.valueOf((short) 1), descriptor.productId()); + Assert.assertEquals(Short.valueOf((short) 2), descriptor.vendorId()); + Assert.assertEquals("test_product", descriptor.productName()); + Assert.assertEquals("test_manufacturer", descriptor.manufacturer()); + Assert.assertEquals("SN123", descriptor.serialNumber()); + } + + @Test + public void test_instance_with_missing_description() { + // Given + SerialPortDescriptor.Builder builder = + new SerialPortDescriptor.Builder<>() + .portId("ABCD1") + .portName("/dev/ttyUSB0") + .productId((short) 1) + .vendorId((short) 2) + .productName("test_product") + .manufacturer("test_manufacturer") + .serialNumber("SN123"); + // When + SerialPortDescriptor descriptor = builder.build(); + + // Then + Assert.assertEquals("ABCD1", descriptor.portId()); + Assert.assertEquals("/dev/ttyUSB0", descriptor.portName()); + Assert.assertEquals(null, descriptor.description()); + Assert.assertEquals(Short.valueOf((short) 1), descriptor.productId()); + Assert.assertEquals(Short.valueOf((short) 2), descriptor.vendorId()); + Assert.assertEquals("test_product", descriptor.productName()); + Assert.assertEquals("test_manufacturer", descriptor.manufacturer()); + Assert.assertEquals("SN123", descriptor.serialNumber()); + } + + @Test + public void test_instance_with_missing_productId() { + // Given + SerialPortDescriptor.Builder builder = + new SerialPortDescriptor.Builder<>() + .portId("ABCD1") + .portName("/dev/ttyUSB0") + .description("USB Serial Port") + .vendorId((short) 2) + .productName("test_product") + .manufacturer("test_manufacturer") + .serialNumber("SN123"); + // When + SerialPortDescriptor descriptor = builder.build(); + + // Then + Assert.assertEquals("ABCD1", descriptor.portId()); + Assert.assertEquals("/dev/ttyUSB0", descriptor.portName()); + Assert.assertEquals("USB Serial Port", descriptor.description()); + Assert.assertEquals(null, descriptor.productId()); + Assert.assertEquals(Short.valueOf((short) 2), descriptor.vendorId()); + Assert.assertEquals("test_product", descriptor.productName()); + Assert.assertEquals("test_manufacturer", descriptor.manufacturer()); + Assert.assertEquals("SN123", descriptor.serialNumber()); + } + + @Test + public void test_instance_with_missing_vendorId() { + // Given + SerialPortDescriptor.Builder builder = + new SerialPortDescriptor.Builder<>() + .portId("ABCD1") + .portName("/dev/ttyUSB0") + .description("USB Serial Port") + .productId((short) 1) + .productName("test_product") + .manufacturer("test_manufacturer") + .serialNumber("SN123"); + // When + SerialPortDescriptor descriptor = builder.build(); + + // Then + Assert.assertEquals("ABCD1", descriptor.portId()); + Assert.assertEquals("/dev/ttyUSB0", descriptor.portName()); + Assert.assertEquals("USB Serial Port", descriptor.description()); + Assert.assertEquals(Short.valueOf((short) 1), descriptor.productId()); + Assert.assertEquals(null, descriptor.vendorId()); + Assert.assertEquals("test_product", descriptor.productName()); + Assert.assertEquals("test_manufacturer", descriptor.manufacturer()); + Assert.assertEquals("SN123", descriptor.serialNumber()); + } + + @Test + public void test_instance_with_missing_productName() { + // Given + SerialPortDescriptor.Builder builder = + new SerialPortDescriptor.Builder<>() + .portId("ABCD1") + .portName("/dev/ttyUSB0") + .description("USB Serial Port") + .productId((short) 1) + .vendorId((short) 2) + .manufacturer("test_manufacturer") + .serialNumber("SN123"); + // When + SerialPortDescriptor descriptor = builder.build(); + + // Then + Assert.assertEquals("ABCD1", descriptor.portId()); + Assert.assertEquals("/dev/ttyUSB0", descriptor.portName()); + Assert.assertEquals("USB Serial Port", descriptor.description()); + Assert.assertEquals(Short.valueOf((short) 1), descriptor.productId()); + Assert.assertEquals(Short.valueOf((short) 2), descriptor.vendorId()); + Assert.assertEquals(null, descriptor.productName()); + Assert.assertEquals("test_manufacturer", descriptor.manufacturer()); + Assert.assertEquals("SN123", descriptor.serialNumber()); + } + + @Test + public void test_instance_with_missing_manufacturer() { + // Given + SerialPortDescriptor.Builder builder = + new SerialPortDescriptor.Builder<>() + .portId("ABCD1") + .portName("/dev/ttyUSB0") + .description("USB Serial Port") + .productId((short) 1) + .vendorId((short) 2) + .productName("test_product") + .serialNumber("SN123"); + // When + SerialPortDescriptor descriptor = builder.build(); + + // Then + Assert.assertEquals("ABCD1", descriptor.portId()); + Assert.assertEquals("/dev/ttyUSB0", descriptor.portName()); + Assert.assertEquals("USB Serial Port", descriptor.description()); + Assert.assertEquals(Short.valueOf((short) 1), descriptor.productId()); + Assert.assertEquals(Short.valueOf((short) 2), descriptor.vendorId()); + Assert.assertEquals("test_product", descriptor.productName()); + Assert.assertEquals(null, descriptor.manufacturer()); + Assert.assertEquals("SN123", descriptor.serialNumber()); + } + + @Test + public void test_instance_with_missing_serialNumber() { + // Given + SerialPortDescriptor.Builder builder = + new SerialPortDescriptor.Builder<>() + .portId("ABCD1") + .portName("/dev/ttyUSB0") + .description("USB Serial Port") + .productId((short) 1) + .vendorId((short) 2) + .productName("test_product") + .manufacturer("test_manufacturer"); + // When + SerialPortDescriptor descriptor = builder.build(); + + // Then + Assert.assertEquals("ABCD1", descriptor.portId()); + Assert.assertEquals("/dev/ttyUSB0", descriptor.portName()); + Assert.assertEquals("USB Serial Port", descriptor.description()); + Assert.assertEquals(Short.valueOf((short) 1), descriptor.productId()); + Assert.assertEquals(Short.valueOf((short) 2), descriptor.vendorId()); + Assert.assertEquals("test_product", descriptor.productName()); + Assert.assertEquals("test_manufacturer", descriptor.manufacturer()); + Assert.assertEquals(null, descriptor.serialNumber()); + } + + @Test + public void test_instance_with_empty_portId() { + // Given + SerialPortDescriptor.Builder builder = + new SerialPortDescriptor.Builder<>() + .portId("") + .portName("/dev/ttyUSB0") + .description("USB Serial Port") + .productId((short) 1) + .vendorId((short) 2) + .productName("test_product") + .manufacturer("test_manufacturer") + .serialNumber("SN123"); + // When + IllegalArgumentException exception = + Assert.assertThrows(IllegalArgumentException.class, () -> builder.build()); + + // Then + Assert.assertEquals("Value 'portId' cannot be empty", exception.getMessage()); + } + + @Test + public void test_instance_with_empty_portName() { + // Given + SerialPortDescriptor.Builder builder = + new SerialPortDescriptor.Builder<>() + .portId("ABCD1") + .portName("") + .description("USB Serial Port") + .productId((short) 1) + .vendorId((short) 2) + .productName("test_product") + .manufacturer("test_manufacturer") + .serialNumber("SN123"); + ; + // When + IllegalArgumentException exception = + Assert.assertThrows(IllegalArgumentException.class, () -> builder.build()); + + // Then + Assert.assertEquals("Value 'portName' cannot be empty", exception.getMessage()); + } + + @Test + public void test_instance_with_empty_description() { + // Given + SerialPortDescriptor.Builder builder = + new SerialPortDescriptor.Builder<>() + .portId("ABCD1") + .portName("/dev/ttyUSB0") + .description("") + .productId((short) 1) + .vendorId((short) 2) + .productName("test_product") + .manufacturer("test_manufacturer") + .serialNumber("SN123"); + ; + // When + IllegalArgumentException exception = + Assert.assertThrows(IllegalArgumentException.class, () -> builder.build()); + + // Then + Assert.assertEquals("Value 'description' cannot be empty", exception.getMessage()); + } + + @Test + public void test_instance_with_empty_productName() { + // Given + SerialPortDescriptor.Builder builder = + new SerialPortDescriptor.Builder<>() + .portId("ABCD1") + .portName("/dev/ttyUSB0") + .description("USB Serial Port") + .productId((short) 1) + .vendorId((short) 2) + .productName("") + .manufacturer("test_manufacturer") + .serialNumber("SN123"); + ; + // When + IllegalArgumentException exception = + Assert.assertThrows(IllegalArgumentException.class, () -> builder.build()); + + // Then + Assert.assertEquals("Value 'productName' cannot be empty", exception.getMessage()); + } + + @Test + public void test_instance_with_empty_manufacturer() { + // Given + SerialPortDescriptor.Builder builder = + new SerialPortDescriptor.Builder<>() + .portId("ABCD1") + .portName("/dev/ttyUSB0") + .description("USB Serial Port") + .productId((short) 1) + .vendorId((short) 2) + .productName("test_product") + .manufacturer("") + .serialNumber("SN123"); + ; + // When + IllegalArgumentException exception = + Assert.assertThrows(IllegalArgumentException.class, () -> builder.build()); + + // Then + Assert.assertEquals("Value 'manufacturer' cannot be empty", exception.getMessage()); + } + + @Test + public void test_instance_with_empty_serialNumber() { + // Given + SerialPortDescriptor.Builder builder = + new SerialPortDescriptor.Builder<>() + .portId("ABCD1") + .portName("/dev/ttyUSB0") + .description("USB Serial Port") + .productId((short) 1) + .vendorId((short) 2) + .productName("test_product") + .manufacturer("test_manufacturer") + .serialNumber(""); + ; + // When + IllegalArgumentException exception = + Assert.assertThrows(IllegalArgumentException.class, () -> builder.build()); + + // Then + Assert.assertEquals("Value 'serialNumber' cannot be empty", exception.getMessage()); + } + + @Test + public void test_equals_with_same_instance() { + // Given + SerialPortDescriptor descriptor = + new SerialPortDescriptor.Builder<>() + .portId("ABCD1") + .portName("/dev/ttyUSB0") + .description("USB Serial Port") + .productId(null) + .vendorId((short) 2) + .productName("test_product") + .manufacturer("test_manufacturer") + .serialNumber("SN123") + .build(); + // When + boolean match = descriptor.equals(descriptor); + + // Then + Assert.assertEquals(true, match); + } + + @Test + public void test_equals_with_identical_object() { + // Given + SerialPortDescriptor descriptor = createStandardDescriptor(); + + SerialPortDescriptor otherDescriptor = createStandardDescriptor(); + // When + boolean match = descriptor.equals(otherDescriptor); + + // Then + Assert.assertEquals(true, match); + } + + @Test + public void test_equals_with_different_object_type() { + // Given + SerialPortDescriptor descriptor = createStandardDescriptor(); + // When + boolean match = descriptor.equals((Object) TICMode.HISTORIC); + + // Then + Assert.assertEquals(false, match); + } + + @Test + public void test_equals_with_different_portId() { + // Given + SerialPortDescriptor descriptor = createStandardDescriptor(); + + SerialPortDescriptor otherDescriptor = + new SerialPortDescriptor.Builder<>() + .portId("ABCD2") + .portName("/dev/ttyUSB0") + .description("USB Serial Port") + .productId((short) 1) + .vendorId((short) 2) + .productName("test_product") + .manufacturer("test_manufacturer") + .serialNumber("SN123") + .build(); + // When + boolean match = descriptor.equals(otherDescriptor); + + // Then + Assert.assertEquals(false, match); + } + + @Test + public void test_equals_with_different_portName() { + // Given + SerialPortDescriptor descriptor = createStandardDescriptor(); + + SerialPortDescriptor otherDescriptor = + new SerialPortDescriptor.Builder<>() + .portId("ABCD1") + .portName("/dev/ttyUSB1") + .description("USB Serial Port") + .productId((short) 1) + .vendorId((short) 2) + .productName("test_product") + .manufacturer("test_manufacturer") + .serialNumber("SN123") + .build(); + // When + boolean match = descriptor.equals(otherDescriptor); + + // Then + Assert.assertEquals(false, match); + } + + @Test + public void test_equals_with_different_description() { + // Given + SerialPortDescriptor descriptor = createStandardDescriptor(); + + SerialPortDescriptor otherDescriptor = + new SerialPortDescriptor.Builder<>() + .portId("ABCD1") + .portName("/dev/ttyUSB0") + .description("USB Serial") + .productId((short) 1) + .vendorId((short) 2) + .productName("test_product") + .manufacturer("test_manufacturer") + .serialNumber("SN123") + .build(); + // When + boolean match = descriptor.equals(otherDescriptor); + + // Then + Assert.assertEquals(false, match); + } + + @Test + public void test_equals_with_different_productId() { + // Given + SerialPortDescriptor descriptor = createStandardDescriptor(); + + SerialPortDescriptor otherDescriptor = + new SerialPortDescriptor.Builder<>() + .portId("ABCD1") + .portName("/dev/ttyUSB0") + .description("USB Serial Port") + .productId((short) 3) + .vendorId((short) 2) + .productName("test_product") + .manufacturer("test_manufacturer") + .serialNumber("SN123") + .build(); + // When + boolean match = descriptor.equals(otherDescriptor); + + // Then + Assert.assertEquals(false, match); + } + + @Test + public void test_equals_with_different_vendorId() { + // Given + SerialPortDescriptor descriptor = createStandardDescriptor(); + + SerialPortDescriptor otherDescriptor = + new SerialPortDescriptor.Builder<>() + .portId("ABCD1") + .portName("/dev/ttyUSB0") + .description("USB Serial Port") + .productId((short) 1) + .vendorId((short) 3) + .productName("test_product") + .manufacturer("test_manufacturer") + .serialNumber("SN123") + .build(); + // When + boolean match = descriptor.equals(otherDescriptor); + + // Then + Assert.assertEquals(false, match); + } + + @Test + public void test_equals_with_different_productName() { + // Given + SerialPortDescriptor descriptor = createStandardDescriptor(); + + SerialPortDescriptor otherDescriptor = + new SerialPortDescriptor.Builder<>() + .portId("ABCD1") + .portName("/dev/ttyUSB0") + .description("USB Serial Port") + .productId((short) 1) + .vendorId((short) 2) + .productName("test_product 2") + .manufacturer("test_manufacturer") + .serialNumber("SN123") + .build(); + // When + boolean match = descriptor.equals(otherDescriptor); + + // Then + Assert.assertEquals(false, match); + } + + @Test + public void test_equals_with_different_manufacturer() { + // Given + SerialPortDescriptor descriptor = createStandardDescriptor(); + + SerialPortDescriptor otherDescriptor = + new SerialPortDescriptor.Builder<>() + .portId("ABCD1") + .portName("/dev/ttyUSB0") + .description("USB Serial Port") + .productId((short) 1) + .vendorId((short) 2) + .productName("test_product") + .manufacturer("test_manufacturer bis") + .serialNumber("SN123") + .build(); + // When + boolean match = descriptor.equals(otherDescriptor); + + // Then + Assert.assertEquals(false, match); + } + + @Test + public void test_equals_with_different_serialNumber() { + // Given + SerialPortDescriptor descriptor = createStandardDescriptor(); + + SerialPortDescriptor otherDescriptor = + new SerialPortDescriptor.Builder<>() + .portId("ABCD1") + .portName("/dev/ttyUSB0") + .description("USB Serial Port") + .productId((short) 1) + .vendorId((short) 2) + .productName("test_product") + .manufacturer("test_manufacturer") + .serialNumber("SN1234") + .build(); + // When + boolean match = descriptor.equals(otherDescriptor); + + // Then + Assert.assertEquals(false, match); + } + + @Test + public void test_hashCode() { + // Given + SerialPortDescriptor descriptor = createStandardDescriptor(); + SerialPortDescriptor sameDescriptor = createStandardDescriptor(); + + // When + int hashCode = descriptor.hashCode(); + int sameHashCode = sameDescriptor.hashCode(); + + // Then + Assert.assertEquals(sameHashCode, hashCode); + } + + @Test + public void test_isNative_with_only_portName() { + // Given + SerialPortDescriptor descriptor = + new SerialPortDescriptor.Builder<>().portName("/dev/ttyUSB0").build(); + // When + boolean isNative = descriptor.isNative(); + + // Then + Assert.assertEquals(true, isNative); + } + + @Test + public void test_isNative_with_only_portId() { + // Given + SerialPortDescriptor descriptor = new SerialPortDescriptor.Builder<>().portId("ABCD1").build(); + // When + boolean isNative = descriptor.isNative(); + + // Then + Assert.assertEquals(false, isNative); + } + + @Test + public void test_isNative_with_portName_and_portId() { + // Given + SerialPortDescriptor descriptor = + new SerialPortDescriptor.Builder<>().portName("/dev/ttyUSB0").portId("ABCD1").build(); + // When + boolean isNative = descriptor.isNative(); + + // Then + Assert.assertEquals(false, isNative); + } + + private SerialPortDescriptor createStandardDescriptor() { + return new SerialPortDescriptor.Builder<>() + .portId("ABCD1") + .portName("/dev/ttyUSB0") + .description("USB Serial Port") + .productId((short) 1) + .vendorId((short) 2) + .productName("test_product") + .manufacturer("test_manufacturer") + .serialNumber("SN123") + .build(); + } +} diff --git a/src/test/java/tic/io/serialport/SerialPortFinderBaseTest.java b/src/test/java/tic/io/serialport/SerialPortFinderBaseTest.java new file mode 100644 index 0000000..7c1d690 --- /dev/null +++ b/src/test/java/tic/io/serialport/SerialPortFinderBaseTest.java @@ -0,0 +1,101 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.io.serialport; + +import java.util.List; +import org.junit.Assert; +import org.junit.Test; + +public class SerialPortFinderBaseTest { + + @Test + public void test_getInstance() { + // Given + + // When + SerialPortFinder instance1 = SerialPortFinderBase.getInstance(); + SerialPortFinder instance2 = SerialPortFinderBase.getInstance(); + + // Then + Assert.assertNotNull(instance1); + Assert.assertNotNull(instance2); + Assert.assertSame(instance1, instance2); + } + + @Test + public void test_findAll() { + // Given + + // When + List descriptors = SerialPortFinderBase.getInstance().findAll(); + + // Then + Assert.assertNotNull(descriptors); + } + + @Test + public void test_findByPortId() { + // Given + String portId = "portId?"; + + // When + SerialPortDescriptor descriptor = SerialPortFinderBase.getInstance().findByPortId(portId); + + // Then + Assert.assertNull(descriptor); + } + + @Test + public void test_findByPortName() { + // Given + String portName = "portName?"; + // When + SerialPortDescriptor descriptor = SerialPortFinderBase.getInstance().findByPortName(portName); + + // Then + Assert.assertNull(descriptor); + } + + @Test + public void test_findByPortIdOrPortName() { + // Given + String portId = "portId?"; + String portName = "portName?"; + // When + SerialPortDescriptor descriptor = + SerialPortFinderBase.getInstance().findByPortIdOrPortName(portId, portName); + + // Then + Assert.assertNull(descriptor); + } + + @Test + public void test_findNative() { + // Given + String portName = "portName?"; + // When + SerialPortDescriptor descriptor = SerialPortFinderBase.getInstance().findNative(portName); + + // Then + Assert.assertNull(descriptor); + } + + @Test + public void test_findByProductIdAndVendorId() { + // Given + short idProduct = 0; + short idVendor = 0; + // When + List descriptors = + SerialPortFinderBase.getInstance().findByProductIdAndVendorId(idProduct, idVendor); + + // Then + Assert.assertNotNull(descriptors); + Assert.assertEquals(0, descriptors.size()); + } +} diff --git a/src/test/java/tic/io/serialport/SerialPortJsonEncoderTest.java b/src/test/java/tic/io/serialport/SerialPortJsonEncoderTest.java new file mode 100644 index 0000000..a16d087 --- /dev/null +++ b/src/test/java/tic/io/serialport/SerialPortJsonEncoderTest.java @@ -0,0 +1,82 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.io.serialport; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import org.json.JSONException; +import org.junit.Test; +import org.skyscreamer.jsonassert.JSONAssert; +import tic.ResourceLoader; + +public class SerialPortJsonEncoderTest { + + @Test + public void encodeShouldSerializeAllFields() + throws JSONException, IOException, URISyntaxException { + // Given + SerialPortDescriptor descriptor = + new SerialPortDescriptor.Builder<>() + .portId("ABCD1") + .portName("COM7") + .description("USB Serial Port") + .productId((short) 1) + .vendorId((short) 2) + .productName("test_product") + .manufacturer("test_manufacturer") + .serialNumber("SN123") + .build(); + + // When + String actualJsonText = SerialPortJsonEncoder.encode(Arrays.asList(descriptor), -1); + + // Then + String expectedJsonText = ResourceLoader.readString("/tic/io/serialport/AllFields.json"); + JSONAssert.assertEquals(expectedJsonText, actualJsonText, false); + } + + @Test + public void encodeShouldOmitNullifiedStrings() + throws JSONException, IOException, URISyntaxException { + // Given + SerialPortDescriptor descriptor = + new SerialPortDescriptor.Builder<>() + .portId("ABCD1") + .portName(null) + .description(null) + .productId((short) 1) + .vendorId((short) 2) + .productName(null) + .manufacturer(null) + .serialNumber(null) + .build(); + + // When + String actualJsonText = SerialPortJsonEncoder.encode(Collections.singletonList(descriptor), 1); + + // Then + String expectedJsonText = ResourceLoader.readString("/tic/io/serialport/NullifiedStrings.json"); + JSONAssert.assertEquals(expectedJsonText, actualJsonText, false); + } + + @Test + public void encodeHandlesNullList() throws IOException, URISyntaxException, JSONException { + // Given + List descriptors = null; + + // When + String actualJsonText = SerialPortJsonEncoder.encode(descriptors); + + // Then + String expectedJsonText = ResourceLoader.readString("/tic/io/serialport/NullList.json"); + JSONAssert.assertEquals(expectedJsonText, actualJsonText, false); + } +} diff --git a/src/test/java/tic/io/usb/UsbPortDescriptorTest.java b/src/test/java/tic/io/usb/UsbPortDescriptorTest.java new file mode 100644 index 0000000..0a011b7 --- /dev/null +++ b/src/test/java/tic/io/usb/UsbPortDescriptorTest.java @@ -0,0 +1,1616 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.io.usb; + +import org.junit.Assert; +import org.junit.Test; +import tic.frame.TICMode; + +public class UsbPortDescriptorTest { + + @Test + public void test_instance_with_all_parameters() { + // Given + + // When + UsbPortDescriptor descriptor = createStandardDescriptor(); + + // Then + Assert.assertEquals(1, descriptor.bcdDevice()); + Assert.assertEquals(2, descriptor.bcdUSB()); + Assert.assertEquals(3, descriptor.bDescriptorType()); + Assert.assertEquals(4, descriptor.bDeviceClass()); + Assert.assertEquals(5, descriptor.bDeviceProtocol()); + Assert.assertEquals(6, descriptor.bDeviceSubClass()); + Assert.assertEquals(7, descriptor.bLength()); + Assert.assertEquals(8, descriptor.bMaxPacketSize0()); + Assert.assertEquals(9, descriptor.bNumConfigurations()); + Assert.assertEquals(10, descriptor.idProduct()); + Assert.assertEquals(11, descriptor.idVendor()); + Assert.assertEquals(12, descriptor.iManufacturer()); + Assert.assertEquals(13, descriptor.iProduct()); + Assert.assertEquals(14, descriptor.iSerialNumber()); + Assert.assertEquals("test_manufacturer", descriptor.manufacturer()); + Assert.assertEquals("test_product", descriptor.product()); + Assert.assertEquals("SN123", descriptor.serialNumber()); + } + + @Test + public void test_instance_with_null_manufacturer() { + // Given + UsbPortDescriptor.Builder builder = + new UsbPortDescriptor.Builder() + .bcdDevice((short) 1) + .bcdUSB((short) 2) + .bDescriptorType((byte) 3) + .bDeviceClass((byte) 4) + .bDeviceProtocol((byte) 5) + .bDeviceSubClass((byte) 6) + .bLength((byte) 7) + .bMaxPacketSize0((byte) 8) + .bNumConfigurations((byte) 9) + .idProduct((short) 10) + .idVendor((short) 11) + .iManufacturer((byte) 12) + .iProduct((byte) 13) + .iSerialNumber((byte) 14) + .manufacturer(null) + .product("test_product") + .serialNumber("SN123"); + // When + UsbPortDescriptor descriptor = builder.build(); + + // Then + Assert.assertEquals(1, descriptor.bcdDevice()); + Assert.assertEquals(2, descriptor.bcdUSB()); + Assert.assertEquals(3, descriptor.bDescriptorType()); + Assert.assertEquals(4, descriptor.bDeviceClass()); + Assert.assertEquals(5, descriptor.bDeviceProtocol()); + Assert.assertEquals(6, descriptor.bDeviceSubClass()); + Assert.assertEquals(7, descriptor.bLength()); + Assert.assertEquals(8, descriptor.bMaxPacketSize0()); + Assert.assertEquals(9, descriptor.bNumConfigurations()); + Assert.assertEquals(10, descriptor.idProduct()); + Assert.assertEquals(11, descriptor.idVendor()); + Assert.assertEquals(12, descriptor.iManufacturer()); + Assert.assertEquals(13, descriptor.iProduct()); + Assert.assertEquals(14, descriptor.iSerialNumber()); + Assert.assertEquals(null, descriptor.manufacturer()); + Assert.assertEquals("test_product", descriptor.product()); + Assert.assertEquals("SN123", descriptor.serialNumber()); + } + + @Test + public void test_instance_with_null_product() { + // Given + UsbPortDescriptor.Builder builder = + new UsbPortDescriptor.Builder() + .bcdDevice((short) 1) + .bcdUSB((short) 2) + .bDescriptorType((byte) 3) + .bDeviceClass((byte) 4) + .bDeviceProtocol((byte) 5) + .bDeviceSubClass((byte) 6) + .bLength((byte) 7) + .bMaxPacketSize0((byte) 8) + .bNumConfigurations((byte) 9) + .idProduct((short) 10) + .idVendor((short) 11) + .iManufacturer((byte) 12) + .iProduct((byte) 13) + .iSerialNumber((byte) 14) + .manufacturer("test_manufacturer") + .product(null) + .serialNumber("SN123"); + // When + UsbPortDescriptor descriptor = builder.build(); + + // Then + Assert.assertEquals(1, descriptor.bcdDevice()); + Assert.assertEquals(2, descriptor.bcdUSB()); + Assert.assertEquals(3, descriptor.bDescriptorType()); + Assert.assertEquals(4, descriptor.bDeviceClass()); + Assert.assertEquals(5, descriptor.bDeviceProtocol()); + Assert.assertEquals(6, descriptor.bDeviceSubClass()); + Assert.assertEquals(7, descriptor.bLength()); + Assert.assertEquals(8, descriptor.bMaxPacketSize0()); + Assert.assertEquals(9, descriptor.bNumConfigurations()); + Assert.assertEquals(10, descriptor.idProduct()); + Assert.assertEquals(11, descriptor.idVendor()); + Assert.assertEquals(12, descriptor.iManufacturer()); + Assert.assertEquals(13, descriptor.iProduct()); + Assert.assertEquals(14, descriptor.iSerialNumber()); + Assert.assertEquals("test_manufacturer", descriptor.manufacturer()); + Assert.assertEquals(null, descriptor.product()); + Assert.assertEquals("SN123", descriptor.serialNumber()); + } + + @Test + public void test_instance_with_null_serialNumber() { + // Given + UsbPortDescriptor.Builder builder = + new UsbPortDescriptor.Builder() + .bcdDevice((short) 1) + .bcdUSB((short) 2) + .bDescriptorType((byte) 3) + .bDeviceClass((byte) 4) + .bDeviceProtocol((byte) 5) + .bDeviceSubClass((byte) 6) + .bLength((byte) 7) + .bMaxPacketSize0((byte) 8) + .bNumConfigurations((byte) 9) + .idProduct((short) 10) + .idVendor((short) 11) + .iManufacturer((byte) 12) + .iProduct((byte) 13) + .iSerialNumber((byte) 14) + .manufacturer("test_manufacturer") + .product("test_product") + .serialNumber(null); + // When + UsbPortDescriptor descriptor = builder.build(); + + // Then + Assert.assertEquals(1, descriptor.bcdDevice()); + Assert.assertEquals(2, descriptor.bcdUSB()); + Assert.assertEquals(3, descriptor.bDescriptorType()); + Assert.assertEquals(4, descriptor.bDeviceClass()); + Assert.assertEquals(5, descriptor.bDeviceProtocol()); + Assert.assertEquals(6, descriptor.bDeviceSubClass()); + Assert.assertEquals(7, descriptor.bLength()); + Assert.assertEquals(8, descriptor.bMaxPacketSize0()); + Assert.assertEquals(9, descriptor.bNumConfigurations()); + Assert.assertEquals(10, descriptor.idProduct()); + Assert.assertEquals(11, descriptor.idVendor()); + Assert.assertEquals(12, descriptor.iManufacturer()); + Assert.assertEquals(13, descriptor.iProduct()); + Assert.assertEquals(14, descriptor.iSerialNumber()); + Assert.assertEquals("test_manufacturer", descriptor.manufacturer()); + Assert.assertEquals("test_product", descriptor.product()); + Assert.assertEquals(null, descriptor.serialNumber()); + } + + @Test + public void test_instance_with_missing_bcdDevice() { + // Given + UsbPortDescriptor.Builder builder = + new UsbPortDescriptor.Builder() + .bcdUSB((short) 2) + .bDescriptorType((byte) 3) + .bDeviceClass((byte) 4) + .bDeviceProtocol((byte) 5) + .bDeviceSubClass((byte) 6) + .bLength((byte) 7) + .bMaxPacketSize0((byte) 8) + .bNumConfigurations((byte) 9) + .idProduct((short) 10) + .idVendor((short) 11) + .iManufacturer((byte) 12) + .iProduct((byte) 13) + .iSerialNumber((byte) 14) + .manufacturer("test_manufacturer") + .product("test_product") + .serialNumber("SN123"); + // When + UsbPortDescriptor descriptor = builder.build(); + + // Then + Assert.assertEquals(0, descriptor.bcdDevice()); + Assert.assertEquals(2, descriptor.bcdUSB()); + Assert.assertEquals(3, descriptor.bDescriptorType()); + Assert.assertEquals(4, descriptor.bDeviceClass()); + Assert.assertEquals(5, descriptor.bDeviceProtocol()); + Assert.assertEquals(6, descriptor.bDeviceSubClass()); + Assert.assertEquals(7, descriptor.bLength()); + Assert.assertEquals(8, descriptor.bMaxPacketSize0()); + Assert.assertEquals(9, descriptor.bNumConfigurations()); + Assert.assertEquals(10, descriptor.idProduct()); + Assert.assertEquals(11, descriptor.idVendor()); + Assert.assertEquals(12, descriptor.iManufacturer()); + Assert.assertEquals(13, descriptor.iProduct()); + Assert.assertEquals(14, descriptor.iSerialNumber()); + Assert.assertEquals("test_manufacturer", descriptor.manufacturer()); + Assert.assertEquals("test_product", descriptor.product()); + Assert.assertEquals("SN123", descriptor.serialNumber()); + } + + @Test + public void test_instance_with_missing_bcdUSB() { + // Given + UsbPortDescriptor.Builder builder = + new UsbPortDescriptor.Builder() + .bcdDevice((short) 1) + .bDescriptorType((byte) 3) + .bDeviceClass((byte) 4) + .bDeviceProtocol((byte) 5) + .bDeviceSubClass((byte) 6) + .bLength((byte) 7) + .bMaxPacketSize0((byte) 8) + .bNumConfigurations((byte) 9) + .idProduct((short) 10) + .idVendor((short) 11) + .iManufacturer((byte) 12) + .iProduct((byte) 13) + .iSerialNumber((byte) 14) + .manufacturer("test_manufacturer") + .product("test_product") + .serialNumber("SN123"); + // When + UsbPortDescriptor descriptor = builder.build(); + + // Then + Assert.assertEquals(1, descriptor.bcdDevice()); + Assert.assertEquals(0, descriptor.bcdUSB()); + Assert.assertEquals(3, descriptor.bDescriptorType()); + Assert.assertEquals(4, descriptor.bDeviceClass()); + Assert.assertEquals(5, descriptor.bDeviceProtocol()); + Assert.assertEquals(6, descriptor.bDeviceSubClass()); + Assert.assertEquals(7, descriptor.bLength()); + Assert.assertEquals(8, descriptor.bMaxPacketSize0()); + Assert.assertEquals(9, descriptor.bNumConfigurations()); + Assert.assertEquals(10, descriptor.idProduct()); + Assert.assertEquals(11, descriptor.idVendor()); + Assert.assertEquals(12, descriptor.iManufacturer()); + Assert.assertEquals(13, descriptor.iProduct()); + Assert.assertEquals(14, descriptor.iSerialNumber()); + Assert.assertEquals("test_manufacturer", descriptor.manufacturer()); + Assert.assertEquals("test_product", descriptor.product()); + Assert.assertEquals("SN123", descriptor.serialNumber()); + } + + @Test + public void test_instance_with_missing_bDescriptorType() { + // Given + UsbPortDescriptor.Builder builder = + new UsbPortDescriptor.Builder() + .bcdDevice((short) 1) + .bcdUSB((short) 2) + .bDeviceClass((byte) 4) + .bDeviceProtocol((byte) 5) + .bDeviceSubClass((byte) 6) + .bLength((byte) 7) + .bMaxPacketSize0((byte) 8) + .bNumConfigurations((byte) 9) + .idProduct((short) 10) + .idVendor((short) 11) + .iManufacturer((byte) 12) + .iProduct((byte) 13) + .iSerialNumber((byte) 14) + .manufacturer("test_manufacturer") + .product("test_product") + .serialNumber("SN123"); + // When + UsbPortDescriptor descriptor = builder.build(); + + // Then + Assert.assertEquals(1, descriptor.bcdDevice()); + Assert.assertEquals(2, descriptor.bcdUSB()); + Assert.assertEquals(0, descriptor.bDescriptorType()); + Assert.assertEquals(4, descriptor.bDeviceClass()); + Assert.assertEquals(5, descriptor.bDeviceProtocol()); + Assert.assertEquals(6, descriptor.bDeviceSubClass()); + Assert.assertEquals(7, descriptor.bLength()); + Assert.assertEquals(8, descriptor.bMaxPacketSize0()); + Assert.assertEquals(9, descriptor.bNumConfigurations()); + Assert.assertEquals(10, descriptor.idProduct()); + Assert.assertEquals(11, descriptor.idVendor()); + Assert.assertEquals(12, descriptor.iManufacturer()); + Assert.assertEquals(13, descriptor.iProduct()); + Assert.assertEquals(14, descriptor.iSerialNumber()); + Assert.assertEquals("test_manufacturer", descriptor.manufacturer()); + Assert.assertEquals("test_product", descriptor.product()); + Assert.assertEquals("SN123", descriptor.serialNumber()); + } + + @Test + public void test_instance_with_missing_bDeviceClass() { + // Given + UsbPortDescriptor.Builder builder = + new UsbPortDescriptor.Builder() + .bcdDevice((short) 1) + .bcdUSB((short) 2) + .bDescriptorType((byte) 3) + .bDeviceProtocol((byte) 5) + .bDeviceSubClass((byte) 6) + .bLength((byte) 7) + .bMaxPacketSize0((byte) 8) + .bNumConfigurations((byte) 9) + .idProduct((short) 10) + .idVendor((short) 11) + .iManufacturer((byte) 12) + .iProduct((byte) 13) + .iSerialNumber((byte) 14) + .manufacturer("test_manufacturer") + .product("test_product") + .serialNumber("SN123"); + // When + UsbPortDescriptor descriptor = builder.build(); + + // Then + Assert.assertEquals(1, descriptor.bcdDevice()); + Assert.assertEquals(2, descriptor.bcdUSB()); + Assert.assertEquals(3, descriptor.bDescriptorType()); + Assert.assertEquals(0, descriptor.bDeviceClass()); + Assert.assertEquals(5, descriptor.bDeviceProtocol()); + Assert.assertEquals(6, descriptor.bDeviceSubClass()); + Assert.assertEquals(7, descriptor.bLength()); + Assert.assertEquals(8, descriptor.bMaxPacketSize0()); + Assert.assertEquals(9, descriptor.bNumConfigurations()); + Assert.assertEquals(10, descriptor.idProduct()); + Assert.assertEquals(11, descriptor.idVendor()); + Assert.assertEquals(12, descriptor.iManufacturer()); + Assert.assertEquals(13, descriptor.iProduct()); + Assert.assertEquals(14, descriptor.iSerialNumber()); + Assert.assertEquals("test_manufacturer", descriptor.manufacturer()); + Assert.assertEquals("test_product", descriptor.product()); + Assert.assertEquals("SN123", descriptor.serialNumber()); + } + + @Test + public void test_instance_with_missing_bDeviceProtocol() { + // Given + UsbPortDescriptor.Builder builder = + new UsbPortDescriptor.Builder() + .bcdDevice((short) 1) + .bcdUSB((short) 2) + .bDescriptorType((byte) 3) + .bDeviceClass((byte) 4) + .bDeviceSubClass((byte) 6) + .bLength((byte) 7) + .bMaxPacketSize0((byte) 8) + .bNumConfigurations((byte) 9) + .idProduct((short) 10) + .idVendor((short) 11) + .iManufacturer((byte) 12) + .iProduct((byte) 13) + .iSerialNumber((byte) 14) + .manufacturer("test_manufacturer") + .product("test_product") + .serialNumber("SN123"); + // When + UsbPortDescriptor descriptor = builder.build(); + + // Then + Assert.assertEquals(1, descriptor.bcdDevice()); + Assert.assertEquals(2, descriptor.bcdUSB()); + Assert.assertEquals(3, descriptor.bDescriptorType()); + Assert.assertEquals(4, descriptor.bDeviceClass()); + Assert.assertEquals(0, descriptor.bDeviceProtocol()); + Assert.assertEquals(6, descriptor.bDeviceSubClass()); + Assert.assertEquals(7, descriptor.bLength()); + Assert.assertEquals(8, descriptor.bMaxPacketSize0()); + Assert.assertEquals(9, descriptor.bNumConfigurations()); + Assert.assertEquals(10, descriptor.idProduct()); + Assert.assertEquals(11, descriptor.idVendor()); + Assert.assertEquals(12, descriptor.iManufacturer()); + Assert.assertEquals(13, descriptor.iProduct()); + Assert.assertEquals(14, descriptor.iSerialNumber()); + Assert.assertEquals("test_manufacturer", descriptor.manufacturer()); + Assert.assertEquals("test_product", descriptor.product()); + Assert.assertEquals("SN123", descriptor.serialNumber()); + } + + @Test + public void test_instance_with_missing_bDeviceSubClass() { + // Given + UsbPortDescriptor.Builder builder = + new UsbPortDescriptor.Builder() + .bcdDevice((short) 1) + .bcdUSB((short) 2) + .bDescriptorType((byte) 3) + .bDeviceClass((byte) 4) + .bDeviceProtocol((byte) 5) + .bLength((byte) 7) + .bMaxPacketSize0((byte) 8) + .bNumConfigurations((byte) 9) + .idProduct((short) 10) + .idVendor((short) 11) + .iManufacturer((byte) 12) + .iProduct((byte) 13) + .iSerialNumber((byte) 14) + .manufacturer("test_manufacturer") + .product("test_product") + .serialNumber("SN123"); + // When + UsbPortDescriptor descriptor = builder.build(); + + // Then + Assert.assertEquals(1, descriptor.bcdDevice()); + Assert.assertEquals(2, descriptor.bcdUSB()); + Assert.assertEquals(3, descriptor.bDescriptorType()); + Assert.assertEquals(4, descriptor.bDeviceClass()); + Assert.assertEquals(5, descriptor.bDeviceProtocol()); + Assert.assertEquals(0, descriptor.bDeviceSubClass()); + Assert.assertEquals(7, descriptor.bLength()); + Assert.assertEquals(8, descriptor.bMaxPacketSize0()); + Assert.assertEquals(9, descriptor.bNumConfigurations()); + Assert.assertEquals(10, descriptor.idProduct()); + Assert.assertEquals(11, descriptor.idVendor()); + Assert.assertEquals(12, descriptor.iManufacturer()); + Assert.assertEquals(13, descriptor.iProduct()); + Assert.assertEquals(14, descriptor.iSerialNumber()); + Assert.assertEquals("test_manufacturer", descriptor.manufacturer()); + Assert.assertEquals("test_product", descriptor.product()); + Assert.assertEquals("SN123", descriptor.serialNumber()); + } + + @Test + public void test_instance_with_missing_bLength() { + // Given + UsbPortDescriptor.Builder builder = + new UsbPortDescriptor.Builder() + .bcdDevice((short) 1) + .bcdUSB((short) 2) + .bDescriptorType((byte) 3) + .bDeviceClass((byte) 4) + .bDeviceProtocol((byte) 5) + .bDeviceSubClass((byte) 6) + .bMaxPacketSize0((byte) 8) + .bNumConfigurations((byte) 9) + .idProduct((short) 10) + .idVendor((short) 11) + .iManufacturer((byte) 12) + .iProduct((byte) 13) + .iSerialNumber((byte) 14) + .manufacturer("test_manufacturer") + .product("test_product") + .serialNumber("SN123"); + // When + UsbPortDescriptor descriptor = builder.build(); + + // Then + Assert.assertEquals(1, descriptor.bcdDevice()); + Assert.assertEquals(2, descriptor.bcdUSB()); + Assert.assertEquals(3, descriptor.bDescriptorType()); + Assert.assertEquals(4, descriptor.bDeviceClass()); + Assert.assertEquals(5, descriptor.bDeviceProtocol()); + Assert.assertEquals(6, descriptor.bDeviceSubClass()); + Assert.assertEquals(0, descriptor.bLength()); + Assert.assertEquals(8, descriptor.bMaxPacketSize0()); + Assert.assertEquals(9, descriptor.bNumConfigurations()); + Assert.assertEquals(10, descriptor.idProduct()); + Assert.assertEquals(11, descriptor.idVendor()); + Assert.assertEquals(12, descriptor.iManufacturer()); + Assert.assertEquals(13, descriptor.iProduct()); + Assert.assertEquals(14, descriptor.iSerialNumber()); + Assert.assertEquals("test_manufacturer", descriptor.manufacturer()); + Assert.assertEquals("test_product", descriptor.product()); + Assert.assertEquals("SN123", descriptor.serialNumber()); + } + + @Test + public void test_instance_with_missing_bMaxPacketSize0() { + // Given + UsbPortDescriptor.Builder builder = + new UsbPortDescriptor.Builder() + .bcdDevice((short) 1) + .bcdUSB((short) 2) + .bDescriptorType((byte) 3) + .bDeviceClass((byte) 4) + .bDeviceProtocol((byte) 5) + .bDeviceSubClass((byte) 6) + .bLength((byte) 7) + .bNumConfigurations((byte) 9) + .idProduct((short) 10) + .idVendor((short) 11) + .iManufacturer((byte) 12) + .iProduct((byte) 13) + .iSerialNumber((byte) 14) + .manufacturer("test_manufacturer") + .product("test_product") + .serialNumber("SN123"); + // When + UsbPortDescriptor descriptor = builder.build(); + + // Then + Assert.assertEquals(1, descriptor.bcdDevice()); + Assert.assertEquals(2, descriptor.bcdUSB()); + Assert.assertEquals(3, descriptor.bDescriptorType()); + Assert.assertEquals(4, descriptor.bDeviceClass()); + Assert.assertEquals(5, descriptor.bDeviceProtocol()); + Assert.assertEquals(6, descriptor.bDeviceSubClass()); + Assert.assertEquals(7, descriptor.bLength()); + Assert.assertEquals(0, descriptor.bMaxPacketSize0()); + Assert.assertEquals(9, descriptor.bNumConfigurations()); + Assert.assertEquals(10, descriptor.idProduct()); + Assert.assertEquals(11, descriptor.idVendor()); + Assert.assertEquals(12, descriptor.iManufacturer()); + Assert.assertEquals(13, descriptor.iProduct()); + Assert.assertEquals(14, descriptor.iSerialNumber()); + Assert.assertEquals("test_manufacturer", descriptor.manufacturer()); + Assert.assertEquals("test_product", descriptor.product()); + Assert.assertEquals("SN123", descriptor.serialNumber()); + } + + @Test + public void test_instance_with_missing_bNumConfigurations() { + // Given + UsbPortDescriptor.Builder builder = + new UsbPortDescriptor.Builder() + .bcdDevice((short) 1) + .bcdUSB((short) 2) + .bDescriptorType((byte) 3) + .bDeviceClass((byte) 4) + .bDeviceProtocol((byte) 5) + .bDeviceSubClass((byte) 6) + .bLength((byte) 7) + .bMaxPacketSize0((byte) 8) + .idProduct((short) 10) + .idVendor((short) 11) + .iManufacturer((byte) 12) + .iProduct((byte) 13) + .iSerialNumber((byte) 14) + .manufacturer("test_manufacturer") + .product("test_product") + .serialNumber("SN123"); + // When + UsbPortDescriptor descriptor = builder.build(); + + // Then + Assert.assertEquals(1, descriptor.bcdDevice()); + Assert.assertEquals(2, descriptor.bcdUSB()); + Assert.assertEquals(3, descriptor.bDescriptorType()); + Assert.assertEquals(4, descriptor.bDeviceClass()); + Assert.assertEquals(5, descriptor.bDeviceProtocol()); + Assert.assertEquals(6, descriptor.bDeviceSubClass()); + Assert.assertEquals(7, descriptor.bLength()); + Assert.assertEquals(8, descriptor.bMaxPacketSize0()); + Assert.assertEquals(0, descriptor.bNumConfigurations()); + Assert.assertEquals(10, descriptor.idProduct()); + Assert.assertEquals(11, descriptor.idVendor()); + Assert.assertEquals(12, descriptor.iManufacturer()); + Assert.assertEquals(13, descriptor.iProduct()); + Assert.assertEquals(14, descriptor.iSerialNumber()); + Assert.assertEquals("test_manufacturer", descriptor.manufacturer()); + Assert.assertEquals("test_product", descriptor.product()); + Assert.assertEquals("SN123", descriptor.serialNumber()); + } + + @Test + public void test_instance_with_missing_idProduct() { + // Given + UsbPortDescriptor.Builder builder = + new UsbPortDescriptor.Builder() + .bcdDevice((short) 1) + .bcdUSB((short) 2) + .bDescriptorType((byte) 3) + .bDeviceClass((byte) 4) + .bDeviceProtocol((byte) 5) + .bDeviceSubClass((byte) 6) + .bLength((byte) 7) + .bMaxPacketSize0((byte) 8) + .bNumConfigurations((byte) 9) + .idVendor((short) 11) + .iManufacturer((byte) 12) + .iProduct((byte) 13) + .iSerialNumber((byte) 14) + .manufacturer("test_manufacturer") + .product("test_product") + .serialNumber("SN123"); + // When + UsbPortDescriptor descriptor = builder.build(); + + // Then + Assert.assertEquals(1, descriptor.bcdDevice()); + Assert.assertEquals(2, descriptor.bcdUSB()); + Assert.assertEquals(3, descriptor.bDescriptorType()); + Assert.assertEquals(4, descriptor.bDeviceClass()); + Assert.assertEquals(5, descriptor.bDeviceProtocol()); + Assert.assertEquals(6, descriptor.bDeviceSubClass()); + Assert.assertEquals(7, descriptor.bLength()); + Assert.assertEquals(8, descriptor.bMaxPacketSize0()); + Assert.assertEquals(9, descriptor.bNumConfigurations()); + Assert.assertEquals(0, descriptor.idProduct()); + Assert.assertEquals(11, descriptor.idVendor()); + Assert.assertEquals(12, descriptor.iManufacturer()); + Assert.assertEquals(13, descriptor.iProduct()); + Assert.assertEquals(14, descriptor.iSerialNumber()); + Assert.assertEquals("test_manufacturer", descriptor.manufacturer()); + Assert.assertEquals("test_product", descriptor.product()); + Assert.assertEquals("SN123", descriptor.serialNumber()); + } + + @Test + public void test_instance_with_missing_idVendor() { + // Given + UsbPortDescriptor.Builder builder = + new UsbPortDescriptor.Builder() + .bcdDevice((short) 1) + .bcdUSB((short) 2) + .bDescriptorType((byte) 3) + .bDeviceClass((byte) 4) + .bDeviceProtocol((byte) 5) + .bDeviceSubClass((byte) 6) + .bLength((byte) 7) + .bMaxPacketSize0((byte) 8) + .bNumConfigurations((byte) 9) + .idProduct((short) 10) + .iManufacturer((byte) 12) + .iProduct((byte) 13) + .iSerialNumber((byte) 14) + .manufacturer("test_manufacturer") + .product("test_product") + .serialNumber("SN123"); + // When + UsbPortDescriptor descriptor = builder.build(); + + // Then + Assert.assertEquals(1, descriptor.bcdDevice()); + Assert.assertEquals(2, descriptor.bcdUSB()); + Assert.assertEquals(3, descriptor.bDescriptorType()); + Assert.assertEquals(4, descriptor.bDeviceClass()); + Assert.assertEquals(5, descriptor.bDeviceProtocol()); + Assert.assertEquals(6, descriptor.bDeviceSubClass()); + Assert.assertEquals(7, descriptor.bLength()); + Assert.assertEquals(8, descriptor.bMaxPacketSize0()); + Assert.assertEquals(9, descriptor.bNumConfigurations()); + Assert.assertEquals(10, descriptor.idProduct()); + Assert.assertEquals(0, descriptor.idVendor()); + Assert.assertEquals(12, descriptor.iManufacturer()); + Assert.assertEquals(13, descriptor.iProduct()); + Assert.assertEquals(14, descriptor.iSerialNumber()); + Assert.assertEquals("test_manufacturer", descriptor.manufacturer()); + Assert.assertEquals("test_product", descriptor.product()); + Assert.assertEquals("SN123", descriptor.serialNumber()); + } + + @Test + public void test_instance_with_missing_iManufacturer() { + // Given + UsbPortDescriptor.Builder builder = + new UsbPortDescriptor.Builder() + .bcdDevice((short) 1) + .bcdUSB((short) 2) + .bDescriptorType((byte) 3) + .bDeviceClass((byte) 4) + .bDeviceProtocol((byte) 5) + .bDeviceSubClass((byte) 6) + .bLength((byte) 7) + .bMaxPacketSize0((byte) 8) + .bNumConfigurations((byte) 9) + .idProduct((short) 10) + .idVendor((short) 11) + .iProduct((byte) 13) + .iSerialNumber((byte) 14) + .manufacturer("test_manufacturer") + .product("test_product") + .serialNumber("SN123"); + // When + UsbPortDescriptor descriptor = builder.build(); + + // Then + Assert.assertEquals(1, descriptor.bcdDevice()); + Assert.assertEquals(2, descriptor.bcdUSB()); + Assert.assertEquals(3, descriptor.bDescriptorType()); + Assert.assertEquals(4, descriptor.bDeviceClass()); + Assert.assertEquals(5, descriptor.bDeviceProtocol()); + Assert.assertEquals(6, descriptor.bDeviceSubClass()); + Assert.assertEquals(7, descriptor.bLength()); + Assert.assertEquals(8, descriptor.bMaxPacketSize0()); + Assert.assertEquals(9, descriptor.bNumConfigurations()); + Assert.assertEquals(10, descriptor.idProduct()); + Assert.assertEquals(11, descriptor.idVendor()); + Assert.assertEquals(0, descriptor.iManufacturer()); + Assert.assertEquals(13, descriptor.iProduct()); + Assert.assertEquals(14, descriptor.iSerialNumber()); + Assert.assertEquals("test_manufacturer", descriptor.manufacturer()); + Assert.assertEquals("test_product", descriptor.product()); + Assert.assertEquals("SN123", descriptor.serialNumber()); + } + + @Test + public void test_instance_with_missing_iProduct() { + // Given + UsbPortDescriptor.Builder builder = + new UsbPortDescriptor.Builder() + .bcdDevice((short) 1) + .bcdUSB((short) 2) + .bDescriptorType((byte) 3) + .bDeviceClass((byte) 4) + .bDeviceProtocol((byte) 5) + .bDeviceSubClass((byte) 6) + .bLength((byte) 7) + .bMaxPacketSize0((byte) 8) + .bNumConfigurations((byte) 9) + .idProduct((short) 10) + .idVendor((short) 11) + .iManufacturer((byte) 12) + .iSerialNumber((byte) 14) + .manufacturer("test_manufacturer") + .product("test_product") + .serialNumber("SN123"); + // When + UsbPortDescriptor descriptor = builder.build(); + + // Then + Assert.assertEquals(1, descriptor.bcdDevice()); + Assert.assertEquals(2, descriptor.bcdUSB()); + Assert.assertEquals(3, descriptor.bDescriptorType()); + Assert.assertEquals(4, descriptor.bDeviceClass()); + Assert.assertEquals(5, descriptor.bDeviceProtocol()); + Assert.assertEquals(6, descriptor.bDeviceSubClass()); + Assert.assertEquals(7, descriptor.bLength()); + Assert.assertEquals(8, descriptor.bMaxPacketSize0()); + Assert.assertEquals(9, descriptor.bNumConfigurations()); + Assert.assertEquals(10, descriptor.idProduct()); + Assert.assertEquals(11, descriptor.idVendor()); + Assert.assertEquals(12, descriptor.iManufacturer()); + Assert.assertEquals(0, descriptor.iProduct()); + Assert.assertEquals(14, descriptor.iSerialNumber()); + Assert.assertEquals("test_manufacturer", descriptor.manufacturer()); + Assert.assertEquals("test_product", descriptor.product()); + Assert.assertEquals("SN123", descriptor.serialNumber()); + } + + @Test + public void test_instance_with_missing_iSerialNumber() { + // Given + UsbPortDescriptor.Builder builder = + new UsbPortDescriptor.Builder() + .bcdDevice((short) 1) + .bcdUSB((short) 2) + .bDescriptorType((byte) 3) + .bDeviceClass((byte) 4) + .bDeviceProtocol((byte) 5) + .bDeviceSubClass((byte) 6) + .bLength((byte) 7) + .bMaxPacketSize0((byte) 8) + .bNumConfigurations((byte) 9) + .idProduct((short) 10) + .idVendor((short) 11) + .iManufacturer((byte) 12) + .iProduct((byte) 13) + .manufacturer("test_manufacturer") + .product("test_product") + .serialNumber("SN123"); + // When + UsbPortDescriptor descriptor = builder.build(); + + // Then + Assert.assertEquals(1, descriptor.bcdDevice()); + Assert.assertEquals(2, descriptor.bcdUSB()); + Assert.assertEquals(3, descriptor.bDescriptorType()); + Assert.assertEquals(4, descriptor.bDeviceClass()); + Assert.assertEquals(5, descriptor.bDeviceProtocol()); + Assert.assertEquals(6, descriptor.bDeviceSubClass()); + Assert.assertEquals(7, descriptor.bLength()); + Assert.assertEquals(8, descriptor.bMaxPacketSize0()); + Assert.assertEquals(9, descriptor.bNumConfigurations()); + Assert.assertEquals(10, descriptor.idProduct()); + Assert.assertEquals(11, descriptor.idVendor()); + Assert.assertEquals(12, descriptor.iManufacturer()); + Assert.assertEquals(13, descriptor.iProduct()); + Assert.assertEquals(0, descriptor.iSerialNumber()); + Assert.assertEquals("test_manufacturer", descriptor.manufacturer()); + Assert.assertEquals("test_product", descriptor.product()); + Assert.assertEquals("SN123", descriptor.serialNumber()); + } + + @Test + public void test_instance_with_missing_manufacturer() { + // Given + UsbPortDescriptor.Builder builder = + new UsbPortDescriptor.Builder() + .bcdDevice((short) 1) + .bcdUSB((short) 2) + .bDescriptorType((byte) 3) + .bDeviceClass((byte) 4) + .bDeviceProtocol((byte) 5) + .bDeviceSubClass((byte) 6) + .bLength((byte) 7) + .bMaxPacketSize0((byte) 8) + .bNumConfigurations((byte) 9) + .idProduct((short) 10) + .idVendor((short) 11) + .iManufacturer((byte) 12) + .iProduct((byte) 13) + .iSerialNumber((byte) 14) + .product("test_product") + .serialNumber("SN123"); + // When + UsbPortDescriptor descriptor = builder.build(); + + // Then + Assert.assertEquals(1, descriptor.bcdDevice()); + Assert.assertEquals(2, descriptor.bcdUSB()); + Assert.assertEquals(3, descriptor.bDescriptorType()); + Assert.assertEquals(4, descriptor.bDeviceClass()); + Assert.assertEquals(5, descriptor.bDeviceProtocol()); + Assert.assertEquals(6, descriptor.bDeviceSubClass()); + Assert.assertEquals(7, descriptor.bLength()); + Assert.assertEquals(8, descriptor.bMaxPacketSize0()); + Assert.assertEquals(9, descriptor.bNumConfigurations()); + Assert.assertEquals(10, descriptor.idProduct()); + Assert.assertEquals(11, descriptor.idVendor()); + Assert.assertEquals(12, descriptor.iManufacturer()); + Assert.assertEquals(13, descriptor.iProduct()); + Assert.assertEquals(14, descriptor.iSerialNumber()); + Assert.assertEquals(null, descriptor.manufacturer()); + Assert.assertEquals("test_product", descriptor.product()); + Assert.assertEquals("SN123", descriptor.serialNumber()); + } + + @Test + public void test_instance_with_missing_product() { + // Given + UsbPortDescriptor.Builder builder = + new UsbPortDescriptor.Builder() + .bcdDevice((short) 1) + .bcdUSB((short) 2) + .bDescriptorType((byte) 3) + .bDeviceClass((byte) 4) + .bDeviceProtocol((byte) 5) + .bDeviceSubClass((byte) 6) + .bLength((byte) 7) + .bMaxPacketSize0((byte) 8) + .bNumConfigurations((byte) 9) + .idProduct((short) 10) + .idVendor((short) 11) + .iManufacturer((byte) 12) + .iProduct((byte) 13) + .iSerialNumber((byte) 14) + .manufacturer("test_manufacturer") + .serialNumber("SN123"); + // When + UsbPortDescriptor descriptor = builder.build(); + + // Then + Assert.assertEquals(1, descriptor.bcdDevice()); + Assert.assertEquals(2, descriptor.bcdUSB()); + Assert.assertEquals(3, descriptor.bDescriptorType()); + Assert.assertEquals(4, descriptor.bDeviceClass()); + Assert.assertEquals(5, descriptor.bDeviceProtocol()); + Assert.assertEquals(6, descriptor.bDeviceSubClass()); + Assert.assertEquals(7, descriptor.bLength()); + Assert.assertEquals(8, descriptor.bMaxPacketSize0()); + Assert.assertEquals(9, descriptor.bNumConfigurations()); + Assert.assertEquals(10, descriptor.idProduct()); + Assert.assertEquals(11, descriptor.idVendor()); + Assert.assertEquals(12, descriptor.iManufacturer()); + Assert.assertEquals(13, descriptor.iProduct()); + Assert.assertEquals(14, descriptor.iSerialNumber()); + Assert.assertEquals("test_manufacturer", descriptor.manufacturer()); + Assert.assertEquals(null, descriptor.product()); + Assert.assertEquals("SN123", descriptor.serialNumber()); + } + + @Test + public void test_instance_with_missing_serialNumber() { + // Given + UsbPortDescriptor.Builder builder = + new UsbPortDescriptor.Builder() + .bcdDevice((short) 1) + .bcdUSB((short) 2) + .bDescriptorType((byte) 3) + .bDeviceClass((byte) 4) + .bDeviceProtocol((byte) 5) + .bDeviceSubClass((byte) 6) + .bLength((byte) 7) + .bMaxPacketSize0((byte) 8) + .bNumConfigurations((byte) 9) + .idProduct((short) 10) + .idVendor((short) 11) + .iManufacturer((byte) 12) + .iProduct((byte) 13) + .iSerialNumber((byte) 14) + .manufacturer("test_manufacturer") + .product("test_product"); + // When + UsbPortDescriptor descriptor = builder.build(); + + // Then + Assert.assertEquals(1, descriptor.bcdDevice()); + Assert.assertEquals(2, descriptor.bcdUSB()); + Assert.assertEquals(3, descriptor.bDescriptorType()); + Assert.assertEquals(4, descriptor.bDeviceClass()); + Assert.assertEquals(5, descriptor.bDeviceProtocol()); + Assert.assertEquals(6, descriptor.bDeviceSubClass()); + Assert.assertEquals(7, descriptor.bLength()); + Assert.assertEquals(8, descriptor.bMaxPacketSize0()); + Assert.assertEquals(9, descriptor.bNumConfigurations()); + Assert.assertEquals(10, descriptor.idProduct()); + Assert.assertEquals(11, descriptor.idVendor()); + Assert.assertEquals(12, descriptor.iManufacturer()); + Assert.assertEquals(13, descriptor.iProduct()); + Assert.assertEquals(14, descriptor.iSerialNumber()); + Assert.assertEquals("test_manufacturer", descriptor.manufacturer()); + Assert.assertEquals("test_product", descriptor.product()); + Assert.assertEquals(null, descriptor.serialNumber()); + } + + @Test + public void test_instance_with_empty_manufacturer() { + // Given + UsbPortDescriptor.Builder builder = + new UsbPortDescriptor.Builder() + .bcdDevice((short) 1) + .bcdUSB((short) 2) + .bDescriptorType((byte) 3) + .bDeviceClass((byte) 4) + .bDeviceProtocol((byte) 5) + .bDeviceSubClass((byte) 6) + .bLength((byte) 7) + .bMaxPacketSize0((byte) 8) + .bNumConfigurations((byte) 9) + .idProduct((short) 10) + .idVendor((short) 11) + .iManufacturer((byte) 12) + .iProduct((byte) 13) + .iSerialNumber((byte) 14) + .manufacturer("") + .product("test_product") + .serialNumber("SN123"); + // When + IllegalArgumentException exception = + Assert.assertThrows(IllegalArgumentException.class, () -> builder.build()); + + // Then + Assert.assertEquals("Value 'manufacturer' cannot be empty", exception.getMessage()); + } + + @Test + public void test_instance_with_empty_product() { + // Given + UsbPortDescriptor.Builder builder = + new UsbPortDescriptor.Builder() + .bcdDevice((short) 1) + .bcdUSB((short) 2) + .bDescriptorType((byte) 3) + .bDeviceClass((byte) 4) + .bDeviceProtocol((byte) 5) + .bDeviceSubClass((byte) 6) + .bLength((byte) 7) + .bMaxPacketSize0((byte) 8) + .bNumConfigurations((byte) 9) + .idProduct((short) 10) + .idVendor((short) 11) + .iManufacturer((byte) 12) + .iProduct((byte) 13) + .iSerialNumber((byte) 14) + .manufacturer("test_manufacturer") + .product("") + .serialNumber("SN123"); + // When + IllegalArgumentException exception = + Assert.assertThrows(IllegalArgumentException.class, () -> builder.build()); + + // Then + Assert.assertEquals("Value 'product' cannot be empty", exception.getMessage()); + } + + @Test + public void test_instance_with_empty_serialNumber() { + // Given + UsbPortDescriptor.Builder builder = + new UsbPortDescriptor.Builder() + .bcdDevice((short) 1) + .bcdUSB((short) 2) + .bDescriptorType((byte) 3) + .bDeviceClass((byte) 4) + .bDeviceProtocol((byte) 5) + .bDeviceSubClass((byte) 6) + .bLength((byte) 7) + .bMaxPacketSize0((byte) 8) + .bNumConfigurations((byte) 9) + .idProduct((short) 10) + .idVendor((short) 11) + .iManufacturer((byte) 12) + .iProduct((byte) 13) + .iSerialNumber((byte) 14) + .manufacturer("test_manufacturer") + .product("test_product") + .serialNumber(""); + // When + IllegalArgumentException exception = + Assert.assertThrows(IllegalArgumentException.class, () -> builder.build()); + + // Then + Assert.assertEquals("Value 'serialNumber' cannot be empty", exception.getMessage()); + } + + @Test + public void test_equals_with_same_instance() { + // Given + UsbPortDescriptor descriptor = createStandardDescriptor(); + // When + boolean match = descriptor.equals(descriptor); + + // Then + Assert.assertEquals(true, match); + } + + @Test + public void test_equals_with_identical_object() { + // Given + UsbPortDescriptor descriptor = createStandardDescriptor(); + + UsbPortDescriptor otherDescriptor = createStandardDescriptor(); + // When + boolean match = descriptor.equals(otherDescriptor); + + // Then + Assert.assertEquals(true, match); + } + + @Test + public void test_equals_with_different_object_type() { + // Given + UsbPortDescriptor descriptor = createStandardDescriptor(); + // When + boolean match = descriptor.equals((Object) TICMode.HISTORIC); + + // Then + Assert.assertEquals(false, match); + } + + @Test + public void test_equals_with_different_bcdDevice() { + // Given + UsbPortDescriptor descriptor = createStandardDescriptor(); + + UsbPortDescriptor otherDescriptor = + new UsbPortDescriptor.Builder() + .bcdUSB((short) 2) + .bDescriptorType((byte) 3) + .bDeviceClass((byte) 4) + .bDeviceProtocol((byte) 5) + .bDeviceSubClass((byte) 6) + .bLength((byte) 7) + .bMaxPacketSize0((byte) 8) + .bNumConfigurations((byte) 9) + .idProduct((short) 10) + .idVendor((short) 11) + .iManufacturer((byte) 12) + .iProduct((byte) 13) + .iSerialNumber((byte) 14) + .manufacturer("test_manufacturer") + .product("test_product") + .serialNumber("SN123") + .build(); + // When + boolean match = descriptor.equals(otherDescriptor); + + // Then + Assert.assertEquals(false, match); + } + + @Test + public void test_equals_with_different_bcdUSB() { + // Given + UsbPortDescriptor descriptor = createStandardDescriptor(); + + UsbPortDescriptor otherDescriptor = + new UsbPortDescriptor.Builder() + .bcdDevice((short) 1) + .bDescriptorType((byte) 3) + .bDeviceClass((byte) 4) + .bDeviceProtocol((byte) 5) + .bDeviceSubClass((byte) 6) + .bLength((byte) 7) + .bMaxPacketSize0((byte) 8) + .bNumConfigurations((byte) 9) + .idProduct((short) 10) + .idVendor((short) 11) + .iManufacturer((byte) 12) + .iProduct((byte) 13) + .iSerialNumber((byte) 14) + .manufacturer("test_manufacturer") + .product("test_product") + .serialNumber("SN123") + .build(); + // When + boolean match = descriptor.equals(otherDescriptor); + + // Then + Assert.assertEquals(false, match); + } + + @Test + public void test_equals_with_different_bDescriptorType() { + // Given + UsbPortDescriptor descriptor = createStandardDescriptor(); + + UsbPortDescriptor otherDescriptor = + new UsbPortDescriptor.Builder() + .bcdDevice((short) 1) + .bcdUSB((short) 2) + .bDeviceClass((byte) 4) + .bDeviceProtocol((byte) 5) + .bDeviceSubClass((byte) 6) + .bLength((byte) 7) + .bMaxPacketSize0((byte) 8) + .bNumConfigurations((byte) 9) + .idProduct((short) 10) + .idVendor((short) 11) + .iManufacturer((byte) 12) + .iProduct((byte) 13) + .iSerialNumber((byte) 14) + .manufacturer("test_manufacturer") + .product("test_product") + .serialNumber("SN123") + .build(); + // When + boolean match = descriptor.equals(otherDescriptor); + + // Then + Assert.assertEquals(false, match); + } + + @Test + public void test_equals_with_different_bDeviceClass() { + // Given + UsbPortDescriptor descriptor = createStandardDescriptor(); + + UsbPortDescriptor otherDescriptor = + new UsbPortDescriptor.Builder() + .bcdDevice((short) 1) + .bcdUSB((short) 2) + .bDescriptorType((byte) 3) + .bDeviceProtocol((byte) 5) + .bDeviceSubClass((byte) 6) + .bLength((byte) 7) + .bMaxPacketSize0((byte) 8) + .bNumConfigurations((byte) 9) + .idProduct((short) 10) + .idVendor((short) 11) + .iManufacturer((byte) 12) + .iProduct((byte) 13) + .iSerialNumber((byte) 14) + .manufacturer("test_manufacturer") + .product("test_product") + .serialNumber("SN123") + .build(); + // When + boolean match = descriptor.equals(otherDescriptor); + + // Then + Assert.assertEquals(false, match); + } + + @Test + public void test_equals_with_different_bDeviceProtocol() { + // Given + UsbPortDescriptor descriptor = createStandardDescriptor(); + + UsbPortDescriptor otherDescriptor = + new UsbPortDescriptor.Builder() + .bcdDevice((short) 1) + .bcdUSB((short) 2) + .bDescriptorType((byte) 3) + .bDeviceClass((byte) 4) + .bDeviceSubClass((byte) 6) + .bLength((byte) 7) + .bMaxPacketSize0((byte) 8) + .bNumConfigurations((byte) 9) + .idProduct((short) 10) + .idVendor((short) 11) + .iManufacturer((byte) 12) + .iProduct((byte) 13) + .iSerialNumber((byte) 14) + .manufacturer("test_manufacturer") + .product("test_product") + .serialNumber("SN123") + .build(); + // When + boolean match = descriptor.equals(otherDescriptor); + + // Then + Assert.assertEquals(false, match); + } + + @Test + public void test_equals_with_different_bDeviceSubClass() { + // Given + UsbPortDescriptor descriptor = createStandardDescriptor(); + + UsbPortDescriptor otherDescriptor = + new UsbPortDescriptor.Builder() + .bcdDevice((short) 1) + .bcdUSB((short) 2) + .bDescriptorType((byte) 3) + .bDeviceClass((byte) 4) + .bDeviceProtocol((byte) 5) + .bLength((byte) 7) + .bMaxPacketSize0((byte) 8) + .bNumConfigurations((byte) 9) + .idProduct((short) 10) + .idVendor((short) 11) + .iManufacturer((byte) 12) + .iProduct((byte) 13) + .iSerialNumber((byte) 14) + .manufacturer("test_manufacturer") + .product("test_product") + .serialNumber("SN123") + .build(); + // When + boolean match = descriptor.equals(otherDescriptor); + + // Then + Assert.assertEquals(false, match); + } + + @Test + public void test_equals_with_different_bLength() { + // Given + UsbPortDescriptor descriptor = createStandardDescriptor(); + + UsbPortDescriptor otherDescriptor = + new UsbPortDescriptor.Builder() + .bcdDevice((short) 1) + .bcdUSB((short) 2) + .bDescriptorType((byte) 3) + .bDeviceClass((byte) 4) + .bDeviceProtocol((byte) 5) + .bDeviceSubClass((byte) 6) + .bMaxPacketSize0((byte) 8) + .bNumConfigurations((byte) 9) + .idProduct((short) 10) + .idVendor((short) 11) + .iManufacturer((byte) 12) + .iProduct((byte) 13) + .iSerialNumber((byte) 14) + .manufacturer("test_manufacturer") + .product("test_product") + .serialNumber("SN123") + .build(); + // When + boolean match = descriptor.equals(otherDescriptor); + + // Then + Assert.assertEquals(false, match); + } + + @Test + public void test_equals_with_different_bMaxPacketSize0() { + // Given + UsbPortDescriptor descriptor = createStandardDescriptor(); + + UsbPortDescriptor otherDescriptor = + new UsbPortDescriptor.Builder() + .bcdDevice((short) 1) + .bcdUSB((short) 2) + .bDescriptorType((byte) 3) + .bDeviceClass((byte) 4) + .bDeviceProtocol((byte) 5) + .bDeviceSubClass((byte) 6) + .bLength((byte) 7) + .bNumConfigurations((byte) 9) + .idProduct((short) 10) + .idVendor((short) 11) + .iManufacturer((byte) 12) + .iProduct((byte) 13) + .iSerialNumber((byte) 14) + .manufacturer("test_manufacturer") + .product("test_product") + .serialNumber("SN123") + .build(); + // When + boolean match = descriptor.equals(otherDescriptor); + + // Then + Assert.assertEquals(false, match); + } + + @Test + public void test_equals_with_different_bNumConfigurations() { + // Given + UsbPortDescriptor descriptor = createStandardDescriptor(); + + UsbPortDescriptor otherDescriptor = + new UsbPortDescriptor.Builder() + .bcdDevice((short) 1) + .bcdUSB((short) 2) + .bDescriptorType((byte) 3) + .bDeviceClass((byte) 4) + .bDeviceProtocol((byte) 5) + .bDeviceSubClass((byte) 6) + .bLength((byte) 7) + .bMaxPacketSize0((byte) 8) + .idProduct((short) 10) + .idVendor((short) 11) + .iManufacturer((byte) 12) + .iProduct((byte) 13) + .iSerialNumber((byte) 14) + .manufacturer("test_manufacturer") + .product("test_product") + .serialNumber("SN123") + .build(); + // When + boolean match = descriptor.equals(otherDescriptor); + + // Then + Assert.assertEquals(false, match); + } + + @Test + public void test_equals_with_different_idProduct() { + // Given + UsbPortDescriptor descriptor = createStandardDescriptor(); + + UsbPortDescriptor otherDescriptor = + new UsbPortDescriptor.Builder() + .bcdDevice((short) 1) + .bcdUSB((short) 2) + .bDescriptorType((byte) 3) + .bDeviceClass((byte) 4) + .bDeviceProtocol((byte) 5) + .bDeviceSubClass((byte) 6) + .bLength((byte) 7) + .bMaxPacketSize0((byte) 8) + .bNumConfigurations((byte) 9) + .idVendor((short) 11) + .iManufacturer((byte) 12) + .iProduct((byte) 13) + .iSerialNumber((byte) 14) + .manufacturer("test_manufacturer") + .product("test_product") + .serialNumber("SN123") + .build(); + // When + boolean match = descriptor.equals(otherDescriptor); + + // Then + Assert.assertEquals(false, match); + } + + @Test + public void test_equals_with_different_idVendor() { + // Given + UsbPortDescriptor descriptor = createStandardDescriptor(); + + UsbPortDescriptor otherDescriptor = + new UsbPortDescriptor.Builder() + .bcdDevice((short) 1) + .bcdUSB((short) 2) + .bDescriptorType((byte) 3) + .bDeviceClass((byte) 4) + .bDeviceProtocol((byte) 5) + .bDeviceSubClass((byte) 6) + .bLength((byte) 7) + .bMaxPacketSize0((byte) 8) + .bNumConfigurations((byte) 9) + .idProduct((short) 10) + .iManufacturer((byte) 12) + .iProduct((byte) 13) + .iSerialNumber((byte) 14) + .manufacturer("test_manufacturer") + .product("test_product") + .serialNumber("SN123") + .build(); + // When + boolean match = descriptor.equals(otherDescriptor); + + // Then + Assert.assertEquals(false, match); + } + + @Test + public void test_equals_with_different_iManufacturer() { + // Given + UsbPortDescriptor descriptor = createStandardDescriptor(); + + UsbPortDescriptor otherDescriptor = + new UsbPortDescriptor.Builder() + .bcdDevice((short) 1) + .bcdUSB((short) 2) + .bDescriptorType((byte) 3) + .bDeviceClass((byte) 4) + .bDeviceProtocol((byte) 5) + .bDeviceSubClass((byte) 6) + .bLength((byte) 7) + .bMaxPacketSize0((byte) 8) + .bNumConfigurations((byte) 9) + .idProduct((short) 10) + .idVendor((short) 11) + .iProduct((byte) 13) + .iSerialNumber((byte) 14) + .manufacturer("test_manufacturer") + .product("test_product") + .serialNumber("SN123") + .build(); + // When + boolean match = descriptor.equals(otherDescriptor); + + // Then + Assert.assertEquals(false, match); + } + + @Test + public void test_equals_with_different_iProduct() { + // Given + UsbPortDescriptor descriptor = createStandardDescriptor(); + + UsbPortDescriptor otherDescriptor = + new UsbPortDescriptor.Builder() + .bcdDevice((short) 1) + .bcdUSB((short) 2) + .bDescriptorType((byte) 3) + .bDeviceClass((byte) 4) + .bDeviceProtocol((byte) 5) + .bDeviceSubClass((byte) 6) + .bLength((byte) 7) + .bMaxPacketSize0((byte) 8) + .bNumConfigurations((byte) 9) + .idProduct((short) 10) + .idVendor((short) 11) + .iManufacturer((byte) 12) + .iSerialNumber((byte) 14) + .manufacturer("test_manufacturer") + .product("test_product") + .serialNumber("SN123") + .build(); + // When + boolean match = descriptor.equals(otherDescriptor); + + // Then + Assert.assertEquals(false, match); + } + + @Test + public void test_equals_with_different_iSerialNumber() { + // Given + UsbPortDescriptor descriptor = createStandardDescriptor(); + + UsbPortDescriptor otherDescriptor = + new UsbPortDescriptor.Builder() + .bcdDevice((short) 1) + .bcdUSB((short) 2) + .bDescriptorType((byte) 3) + .bDeviceClass((byte) 4) + .bDeviceProtocol((byte) 5) + .bDeviceSubClass((byte) 6) + .bLength((byte) 7) + .bMaxPacketSize0((byte) 8) + .bNumConfigurations((byte) 9) + .idProduct((short) 10) + .idVendor((short) 11) + .iManufacturer((byte) 12) + .iProduct((byte) 13) + .manufacturer("test_manufacturer") + .product("test_product") + .serialNumber("SN123") + .build(); + // When + boolean match = descriptor.equals(otherDescriptor); + + // Then + Assert.assertEquals(false, match); + } + + @Test + public void test_equals_with_different_manufacturer() { + // Given + UsbPortDescriptor descriptor = createStandardDescriptor(); + + UsbPortDescriptor otherDescriptor = + new UsbPortDescriptor.Builder() + .bcdDevice((short) 1) + .bcdUSB((short) 2) + .bDescriptorType((byte) 3) + .bDeviceClass((byte) 4) + .bDeviceProtocol((byte) 5) + .bDeviceSubClass((byte) 6) + .bLength((byte) 7) + .bMaxPacketSize0((byte) 8) + .bNumConfigurations((byte) 9) + .idProduct((short) 10) + .idVendor((short) 11) + .iManufacturer((byte) 12) + .iProduct((byte) 13) + .iSerialNumber((byte) 14) + .manufacturer("test_manufacturer_different") + .product("test_product") + .serialNumber("SN123") + .build(); + // When + boolean match = descriptor.equals(otherDescriptor); + + // Then + Assert.assertEquals(false, match); + } + + @Test + public void test_equals_with_different_product() { + // Given + UsbPortDescriptor descriptor = createStandardDescriptor(); + + UsbPortDescriptor otherDescriptor = + new UsbPortDescriptor.Builder() + .bcdDevice((short) 1) + .bcdUSB((short) 2) + .bDescriptorType((byte) 3) + .bDeviceClass((byte) 4) + .bDeviceProtocol((byte) 5) + .bDeviceSubClass((byte) 6) + .bLength((byte) 7) + .bMaxPacketSize0((byte) 8) + .bNumConfigurations((byte) 9) + .idProduct((short) 10) + .idVendor((short) 11) + .iManufacturer((byte) 12) + .iProduct((byte) 13) + .iSerialNumber((byte) 14) + .manufacturer("test_manufacturer") + .product("test_product_different") + .serialNumber("SN123") + .build(); + // When + boolean match = descriptor.equals(otherDescriptor); + + // Then + Assert.assertEquals(false, match); + } + + @Test + public void test_equals_with_different_serialNumber() { + // Given + UsbPortDescriptor descriptor = createStandardDescriptor(); + + UsbPortDescriptor otherDescriptor = + new UsbPortDescriptor.Builder() + .bcdDevice((short) 1) + .bcdUSB((short) 2) + .bDescriptorType((byte) 3) + .bDeviceClass((byte) 4) + .bDeviceProtocol((byte) 5) + .bDeviceSubClass((byte) 6) + .bLength((byte) 7) + .bMaxPacketSize0((byte) 8) + .bNumConfigurations((byte) 9) + .idProduct((short) 10) + .idVendor((short) 11) + .iManufacturer((byte) 12) + .iProduct((byte) 13) + .iSerialNumber((byte) 14) + .manufacturer("test_manufacturer") + .product("test_product") + .serialNumber("SN123_different") + .build(); + // When + boolean match = descriptor.equals(otherDescriptor); + + // Then + Assert.assertEquals(false, match); + } + + @Test + public void test_hashCode() { + // Given + UsbPortDescriptor descriptor = createStandardDescriptor(); + UsbPortDescriptor sameDescriptor = createStandardDescriptor(); + + // When + int hashCode = descriptor.hashCode(); + int sameHashCode = sameDescriptor.hashCode(); + + // Then + Assert.assertEquals(sameHashCode, hashCode); + } + + private UsbPortDescriptor createStandardDescriptor() { + return new UsbPortDescriptor.Builder() + .bcdDevice((short) 1) + .bcdUSB((short) 2) + .bDescriptorType((byte) 3) + .bDeviceClass((byte) 4) + .bDeviceProtocol((byte) 5) + .bDeviceSubClass((byte) 6) + .bLength((byte) 7) + .bMaxPacketSize0((byte) 8) + .bNumConfigurations((byte) 9) + .idProduct((short) 10) + .idVendor((short) 11) + .iManufacturer((byte) 12) + .iProduct((byte) 13) + .iSerialNumber((byte) 14) + .manufacturer("test_manufacturer") + .product("test_product") + .serialNumber("SN123") + .build(); + } +} diff --git a/src/test/java/tic/io/usb/UsbPortFinderBaseTest.java b/src/test/java/tic/io/usb/UsbPortFinderBaseTest.java new file mode 100644 index 0000000..22a0d8e --- /dev/null +++ b/src/test/java/tic/io/usb/UsbPortFinderBaseTest.java @@ -0,0 +1,79 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.io.usb; + +import java.util.List; +import org.junit.Assert; +import org.junit.Test; + +public class UsbPortFinderBaseTest { + + @Test + public void test_getInstance() { + // Given + + // When + UsbPortFinder instance1 = UsbPortFinderBase.getInstance(); + UsbPortFinder instance2 = UsbPortFinderBase.getInstance(); + + // Then + Assert.assertNotNull(instance1); + Assert.assertNotNull(instance2); + Assert.assertSame(instance1, instance2); + } + + @Test + public void test_findAll() { + // Given + + // When + List descriptors = UsbPortFinderBase.getInstance().findAll(); + + // Then + Assert.assertNotNull(descriptors); + } + + @Test + public void test_findByProductId() { + // Given + short idProduct = 0; + // When + List descriptors = + UsbPortFinderBase.getInstance().findByProductId(idProduct); + + // Then + Assert.assertNotNull(descriptors); + Assert.assertEquals(0, descriptors.size()); + } + + @Test + public void test_findByVendorId() { + // Given + short idVendor = 0; + // When + List descriptors = UsbPortFinderBase.getInstance().findByVendorId(idVendor); + + // Then + Assert.assertNotNull(descriptors); + Assert.assertEquals(0, descriptors.size()); + } + + @Test + public void test_findByProductIdAndVendorId() { + // Given + short idProduct = 0; + short idVendor = 0; + // When + List descriptors = + UsbPortFinderBase.getInstance().findByProductIdAndVendorId(idProduct, idVendor); + + // Then + Assert.assertNotNull(descriptors); + Assert.assertEquals(0, descriptors.size()); + } +} diff --git a/src/test/java/tic/io/usb/UsbPortJsonEncoderTest.java b/src/test/java/tic/io/usb/UsbPortJsonEncoderTest.java new file mode 100644 index 0000000..e75578e --- /dev/null +++ b/src/test/java/tic/io/usb/UsbPortJsonEncoderTest.java @@ -0,0 +1,99 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.io.usb; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.util.Arrays; +import java.util.List; +import org.json.JSONException; +import org.junit.Test; +import org.skyscreamer.jsonassert.JSONAssert; +import tic.ResourceLoader; + +public class UsbPortJsonEncoderTest { + + @Test + public void encodeShouldSerializeAllDescriptorFields() + throws JSONException, IOException, URISyntaxException { + // Given + UsbPortDescriptor descriptor = + new UsbPortDescriptor.Builder() + .bcdDevice((short) 1) + .bcdUSB((short) 2) + .bDescriptorType((byte) 3) + .bDeviceClass((byte) 4) + .bDeviceProtocol((byte) 5) + .bDeviceSubClass((byte) 6) + .bLength((byte) 7) + .bMaxPacketSize0((byte) 8) + .bNumConfigurations((byte) 9) + .idProduct((short) 10) + .idVendor((short) 11) + .iManufacturer((byte) 12) + .iProduct((byte) 13) + .iSerialNumber((byte) 14) + .manufacturer("test_manufacturer") + .product("test_product") + .serialNumber("SN123") + .build(); + + // When + String actualJsonText = UsbPortJsonEncoder.encode(Arrays.asList(descriptor), -1); + + // Then + String expectedJsonText = ResourceLoader.readString("/tic/io/usb/AllDescriptorFields.json"); + JSONAssert.assertEquals(expectedJsonText, actualJsonText, false); + } + + @Test + public void encodeShouldOmitNullStringFields() + throws JSONException, IOException, URISyntaxException { + // Given + UsbPortDescriptor descriptor = + new UsbPortDescriptor.Builder() + .bcdDevice((short) 1) + .bcdUSB((short) 2) + .bDescriptorType((byte) 3) + .bDeviceClass((byte) 4) + .bDeviceProtocol((byte) 5) + .bDeviceSubClass((byte) 6) + .bLength((byte) 7) + .bMaxPacketSize0((byte) 8) + .bNumConfigurations((byte) 9) + .idProduct((short) 10) + .idVendor((short) 11) + .iManufacturer((byte) 12) + .iProduct((byte) 13) + .iSerialNumber((byte) 14) + .manufacturer(null) + .product(null) + .serialNumber(null) + .build(); + + // When + String actualJsonText = UsbPortJsonEncoder.encode(Arrays.asList(descriptor), -1); + + // Then + String expectedJsonText = ResourceLoader.readString("/tic/io/usb/WithNullStringFields.json"); + JSONAssert.assertEquals(expectedJsonText, actualJsonText, false); + } + + @Test + public void encodeHandlesNullList() throws IOException, URISyntaxException, JSONException { + // Given + List list = null; + + // When + String actualJsonText = UsbPortJsonEncoder.encode(list); + + // Then + String expectedJsonText = ResourceLoader.readString("/tic/io/usb/NullList.json"); + JSONAssert.assertEquals(expectedJsonText, actualJsonText, false); + } +} diff --git a/src/test/java/tic/mock/FunctionCall.java b/src/test/java/tic/mock/FunctionCall.java new file mode 100644 index 0000000..bc147d6 --- /dev/null +++ b/src/test/java/tic/mock/FunctionCall.java @@ -0,0 +1,23 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.mock; + +@SuppressWarnings("javadoc") +public class FunctionCall { + public long captureTime; + + public FunctionCall() { + super(); + this.captureTime = System.nanoTime(); + } + + public FunctionCall(long captureTime) { + super(); + this.captureTime = captureTime; + } +} diff --git a/src/test/java/tic/service/config/TIC2WebSocketConfigurationLoaderTest.java b/src/test/java/tic/service/config/TIC2WebSocketConfigurationLoaderTest.java new file mode 100644 index 0000000..0914765 --- /dev/null +++ b/src/test/java/tic/service/config/TIC2WebSocketConfigurationLoaderTest.java @@ -0,0 +1,193 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.service.config; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import java.util.Arrays; +import org.json.JSONException; +import org.junit.Test; +import tic.ResourceLoader; +import tic.frame.TICMode; + +public class TIC2WebSocketConfigurationLoaderTest { + + @Test + public void load_minimalConfiguration_ok() throws Exception { + // Given + String path = ResourceLoader.getFilePath("/tic/service/config_minimal.json"); + + // When + TIC2WebSocketConfiguration cfg = TIC2WebSocketConfigurationLoader.load(path); + + // Then + assertEquals(1234, cfg.getServerPort()); + assertEquals(TICMode.AUTO, cfg.getTicMode()); + assertNull(cfg.getTicPortNames()); + } + + @Test + public void load_fullConfiguration_ok() throws Exception { + // Given + String path = ResourceLoader.getFilePath("/tic/service/config_full.json"); + + // When + TIC2WebSocketConfiguration cfg = TIC2WebSocketConfigurationLoader.load(path); + + // Then + assertEquals(1234, cfg.getServerPort()); + assertEquals(TICMode.HISTORIC, cfg.getTicMode()); + assertEquals(Arrays.asList("COM3", "COM4"), cfg.getTicPortNames()); + } + + @Test + public void load_ticPortNamesEmptyArray_resultsInNull() throws Exception { + // Given + String path = ResourceLoader.getFilePath("/tic/service/config_empty_portnames.json"); + + // When + TIC2WebSocketConfiguration cfg = TIC2WebSocketConfigurationLoader.load(path); + + // Then + assertEquals(1234, cfg.getServerPort()); + assertEquals(TICMode.AUTO, cfg.getTicMode()); + assertNull(cfg.getTicPortNames()); + } + + @Test + public void load_ticModeLowercase_ok() throws Exception { + // Given + String path = ResourceLoader.getFilePath("/tic/service/config_mode_lowercase.json"); + + // When + TIC2WebSocketConfiguration cfg = TIC2WebSocketConfigurationLoader.load(path); + + // Then + assertEquals(1234, cfg.getServerPort()); + assertEquals(TICMode.HISTORIC, cfg.getTicMode()); + } + + @Test + public void load_missingServerPort_throwsIllegalStateException() throws Exception { + // Given + String path = ResourceLoader.getFilePath("/tic/service/config_invalid_missing_port.json"); + Exception exception = null; + + // When + try { + TIC2WebSocketConfigurationLoader.load(path); + } catch (Exception ex) { + exception = ex; + } + + // Then + assertNotNull(exception); + assertNotNull(exception.getCause()); + assertTrue(exception.getCause() instanceof IllegalArgumentException); + } + + @Test + public void load_serverPortOutOfRange_throwsIllegalStateException() throws Exception { + // Given + String path = ResourceLoader.getFilePath("/tic/service/config_invalid_port_range.json"); + Exception exception = null; + + // When + try { + TIC2WebSocketConfigurationLoader.load(path); + } catch (Exception ex) { + exception = ex; + } + + // Then + assertNotNull(exception); + assertNotNull(exception.getCause()); + assertTrue(exception.getCause() instanceof IllegalArgumentException); + } + + @Test + public void load_invalidTicMode_throwsIllegalStateException() throws Exception { + // Given + String path = ResourceLoader.getFilePath("/tic/service/config_invalid_mode.json"); + Exception exception = null; + + // When + try { + TIC2WebSocketConfigurationLoader.load(path); + } catch (Exception ex) { + exception = ex; + } + + // Then + assertNotNull(exception); + assertNotNull(exception.getCause()); + assertTrue(exception.getCause() instanceof IllegalArgumentException); + } + + @Test + public void load_emptyPortName_throwsIllegalStateException() throws Exception { + // Given + String path = ResourceLoader.getFilePath("/tic/service/config_invalid_portnames_empty.json"); + Exception exception = null; + + // When + try { + TIC2WebSocketConfigurationLoader.load(path); + } catch (Exception ex) { + exception = ex; + } + + // Then + assertNotNull(exception); + assertNotNull(exception.getCause()); + assertTrue(exception.getCause() instanceof IllegalArgumentException); + } + + @Test + public void load_duplicatePortNameAfterTrim_throwsIllegalStateException() throws Exception { + // Given + String path = + ResourceLoader.getFilePath("/tic/service/config_invalid_portnames_duplicates_trim.json"); + Exception exception = null; + + // When + try { + TIC2WebSocketConfigurationLoader.load(path); + } catch (Exception ex) { + exception = ex; + } + + // Then + assertNotNull(exception); + assertNotNull(exception.getCause()); + assertTrue(exception.getCause() instanceof IllegalArgumentException); + } + + @Test + public void load_nullPortNameElement_throwsIllegalStateException() throws Exception { + // Given + String path = + ResourceLoader.getFilePath("/tic/service/config_invalid_portnames_null_element.json"); + Exception exception = null; + + // When + try { + TIC2WebSocketConfigurationLoader.load(path); + } catch (Exception ex) { + exception = ex; + } + + // Then + assertNotNull(exception); + assertNotNull(exception.getCause()); + assertTrue(exception.getCause() instanceof JSONException); + } +} diff --git a/src/test/java/tic/stream/configuration/TICStreamConfigurationLoaderTest.java b/src/test/java/tic/stream/configuration/TICStreamConfigurationLoaderTest.java new file mode 100644 index 0000000..8d5cd7f --- /dev/null +++ b/src/test/java/tic/stream/configuration/TICStreamConfigurationLoaderTest.java @@ -0,0 +1,187 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.stream.configuration; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Objects; +import org.junit.Assert; +import org.junit.Test; +import tic.ResourceLoader; +import tic.frame.TICMode; +import tic.stream.identifier.TICStreamIdentifierType; + +public class TICStreamConfigurationLoaderTest { + + @Test + public void test_load_withValidPortNameConfig_returnsConfiguration() + throws IOException, URISyntaxException { + // Given + String configPath = + ResourceLoader.getFilePath("/tic/stream/configuration/withValidPortNameConfig.json"); + + // When + TICStreamConfiguration configuration = TICStreamConfigurationLoader.load(configPath); + + // Then + Assert.assertEquals(TICMode.HISTORIC, configuration.getTicMode()); + Assert.assertEquals(25, configuration.getTimeout()); + Assert.assertEquals(TICStreamIdentifierType.PORT_NAME, configuration.getIdentifier().getType()); + Assert.assertEquals("COM7", configuration.getIdentifier().getPortName()); + } + + @Test + public void test_load_withPortIdIdentifier_usesDefaults() throws IOException, URISyntaxException { + // Given + String configPath = + ResourceLoader.getFilePath("/tic/stream/configuration/withPortIdIdentifier.json"); + + // When + TICStreamConfiguration configuration = TICStreamConfigurationLoader.load(configPath); + + // Then + Assert.assertEquals(TICMode.AUTO, configuration.getTicMode()); + Assert.assertEquals(10, configuration.getTimeout()); + Assert.assertEquals("12345", configuration.getIdentifier().getPortId()); + } + + @Test + public void test_load_withMissingFile_throwsIllegalStateException() { + // Given + String missingPath = "missing-config-" + System.nanoTime() + ".json"; + + // When + IllegalStateException exception = + Assert.assertThrows( + IllegalStateException.class, () -> TICStreamConfigurationLoader.load(missingPath)); + + // Then + Assert.assertTrue(exception.getMessage().contains("Unable to load")); + Assert.assertTrue(exception.getCause() instanceof IOException); + } + + @Test + public void test_load_withInvalidTimeout_throwsIllegalArgumentException() + throws IOException, URISyntaxException { + // Given + String configPath = + ResourceLoader.getFilePath("/tic/stream/configuration/withInvalidTimeout.json"); + + // When + IllegalArgumentException exception = + Assert.assertThrows( + IllegalArgumentException.class, () -> TICStreamConfigurationLoader.load(configPath)); + + // Then + Assert.assertTrue(exception.getMessage().contains("Timeout")); + } + + @Test + public void test_load_withMissingIdentifier_throwsIllegalArgumentException() + throws IOException, URISyntaxException { + // Given + String configPath = + ResourceLoader.getFilePath("/tic/stream/configuration/withMissingIdentifier.json"); + + // When + IllegalArgumentException exception = + Assert.assertThrows( + IllegalArgumentException.class, () -> TICStreamConfigurationLoader.load(configPath)); + + // Then + Assert.assertTrue(exception.getMessage().contains("identifier")); + } + + @Test + public void test_load_withInvalidIdentifierType_throwsIllegalArgumentException() + throws IOException, URISyntaxException { + // Given + String configPath = + ResourceLoader.getFilePath("/tic/stream/configuration/withInvalidIdentifierType.json"); + + // When + IllegalArgumentException exception = + Assert.assertThrows( + IllegalArgumentException.class, + () -> TICStreamConfigurationLoader.load(configPath.toString())); + + // Then + Assert.assertTrue(exception.getMessage().contains("Invalid TIC stream identifier type")); + } + + @Test + public void test_load_withInvalidTicMode_throwsIllegalArgumentException() + throws IOException, URISyntaxException { + // Given + String configPath = + ResourceLoader.getFilePath("/tic/stream/configuration/withInvalidTicMode.json"); + + // When + IllegalArgumentException exception = + Assert.assertThrows( + IllegalArgumentException.class, + () -> TICStreamConfigurationLoader.load(configPath.toString())); + + // Then + Assert.assertTrue(exception.getMessage().contains("No enum constant")); + } + + @Test + public void test_load_withResourceFile_returnsConfiguration() throws Exception { + // Given + String resourceLocation = "tic/stream/configuration/loader-valid.json"; + Path resourcePath = + Paths.get( + Objects.requireNonNull( + TICStreamConfigurationLoaderTest.class + .getClassLoader() + .getResource(resourceLocation)) + .toURI()); + + // When + TICStreamConfiguration configuration = + TICStreamConfigurationLoader.load(resourcePath.toString()); + + // Then + Assert.assertEquals(TICMode.STANDARD, configuration.getTicMode()); + Assert.assertEquals(42, configuration.getTimeout()); + Assert.assertEquals("COM9", configuration.getIdentifier().getPortName()); + } + + @Test + public void test_load_withEmptyFilePath_throwsIllegalStateException() { + // Given + String emptyPath = ""; + + // When + IllegalStateException exception = + Assert.assertThrows( + IllegalStateException.class, () -> TICStreamConfigurationLoader.load(emptyPath)); + + // Then + Assert.assertTrue(exception.getMessage().contains("Unable to load")); + Assert.assertTrue(exception.getCause() instanceof IOException); + } + + @Test + public void test_load_withNullFilePath_throwsIllegalStateException() { + // Given + String nullPath = null; + + // When + IllegalStateException exception = + Assert.assertThrows( + IllegalStateException.class, () -> TICStreamConfigurationLoader.load(nullPath)); + + // Then + Assert.assertTrue(exception.getMessage().contains("Unable to load")); + Assert.assertTrue(exception.getCause() instanceof NullPointerException); + } +} diff --git a/src/test/java/tic/stream/configuration/TICStreamConfigurationTest.java b/src/test/java/tic/stream/configuration/TICStreamConfigurationTest.java new file mode 100644 index 0000000..2b1a395 --- /dev/null +++ b/src/test/java/tic/stream/configuration/TICStreamConfigurationTest.java @@ -0,0 +1,128 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.stream.configuration; + +import tic.frame.TICMode; +import org.junit.Assert; +import org.junit.Test; + +import tic.stream.identifier.SerialPortId; +import tic.stream.identifier.SerialPortName; +import tic.stream.identifier.TICStreamIdentifier; + +public class TICStreamConfigurationTest { + + @Test + public void test_constructor_withValidParametersByPortName_setsFields() { + // Given + TICStreamIdentifier identifier = newIdentifierByPortName(); + + // When + TICStreamConfiguration configuration = + new TICStreamConfiguration(TICMode.STANDARD, identifier, 30); + + // Then + Assert.assertEquals(TICMode.STANDARD, configuration.getTicMode()); + Assert.assertSame(identifier, configuration.getIdentifier()); + Assert.assertEquals(30, configuration.getTimeout()); + } + + @Test + public void test_constructor_withValidParametersByPortId_setsFields() { + // Given + TICStreamIdentifier identifier = newIdentifierByPortId(); + + // When + TICStreamConfiguration configuration = + new TICStreamConfiguration(TICMode.HISTORIC, identifier, 15); + + // Then + Assert.assertEquals(TICMode.HISTORIC, configuration.getTicMode()); + Assert.assertSame(identifier, configuration.getIdentifier()); + Assert.assertEquals(15, configuration.getTimeout()); + } + + @Test + public void test_constructor_withNullTicMode_throwsException() { + // Given + TICStreamIdentifier identifier = newIdentifierByPortName(); + + // When + IllegalArgumentException exception = + Assert.assertThrows( + IllegalArgumentException.class, () -> new TICStreamConfiguration(null, identifier, 10)); + + // Then + Assert.assertTrue(exception.getMessage().contains("cannot be null")); + } + + @Test + public void test_constructor_withNullIdentifier_throwsException() { + // Given + TICMode mode = TICMode.HISTORIC; + + // When + IllegalArgumentException exception = + Assert.assertThrows( + IllegalArgumentException.class, () -> new TICStreamConfiguration(mode, null, 10)); + + // Then + Assert.assertTrue(exception.getMessage().contains("identifier cannot be null")); + } + + @Test + public void test_constructor_withZeroTimeout_throwsException() { + // Given + TICStreamIdentifier identifier = newIdentifierByPortName(); + + // When + IllegalArgumentException exception = + Assert.assertThrows( + IllegalArgumentException.class, + () -> new TICStreamConfiguration(TICMode.AUTO, identifier, 0)); + + // Then + Assert.assertTrue(exception.getMessage().contains("positive integer")); + } + + @Test + public void test_constructor_withNegativeTimeout_throwsException() { + // Given + TICStreamIdentifier identifier = newIdentifierByPortName(); + + // When + IllegalArgumentException exception = + Assert.assertThrows( + IllegalArgumentException.class, + () -> new TICStreamConfiguration(TICMode.AUTO, identifier, -5)); + + // Then + Assert.assertTrue(exception.getMessage().contains("positive integer")); + } + + @Test + public void test_constructor_withMaxTimeout_allowed() { + // Given + TICStreamIdentifier identifier = newIdentifierByPortName(); + + // When + TICStreamConfiguration configuration = + new TICStreamConfiguration(TICMode.AUTO, identifier, Integer.MAX_VALUE); + + // Then + Assert.assertEquals(Integer.MAX_VALUE, configuration.getTimeout()); + } + + private static TICStreamIdentifier newIdentifierByPortName() { + return new TICStreamIdentifier(new SerialPortName("COM1")); + } + + private static TICStreamIdentifier newIdentifierByPortId() { + return new TICStreamIdentifier(new SerialPortId("12345")); + } +} diff --git a/src/test/java/tic/util/message/codec/MessageJsonCodecTest.java b/src/test/java/tic/util/message/codec/MessageJsonCodecTest.java new file mode 100644 index 0000000..31f49f2 --- /dev/null +++ b/src/test/java/tic/util/message/codec/MessageJsonCodecTest.java @@ -0,0 +1,467 @@ +// Copyright (C) 2025 Enedis Smarties team +// +// SPDX-FileContributor: Jehan BOUSCH +// SPDX-FileContributor: Mathieu SABARTHES +// +// SPDX-License-Identifier: Apache-2.0 + +package tic.util.message.codec; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.util.List; +import org.json.JSONObject; +import org.junit.Assert; +import org.junit.Test; +import tic.ResourceLoader; +import tic.core.TICIdentifier; +import tic.service.message.RequestGetAvailableTICs; +import tic.service.message.RequestGetModemsInfo; +import tic.service.message.RequestReadTIC; +import tic.service.message.RequestSubscribeTIC; +import tic.service.message.RequestUnsubscribeTIC; +import tic.util.message.Message; +import tic.util.message.MessageType; +import tic.util.message.exception.MessageException; +import tic.util.message.exception.UnsupportedMessageException; + +public class MessageJsonCodecTest { + + private static JSONObject readJsonObject(String resourcePath) + throws IOException, URISyntaxException { + String jsonText = ResourceLoader.readString(resourcePath); + return new JSONObject(jsonText); + } + + @Test + public void decodeFromJsonObject_withGetAvailableTICs() throws Exception { + // Given + JSONObject jsonObject = readJsonObject("/tic/util/message/codec/RequestGetAvailableTICs.json"); + + // When + Message message = MessageJsonCodec.getInstance().decodeFromJsonObject(jsonObject); + + // Then + Assert.assertTrue(message instanceof RequestGetAvailableTICs); + Assert.assertEquals(MessageType.REQUEST, message.getType()); + Assert.assertEquals(RequestGetAvailableTICs.NAME, message.getName()); + } + + @Test + public void decodeFromJsonObject_withGetModemsInfo() throws Exception { + // Given + JSONObject jsonObject = readJsonObject("/tic/util/message/codec/RequestGetModemsInfo.json"); + + // When + Message message = MessageJsonCodec.getInstance().decodeFromJsonObject(jsonObject); + + // Then + Assert.assertTrue(message instanceof RequestGetModemsInfo); + Assert.assertEquals(MessageType.REQUEST, message.getType()); + Assert.assertEquals(RequestGetModemsInfo.NAME, message.getName()); + } + + @Test + public void decodeFromJsonObject_withReadTIC_allFields() throws Exception { + // Given + JSONObject jsonObject = + readJsonObject("/tic/util/message/codec/RequestReadTIC_WithAllFields.json"); + + // When + Message message = MessageJsonCodec.getInstance().decodeFromJsonObject(jsonObject); + + // Then + Assert.assertTrue(message instanceof RequestReadTIC); + RequestReadTIC request = (RequestReadTIC) message; + Assert.assertEquals(RequestReadTIC.NAME, request.getName()); + + TICIdentifier identifier = request.getData(); + Assert.assertNotNull(identifier); + Assert.assertEquals("/dev/ttyUSB0", identifier.getPortName()); + Assert.assertEquals("1-1", identifier.getPortId()); + Assert.assertEquals("010203040506", identifier.getSerialNumber()); + } + + @Test + public void decodeFromJsonObject_withReadTIC_withPortId() throws Exception { + // Given + JSONObject jsonObject = + readJsonObject("/tic/util/message/codec/RequestReadTIC_WithPortId.json"); + + // When + Message message = MessageJsonCodec.getInstance().decodeFromJsonObject(jsonObject); + + // Then + Assert.assertTrue(message instanceof RequestReadTIC); + RequestReadTIC request = (RequestReadTIC) message; + Assert.assertEquals(RequestReadTIC.NAME, request.getName()); + + TICIdentifier identifier = request.getData(); + Assert.assertNotNull(identifier); + Assert.assertNull(identifier.getPortName()); + Assert.assertEquals("1-1", identifier.getPortId()); + Assert.assertNull(identifier.getSerialNumber()); + } + + @Test + public void decodeFromJsonObject_withReadTIC_withPortName() throws Exception { + // Given + JSONObject jsonObject = + readJsonObject("/tic/util/message/codec/RequestReadTIC_WithPortName.json"); + + // When + Message message = MessageJsonCodec.getInstance().decodeFromJsonObject(jsonObject); + + // Then + Assert.assertTrue(message instanceof RequestReadTIC); + RequestReadTIC request = (RequestReadTIC) message; + Assert.assertEquals(RequestReadTIC.NAME, request.getName()); + + TICIdentifier identifier = request.getData(); + Assert.assertNotNull(identifier); + Assert.assertEquals("/dev/ttyUSB0", identifier.getPortName()); + Assert.assertNull(identifier.getPortId()); + Assert.assertNull(identifier.getSerialNumber()); + } + + @Test + public void decodeFromJsonObject_withReadTIC_withSerialNumber() throws Exception { + // Given + JSONObject jsonObject = + readJsonObject("/tic/util/message/codec/RequestReadTIC_WithSerialNumber.json"); + + // When + Message message = MessageJsonCodec.getInstance().decodeFromJsonObject(jsonObject); + + // Then + Assert.assertTrue(message instanceof RequestReadTIC); + RequestReadTIC request = (RequestReadTIC) message; + Assert.assertEquals(RequestReadTIC.NAME, request.getName()); + + TICIdentifier identifier = request.getData(); + Assert.assertNotNull(identifier); + Assert.assertNull(identifier.getPortName()); + Assert.assertNull(identifier.getPortId()); + Assert.assertEquals("010203040506", identifier.getSerialNumber()); + } + + @Test + public void decodeFromJsonObject_withSubscribeTIC_noData() throws Exception { + // Given + JSONObject jsonObject = + readJsonObject("/tic/util/message/codec/RequestSubscribeTIC_WithNoData.json"); + + // When + Message message = MessageJsonCodec.getInstance().decodeFromJsonObject(jsonObject); + + // Then + Assert.assertTrue(message instanceof RequestSubscribeTIC); + RequestSubscribeTIC request = (RequestSubscribeTIC) message; + Assert.assertNull(request.getData()); + } + + @Test + public void decodeFromJsonObject_withSubscribeTIC_emptyArray() throws Exception { + // Given + JSONObject jsonObject = + readJsonObject("/tic/util/message/codec/RequestSubscribeTIC_WithEmptyArray.json"); + + // When + Message message = MessageJsonCodec.getInstance().decodeFromJsonObject(jsonObject); + + // Then + Assert.assertTrue(message instanceof RequestSubscribeTIC); + RequestSubscribeTIC request = (RequestSubscribeTIC) message; + Assert.assertNotNull(request.getData()); + Assert.assertTrue(request.getData().isEmpty()); + } + + @Test + public void decodeFromJsonObject_withSubscribeTIC_oneIdentifierList() throws Exception { + // Given + JSONObject jsonObject = + readJsonObject("/tic/util/message/codec/RequestSubscribeTIC_WithOneIdentifierList.json"); + // When + Message message = MessageJsonCodec.getInstance().decodeFromJsonObject(jsonObject); + + // Then + Assert.assertTrue(message instanceof RequestSubscribeTIC); + RequestSubscribeTIC request = (RequestSubscribeTIC) message; + + List identifiers = request.getData(); + Assert.assertNotNull(identifiers); + Assert.assertEquals(1, identifiers.size()); + Assert.assertEquals("COM7", identifiers.get(0).getPortName()); + Assert.assertNull(identifiers.get(0).getPortId()); + Assert.assertNull(identifiers.get(0).getSerialNumber()); + } + + @Test + public void decodeFromJsonObject_withSubscribeTIC_oneIdentifier() throws Exception { + // Given + JSONObject jsonObject = + readJsonObject("/tic/util/message/codec/RequestSubscribeTIC_WithOneIdentifier.json"); + + // When + Message message = MessageJsonCodec.getInstance().decodeFromJsonObject(jsonObject); + + // Then + Assert.assertTrue(message instanceof RequestSubscribeTIC); + RequestSubscribeTIC request = (RequestSubscribeTIC) message; + + List identifiers = request.getData(); + Assert.assertNotNull(identifiers); + Assert.assertEquals(1, identifiers.size()); + Assert.assertNull(identifiers.get(0).getPortName()); + Assert.assertNull(identifiers.get(0).getPortId()); + Assert.assertEquals("010203040506", identifiers.get(0).getSerialNumber()); + } + + @Test + public void decodeFromJsonObject_withUnsubscribeTIC_noData() throws Exception { + // Given + JSONObject jsonObject = + readJsonObject("/tic/util/message/codec/RequestUnsubscribeTIC_WithNoData.json"); + // When + Message message = MessageJsonCodec.getInstance().decodeFromJsonObject(jsonObject); + + // Then + Assert.assertTrue(message instanceof RequestUnsubscribeTIC); + RequestUnsubscribeTIC request = (RequestUnsubscribeTIC) message; + Assert.assertNull(request.getData()); + } + + @Test + public void decodeFromJsonObject_withUnsubscribeTIC_emptyArray() throws Exception { + // Given + JSONObject jsonObject = + readJsonObject("/tic/util/message/codec/RequestUnsubscribeTIC_WithEmptyArray.json"); + // When + Message message = MessageJsonCodec.getInstance().decodeFromJsonObject(jsonObject); + + // Then + Assert.assertTrue(message instanceof RequestUnsubscribeTIC); + RequestUnsubscribeTIC request = (RequestUnsubscribeTIC) message; + Assert.assertNotNull(request.getData()); + Assert.assertTrue(request.getData().isEmpty()); + } + + @Test + public void decodeFromJsonObject_withUnsubscribeTIC_oneIdentifierList() throws Exception { + // Given + JSONObject jsonObject = + readJsonObject("/tic/util/message/codec/RequestUnsubscribeTIC_WithOneIdentifierList.json"); + + // When + Message message = MessageJsonCodec.getInstance().decodeFromJsonObject(jsonObject); + + // Then + Assert.assertTrue(message instanceof RequestUnsubscribeTIC); + RequestUnsubscribeTIC request = (RequestUnsubscribeTIC) message; + + List identifiers = request.getData(); + Assert.assertNotNull(identifiers); + Assert.assertEquals(1, identifiers.size()); + Assert.assertEquals("COM7", identifiers.get(0).getPortName()); + Assert.assertNull(identifiers.get(0).getPortId()); + Assert.assertNull(identifiers.get(0).getSerialNumber()); + } + + @Test + public void decodeFromJsonObject_withUnsubscribeTIC_oneIdentifier() throws Exception { + // Given + JSONObject jsonObject = + readJsonObject("/tic/util/message/codec/RequestUnsubscribeTIC_WithOneIdentifier.json"); + + // When + Message message = MessageJsonCodec.getInstance().decodeFromJsonObject(jsonObject); + + // Then + Assert.assertTrue(message instanceof RequestUnsubscribeTIC); + RequestUnsubscribeTIC request = (RequestUnsubscribeTIC) message; + + List identifiers = request.getData(); + Assert.assertNotNull(identifiers); + Assert.assertEquals(1, identifiers.size()); + Assert.assertEquals("COM7", identifiers.get(0).getPortName()); + Assert.assertNull(identifiers.get(0).getPortId()); + Assert.assertNull(identifiers.get(0).getSerialNumber()); + } + + @Test + public void decodeFromJsonObject_withNullJson() { + // Given + JSONObject jsonObject = null; + Exception exception = null; + + // When + try { + MessageJsonCodec.getInstance().decodeFromJsonObject(jsonObject); + Assert.fail("Expected MessageException to be thrown"); + } catch (Exception ex) { + exception = ex; + } + + // Then + Assert.assertNotNull(exception); + Assert.assertTrue(exception instanceof MessageException); + } + + @Test + public void decodeFromJsonObject_withMissingName() throws Exception { + // Given + JSONObject jsonObject = readJsonObject("/tic/util/message/codec/Invalid_MissingName.json"); + Exception exception = null; + + // When + try { + MessageJsonCodec.getInstance().decodeFromJsonObject(jsonObject); + Assert.fail("Expected MessageException to be thrown"); + } catch (Exception ex) { + exception = ex; + } + + // Then + Assert.assertNotNull(exception); + Assert.assertTrue(exception instanceof MessageException); + } + + @Test + public void decodeFromJsonObject_withMissingType() throws Exception { + // Given + JSONObject jsonObject = readJsonObject("/tic/util/message/codec/Invalid_MissingType.json"); + Exception exception = null; + + // When + try { + MessageJsonCodec.getInstance().decodeFromJsonObject(jsonObject); + Assert.fail("Expected MessageException to be thrown"); + } catch (Exception ex) { + exception = ex; + } + + // Then + Assert.assertNotNull(exception); + Assert.assertTrue(exception instanceof MessageException); + } + + @Test + public void decodeFromJsonObject_withNonRequestType() throws Exception { + // Given + JSONObject jsonObject = readJsonObject("/tic/util/message/codec/Invalid_TypeEvent.json"); + Exception exception = null; + + // When + try { + MessageJsonCodec.getInstance().decodeFromJsonObject(jsonObject); + Assert.fail("Expected MessageException to be thrown"); + } catch (Exception ex) { + exception = ex; + } + + // Then + Assert.assertNotNull(exception); + Assert.assertTrue(exception instanceof MessageException); + } + + @Test + public void decodeFromJsonObject_withUnsupportedName() throws Exception { + // Given + JSONObject jsonObject = readJsonObject("/tic/util/message/codec/Invalid_UnsupportedName.json"); + Exception exception = null; + + // When + try { + MessageJsonCodec.getInstance().decodeFromJsonObject(jsonObject); + Assert.fail("Expected UnsupportedMessageException to be thrown"); + } catch (Exception ex) { + exception = ex; + } + + // Then + Assert.assertNotNull(exception); + Assert.assertTrue(exception instanceof UnsupportedMessageException); + } + + @Test + public void decodeFromJsonObject_withReadTicMissingData() throws Exception { + // Given + JSONObject jsonObject = + readJsonObject("/tic/util/message/codec/Invalid_ReadTIC_MissingData.json"); + Exception exception = null; + + // When + try { + MessageJsonCodec.getInstance().decodeFromJsonObject(jsonObject); + Assert.fail("Expected MessageException to be thrown"); + } catch (Exception ex) { + exception = ex; + } + // Then + Assert.assertNotNull(exception); + Assert.assertTrue(exception instanceof MessageException); + } + + @Test + public void encodeToJsonObject_withGetAvailableTICs() { + // Given + Message message = new RequestGetAvailableTICs(); + + // When + JSONObject json = MessageJsonCodec.getInstance().encodeToJsonObject(message); + + // Then + Assert.assertEquals(RequestGetAvailableTICs.NAME, json.getString("name")); + Assert.assertEquals(MessageType.REQUEST.toString(), json.getString("type")); + Assert.assertFalse(json.has("data")); + } + + @Test + public void encodeToJsonObject_withGetModemsInfo() { + // Given + Message message = new RequestGetModemsInfo(); + + // When + JSONObject json = MessageJsonCodec.getInstance().encodeToJsonObject(message); + + // Then + Assert.assertEquals(RequestGetModemsInfo.NAME, json.getString("name")); + Assert.assertEquals(MessageType.REQUEST.toString(), json.getString("type")); + Assert.assertFalse(json.has("data")); + } + + @Test + public void encodeToJsonObject_withReadTIC() { + // Given + TICIdentifier identifier = new TICIdentifier.Builder().portName("COM7").build(); + Message message = new RequestReadTIC(identifier); + + // When + JSONObject json = MessageJsonCodec.getInstance().encodeToJsonObject(message); + + // Then + Assert.assertEquals(RequestReadTIC.NAME, json.getString("name")); + Assert.assertEquals(MessageType.REQUEST.toString(), json.getString("type")); + Assert.assertTrue(json.has("data")); + + JSONObject data = json.getJSONObject("data"); + Assert.assertEquals("COM7", data.getString("portName")); + Assert.assertTrue(data.isNull("portId")); + Assert.assertTrue(data.isNull("serialNumber")); + } + + @Test + public void encodeToJsonObject_withSubscribeTICNullList() { + // Given + Message message = new RequestSubscribeTIC(null); + + // When + JSONObject json = MessageJsonCodec.getInstance().encodeToJsonObject(message); + + // Then + Assert.assertEquals(RequestSubscribeTIC.NAME, json.getString("name")); + Assert.assertEquals(MessageType.REQUEST.toString(), json.getString("type")); + Assert.assertTrue(json.has("data")); + Assert.assertEquals(0, json.getJSONArray("data").length()); + } +} diff --git a/src/test/resources/tic/frame/codec/ticFrameHistoric.txt b/src/test/resources/tic/frame/codec/ticFrameHistoric.txt new file mode 100644 index 0000000..10262c4 --- /dev/null +++ b/src/test/resources/tic/frame/codec/ticFrameHistoric.txt @@ -0,0 +1,10 @@ + +ADCO 812164417227 D +OPTARIF BASE 0 +ISOUSC 15 < +BASE 000000104 P +PTEC TH.. $ +IINST 000 W +IMAX 000 ? +PAPP 00000 ! +MOTDETAT 000000 B  \ No newline at end of file diff --git a/src/test/resources/tic/frame/codec/ticFrameHistoric_full_details.json b/src/test/resources/tic/frame/codec/ticFrameHistoric_full_details.json new file mode 100644 index 0000000..a365d7b --- /dev/null +++ b/src/test/resources/tic/frame/codec/ticFrameHistoric_full_details.json @@ -0,0 +1,50 @@ +{ + "mode": "HISTORIC", + "groupList": [ + { + "label": "ADCO", + "value": "812164417227", + "isValid": true + }, + { + "label": "OPTARIF", + "value": "BASE", + "isValid": true + }, + { + "label": "ISOUSC", + "value": "15", + "isValid": true + }, + { + "label": "BASE", + "value": "000000104", + "isValid": true + }, + { + "label": "PTEC", + "value": "TH..", + "isValid": true + }, + { + "label": "IINST", + "value": "000", + "isValid": true + }, + { + "label": "IMAX", + "value": "000", + "isValid": true + }, + { + "label": "PAPP", + "value": "00000", + "isValid": true + }, + { + "label": "MOTDETAT", + "value": "000000", + "isValid": false + } + ] +} \ No newline at end of file diff --git a/src/test/resources/tic/frame/codec/ticFrameStandard.txt b/src/test/resources/tic/frame/codec/ticFrameStandard.txt new file mode 100644 index 0000000..f921d27 --- /dev/null +++ b/src/test/resources/tic/frame/codec/ticFrameStandard.txt @@ -0,0 +1,39 @@ + +ADSC 031664001115 ) +VTIC 02 J +DATE E170915101601 > +NGTF H PLEINE/CREUSE \ +LTARF INDEX INACTIF 2 3 +EAST 000000000 O +EASF01 000000000 " +EASF02 000000000 # +EASF03 000000000 $ +EASF04 000000000 % +EASF05 000000000 & +EASF06 000000000 ' +EASF07 000000000 ( +EASF08 000000000 ) +EASF09 000000000 * +EASF10 000000000 " +EASD01 000000000 +EASD02 000000000 ! +EASD03 000000000 " +EASD04 000000000 # +IRMS1 000 . +URMS1 230 ? +PREF 03 B +PCOUP 02 [ +SINSTS 00000 F +SMAXSN E170915100926 00000 3 +SMAXSN-1 E170913000000 00000 = +CCASN E170913113000 00000 2 +CCASN-1 E170913110000 00000 M +UMOY1 E170915101500 230 . +STGE 000A4411 @ +MSG1 PAS DE MESSAGE < +PRM 00000000000000 A +RELAIS 000 B +NTARF 02 O +NJOURF 00 & +NJOURF+1 00 B +PJOURF+1 00008002 0100C001 06008002 1230C001 15308002 NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE T  \ No newline at end of file diff --git a/src/test/resources/tic/frame/codec/ticFrameStandard_PCOUP_Invalid.txt b/src/test/resources/tic/frame/codec/ticFrameStandard_PCOUP_Invalid.txt new file mode 100644 index 0000000..11d2b6d --- /dev/null +++ b/src/test/resources/tic/frame/codec/ticFrameStandard_PCOUP_Invalid.txt @@ -0,0 +1,39 @@ + +ADSC 031664001115 ) +VTIC 02 J +DATE E170915101601 > +NGTF H PLEINE/CREUSE \ +LTARF INDEX INACTIF 2 3 +EAST 000000000 O +EASF01 000000000 " +EASF02 000000000 # +EASF03 000000000 $ +EASF04 000000000 % +EASF05 000000000 & +EASF06 000000000 ' +EASF07 000000000 ( +EASF08 000000000 ) +EASF09 000000000 * +EASF10 000000000 " +EASD01 000000000 +EASD02 000000000 ! +EASD03 000000000 " +EASD04 000000000 # +IRMS1 000 . +URMS1 230 ? +PREF 03 B +PCOUP 02 \ +SINSTS 00000 F +SMAXSN E170915100926 00000 3 +SMAXSN-1 E170913000000 00000 = +CCASN E170913113000 00000 2 +CCASN-1 E170913110000 00000 M +UMOY1 E170915101500 230 . +STGE 000A4411 @ +MSG1 PAS DE MESSAGE < +PRM 00000000000000 A +RELAIS 000 B +NTARF 02 O +NJOURF 00 & +NJOURF+1 00 B +PJOURF+1 00008002 0100C001 06008002 1230C001 15308002 NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE T  \ No newline at end of file diff --git a/src/test/resources/tic/frame/codec/ticFrameStandard_summarized.json b/src/test/resources/tic/frame/codec/ticFrameStandard_summarized.json new file mode 100644 index 0000000..af500c5 --- /dev/null +++ b/src/test/resources/tic/frame/codec/ticFrameStandard_summarized.json @@ -0,0 +1,40 @@ +{ + "ADSC": "031664001115", + "VTIC": "02", + "DATE": "E170915101601\t", + "NGTF": "H PLEINE/CREUSE ", + "LTARF": "INDEX INACTIF 2 ", + "EAST": "000000000", + "EASF01": "000000000", + "EASF02": "000000000", + "EASF03": "000000000", + "EASF04": "000000000", + "EASF05": "000000000", + "EASF06": "000000000", + "EASF07": "000000000", + "EASF08": "000000000", + "EASF09": "000000000", + "EASF10": "000000000", + "EASD01": "000000000", + "EASD02": "000000000", + "EASD03": "000000000", + "EASD04": "000000000", + "IRMS1": "000", + "URMS1": "230", + "PREF": "03", + "!PCOUP": "02", + "SINSTS": "00000", + "SMAXSN": "E170915100926\t00000", + "SMAXSN-1": "E170913000000\t00000", + "CCASN": "E170913113000\t00000", + "CCASN-1": "E170913110000\t00000", + "UMOY1": "E170915101500\t230", + "STGE": "000A4411", + "MSG1": "PAS DE MESSAGE ", + "PRM": "00000000000000", + "RELAIS": "000", + "NTARF": "02", + "NJOURF": "00", + "NJOURF+1": "00", + "PJOURF+1": "00008002 0100C001 06008002 1230C001 15308002 NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE" +} \ No newline at end of file diff --git a/src/test/resources/tic/io/modem/AllFields.json b/src/test/resources/tic/io/modem/AllFields.json new file mode 100644 index 0000000..6eeb440 --- /dev/null +++ b/src/test/resources/tic/io/modem/AllFields.json @@ -0,0 +1,11 @@ +{ + "modemType": "MICHAUD", + "serialNumber": "SN123", + "productId": 24577, + "description": "USB Serial Port", + "vendorId": 1027, + "portName": "COM7", + "portId": "ABCD1", + "productName": "test_product", + "manufacturer": "test_manufacturer" +} diff --git a/src/test/resources/tic/io/modem/Descriptor.json b/src/test/resources/tic/io/modem/Descriptor.json new file mode 100644 index 0000000..de06388 --- /dev/null +++ b/src/test/resources/tic/io/modem/Descriptor.json @@ -0,0 +1,11 @@ +{ + "modemType": "MICHAUD", + "serialNumber": "SN123", + "productId": 24577, + "description": "USB Serial Port", + "vendorId": 1027, + "portName": "COM7", + "portId": "ABCD1", + "productName": "test_product", + "manufacturer": "test_manufacturer" +} \ No newline at end of file diff --git a/src/test/resources/tic/io/modem/NullList.json b/src/test/resources/tic/io/modem/NullList.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/src/test/resources/tic/io/modem/NullList.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/src/test/resources/tic/io/modem/NullModemType.json b/src/test/resources/tic/io/modem/NullModemType.json new file mode 100644 index 0000000..122b94b --- /dev/null +++ b/src/test/resources/tic/io/modem/NullModemType.json @@ -0,0 +1,6 @@ +{ + "modemType": null, + "productId": 1234, + "vendorId": 5678, + "portName": "COM8" +} \ No newline at end of file diff --git a/src/test/resources/tic/io/serialport/AllFields.json b/src/test/resources/tic/io/serialport/AllFields.json new file mode 100644 index 0000000..a5ec424 --- /dev/null +++ b/src/test/resources/tic/io/serialport/AllFields.json @@ -0,0 +1,12 @@ +[ + { + "serialNumber": "SN123", + "productId": 1, + "description": "USB Serial Port", + "vendorId": 2, + "portName": "COM7", + "portId": "ABCD1", + "productName": "test_product", + "manufacturer": "test_manufacturer" + } +] \ No newline at end of file diff --git a/src/test/resources/tic/io/serialport/NullList.json b/src/test/resources/tic/io/serialport/NullList.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/src/test/resources/tic/io/serialport/NullList.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/src/test/resources/tic/io/serialport/NullifiedStrings.json b/src/test/resources/tic/io/serialport/NullifiedStrings.json new file mode 100644 index 0000000..0c565d4 --- /dev/null +++ b/src/test/resources/tic/io/serialport/NullifiedStrings.json @@ -0,0 +1,7 @@ +[ + { + "productId": 1, + "vendorId": 2, + "portId": "ABCD1" + } +] \ No newline at end of file diff --git a/src/test/resources/tic/io/usb/AllDescriptorFields.json b/src/test/resources/tic/io/usb/AllDescriptorFields.json new file mode 100644 index 0000000..c4c2c92 --- /dev/null +++ b/src/test/resources/tic/io/usb/AllDescriptorFields.json @@ -0,0 +1,21 @@ +[ + { + "bcdDevice": 1, + "bcdUSB": 2, + "bDescriptorType": 3, + "bDeviceClass": 4, + "bDeviceProtocol": 5, + "bDeviceSubClass": 6, + "bLength": 7, + "bMaxPacketSize0": 8, + "bNumConfigurations": 9, + "idProduct": 10, + "idVendor": 11, + "iManufacturer": 12, + "iProduct": 13, + "iSerialNumber": 14, + "manufacturer": "test_manufacturer", + "product": "test_product", + "serialNumber": "SN123" + } +] \ No newline at end of file diff --git a/src/test/resources/tic/io/usb/NullList.json b/src/test/resources/tic/io/usb/NullList.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/src/test/resources/tic/io/usb/NullList.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/src/test/resources/tic/io/usb/WithNullStringFields.json b/src/test/resources/tic/io/usb/WithNullStringFields.json new file mode 100644 index 0000000..5057cfb --- /dev/null +++ b/src/test/resources/tic/io/usb/WithNullStringFields.json @@ -0,0 +1,18 @@ +[ + { + "bcdDevice": 1, + "bcdUSB": 2, + "bDescriptorType": 3, + "bDeviceClass": 4, + "bDeviceProtocol": 5, + "bDeviceSubClass": 6, + "bLength": 7, + "bMaxPacketSize0": 8, + "bNumConfigurations": 9, + "idProduct": 10, + "idVendor": 11, + "iManufacturer": 12, + "iProduct": 13, + "iSerialNumber": 14 + } +] \ No newline at end of file diff --git a/src/test/resources/tic/service/config_empty_portnames.json b/src/test/resources/tic/service/config_empty_portnames.json new file mode 100644 index 0000000..55bfc78 --- /dev/null +++ b/src/test/resources/tic/service/config_empty_portnames.json @@ -0,0 +1,4 @@ +{ + "serverPort": 1234, + "ticPortNames": [] +} diff --git a/src/test/resources/tic/service/config_full.json b/src/test/resources/tic/service/config_full.json new file mode 100644 index 0000000..99ccb59 --- /dev/null +++ b/src/test/resources/tic/service/config_full.json @@ -0,0 +1,5 @@ +{ + "serverPort": 1234, + "ticMode": "HISTORIC", + "ticPortNames": ["COM3", "COM4"] +} diff --git a/src/test/resources/tic/service/config_invalid_missing_port.json b/src/test/resources/tic/service/config_invalid_missing_port.json new file mode 100644 index 0000000..594f1a3 --- /dev/null +++ b/src/test/resources/tic/service/config_invalid_missing_port.json @@ -0,0 +1,3 @@ +{ + "ticMode": "AUTO" +} diff --git a/src/test/resources/tic/service/config_invalid_mode.json b/src/test/resources/tic/service/config_invalid_mode.json new file mode 100644 index 0000000..b535d8e --- /dev/null +++ b/src/test/resources/tic/service/config_invalid_mode.json @@ -0,0 +1,4 @@ +{ + "serverPort": 1234, + "ticMode": "not-a-mode" +} diff --git a/src/test/resources/tic/service/config_invalid_port_range.json b/src/test/resources/tic/service/config_invalid_port_range.json new file mode 100644 index 0000000..a18f250 --- /dev/null +++ b/src/test/resources/tic/service/config_invalid_port_range.json @@ -0,0 +1,3 @@ +{ + "serverPort": 0 +} diff --git a/src/test/resources/tic/service/config_invalid_portnames_duplicates_trim.json b/src/test/resources/tic/service/config_invalid_portnames_duplicates_trim.json new file mode 100644 index 0000000..fc5fb43 --- /dev/null +++ b/src/test/resources/tic/service/config_invalid_portnames_duplicates_trim.json @@ -0,0 +1,4 @@ +{ + "serverPort": 1234, + "ticPortNames": [" COM3 ", "COM3"] +} diff --git a/src/test/resources/tic/service/config_invalid_portnames_empty.json b/src/test/resources/tic/service/config_invalid_portnames_empty.json new file mode 100644 index 0000000..1f5c5f0 --- /dev/null +++ b/src/test/resources/tic/service/config_invalid_portnames_empty.json @@ -0,0 +1,4 @@ +{ + "serverPort": 1234, + "ticPortNames": [""] +} diff --git a/src/test/resources/tic/service/config_invalid_portnames_null_element.json b/src/test/resources/tic/service/config_invalid_portnames_null_element.json new file mode 100644 index 0000000..ab880d4 --- /dev/null +++ b/src/test/resources/tic/service/config_invalid_portnames_null_element.json @@ -0,0 +1,4 @@ +{ + "serverPort": 1234, + "ticPortNames": [null] +} diff --git a/src/test/resources/tic/service/config_minimal.json b/src/test/resources/tic/service/config_minimal.json new file mode 100644 index 0000000..12ef0db --- /dev/null +++ b/src/test/resources/tic/service/config_minimal.json @@ -0,0 +1,3 @@ +{ + "serverPort": 1234 +} diff --git a/src/test/resources/tic/service/config_mode_lowercase.json b/src/test/resources/tic/service/config_mode_lowercase.json new file mode 100644 index 0000000..10d3481 --- /dev/null +++ b/src/test/resources/tic/service/config_mode_lowercase.json @@ -0,0 +1,4 @@ +{ + "serverPort": 1234, + "ticMode": "historic" +} diff --git a/src/test/resources/tic/stream/configuration/loader-valid.json b/src/test/resources/tic/stream/configuration/loader-valid.json new file mode 100644 index 0000000..a261841 --- /dev/null +++ b/src/test/resources/tic/stream/configuration/loader-valid.json @@ -0,0 +1,8 @@ +{ + "ticMode": "STANDARD", + "timeout": 42, + "identifier": { + "type": "PORT_NAME", + "value": "COM9" + } +} diff --git a/src/test/resources/tic/stream/configuration/withInvalidIdentifierType.json b/src/test/resources/tic/stream/configuration/withInvalidIdentifierType.json new file mode 100644 index 0000000..801e2d7 --- /dev/null +++ b/src/test/resources/tic/stream/configuration/withInvalidIdentifierType.json @@ -0,0 +1,6 @@ +{ + "identifier": { + "type": "USB", + "value": "device" + } +} \ No newline at end of file diff --git a/src/test/resources/tic/stream/configuration/withInvalidTicMode.json b/src/test/resources/tic/stream/configuration/withInvalidTicMode.json new file mode 100644 index 0000000..d6edcf1 --- /dev/null +++ b/src/test/resources/tic/stream/configuration/withInvalidTicMode.json @@ -0,0 +1,8 @@ +{ + "ticMode": "INVALID_MODE", + "timeout": 42, + "identifier": { + "type": "PORT_NAME", + "value": "COM9" + } +} \ No newline at end of file diff --git a/src/test/resources/tic/stream/configuration/withInvalidTimeout.json b/src/test/resources/tic/stream/configuration/withInvalidTimeout.json new file mode 100644 index 0000000..79284d5 --- /dev/null +++ b/src/test/resources/tic/stream/configuration/withInvalidTimeout.json @@ -0,0 +1,7 @@ +{ + "timeout": 0, + "identifier": { + "type": "PORT_NAME", + "value": "COM1" + } +} \ No newline at end of file diff --git a/src/test/resources/tic/stream/configuration/withMissingIdentifier.json b/src/test/resources/tic/stream/configuration/withMissingIdentifier.json new file mode 100644 index 0000000..f7a6f7f --- /dev/null +++ b/src/test/resources/tic/stream/configuration/withMissingIdentifier.json @@ -0,0 +1,4 @@ +{ + "ticMode": "STANDARD", + "timeout": 15 +} \ No newline at end of file diff --git a/src/test/resources/tic/stream/configuration/withPortIdIdentifier.json b/src/test/resources/tic/stream/configuration/withPortIdIdentifier.json new file mode 100644 index 0000000..3ab7808 --- /dev/null +++ b/src/test/resources/tic/stream/configuration/withPortIdIdentifier.json @@ -0,0 +1,6 @@ +{ + "identifier": { + "type": "PORT_ID", + "value": "12345" + } +} \ No newline at end of file diff --git a/src/test/resources/tic/stream/configuration/withValidPortNameConfig.json b/src/test/resources/tic/stream/configuration/withValidPortNameConfig.json new file mode 100644 index 0000000..bb0c957 --- /dev/null +++ b/src/test/resources/tic/stream/configuration/withValidPortNameConfig.json @@ -0,0 +1,8 @@ +{ + "ticMode":"HISTORIC", + "timeout":25, + "identifier": { + "type":"PORT_NAME", + "value":"COM7" + } +} \ No newline at end of file diff --git a/src/test/resources/tic/util/message/codec/Invalid_MissingName.json b/src/test/resources/tic/util/message/codec/Invalid_MissingName.json new file mode 100644 index 0000000..1c4fc0f --- /dev/null +++ b/src/test/resources/tic/util/message/codec/Invalid_MissingName.json @@ -0,0 +1,3 @@ +{ + "type": "REQUEST" +} diff --git a/src/test/resources/tic/util/message/codec/Invalid_MissingType.json b/src/test/resources/tic/util/message/codec/Invalid_MissingType.json new file mode 100644 index 0000000..603a2d9 --- /dev/null +++ b/src/test/resources/tic/util/message/codec/Invalid_MissingType.json @@ -0,0 +1,3 @@ +{ + "name": "GetAvailableTICs" +} diff --git a/src/test/resources/tic/util/message/codec/Invalid_ReadTIC_MissingData.json b/src/test/resources/tic/util/message/codec/Invalid_ReadTIC_MissingData.json new file mode 100644 index 0000000..e7e7aa8 --- /dev/null +++ b/src/test/resources/tic/util/message/codec/Invalid_ReadTIC_MissingData.json @@ -0,0 +1,4 @@ +{ + "type": "REQUEST", + "name": "ReadTIC" +} \ No newline at end of file diff --git a/src/test/resources/tic/util/message/codec/Invalid_TypeEvent.json b/src/test/resources/tic/util/message/codec/Invalid_TypeEvent.json new file mode 100644 index 0000000..0b975ad --- /dev/null +++ b/src/test/resources/tic/util/message/codec/Invalid_TypeEvent.json @@ -0,0 +1,4 @@ +{ + "type": "EVENT", + "name": "GetAvailableTICs" +} \ No newline at end of file diff --git a/src/test/resources/tic/util/message/codec/Invalid_UnsupportedName.json b/src/test/resources/tic/util/message/codec/Invalid_UnsupportedName.json new file mode 100644 index 0000000..7d9bec5 --- /dev/null +++ b/src/test/resources/tic/util/message/codec/Invalid_UnsupportedName.json @@ -0,0 +1,4 @@ +{ + "type": "REQUEST", + "name": "Nope" +} \ No newline at end of file diff --git a/src/test/resources/tic/util/message/codec/RequestGetAvailableTICs.json b/src/test/resources/tic/util/message/codec/RequestGetAvailableTICs.json new file mode 100644 index 0000000..0bfbadd --- /dev/null +++ b/src/test/resources/tic/util/message/codec/RequestGetAvailableTICs.json @@ -0,0 +1,4 @@ +{ + "type": "REQUEST", + "name": "GetAvailableTICs" +} \ No newline at end of file diff --git a/src/test/resources/tic/util/message/codec/RequestGetModemsInfo.json b/src/test/resources/tic/util/message/codec/RequestGetModemsInfo.json new file mode 100644 index 0000000..7b2a4f6 --- /dev/null +++ b/src/test/resources/tic/util/message/codec/RequestGetModemsInfo.json @@ -0,0 +1,4 @@ +{ + "type": "REQUEST", + "name": "GetModemsInfo" +} \ No newline at end of file diff --git a/src/test/resources/tic/util/message/codec/RequestReadTIC_WithAllFields.json b/src/test/resources/tic/util/message/codec/RequestReadTIC_WithAllFields.json new file mode 100644 index 0000000..6541c40 --- /dev/null +++ b/src/test/resources/tic/util/message/codec/RequestReadTIC_WithAllFields.json @@ -0,0 +1,9 @@ +{ + "type": "REQUEST", + "name": "ReadTIC", + "data": { + "serialNumber": "010203040506", + "portName": "/dev/ttyUSB0", + "portId": "1-1" + } +} \ No newline at end of file diff --git a/src/test/resources/tic/util/message/codec/RequestReadTIC_WithPortId.json b/src/test/resources/tic/util/message/codec/RequestReadTIC_WithPortId.json new file mode 100644 index 0000000..d8b8ffd --- /dev/null +++ b/src/test/resources/tic/util/message/codec/RequestReadTIC_WithPortId.json @@ -0,0 +1,7 @@ +{ + "type": "REQUEST", + "name": "ReadTIC", + "data": { + "portId": "1-1" + } +} \ No newline at end of file diff --git a/src/test/resources/tic/util/message/codec/RequestReadTIC_WithPortName.json b/src/test/resources/tic/util/message/codec/RequestReadTIC_WithPortName.json new file mode 100644 index 0000000..5ff5c68 --- /dev/null +++ b/src/test/resources/tic/util/message/codec/RequestReadTIC_WithPortName.json @@ -0,0 +1,7 @@ +{ + "type": "REQUEST", + "name": "ReadTIC", + "data": { + "portName": "/dev/ttyUSB0" + } +} \ No newline at end of file diff --git a/src/test/resources/tic/util/message/codec/RequestReadTIC_WithSerialNumber.json b/src/test/resources/tic/util/message/codec/RequestReadTIC_WithSerialNumber.json new file mode 100644 index 0000000..b68ffed --- /dev/null +++ b/src/test/resources/tic/util/message/codec/RequestReadTIC_WithSerialNumber.json @@ -0,0 +1,7 @@ +{ + "type": "REQUEST", + "name": "ReadTIC", + "data": { + "serialNumber": "010203040506" + } +} \ No newline at end of file diff --git a/src/test/resources/tic/util/message/codec/RequestSubscribeTIC_WithEmptyArray.json b/src/test/resources/tic/util/message/codec/RequestSubscribeTIC_WithEmptyArray.json new file mode 100644 index 0000000..233fdf6 --- /dev/null +++ b/src/test/resources/tic/util/message/codec/RequestSubscribeTIC_WithEmptyArray.json @@ -0,0 +1,5 @@ +{ + "type": "REQUEST", + "name": "SubscribeTIC", + "data": [] +} \ No newline at end of file diff --git a/src/test/resources/tic/util/message/codec/RequestSubscribeTIC_WithNoData.json b/src/test/resources/tic/util/message/codec/RequestSubscribeTIC_WithNoData.json new file mode 100644 index 0000000..9edfe7e --- /dev/null +++ b/src/test/resources/tic/util/message/codec/RequestSubscribeTIC_WithNoData.json @@ -0,0 +1,4 @@ +{ + "type": "REQUEST", + "name": "SubscribeTIC" +} \ No newline at end of file diff --git a/src/test/resources/tic/util/message/codec/RequestSubscribeTIC_WithOneIdentifier.json b/src/test/resources/tic/util/message/codec/RequestSubscribeTIC_WithOneIdentifier.json new file mode 100644 index 0000000..121cb8a --- /dev/null +++ b/src/test/resources/tic/util/message/codec/RequestSubscribeTIC_WithOneIdentifier.json @@ -0,0 +1,7 @@ +{ + "type": "REQUEST", + "name": "SubscribeTIC", + "data": { + "serialNumber": "010203040506" + } +} \ No newline at end of file diff --git a/src/test/resources/tic/util/message/codec/RequestSubscribeTIC_WithOneIdentifierList.json b/src/test/resources/tic/util/message/codec/RequestSubscribeTIC_WithOneIdentifierList.json new file mode 100644 index 0000000..91e1521 --- /dev/null +++ b/src/test/resources/tic/util/message/codec/RequestSubscribeTIC_WithOneIdentifierList.json @@ -0,0 +1,9 @@ +{ + "type": "REQUEST", + "name": "SubscribeTIC", + "data": [ + { + "portName": "COM7" + } + ] +} \ No newline at end of file diff --git a/src/test/resources/tic/util/message/codec/RequestUnsubscribeTIC_WithEmptyArray.json b/src/test/resources/tic/util/message/codec/RequestUnsubscribeTIC_WithEmptyArray.json new file mode 100644 index 0000000..0931178 --- /dev/null +++ b/src/test/resources/tic/util/message/codec/RequestUnsubscribeTIC_WithEmptyArray.json @@ -0,0 +1,5 @@ +{ + "type": "REQUEST", + "name": "UnsubscribeTIC", + "data": [] +} \ No newline at end of file diff --git a/src/test/resources/tic/util/message/codec/RequestUnsubscribeTIC_WithNoData.json b/src/test/resources/tic/util/message/codec/RequestUnsubscribeTIC_WithNoData.json new file mode 100644 index 0000000..0e46a9e --- /dev/null +++ b/src/test/resources/tic/util/message/codec/RequestUnsubscribeTIC_WithNoData.json @@ -0,0 +1,4 @@ +{ + "type": "REQUEST", + "name": "UnsubscribeTIC" +} \ No newline at end of file diff --git a/src/test/resources/tic/util/message/codec/RequestUnsubscribeTIC_WithOneIdentifier.json b/src/test/resources/tic/util/message/codec/RequestUnsubscribeTIC_WithOneIdentifier.json new file mode 100644 index 0000000..3fe8a10 --- /dev/null +++ b/src/test/resources/tic/util/message/codec/RequestUnsubscribeTIC_WithOneIdentifier.json @@ -0,0 +1,7 @@ +{ + "type": "REQUEST", + "name": "UnsubscribeTIC", + "data": { + "portName": "COM7" + } +} \ No newline at end of file diff --git a/src/test/resources/tic/util/message/codec/RequestUnsubscribeTIC_WithOneIdentifierList.json b/src/test/resources/tic/util/message/codec/RequestUnsubscribeTIC_WithOneIdentifierList.json new file mode 100644 index 0000000..b284382 --- /dev/null +++ b/src/test/resources/tic/util/message/codec/RequestUnsubscribeTIC_WithOneIdentifierList.json @@ -0,0 +1,9 @@ +{ + "type": "REQUEST", + "name": "UnsubscribeTIC", + "data": [ + { + "portName": "COM7" + } + ] +} \ No newline at end of file