From 87ac9edb1e9b356405d6028f1a1798382a143bfa Mon Sep 17 00:00:00 2001 From: Paul-Christian Volkmer Date: Mon, 5 Aug 2024 19:23:58 +0200 Subject: [PATCH] Initial commit --- .gitignore | 40 ++ LICENSE.txt | 661 ++++++++++++++++++ README.md | 6 + build.gradle.kts | 57 ++ dev-compose.yml | 19 + docs/screenshot.jpeg | Bin 0 -> 55268 bytes gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 43453 bytes gradle/wrapper/gradle-wrapper.properties | 7 + gradlew | 249 +++++++ gradlew.bat | 92 +++ settings.gradle.kts | 1 + .../OncoAnalyticsMonitorApplication.kt | 34 + .../conditions/ConditionInMemoryRepository.kt | 32 + .../monitor/conditions/Statistics.kt | 8 + .../oncoanalytics/monitor/helpers.kt | 75 ++ .../topiclisteners/ObdsXmlTopicMonitor.kt | 79 +++ .../monitor/topiclisteners/TopicMonitor.kt | 21 + .../monitor/web/EventStreamController.kt | 23 + .../monitor/web/HomeController.kt | 14 + .../monitor/web/StatisticsController.kt | 30 + src/main/resources/application-dev.yml | 8 + src/main/resources/application.yml | 18 + src/main/resources/static/images/db.png | Bin 0 -> 3042 bytes src/main/resources/static/images/job.png | Bin 0 -> 1988 bytes src/main/resources/static/images/kafka.png | Bin 0 -> 3335 bytes src/main/resources/static/images/topic.png | Bin 0 -> 985 bytes src/main/resources/templates/index.html | 185 +++++ .../OncoAnalyticsMonitorApplicationTests.kt | 13 + 28 files changed, 1672 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE.txt create mode 100644 README.md create mode 100644 build.gradle.kts create mode 100644 dev-compose.yml create mode 100644 docs/screenshot.jpeg create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100755 gradlew create mode 100644 gradlew.bat create mode 100644 settings.gradle.kts create mode 100644 src/main/kotlin/dev/pcvolkmer/oncoanalytics/monitor/OncoAnalyticsMonitorApplication.kt create mode 100644 src/main/kotlin/dev/pcvolkmer/oncoanalytics/monitor/conditions/ConditionInMemoryRepository.kt create mode 100644 src/main/kotlin/dev/pcvolkmer/oncoanalytics/monitor/conditions/Statistics.kt create mode 100644 src/main/kotlin/dev/pcvolkmer/oncoanalytics/monitor/helpers.kt create mode 100644 src/main/kotlin/dev/pcvolkmer/oncoanalytics/monitor/topiclisteners/ObdsXmlTopicMonitor.kt create mode 100644 src/main/kotlin/dev/pcvolkmer/oncoanalytics/monitor/topiclisteners/TopicMonitor.kt create mode 100644 src/main/kotlin/dev/pcvolkmer/oncoanalytics/monitor/web/EventStreamController.kt create mode 100644 src/main/kotlin/dev/pcvolkmer/oncoanalytics/monitor/web/HomeController.kt create mode 100644 src/main/kotlin/dev/pcvolkmer/oncoanalytics/monitor/web/StatisticsController.kt create mode 100644 src/main/resources/application-dev.yml create mode 100644 src/main/resources/application.yml create mode 100644 src/main/resources/static/images/db.png create mode 100644 src/main/resources/static/images/job.png create mode 100644 src/main/resources/static/images/kafka.png create mode 100644 src/main/resources/static/images/topic.png create mode 100644 src/main/resources/templates/index.html create mode 100644 src/test/kotlin/dev/pcvolkmer/oncoanalytics/monitor/OncoAnalyticsMonitorApplicationTests.kt diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5a979af --- /dev/null +++ b/.gitignore @@ -0,0 +1,40 @@ +HELP.md +.gradle +build/ +!gradle/wrapper/gradle-wrapper.jar +!**/src/main/**/build/ +!**/src/test/**/build/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache +bin/ +!**/src/main/**/bin/ +!**/src/test/**/bin/ + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr +out/ +!**/src/main/**/out/ +!**/src/test/**/out/ + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + +### VS Code ### +.vscode/ + +### Kotlin ### +.kotlin diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..0ad25db --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,661 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +. diff --git a/README.md b/README.md new file mode 100644 index 0000000..97781c6 --- /dev/null +++ b/README.md @@ -0,0 +1,6 @@ +# onco-analytics-monitor + +Diese Anwendung überwacht die konfigurierten Topics, ermittelt die Anzahl der Conditions nach ICD10-Gruppe sortiert +und zeigt diese in Echtzeit an. + +![Screenshot](docs/screenshot.jpeg) diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 0000000..5978aa4 --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,57 @@ +plugins { + id("org.springframework.boot") version "3.3.2" + id("io.spring.dependency-management") version "1.1.6" + id("org.graalvm.buildtools.native") version "0.10.2" + kotlin("jvm") version "1.9.24" + kotlin("plugin.spring") version "1.9.24" +} + +group = "dev.pcvolkmer.onco-analytics" +version = "0.0.1-SNAPSHOT" + +java { + toolchain { + languageVersion = JavaLanguageVersion.of(21) + } +} + +configurations { + compileOnly { + extendsFrom(configurations.annotationProcessor.get()) + } +} + +repositories { + mavenCentral() +} + +dependencies { + implementation("org.springframework.boot:spring-boot-starter-integration") + implementation("org.springframework.boot:spring-boot-starter-thymeleaf") + implementation("org.springframework.boot:spring-boot-starter-webflux") + implementation("com.fasterxml.jackson.module:jackson-module-kotlin") + implementation("io.projectreactor.kotlin:reactor-kotlin-extensions") + implementation("org.jetbrains.kotlin:kotlin-reflect") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-reactor") + implementation("org.springframework.kafka:spring-kafka") + implementation("commons-codec:commons-codec") + developmentOnly("org.springframework.boot:spring-boot-devtools") + developmentOnly("org.springframework.boot:spring-boot-docker-compose") + annotationProcessor("org.springframework.boot:spring-boot-configuration-processor") + testImplementation("org.springframework.boot:spring-boot-starter-test") + testImplementation("io.projectreactor:reactor-test") + testImplementation("org.jetbrains.kotlin:kotlin-test-junit5") + testImplementation("org.springframework.integration:spring-integration-test") + testImplementation("org.springframework.kafka:spring-kafka-test") + testRuntimeOnly("org.junit.platform:junit-platform-launcher") +} + +kotlin { + compilerOptions { + freeCompilerArgs.addAll("-Xjsr305=strict") + } +} + +tasks.withType { + useJUnitPlatform() +} diff --git a/dev-compose.yml b/dev-compose.yml new file mode 100644 index 0000000..7f8f37d --- /dev/null +++ b/dev-compose.yml @@ -0,0 +1,19 @@ +services: + + kafka: + image: bitnami/kafka + hostname: kafka + ports: + - "9092:9092" + - "9094:9094" + environment: + ALLOW_PLAINTEXT_LISTENER: "yes" + KAFKA_CFG_NODE_ID: "0" + KAFKA_CFG_PROCESS_ROLES: "controller,broker" + KAFKA_CFG_LISTENERS: PLAINTEXT://:9092,CONTROLLER://:9093,EXTERNAL://:9094 + KAFKA_CFG_ADVERTISED_LISTENERS: PLAINTEXT://kafka:9092,EXTERNAL://localhost:9094 + KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP: CONTROLLER:PLAINTEXT,EXTERNAL:PLAINTEXT,PLAINTEXT:PLAINTEXT + KAFKA_CFG_INTER_BROKER_LISTENER_NAME: PLAINTEXT + KAFKA_CFG_AUTO_CREATE_TOPICS_ENABLE: true + KAFKA_CFG_CONTROLLER_QUORUM_VOTERS: 0@kafka:9093 + KAFKA_CFG_CONTROLLER_LISTENER_NAMES: CONTROLLER diff --git a/docs/screenshot.jpeg b/docs/screenshot.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..4d20542cb52b7f22b707bdf5bf02846bd0413fa2 GIT binary patch literal 55268 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 P_Ty5is1sil{+$0m0@q4~ literal 0 HcmV?d00001 diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..e6441136f3d4ba8a0da8d277868979cfbc8ad796 GIT binary patch literal 43453 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 yu?e%!_ptzGB|8GrCfu%p?(_ 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
NnX)EH+Nua)3Y(c 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 '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..7101f8e --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,92 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/settings.gradle.kts b/settings.gradle.kts new file mode 100644 index 0000000..aa1e447 --- /dev/null +++ b/settings.gradle.kts @@ -0,0 +1 @@ +rootProject.name = "onco-analytics-monitor" diff --git a/src/main/kotlin/dev/pcvolkmer/oncoanalytics/monitor/OncoAnalyticsMonitorApplication.kt b/src/main/kotlin/dev/pcvolkmer/oncoanalytics/monitor/OncoAnalyticsMonitorApplication.kt new file mode 100644 index 0000000..aef3875 --- /dev/null +++ b/src/main/kotlin/dev/pcvolkmer/oncoanalytics/monitor/OncoAnalyticsMonitorApplication.kt @@ -0,0 +1,34 @@ +package dev.pcvolkmer.oncoanalytics.monitor + +import dev.pcvolkmer.oncoanalytics.monitor.conditions.ConditionInMemoryRepository +import dev.pcvolkmer.oncoanalytics.monitor.conditions.Statistics +import org.springframework.boot.autoconfigure.SpringBootApplication +import org.springframework.boot.runApplication +import org.springframework.context.annotation.Bean +import reactor.core.publisher.Sinks + +typealias StatisticsSink = Sinks.Many + +@SpringBootApplication +class OncoAnalyticsMonitorApplication { + + @Bean + fun statisticsEventProducer(): StatisticsSink { + return Sinks.many().multicast().onBackpressureBuffer() + } + + @Bean + fun obdsXmlConditionRepository(): ConditionInMemoryRepository { + return ConditionInMemoryRepository() + } + + @Bean + fun obdsFhirConditionRepository(): ConditionInMemoryRepository { + return ConditionInMemoryRepository() + } + +} + +fun main(args: Array) { + runApplication(*args) +} \ No newline at end of file diff --git a/src/main/kotlin/dev/pcvolkmer/oncoanalytics/monitor/conditions/ConditionInMemoryRepository.kt b/src/main/kotlin/dev/pcvolkmer/oncoanalytics/monitor/conditions/ConditionInMemoryRepository.kt new file mode 100644 index 0000000..c274fa5 --- /dev/null +++ b/src/main/kotlin/dev/pcvolkmer/oncoanalytics/monitor/conditions/ConditionInMemoryRepository.kt @@ -0,0 +1,32 @@ +package dev.pcvolkmer.oncoanalytics.monitor.conditions + +import org.apache.commons.codec.digest.DigestUtils + +@JvmInline +value class ConditionId(val value: String) + +data class Condition(val id: ConditionId, val version: Int, val icd10: String) { + companion object { + fun generateConditionId(patientId: String, tumorId: String): ConditionId { + return ConditionId(DigestUtils.sha256Hex("$patientId-$tumorId")) + } + } +} + +class ConditionInMemoryRepository { + + private val conditions = mutableMapOf() + + fun saveIfNewerVersion(condition: Condition): Boolean { + if ((this.conditions[condition.id]?.version ?: 0) < condition.version) { + this.conditions[condition.id] = condition + return true + } + return false + } + + fun findAll(): List { + return conditions.values.toList() + } + +} \ No newline at end of file diff --git a/src/main/kotlin/dev/pcvolkmer/oncoanalytics/monitor/conditions/Statistics.kt b/src/main/kotlin/dev/pcvolkmer/oncoanalytics/monitor/conditions/Statistics.kt new file mode 100644 index 0000000..745ce59 --- /dev/null +++ b/src/main/kotlin/dev/pcvolkmer/oncoanalytics/monitor/conditions/Statistics.kt @@ -0,0 +1,8 @@ +package dev.pcvolkmer.oncoanalytics.monitor.conditions + +data class Statistics( + val name: String, + val entries: List +) + +data class StatisticsEntry(val name: String, val count: Int) \ No newline at end of file diff --git a/src/main/kotlin/dev/pcvolkmer/oncoanalytics/monitor/helpers.kt b/src/main/kotlin/dev/pcvolkmer/oncoanalytics/monitor/helpers.kt new file mode 100644 index 0000000..853b30b --- /dev/null +++ b/src/main/kotlin/dev/pcvolkmer/oncoanalytics/monitor/helpers.kt @@ -0,0 +1,75 @@ +package dev.pcvolkmer.oncoanalytics.monitor + +import dev.pcvolkmer.oncoanalytics.monitor.conditions.ConditionInMemoryRepository +import dev.pcvolkmer.oncoanalytics.monitor.conditions.Statistics +import dev.pcvolkmer.oncoanalytics.monitor.conditions.StatisticsEntry + +val allKeys = listOf( + "C00-C14", + "C15", + "C16", + "C18-C21", + "C22", + "C23-C24", + "C25", + "C32", + "C33-C34", + "C50, D05", + "C53, D06", + "C54-C55", + "C56, D39.1", + "C61", + "C62", + "C64", + "C67, D09.0, D41.4", + "C70-C72", + "C73", + "C81", + "C82-C88, C96", + "C90", + "C91-C95", + "Other" +) + +fun fetchStatistics(name: String, source: ConditionInMemoryRepository): Statistics { + fun mapIcd10Code(code: String): String { + val c = when (code) { + "D39.1", "D09.0", "D41.4" -> code + else -> code.split('.').first() + } + + return when (c) { + "C00", "C01", "C02", "C03", "C04", "C05", "C06", "C07", "C08", "C09", "C10", "C11", "C12", "C13", "C14" -> "C00-C14" + "C15" -> "C15" + "C16" -> "C16" + "C18", "C19", "C20", "C21" -> "C18-C21" + "C22" -> "C22" + "C23", "C24" -> "C23-C24" + "C25" -> "C25" + "C32" -> "C32" + "C33", "C34" -> "C33-C34" + "C43" -> "C43" + "C50", "D05" -> "C50, D05" + "C53", "D06" -> "C53, D06" + "C54", "C55" -> "C54-C55" + "C56", "D39.1" -> "C56, D39.1" + "C61" -> "C61" + "C62" -> "C62" + "C64" -> "C64" + "C67", "D09.0", "D41.4" -> "C67, D09.0, D41.4" + "C70", "C71", "C72" -> "C70-C72" + "C73" -> "C73" + "C81" -> "C81" + "C82", "C83", "C84", "C85", "C86", "C87", "C88", "C96" -> "C82-C88, C96" + "C90" -> "C90" + "C91", "C92", "C93", "C94", "C95" -> "C91-C95" + else -> "Other" + } + } + + val entries = source.findAll() + .groupBy { mapIcd10Code(it.icd10) } + .mapValues { it.value.size } + + return Statistics(name, allKeys.map { StatisticsEntry(it, 0) }.map { StatisticsEntry(it.name, entries.getOrDefault(it.name, 0)) }) +} \ No newline at end of file diff --git a/src/main/kotlin/dev/pcvolkmer/oncoanalytics/monitor/topiclisteners/ObdsXmlTopicMonitor.kt b/src/main/kotlin/dev/pcvolkmer/oncoanalytics/monitor/topiclisteners/ObdsXmlTopicMonitor.kt new file mode 100644 index 0000000..c4e4a4e --- /dev/null +++ b/src/main/kotlin/dev/pcvolkmer/oncoanalytics/monitor/topiclisteners/ObdsXmlTopicMonitor.kt @@ -0,0 +1,79 @@ +package dev.pcvolkmer.oncoanalytics.monitor.topiclisteners + +import com.fasterxml.jackson.annotation.JsonAlias +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonIgnoreProperties +import com.fasterxml.jackson.databind.ObjectMapper +import dev.pcvolkmer.oncoanalytics.monitor.StatisticsSink +import dev.pcvolkmer.oncoanalytics.monitor.conditions.Condition +import dev.pcvolkmer.oncoanalytics.monitor.conditions.ConditionInMemoryRepository +import dev.pcvolkmer.oncoanalytics.monitor.fetchStatistics +import org.springframework.beans.factory.annotation.Qualifier +import org.springframework.kafka.annotation.KafkaListener +import org.springframework.kafka.support.KafkaHeaders +import org.springframework.messaging.handler.annotation.Header +import org.springframework.messaging.handler.annotation.Payload +import org.springframework.stereotype.Component +import org.xml.sax.InputSource +import java.io.StringReader +import javax.xml.xpath.XPathFactory + +@Component +class ObdsXmlTopicMonitor( + @Qualifier("obdsXmlConditionRepository") + private val conditionRepository: ConditionInMemoryRepository, + private val objectMapper: ObjectMapper, + statisticsEventProducer: StatisticsSink, +) : TopicMonitor(statisticsEventProducer) { + + @KafkaListener(topicPattern = "input.*") + override fun handleTopicRecord( + @Header(KafkaHeaders.RECEIVED_TOPIC) topic: String, + @Header(KafkaHeaders.RECEIVED_TIMESTAMP) timestamp: Long, + @Header(KafkaHeaders.RECEIVED_KEY) key: String, + @Payload payload: String, + ) { + try { + val p = objectMapper.readValue(payload, Record::class.java) + val xPath = XPathFactory.newDefaultInstance().newXPath() + + // Use local-name() due to XML namespace + val patientId = xPath.evaluate( + "//*[local-name()='Patienten_Stammdaten']/@Patient_ID", + InputSource(StringReader(p.payload.data)) + ) + val tumorId = xPath.evaluate( + "//*[local-name()='Tumorzuordnung']/@Tumor_ID", + InputSource(StringReader(p.payload.data)) + ) + val icd10 = xPath.evaluate( + "//*[local-name()='Primaertumor_ICD_Code']/text()", + InputSource(StringReader(p.payload.data)) + ) + + val updated = conditionRepository.saveIfNewerVersion( + Condition( + Condition.generateConditionId(patientId, tumorId), + p.payload.version, + icd10 + ) + ) + + if (updated) { + sendUpdatedStatistics(fetchStatistics("obdsxml", conditionRepository)) + } + } catch (e: Exception) { + // Ignore + } + } + + @JsonIgnoreProperties(ignoreUnknown = true) + class Record @JsonCreator constructor(val payload: RecordPayload) + + class RecordPayload @JsonCreator constructor( + @JsonAlias("ID") val id: Int, + @JsonAlias("YEAR") val year: String, + @JsonAlias("VERSIONSNUMMER") val version: Int, + @JsonAlias("XML_DATEN") val data: String + ) +} \ No newline at end of file diff --git a/src/main/kotlin/dev/pcvolkmer/oncoanalytics/monitor/topiclisteners/TopicMonitor.kt b/src/main/kotlin/dev/pcvolkmer/oncoanalytics/monitor/topiclisteners/TopicMonitor.kt new file mode 100644 index 0000000..4ca0d34 --- /dev/null +++ b/src/main/kotlin/dev/pcvolkmer/oncoanalytics/monitor/topiclisteners/TopicMonitor.kt @@ -0,0 +1,21 @@ +package dev.pcvolkmer.oncoanalytics.monitor.topiclisteners + +import dev.pcvolkmer.oncoanalytics.monitor.conditions.Statistics +import org.apache.kafka.common.TopicPartition +import org.springframework.kafka.listener.ConsumerSeekAware +import org.springframework.kafka.listener.ConsumerSeekAware.ConsumerSeekCallback +import reactor.core.publisher.Sinks + +abstract class TopicMonitor(private val statisticsEventProducer: Sinks.Many) : ConsumerSeekAware { + + abstract fun handleTopicRecord(topic: String, timestamp: Long, key: String, payload: String) + + fun sendUpdatedStatistics(statistics: Statistics) { + statisticsEventProducer.emitNext(statistics) { _, _ -> false } + } + + override fun onPartitionsAssigned(assignments: MutableMap, callback: ConsumerSeekCallback) { + callback.seekToBeginning(assignments.keys) + } + +} \ No newline at end of file diff --git a/src/main/kotlin/dev/pcvolkmer/oncoanalytics/monitor/web/EventStreamController.kt b/src/main/kotlin/dev/pcvolkmer/oncoanalytics/monitor/web/EventStreamController.kt new file mode 100644 index 0000000..8e6e0dd --- /dev/null +++ b/src/main/kotlin/dev/pcvolkmer/oncoanalytics/monitor/web/EventStreamController.kt @@ -0,0 +1,23 @@ +package dev.pcvolkmer.oncoanalytics.monitor.web + +import dev.pcvolkmer.oncoanalytics.monitor.StatisticsSink +import dev.pcvolkmer.oncoanalytics.monitor.conditions.Statistics +import org.springframework.http.MediaType +import org.springframework.http.codec.ServerSentEvent +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.RestController +import reactor.core.publisher.Flux + +@RestController +class EventStreamController( + private val statisticsEventProducer: StatisticsSink, +) { + + @GetMapping(path = ["/events"], produces = [MediaType.TEXT_EVENT_STREAM_VALUE]) + fun eventStream(): Flux> { + return statisticsEventProducer.asFlux().map { + ServerSentEvent.builder(it).event(it.name).build() + }.doOnComplete { println("X") } + } + +} \ No newline at end of file diff --git a/src/main/kotlin/dev/pcvolkmer/oncoanalytics/monitor/web/HomeController.kt b/src/main/kotlin/dev/pcvolkmer/oncoanalytics/monitor/web/HomeController.kt new file mode 100644 index 0000000..28072bc --- /dev/null +++ b/src/main/kotlin/dev/pcvolkmer/oncoanalytics/monitor/web/HomeController.kt @@ -0,0 +1,14 @@ +package dev.pcvolkmer.oncoanalytics.monitor.web + +import org.springframework.stereotype.Controller +import org.springframework.web.bind.annotation.GetMapping + +@Controller +class HomeController { + + @GetMapping + fun index(): String { + return "index" + } + +} \ No newline at end of file diff --git a/src/main/kotlin/dev/pcvolkmer/oncoanalytics/monitor/web/StatisticsController.kt b/src/main/kotlin/dev/pcvolkmer/oncoanalytics/monitor/web/StatisticsController.kt new file mode 100644 index 0000000..6d126ce --- /dev/null +++ b/src/main/kotlin/dev/pcvolkmer/oncoanalytics/monitor/web/StatisticsController.kt @@ -0,0 +1,30 @@ +package dev.pcvolkmer.oncoanalytics.monitor.web + +import dev.pcvolkmer.oncoanalytics.monitor.conditions.ConditionInMemoryRepository +import dev.pcvolkmer.oncoanalytics.monitor.conditions.Statistics +import dev.pcvolkmer.oncoanalytics.monitor.fetchStatistics +import org.springframework.beans.factory.annotation.Qualifier +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RestController + +@RestController +@RequestMapping(path = ["/statistics"]) +class StatisticsController( + @Qualifier("obdsXmlConditionRepository") + private val obdsXmlConditionRepository: ConditionInMemoryRepository, + @Qualifier("obdsFhirConditionRepository") + private val obdsFhirConditionRepository: ConditionInMemoryRepository, +) { + + @GetMapping(path = ["obdsxml"]) + fun obdsxmlStatistics(): Statistics { + return fetchStatistics("obdsxml", obdsXmlConditionRepository) + } + + @GetMapping(path = ["obdsfhir"]) + fun obdsfhirStatistics(): Statistics { + return fetchStatistics("obdfhir", obdsFhirConditionRepository) + } + +} \ No newline at end of file diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml new file mode 100644 index 0000000..80bc974 --- /dev/null +++ b/src/main/resources/application-dev.yml @@ -0,0 +1,8 @@ +spring: + application: + name: onco-analytics-monitor + + docker: + compose: + file: dev-compose.yml + diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml new file mode 100644 index 0000000..9a29b4c --- /dev/null +++ b/src/main/resources/application.yml @@ -0,0 +1,18 @@ +spring: + application: + name: onco-analytics-monitor + + kafka: + consumer: + group-id: ${spring.application.name} + + web: + resources: + cache: + cachecontrol: + max-age: 1d + chain: + strategy: + content: + enabled: true + paths: /**/*.js,/**/*.css,/**/*.svg,/**/*.jpeg \ No newline at end of file diff --git a/src/main/resources/static/images/db.png b/src/main/resources/static/images/db.png new file mode 100644 index 0000000000000000000000000000000000000000..663862dd3269768d3aa7e8fa452575d32787db50 GIT binary patch literal 3042 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/static/images/kafka.png b/src/main/resources/static/images/kafka.png new file mode 100644 index 0000000000000000000000000000000000000000..daf45d8bf8f0bfb24ce86ff371092f9775d73918 GIT binary patch literal 3335 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 b_m6Rt;tZ!VQ@omh*^ + + + + onco-analytics-monitor + + + + +
+ +
+

onco-analytics-monitor

+

+ Überwachung der einzelnen Kafka Topics und enthaltener Conditions - aufgeteilt nach ICD10-Gruppe. +

+
+ +
+
+ +
Onkostar Database
+
+
+
+ +
Kafka Connect
+
+
+
+ +
Kafka Topic oBDS XML
+
+
+
+
+
+
+ +
oBDS-to-fhir
+
+
+
+ +
Kafka Topic oBDS FHIR
+
+
+
+
+
+ +
+ + + + + \ No newline at end of file diff --git a/src/test/kotlin/dev/pcvolkmer/oncoanalytics/monitor/OncoAnalyticsMonitorApplicationTests.kt b/src/test/kotlin/dev/pcvolkmer/oncoanalytics/monitor/OncoAnalyticsMonitorApplicationTests.kt new file mode 100644 index 0000000..1c47f36 --- /dev/null +++ b/src/test/kotlin/dev/pcvolkmer/oncoanalytics/monitor/OncoAnalyticsMonitorApplicationTests.kt @@ -0,0 +1,13 @@ +package dev.pcvolkmer.oncoanalytics.monitor + +import org.junit.jupiter.api.Test +import org.springframework.boot.test.context.SpringBootTest + +@SpringBootTest +class OncoAnalyticsMonitorApplicationTests { + + @Test + fun contextLoads() { + } + +}