├── .gitignore ├── .project ├── Attribution.txt ├── Dockerfile ├── Dockerfile.build ├── Jenkinsfile ├── LICENSE ├── Makefile ├── README.md ├── ReleaseNotes.md ├── docker-files ├── application.properties ├── bootstrap.properties └── rule-template.drl ├── pom.xml ├── raml └── support-rulesengine.raml └── src ├── main ├── java │ └── org │ │ └── edgexfoundry │ │ ├── Application.java │ │ ├── HeartBeat.java │ │ ├── controller │ │ ├── PingController.java │ │ ├── RuleEngineController.java │ │ └── impl │ │ │ ├── LocalErrorController.java │ │ │ ├── PingControllerImpl.java │ │ │ └── RuleEngineControllerImpl.java │ │ ├── engine │ │ ├── CommandExecutor.java │ │ ├── RuleCreator.java │ │ └── RuleEngine.java │ │ ├── export │ │ └── registration │ │ │ ├── ExportClient.java │ │ │ └── ExportClientImpl.java │ │ ├── messaging │ │ └── ZeroMQEventSubscriber.java │ │ └── rule │ │ └── domain │ │ ├── Action.java │ │ ├── Condition.java │ │ ├── Rule.java │ │ └── ValueCheck.java └── resources │ ├── application.properties │ ├── banner.txt │ ├── bootstrap.properties │ └── rule-template.drl └── test ├── java └── org │ └── edgexfoundry │ ├── controller │ ├── PingControllerTest.java │ ├── RuleEngineControllerTest.java │ └── integration │ │ └── RuleEngineControllerTest.java │ ├── engine │ ├── CommandExecutorTest.java │ ├── RuleCreatorTest.java │ ├── RunEngineTest.java │ └── integration │ │ └── RuleEngineTest.java │ ├── export │ └── registration │ │ └── integration │ │ └── web │ │ ├── ExportClientImplTest.java │ │ ├── LocalErrorControllerTest.java │ │ ├── TestHttpServletRequest.java │ │ └── TestHttpServletResponse.java │ ├── messaging │ └── ZeroMQEventSubscriberTest.java │ └── rule │ └── domain │ └── data │ ├── ActionData.java │ ├── ConditionData.java │ ├── RuleData.java │ └── ValueCheckData.java └── resources ├── bad-rule-template.drl ├── raml └── support-rulesengine.raml ├── rule-template.drl └── rule.txt /.gitignore: -------------------------------------------------------------------------------- 1 | ### /.gitignore-boilerplates/Global/Eclipse.gitignore 2 | *.pydevproject 3 | .metadata 4 | bin/ 5 | tmp/** 6 | tmp/**/* 7 | *.tmp 8 | *.bak 9 | *.swp 10 | *~.nib 11 | local.properties 12 | .loadpath 13 | .classpath 14 | .factorypath 15 | .settings/ 16 | .springBeans 17 | 18 | # External tool builders 19 | .externalToolBuilders/ 20 | 21 | # Locally stored "Eclipse launch configurations" 22 | *.launch 23 | 24 | # CDT-specific 25 | .cproject 26 | 27 | # PDT-specific 28 | .buildpath 29 | 30 | ### .gitignore-boilerplates/Global/OSX.gitignore 31 | .DS_Store 32 | .AppleDouble 33 | .LSOverride 34 | Icon 35 | 36 | # Thumbnails 37 | ._* 38 | 39 | # Files that might appear on external disk 40 | .Spotlight-V100 41 | .Trashes 42 | 43 | ### .gitignore-boilerplates/Java.gitignore 44 | *.class 45 | 46 | # Package Files # 47 | *.jar 48 | *.war 49 | *.ear 50 | 51 | # Intellij 52 | .idea/ 53 | *.iml 54 | *.iws 55 | 56 | # Maven 57 | log/ 58 | target/ 59 | /.apt_generated/ 60 | .mvn/ 61 | .m2/ 62 | mvnw 63 | mvnw.cmd 64 | 65 | #EdgeX logging 66 | logs/ 67 | /bin/ 68 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | support-rulesengine 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | org.sonarlint.eclipse.core.sonarlintBuilder 15 | 16 | 17 | 18 | 19 | org.eclipse.m2e.core.maven2Builder 20 | 21 | 22 | 23 | 24 | 25 | org.eclipse.jdt.core.javanature 26 | org.eclipse.m2e.core.maven2Nature 27 | 28 | 29 | -------------------------------------------------------------------------------- /Attribution.txt: -------------------------------------------------------------------------------- 1 | The following open source projects are referenced by Support Rules Engine: 2 | 3 | Spring Cloud (Apache 2.0) - http://projects.spring.io/spring-cloud/ 4 | https://github.com/spring-cloud/spring-cloud-release/blob/master/LICENSE.txt 5 | 6 | Spring Boot (Apache 2.0) - https://projects.spring.io/spring-boot/ 7 | https://github.com/spring-projects/spring-boot/blob/master/LICENSE.txt 8 | 9 | Spring Framework (Apache 2.0) - http://projects.spring.io/spring-framework/ 10 | https://github.com/spring-projects/spring-framework 11 | 12 | Log4J (Apache 2.0) - https://logging.apache.org/log4j/2.x/ 13 | https://logging.apache.org/log4j/2.0/license.html 14 | 15 | Resteasy, JBoss (Apache 2.0) - http://resteasy.jboss.org/ 16 | https://github.com/resteasy/Resteasy/blob/master/License.html 17 | 18 | Freemarker (Apache 2.0) - http://freemarker.org/ 19 | http://freemarker.org/docs/app_license.html 20 | 21 | GSON (Apache 2.0) - https://github.com/google/gson 22 | https://github.com/google/gson/blob/master/LICENSE 23 | 24 | Jackson Core (Apache 2.0) - https://github.com/FasterXML/jackson-core/wiki 25 | https://github.com/FasterXML/jackson-core/wiki 26 | 27 | JeroMQ (Mozilla Public License 2.0) - https://github.com/zeromq/jeromq 28 | https://github.com/zeromq/jeromq/blob/master/LICENSE 29 | 30 | 31 | Junit (EPL 1.0) - http://junit.org/junit4/ 32 | http://junit.org/junit4/license.html 33 | 34 | 35 | Kie Drools (Apache 2.0) - http://www.kiegroup.org/ 36 | https://github.com/kiegroup/drools/blob/master/LICENSE-ASL-2.0.txt 37 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Copyright 2016-2017 Dell Inc. 3 | # Copyright 2018 Dell Technologies, Inc. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | ############################################################################### 18 | # Docker image for Rules Engine micro service 19 | # FROM java:8 20 | FROM alpine:3.6 21 | 22 | RUN apk --update add openjdk8-jre 23 | 24 | # environment variables 25 | ENV APP_DIR=/edgex/edgex-support-rulesengine 26 | ENV TEMPLATE_DIR=/edgex/edgex-support-rulesengine/templates 27 | ENV APP=support-rulesengine.jar 28 | ENV APP_PORT=48075 29 | 30 | #copy JAR and property files to the image 31 | COPY target/*.jar $APP_DIR/$APP 32 | COPY docker-files/*.properties $APP_DIR/ 33 | #copy drool template to templates location 34 | COPY docker-files/*.drl $TEMPLATE_DIR/ 35 | 36 | RUN mkdir /edgex/edgex-support-rulesengine/rules 37 | RUN echo "this directory is reserved for EdgeX Foundry Drools rule files" > /edgex/edgex-support-rulesengine/rules/README 38 | 39 | #expose support rulesengine port 40 | EXPOSE $APP_PORT 41 | 42 | #set the working directory 43 | WORKDIR $APP_DIR 44 | 45 | #kick off the micro service 46 | ENTRYPOINT java -jar -Djava.security.egd=file:/dev/urandom -Xmx100M $APP -------------------------------------------------------------------------------- /Dockerfile.build: -------------------------------------------------------------------------------- 1 | FROM maven:3.6.2 2 | 3 | RUN apt-get update && \ 4 | apt-get install -y make 5 | 6 | COPY --from=docker:latest /usr/local/bin/docker /usr/local/bin/docker -------------------------------------------------------------------------------- /Jenkinsfile: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2019 Intel Corporation 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | // 16 | 17 | loadGlobalLibrary() 18 | 19 | pipeline { 20 | agent { 21 | label 'centos7-docker-4c-2g' 22 | } 23 | 24 | options { 25 | timestamps() 26 | } 27 | 28 | stages { 29 | stage('LF Prep') { 30 | steps { 31 | edgeXSetupEnvironment() 32 | edgeXSemver 'init' 33 | script { 34 | def semverVersion = edgeXSemver() 35 | env.setProperty('VERSION', semverVersion) 36 | sh 'echo $VERSION > VERSION' 37 | stash name: 'semver', includes: '.semver/**,VERSION', useDefaultExcludes: false 38 | } 39 | } 40 | } 41 | 42 | stage('Multi-Arch Build') { 43 | // fan out 44 | parallel { 45 | stage('Build amd64') { 46 | agent { 47 | label 'centos7-docker-4c-2g' 48 | } 49 | stages { 50 | stage('Phase 1') { 51 | agent { 52 | dockerfile { 53 | filename 'Dockerfile.build' 54 | label 'centos7-docker-4c-2g' 55 | args '-v /var/run/docker.sock:/var/run/docker.sock -v $PWD:/root -w /root -u 0:0 --privileged' 56 | reuseNode true 57 | } 58 | } 59 | stages { 60 | stage('Test') { 61 | steps { 62 | sh 'make test' 63 | } 64 | } 65 | stage('Maven Package') { 66 | when { expression { edgex.isReleaseStream() } } 67 | 68 | steps { 69 | sh 'make build' 70 | } 71 | } 72 | stage('Docker Build') { 73 | when { expression { edgex.isReleaseStream() } } 74 | 75 | steps { 76 | unstash 'semver' 77 | 78 | sh 'echo Currently Building version: `cat ./VERSION`' 79 | 80 | script { 81 | // This is the main docker image that will be pushed 82 | // BASE image = image from above 83 | image_amd64 = docker.build( 84 | 'docker-support-rulesengine', 85 | "--label 'git_sha=${env.GIT_COMMIT}' ." 86 | ) 87 | } 88 | } 89 | } 90 | } 91 | } 92 | 93 | // this should be back on the original node that has the tools required to run the login script 94 | stage('Phase 2') { 95 | stages { 96 | stage('Docker Push') { 97 | when { expression { edgex.isReleaseStream() } } 98 | 99 | steps { 100 | script { 101 | edgeXDockerLogin(settingsFile: 'support-rulesengine-settings') 102 | 103 | docker.withRegistry("https://${env.DOCKER_REGISTRY}:10004") { 104 | image_amd64.push("${env.SEMVER_BRANCH}") 105 | image_amd64.push("${env.VERSION}") 106 | image_amd64.push("${env.GIT_COMMIT}-${env.VERSION}") 107 | } 108 | } 109 | } 110 | } 111 | } 112 | } 113 | } 114 | } 115 | stage('Build arm64') { 116 | agent { 117 | label 'ubuntu18.04-docker-arm64-4c-16g' 118 | } 119 | stages { 120 | stage('Phase 1') { 121 | agent { 122 | dockerfile { 123 | filename 'Dockerfile.build' 124 | label 'ubuntu18.04-docker-arm64-4c-16g' 125 | args '-v /var/run/docker.sock:/var/run/docker.sock -v $PWD:/root -w /root -u 0:0 --privileged' 126 | reuseNode true 127 | } 128 | } 129 | stages { 130 | stage('Test') { 131 | steps { 132 | sh 'make test' 133 | } 134 | } 135 | stage('Maven Package') { 136 | when { expression { edgex.isReleaseStream() } } 137 | 138 | steps { 139 | sh 'make build' 140 | } 141 | } 142 | stage('Docker Build') { 143 | when { expression { edgex.isReleaseStream() } } 144 | 145 | steps { 146 | unstash 'semver' 147 | 148 | sh 'echo Currently Building version: `cat ./VERSION`' 149 | 150 | script { 151 | // This is the main docker image that will be pushed 152 | // BASE image = image from above 153 | image_arm64 = docker.build( 154 | 'docker-support-rulesengine-arm64', 155 | "--label 'git_sha=${env.GIT_COMMIT}' ." 156 | ) 157 | } 158 | } 159 | } 160 | } 161 | } 162 | 163 | stage('Phase 2') { 164 | stages { 165 | stage('Docker Push') { 166 | when { expression { edgex.isReleaseStream() } } 167 | 168 | steps { 169 | script { 170 | edgeXDockerLogin(settingsFile: 'support-rulesengine-settings') 171 | 172 | docker.withRegistry("https://${env.DOCKER_REGISTRY}:10004") { 173 | image_arm64.push("${env.SEMVER_BRANCH}") 174 | image_arm64.push("${env.VERSION}") 175 | image_arm64.push("${env.GIT_COMMIT}-${env.VERSION}") 176 | } 177 | } 178 | } 179 | } 180 | } 181 | } 182 | } 183 | } 184 | } 185 | } 186 | 187 | stage('SemVer Tag') { 188 | when { expression { edgex.isReleaseStream() } } 189 | steps { 190 | unstash 'semver' 191 | sh 'echo v${VERSION}' 192 | edgeXSemver('tag') 193 | edgeXInfraLFToolsSign(command: 'git-tag', version: 'v${VERSION}') 194 | } 195 | } 196 | 197 | stage('Semver Bump Pre-Release Version') { 198 | when { expression { edgex.isReleaseStream() } } 199 | steps { 200 | edgeXSemver('bump pre') 201 | edgeXSemver('push') 202 | } 203 | } 204 | } 205 | 206 | post { 207 | failure { 208 | script { 209 | currentBuild.result = "FAILED" 210 | } 211 | } 212 | always { 213 | edgeXInfraPublish() 214 | } 215 | } 216 | } 217 | 218 | def loadGlobalLibrary(branch = '*/master') { 219 | library(identifier: 'edgex-global-pipelines@master', 220 | retriever: legacySCM([ 221 | $class: 'GitSCM', 222 | userRemoteConfigs: [[url: 'https://github.com/edgexfoundry/edgex-global-pipelines.git']], 223 | branches: [[name: branch]], 224 | doGenerateSubmoduleConfigurations: false, 225 | extensions: [[ 226 | $class: 'SubmoduleOption', 227 | recursiveSubmodules: true, 228 | ]]] 229 | ) 230 | ) _ 231 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright 2017 Dell, Inc. 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: clean build 2 | 3 | # VERSION file is not needed for local development, In the CI/CD pipeline, a temporary VERSION file is written 4 | # if you need a specific version, just override below 5 | VERSION=$(shell cat ./VERSION 2>/dev/null || echo 0.0.0) 6 | 7 | # This pulls the version of the SDK from the go.mod file. If the SDK is the only required module, 8 | # it must first remove the word 'required' so the offset of $2 is the same if there are multiple required modules 9 | 10 | MICROSERVICE=support-rulesengine 11 | MAVEN_OPTIONS="-Dmaven.wagon.http.ssl.insecure=true -Dmaven.wagon.http.ssl.allowall=true -Dmaven.wagon.http.ssl.ignore.validity.dates=true" 12 | GIT_SHA=$(shell git rev-parse HEAD) 13 | 14 | build: 15 | mvn package $(MAVEN_OPTIONS) 16 | 17 | # NOTE: This is only used for local development. Jenkins CI does not use this make target 18 | docker: 19 | docker build \ 20 | --build-arg http_proxy \ 21 | --build-arg https_proxy \ 22 | -f Dockerfile \ 23 | --label "git_sha=$(GIT_SHA)" \ 24 | -t edgexfoundry/docker-support-rulesengine:$(GIT_SHA) \ 25 | -t edgexfoundry/docker-support-rulesengine:$(VERSION) \ 26 | -t edgexfoundry/docker-support-rulesengine:latest \ 27 | . 28 | 29 | test: 30 | mvn test $(MAVEN_OPTIONS) 31 | 32 | clean: 33 | mvn clean $(MAVEN_OPTIONS) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Main Author: Jim White 2 | 3 | Copyright 2016-19, Dell, Inc. 4 | 5 | Rules Engine Micro Service receives data from the export service (via 0MQ) and then triggers actuation based on event data it receives and analyzes. Built on Drools technology. 6 | 7 | -------------------------------------------------------------------------------- /ReleaseNotes.md: -------------------------------------------------------------------------------- 1 | # v1.0 (5/28/2019) 2 | #Release Notes 3 | Updated to ignore CBOR data messages. 4 | 5 | # v0.2 (10/20/2017) 6 | # Release Notes 7 | 8 | ## Notable Changes 9 | The Barcelona Release (v 0.2) of the Support Rules Engine micro service includes the following: 10 | * Application of Google Style Guidelines to the code base 11 | * Increase in unit/intergration tests from 27 tests to 115 tests 12 | * POM changes for appropriate repository information for distribution/repos management, checkstyle plugins, etc. 13 | * Removed all references to unfinished DeviceManager work as part of Dell Fuse 14 | * Added Dockerfile for creation of micro service targeted for ARM64 15 | * Added interfaces for all Controller classes 16 | 17 | ## Bug Fixes 18 | * Removed OS specific file path for logging file 19 | * Provide option to include stack trace in log outputs 20 | 21 | ## Pull Request/Commit Details 22 | - [#11](https://github.com/edgexfoundry/support-rulesengine/pull/11) - Remove staging plugin contributed by Jeremy Phelps ([JPWKU](https://github.com/JPWKU)) 23 | - [#10](https://github.com/edgexfoundry/support-rulesengine/pull/10) - Fixes Maven artifact dependency path contributed by Tyler Cox ([trcox](https://github.com/trcox)) 24 | - [#9](https://github.com/edgexfoundry/support-rulesengine/pull/9) - harden work in progress. Added google style checks, added repos to p… contributed by Jim White ([jpwhitemn](https://github.com/jpwhitemn)) 25 | - [#8](https://github.com/edgexfoundry/support-rulesengine/pull/8) - Removed device manager url refs in properties files contributed by Jim White ([jpwhitemn](https://github.com/jpwhitemn)) 26 | - [#7](https://github.com/edgexfoundry/support-rulesengine/pull/7) - Added support for aarch64 arch contributed by ([feclare](https://github.com/feclare)) 27 | - [#6](https://github.com/edgexfoundry/support-rulesengine/pull/6) - Adds Docker build capability contributed by Tyler Cox ([trcox](https://github.com/trcox)) 28 | - [#5](https://github.com/edgexfoundry/support-rulesengine/issues/5) - is rulesengine working currently? 29 | - [#4](https://github.com/edgexfoundry/support-rulesengine/pull/4) - Fixes Log File Path contributed by Tyler Cox ([trcox](https://github.com/trcox)) 30 | - [#3](https://github.com/edgexfoundry/support-rulesengine/issues/3) - Log File Path not Platform agnostic 31 | - [#2](https://github.com/edgexfoundry/support-rulesengine/pull/2) - Add distributionManagement for artifact storage contributed by Andrew Grimberg ([tykeal](https://github.com/tykeal)) 32 | - [#1](https://github.com/edgexfoundry/support-rulesengine/pull/1) - Contributed Project Fuse source code contributed by Tyler Cox ([trcox](https://github.com/trcox)) 33 | 34 | -------------------------------------------------------------------------------- /docker-files/application.properties: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Copyright 2016-17 Dell Inc. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | # @microservice: support-rulesengine 17 | # @author: Jim White, Dell 18 | # @version: 1.0.0 19 | ############################################################################### 20 | #--Docker container specific app properties ----- 21 | #-----------------General Config----------------------------------------------- 22 | #every 5 minutes (in milliseconds) 23 | heart.beat.time=300000 24 | #messages 25 | heart.beat.msg=Support Rules Engine data heart beat 26 | app.open.msg=This is the Support Rules Engine Microservice. 27 | # set port (override Spring boot default port 8080 ) 28 | server.port=48075 29 | #-----------------App Service Configurable Rules Config---------------------------------------- 30 | #Turn on/off registration of rules engine as app-service-configurable client. 31 | #Set to false to receive messages directly from core data 32 | export.client=false 33 | expect.serializedjava=false 34 | #export.client.registration.url=http://localhost:48071/api/v1 35 | export.client.registration.url=http://edgex-export-client:48071/api/v1 36 | export.client.registration.name=EdgeXRulesEngine 37 | #use port 5566 when connected to app-service-configurable 38 | #use port 5563 when connected to core data directly 39 | export.zeromq.port=5566 40 | #export.zeromq.port=5563 41 | #export.zeromq.host=tcp://localhost 42 | export.zeromq.host=tcp://edgex-app-service-configurable-rules 43 | #how long to wait to retry registration 44 | export.client.registration.retry.time=10000 45 | #how many times to try registration before exiting 46 | export.client.registration.retry.attempts=100 47 | #-----------------Logging Config----------------------------------------------- 48 | #logging levels (used to control log4j entries) 49 | logging.level.org.springframework=ERROR 50 | logging.level.org.apache=ERROR 51 | logging.level.org.edgexfoundry=INFO 52 | #log files are rotated after 10MB by default in Spring boot 53 | logging.file=/edgex/logs/edgex-support-rulesengine.log 54 | #print stack traces with errors on REST calls 55 | print.stacktrace=false 56 | #-----------------Drools Config----------------------------------------------- 57 | #Drools drl resource path 58 | #rules.default.path=/edgex/rules 59 | rules.default.path=/edgex/edgex-support-rulesengine/rules 60 | rules.packagename=org.edgexfoundry.rules 61 | rules.fileextension=.drl 62 | #rules.template.path=./src/main/resources 63 | #rules.template.path=/edgex/templates 64 | rules.template.path=/edgex/edgex-support-rulesengine/templates 65 | rules.template.name=rule-template.drl 66 | rules.template.encoding=UTF-8 67 | #IOT core data database service connection information 68 | #core.db.command.url=http://localhost:48082/api/v1/device 69 | core.db.command.url=http://edgex-core-command:48082/api/v1/device 70 | #IOT metadata database service connection information 71 | #meta.db.addressable.url=http://localhost:48081/api/v1/addressable 72 | #meta.db.deviceservice.url=http://localhost:48081/api/v1/deviceservice 73 | #meta.db.deviceprofile.url=http://localhost:48081/api/v1/deviceprofile 74 | #meta.db.device.url=http://localhost:48081/api/v1/device 75 | #meta.db.devicereport.url=http://localhost:48081/api/v1/devicereport 76 | #meta.db.command.url=http://localhost:48081/api/v1/command 77 | #meta.db.event.url=http://localhost:48081/api/v1/event 78 | #meta.db.schedule.url=http://localhost:48081/api/v1/schedule 79 | #meta.db.provisionwatcher.url=http://localhost:48081/api/v1/provisionwatcher 80 | meta.db.addressable.url=http://edgex-core-metadata:48081/api/v1/addressable 81 | meta.db.deviceservice.url=http://edgex-core-metadata:48081/api/v1/deviceservice 82 | meta.db.deviceprofile.url=http://edgex-core-metadata:48081/api/v1/deviceprofile 83 | meta.db.device.url=http://edgex-core-metadata:48081/api/v1/device 84 | meta.db.devicereport.url=http://edgex-core-metadata:48081/api/v1/devicereport 85 | meta.db.command.url=http://edgex-core-metadata:48081/api/v1/command 86 | meta.db.event.url=http://edgex-core-metadata:48081/api/v1/event 87 | meta.db.schedule.url=http://edgex-core-metadata:48081/api/v1/schedule 88 | meta.db.provisionwatcher.url=http://edgex-core-metadata:48081/api/v1/provisionwatcher 89 | #-----------------Remote Logging Config------------------------------------------ 90 | logging.remote.enable=false 91 | #logging.remote.url=http://localhost:48061/api/v1/logs 92 | logging.remote.url=http://edgex-support-logging:48061/api/v1/logs 93 | -------------------------------------------------------------------------------- /docker-files/bootstrap.properties: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Copyright 2016-2017 Dell Inc. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | ############################################################################### 17 | spring.application.name=edgex-support-rulesengine 18 | spring.cloud.consul.host=edgex-core-consul 19 | spring.cloud.consul.port=8500 20 | spring.cloud.consul.config.profileSeparator=; 21 | spring.cloud.consul.enabled=false 22 | spring.profiles.active=docker -------------------------------------------------------------------------------- /docker-files/rule-template.drl: -------------------------------------------------------------------------------- 1 | package org.edgexfoundry.rules; 2 | global org.edgexfoundry.engine.CommandExecutor executor; 3 | global org.edgexfoundry.support.logging.client.EdgeXLogger logger; 4 | import org.edgexfoundry.domain.core.Event; 5 | import org.edgexfoundry.domain.core.Reading; 6 | import java.util.Map; 7 | rule "${rulename}" 8 | when 9 | $e:Event($rlist: readings && device=="${conddeviceid}") 10 | <#if valuechecks??> 11 | <#assign idx = 0> 12 | <#list valuechecks as valuecheck> 13 | $r${idx}:Reading(name=="${valuecheck.parameter}" && ${valuecheck.operand1} ${valuecheck.operation} ${valuecheck.operand2}) from $rlist 14 | <#assign idx = idx + 1> 15 | 16 | 17 | then 18 | executor.fireCommand("${actiondeviceid}", "${actioncommandid}", "${commandbody}"); 19 | logger.info("${log}"); 20 | end -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 9 | 12 | 4.0.0 13 | org.edgexfoundry 14 | support-rulesengine 15 | 1.1.0 16 | EdgeX Foundry Rules Engine Micro Service 17 | EdgeX Foundry Rules Engine Micro Service 18 | 19 | 20 | Brixton.SR5 21 | 6.4.0.Final 22 | 3.0.13.Final 23 | 0.5.1 24 | 0.5.0 25 | 0.2.0 26 | 0.5.0 27 | 0.5.0 28 | 0.5.0 29 | 0.5.0 30 | 2.5.5 31 | UTF-8 32 | UTF-8 33 | 1.8 34 | https://nexus.edgexfoundry.org 35 | content/repositories 36 | 2.17 37 | 38 | 39 | 40 | org.springframework.boot 41 | spring-boot-starter-parent 42 | 1.3.7.RELEASE 43 | 44 | 45 | 46 | 47 | snapshots 48 | EdgeX Snapshot Repository 49 | ${nexusproxy}/${repobasepath}/snapshots 50 | 51 | 52 | 53 | 54 | 55 | org.springframework.boot 56 | spring-boot-starter-web 57 | 58 | 59 | org.springframework.boot 60 | spring-boot-starter 61 | 62 | 63 | org.springframework.boot 64 | spring-boot-starter-logging 65 | 66 | 67 | 68 | 69 | org.springframework.boot 70 | spring-boot-starter-log4j 71 | 72 | 73 | log4j 74 | log4j 75 | 76 | 77 | org.jboss.resteasy 78 | resteasy-client 79 | ${resteasy.version} 80 | 81 | 82 | org.slf4j 83 | slf4j-simple 84 | 85 | 86 | 87 | 88 | org.jboss.resteasy 89 | resteasy-jackson-provider 90 | ${resteasy.version} 91 | 92 | 93 | org.freemarker 94 | freemarker 95 | 96 | 97 | com.fasterxml.jackson.core 98 | jackson-annotations 99 | 100 | 101 | org.zeromq 102 | jeromq 103 | ${zeromq.version} 104 | 105 | 106 | org.springframework.cloud 107 | spring-cloud-starter-consul-all 108 | 109 | 110 | javax.ws.rs 111 | jsr311-api 112 | 113 | 114 | com.google.code.findbugs 115 | jsr305 116 | 117 | 118 | 119 | 120 | org.edgexfoundry 121 | core-domain 122 | ${core-domain.version} 123 | 124 | 125 | org.edgexfoundry 126 | export-domain 127 | ${export-domain.version} 128 | 129 | 130 | org.edgexfoundry 131 | core-command-client 132 | ${core-command-client.version} 133 | 134 | 135 | org.edgexfoundry 136 | core-exception 137 | ${core-exception.version} 138 | 139 | 140 | org.kie 141 | kie-ci 142 | ${drools.version} 143 | 144 | 145 | org.edgexfoundry 146 | core-test 147 | ${core-test.version} 148 | test 149 | 150 | 151 | org.edgexfoundry 152 | support-logging-client 153 | ${support-logging-client.version} 154 | 155 | 156 | junit 157 | junit 158 | test 159 | 160 | 161 | org.springframework.boot 162 | spring-boot-starter-test 163 | test 164 | 165 | 166 | org.springframework 167 | spring-test 168 | test 169 | 170 | 171 | 172 | 173 | 174 | 175 | org.springframework.cloud 176 | spring-cloud-dependencies 177 | ${spring.cloud.version} 178 | pom 179 | import 180 | 181 | 182 | 183 | 184 | 185 | 186 | RequiresNone 187 | 188 | org.edgexfoundry.test.category.RequiresNone 189 | 190 | 191 | true 192 | 193 | 194 | 195 | Requires 196 | 197 | org.edgexfoundry.test.category.RequiresSpring 198 | org.edgexfoundry.test.category.RequiresWeb 199 | org.edgexfoundry.test.category.RequiresMongo 200 | 201 | 202 | 203 | 204 | ${project.artifactId} 205 | 206 | 207 | org.springframework.boot 208 | spring-boot-maven-plugin 209 | 210 | 211 | org.apache.maven.plugins 212 | maven-compiler-plugin 213 | 214 | ${java.version} 215 | ${java.version} 216 | 217 | 218 | 219 | maven-surefire-plugin 220 | 221 | ${testcase.groups} 222 | 223 | 224 | 225 | org.apache.maven.plugins 226 | maven-dependency-plugin 227 | 3.0.1 228 | 229 | 230 | 231 | org.edgexfoundry 232 | support-rulesengine 233 | ${version} 234 | . 235 | support-rulesengine.jar 236 | 237 | 238 | 239 | 240 | 241 | org.apache.maven.plugins 242 | maven-checkstyle-plugin 243 | ${checkstyle.plugin.version} 244 | 245 | 246 | validate 247 | validate 248 | 249 | google_checks.xml 250 | true 251 | error 252 | false 253 | false 254 | true 255 | ${project.build.directory}/edgex-checkstyles-result.xml 256 | 257 | 258 | check 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 268 | 269 | org.eclipse.m2e 270 | lifecycle-mapping 271 | 1.0.0 272 | 273 | 274 | 275 | 276 | 277 | org.apache.maven.plugins 278 | maven-checkstyle-plugin 279 | [2.17,) 280 | 281 | check 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | releases 298 | EdgeX Release Repository 299 | ${nexusproxy}/${repobasepath}/releases 300 | 301 | 302 | staging 303 | EdgeX Staging Repository 304 | ${nexusproxy}/${repobasepath}/staging 305 | 306 | 307 | snapshots 308 | EdgeX Snapshot Repository 309 | ${nexusproxy}/${repobasepath}/snapshots 310 | 311 | 312 | 313 | -------------------------------------------------------------------------------- /raml/support-rulesengine.raml: -------------------------------------------------------------------------------- 1 | #%RAML 0.8 2 | title: support-rulesengine 3 | version: "1.0.0" 4 | baseUri: "http://localhost:48075/api/v1" 5 | schemas: 6 | - 7 | rule: '{"type":"object","$schema":"http://json-schema.org/draft-03/schema#","description":"EdgeX Support Rules Engine rule","title":"rule","properties":{"name":{"type":"string","required":true,"title":"name"}, "action":{"type":"object","properties":{"device":{"type":"string","required":true,"title":"device"},"command":{"type":"string","required":true,"title":"command"},"body":{"type":"string","required":true,"title":"body"}}}, "condition":{"type":"object","properties":{"device":{"type":"string","required":true,"title":"device"},"checks":{"type":"array","required":false,"title":"checks","items":{"type":"object","properties":{"parameter":{"type":"string","required":false,"title":"parameter"},"operand1":{"type":"string","required":false,"title":"operand1"},"operation":{"type":"string","required":false,"title":"operation"},"operand2":{"type":"string","required":false,"title":"operand2"}}},"uniqueItems":false}}}, "log":{"type":"string","required":false,"title":"log"}}}' 8 | /rule: 9 | displayName: rules 10 | description: example - http://localhost:48075/api/v1/rule 11 | post: 12 | description: Add a new rule. ServcieException (HTTP 503) for unknown or unanticipated issues. 13 | displayName: add a rule 14 | body: 15 | application/json: 16 | schema: rule 17 | example: '{"name":"motortoofastsignal", "condition": {"device":"562114e9e4b0385849b96cd8","checks":[ {"parameter":"RPM", "operand1":"Integer.parseInt(value)", "operation":">","operand2":"1200" } ] }, "action" : {"device":"56325f7ee4b05eaae5a89ce1","command":"56325f6de4b05eaae5a89cdc","body":"{\\\"value\\\":\\\"3\\\"}"},"log":"Patlite warning triggered for engine speed too high" }' 18 | responses: 19 | "200": 20 | description: boolean indicating success of adding the new rule 21 | "503": 22 | description: for unknown or unanticipated issues 23 | get: 24 | description: Return all rule names. ServcieException (HTTP 503) for unknown or unanticipated issues. 25 | displayName: get all rule names 26 | responses: 27 | "200": 28 | description: list of strings 29 | body: 30 | application/json: 31 | example: '["motortoofastsignal"]' 32 | "503": 33 | description: for unknown or unanticipated issues. 34 | /rule/name/{rulename}: 35 | displayName: rule (by name) 36 | description: example - http://localhost:48075/api/v1/rule/name/temptoohi (where temptoohi is the name of a rule) 37 | uriParameters: 38 | rulename: 39 | displayName: rulename 40 | description: Unique name of the rule 41 | type: string 42 | required: true 43 | repeat: false 44 | delete: 45 | description: Remove the rule designated by name. ServcieException (HTTP 503) for unknown or unanticipated issues. 46 | displayName: remove a rule by name 47 | responses: 48 | "200": 49 | description: boolean indicating success of the remove operation 50 | "503": 51 | description: for unknown or unanticipated issues. 52 | /ping: 53 | displayName: Ping Resource 54 | description: example - http://localhost:48075/api/v1/ping 55 | get: 56 | description: Test service providing an indication that the service is available. 57 | displayName: service up check 58 | responses: 59 | "200": 60 | description: return value of "pong" 61 | "503": 62 | description: for unknown or unanticipated issues 63 | -------------------------------------------------------------------------------- /src/main/java/org/edgexfoundry/Application.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2017 Dell Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | * 14 | * @microservice: support-rulesengine 15 | * @author: Jim White, Dell 16 | * @version: 1.0.0 17 | *******************************************************************************/ 18 | 19 | package org.edgexfoundry; 20 | 21 | import org.edgexfoundry.messaging.ZeroMQEventSubscriber; 22 | import org.springframework.boot.SpringApplication; 23 | import org.springframework.boot.autoconfigure.SpringBootApplication; 24 | import org.springframework.cloud.client.discovery.EnableDiscoveryClient; 25 | import org.springframework.context.ConfigurableApplicationContext; 26 | import org.springframework.scheduling.annotation.EnableAsync; 27 | 28 | @SpringBootApplication(scanBasePackages = {"org.edgexfoundry", "org.springframework.cloud.client"}) 29 | @EnableAsync 30 | @EnableDiscoveryClient 31 | public class Application { 32 | 33 | public static void main(String[] args) { 34 | ConfigurableApplicationContext ctx = SpringApplication.run(Application.class, args); 35 | String welcomeMsg = ctx.getEnvironment().getProperty("app.open.msg"); 36 | ZeroMQEventSubscriber sub = ctx.getBean(ZeroMQEventSubscriber.class); 37 | System.out.println(welcomeMsg); 38 | sub.receive(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/org/edgexfoundry/HeartBeat.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2017 Dell Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | * 14 | * @microservice: support-rulesengine 15 | * @author: Jim White, Dell 16 | * @version: 1.0.0 17 | *******************************************************************************/ 18 | 19 | package org.edgexfoundry; 20 | 21 | import org.springframework.beans.factory.annotation.Value; 22 | import org.springframework.scheduling.annotation.EnableScheduling; 23 | import org.springframework.scheduling.annotation.Scheduled; 24 | import org.springframework.stereotype.Component; 25 | 26 | @EnableScheduling 27 | @Component 28 | public class HeartBeat { 29 | 30 | private static final org.edgexfoundry.support.logging.client.EdgeXLogger logger = 31 | org.edgexfoundry.support.logging.client.EdgeXLoggerFactory.getEdgeXLogger(HeartBeat.class); 32 | 33 | @Value("${heart.beat.msg}") 34 | private String heartBeatMsg; 35 | 36 | @Scheduled(fixedRateString = "${heart.beat.time}") 37 | public void pulse() { 38 | logger.info(heartBeatMsg); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/org/edgexfoundry/controller/PingController.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2017 Dell Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | * 14 | * @microservice: support-rulesengine 15 | * @author: Jim White, Dell 16 | * @version: 1.0.0 17 | *******************************************************************************/ 18 | 19 | package org.edgexfoundry.controller; 20 | 21 | public interface PingController { 22 | 23 | /** 24 | * Test service providing an indication that the service is available. 25 | * 26 | * @throws ServcieException (HTTP 503) for unknown or unanticipated issues 27 | */ 28 | String ping(); 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/org/edgexfoundry/controller/RuleEngineController.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2017 Dell Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | * 14 | * @microservice: support-rulesengine 15 | * @author: Jim White, Dell 16 | * @version: 1.0.0 17 | *******************************************************************************/ 18 | 19 | package org.edgexfoundry.controller; 20 | 21 | import java.util.List; 22 | 23 | import org.edgexfoundry.rule.domain.Rule; 24 | import org.springframework.web.bind.annotation.PathVariable; 25 | import org.springframework.web.bind.annotation.RequestBody; 26 | 27 | public interface RuleEngineController { 28 | 29 | List ruleNames(); 30 | 31 | boolean addRule(@RequestBody Rule rule); 32 | 33 | boolean removeRule(@PathVariable String rulename); 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/org/edgexfoundry/controller/impl/LocalErrorController.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2017 Dell Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | * 14 | * @microservice: support-rulesengine 15 | * @author: Jim White, Dell 16 | * @version: 1.0.0 17 | *******************************************************************************/ 18 | 19 | package org.edgexfoundry.controller.impl; 20 | 21 | import java.util.Map; 22 | 23 | import javax.servlet.http.HttpServletRequest; 24 | import javax.servlet.http.HttpServletResponse; 25 | 26 | import org.springframework.beans.factory.annotation.Autowired; 27 | import org.springframework.beans.factory.annotation.Value; 28 | import org.springframework.boot.autoconfigure.web.ErrorAttributes; 29 | import org.springframework.boot.autoconfigure.web.ErrorController; 30 | import org.springframework.web.bind.annotation.RequestMapping; 31 | import org.springframework.web.bind.annotation.RestController; 32 | import org.springframework.web.context.request.RequestAttributes; 33 | import org.springframework.web.context.request.ServletRequestAttributes; 34 | 35 | @RestController 36 | public class LocalErrorController implements ErrorController { 37 | private static final String PATH = "/error"; 38 | 39 | @Value("${print.stacktrace:false}") 40 | private boolean printTraces; 41 | 42 | @Autowired 43 | private ErrorAttributes errorAttributes; 44 | 45 | @RequestMapping(value = PATH) 46 | public String error(HttpServletRequest request, HttpServletResponse response) { 47 | Map errorInfo = getErrorAttributes(request, printTraces); 48 | return errorInfo.get("message") + "\n\n" + errorInfo.get("trace"); 49 | } 50 | 51 | @Override 52 | public String getErrorPath() { 53 | return PATH; 54 | } 55 | 56 | private Map getErrorAttributes(HttpServletRequest request, 57 | boolean includeStackTrace) { 58 | RequestAttributes requestAttributes = new ServletRequestAttributes(request); 59 | return errorAttributes.getErrorAttributes(requestAttributes, includeStackTrace); 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/org/edgexfoundry/controller/impl/PingControllerImpl.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2017 Dell Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | * 14 | * @microservice: support-rulesengine 15 | * @author: Jim White, Dell 16 | * @version: 1.0.0 17 | *******************************************************************************/ 18 | 19 | package org.edgexfoundry.controller.impl; 20 | 21 | import org.edgexfoundry.controller.PingController; 22 | import org.edgexfoundry.exception.controller.ServiceException; 23 | import org.springframework.web.bind.annotation.RequestMapping; 24 | import org.springframework.web.bind.annotation.RequestMethod; 25 | import org.springframework.web.bind.annotation.RestController; 26 | 27 | @RestController 28 | @RequestMapping("/api/v1/ping") 29 | public class PingControllerImpl implements PingController { 30 | 31 | private static final org.edgexfoundry.support.logging.client.EdgeXLogger logger = 32 | org.edgexfoundry.support.logging.client.EdgeXLoggerFactory 33 | .getEdgeXLogger(PingControllerImpl.class); 34 | 35 | /** 36 | * Test service providing an indication that the service is available. 37 | * 38 | * @throws ServcieException (HTTP 503) for unknown or unanticipated issues 39 | */ 40 | @Override 41 | @RequestMapping(method = RequestMethod.GET) 42 | public String ping() { 43 | try { 44 | return "pong"; 45 | } catch (Exception e) { 46 | logger.error("Error on ping: " + e.getMessage()); 47 | throw new ServiceException(e); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/org/edgexfoundry/controller/impl/RuleEngineControllerImpl.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2017 Dell Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | * 14 | * @microservice: support-rulesengine 15 | * @author: Jim White, Dell 16 | * @version: 1.0.0 17 | *******************************************************************************/ 18 | 19 | package org.edgexfoundry.controller.impl; 20 | 21 | import java.util.List; 22 | 23 | import org.edgexfoundry.controller.RuleEngineController; 24 | import org.edgexfoundry.engine.RuleCreator; 25 | import org.edgexfoundry.engine.RuleEngine; 26 | import org.edgexfoundry.exception.controller.ServiceException; 27 | import org.edgexfoundry.rule.domain.Rule; 28 | import org.springframework.beans.factory.annotation.Autowired; 29 | import org.springframework.web.bind.annotation.PathVariable; 30 | import org.springframework.web.bind.annotation.RequestBody; 31 | import org.springframework.web.bind.annotation.RequestMapping; 32 | import org.springframework.web.bind.annotation.RequestMethod; 33 | import org.springframework.web.bind.annotation.RestController; 34 | 35 | @RestController 36 | @RequestMapping("/api/v1/rule") 37 | public class RuleEngineControllerImpl implements RuleEngineController { 38 | 39 | private static final org.edgexfoundry.support.logging.client.EdgeXLogger logger = 40 | org.edgexfoundry.support.logging.client.EdgeXLoggerFactory 41 | .getEdgeXLogger(RuleEngineControllerImpl.class); 42 | 43 | @Autowired 44 | private RuleEngine engine; 45 | 46 | @Autowired 47 | private RuleCreator creator; 48 | 49 | @RequestMapping(method = RequestMethod.GET) 50 | @Override 51 | public List ruleNames() { 52 | try { 53 | return engine.getRulenames(); 54 | } catch (Exception e) { 55 | logger.error("Problem getting rule names"); 56 | throw new ServiceException(e); 57 | } 58 | } 59 | 60 | @RequestMapping(method = RequestMethod.POST) 61 | @Override 62 | public boolean addRule(@RequestBody Rule rule) { 63 | try { 64 | engine.addRule(creator.createDroolRule(rule), rule.getName()); 65 | logger.info("Rule named: " + rule.getName() + " added."); 66 | return true; 67 | } catch (Exception e) { 68 | logger.error("Problem adding a new rule called: " + rule.getName()); 69 | throw new ServiceException(e); 70 | } 71 | } 72 | 73 | @RequestMapping(value = "/name/{rulename}", method = RequestMethod.DELETE) 74 | @Override 75 | public boolean removeRule(@PathVariable String rulename) { 76 | try { 77 | engine.removeRule(rulename); 78 | logger.info("Rule named: " + rulename + " removed"); 79 | return true; 80 | } catch (Exception e) { 81 | logger.error("Problem removing the rule called: " + rulename); 82 | throw new ServiceException(e); 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/main/java/org/edgexfoundry/engine/CommandExecutor.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2017 Dell Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | * 14 | * @microservice: support-rulesengine 15 | * @author: Jim White, Dell 16 | * @version: 1.0.0 17 | *******************************************************************************/ 18 | 19 | package org.edgexfoundry.engine; 20 | 21 | import org.edgexfoundry.controller.CmdClient; 22 | import org.springframework.beans.factory.annotation.Autowired; 23 | import org.springframework.scheduling.annotation.Async; 24 | import org.springframework.stereotype.Component; 25 | 26 | @Component 27 | public class CommandExecutor { 28 | 29 | @Autowired 30 | private CmdClient client; 31 | 32 | private static final org.edgexfoundry.support.logging.client.EdgeXLogger logger = 33 | org.edgexfoundry.support.logging.client.EdgeXLoggerFactory 34 | .getEdgeXLogger(CommandExecutor.class); 35 | 36 | @Async 37 | public void fireCommand(String deviceId, String commandId, String body) { 38 | logger.info( 39 | "Sending request to: " + deviceId + "for command: " + commandId + " with body: " + body); 40 | try { 41 | // for now - all rule engine requests are puts 42 | forwardRequest(deviceId, commandId, body, true); 43 | } catch (Exception exception) { 44 | logger.error("Problem sending command to the device service " + exception); 45 | } 46 | } 47 | 48 | private void forwardRequest(String id, String commandId, String body, boolean isPut) { 49 | if (client != null) { 50 | if (isPut) 51 | logger.debug("Resposne from command put is: " + client.put(id, commandId, body)); 52 | else 53 | logger.debug("Resposne from command get is: " + client.get(id, commandId)); 54 | } else { 55 | logger.error("Command Client not available - no command sent for: " + id + " to " + commandId 56 | + " containing: " + body); 57 | } 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/org/edgexfoundry/engine/RuleCreator.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2017 Dell Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | * 14 | * @microservice: support-rulesengine 15 | * @author: Jim White, Dell 16 | * @version: 1.0.0 17 | *******************************************************************************/ 18 | 19 | package org.edgexfoundry.engine; 20 | 21 | import java.io.File; 22 | import java.io.IOException; 23 | import java.io.StringWriter; 24 | import java.io.Writer; 25 | import java.util.HashMap; 26 | import java.util.Map; 27 | 28 | import javax.annotation.PostConstruct; 29 | 30 | import org.edgexfoundry.rule.domain.Rule; 31 | import org.springframework.beans.factory.annotation.Value; 32 | import org.springframework.stereotype.Component; 33 | 34 | import freemarker.template.Configuration; 35 | import freemarker.template.Template; 36 | import freemarker.template.TemplateException; 37 | import freemarker.template.TemplateExceptionHandler; 38 | 39 | @Component 40 | public class RuleCreator { 41 | 42 | private static final org.edgexfoundry.support.logging.client.EdgeXLogger logger = 43 | org.edgexfoundry.support.logging.client.EdgeXLoggerFactory.getEdgeXLogger(RuleCreator.class); 44 | 45 | @Value("${rules.template.path}") 46 | private String templateLocation; 47 | 48 | @Value("${rules.template.name}") 49 | private String templateName; 50 | 51 | @Value("${rules.template.encoding}") 52 | private String templateEncoding; 53 | 54 | private Configuration cfg; 55 | 56 | @PostConstruct 57 | public void init() throws IOException { 58 | try { 59 | cfg = new Configuration(Configuration.getVersion()); 60 | cfg.setDirectoryForTemplateLoading(new File(templateLocation)); 61 | cfg.setDefaultEncoding(templateEncoding); 62 | cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER); 63 | } catch (IOException e) { 64 | logger.error("Problem getting rule template location." + e.getMessage()); 65 | throw e; 66 | } 67 | } 68 | 69 | private Map createMap(Rule rule) { 70 | Map map = new HashMap<>(); 71 | map.put("rulename", rule.getName()); 72 | map.put("conddeviceid", rule.getCondition().getDevice()); 73 | map.put("valuechecks", rule.getCondition().getChecks()); 74 | map.put("actiondeviceid", rule.getAction().getDevice()); 75 | map.put("actioncommandid", rule.getAction().getCommand()); 76 | map.put("commandbody", rule.getAction().getBody()); 77 | map.put("log", rule.getLog()); 78 | return map; 79 | } 80 | 81 | public String createDroolRule(Rule rule) throws TemplateException, IOException { 82 | try { 83 | Template temp = cfg.getTemplate(templateName); 84 | Writer out = new StringWriter(); 85 | temp.process(createMap(rule), out); 86 | return out.toString(); 87 | } catch (IOException iE) { 88 | logger.error("Problem getting rule template file." + iE.getMessage()); 89 | throw iE; 90 | } catch (TemplateException tE) { 91 | logger.error("Problem writing Drool rule." + tE.getMessage()); 92 | throw tE; 93 | } catch (Exception e) { 94 | logger.error("Problem creating rule: " + e.getMessage()); 95 | throw e; 96 | } 97 | } 98 | 99 | } 100 | -------------------------------------------------------------------------------- /src/main/java/org/edgexfoundry/engine/RuleEngine.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2017 Dell Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | * 14 | * @microservice: support-rulesengine 15 | * @author: Jim White, Dell 16 | * @version: 1.0.0 17 | *******************************************************************************/ 18 | 19 | package org.edgexfoundry.engine; 20 | 21 | import java.io.BufferedWriter; 22 | import java.io.File; 23 | import java.io.FileWriter; 24 | import java.io.IOException; 25 | import java.util.ArrayList; 26 | import java.util.Collection; 27 | import java.util.List; 28 | 29 | import javax.annotation.PostConstruct; 30 | 31 | import org.edgexfoundry.domain.core.Event; 32 | import org.edgexfoundry.exception.controller.ServiceException; 33 | import org.kie.api.KieBase; 34 | import org.kie.api.KieBaseConfiguration; 35 | import org.kie.api.KieServices; 36 | import org.kie.api.builder.KieBuilder; 37 | import org.kie.api.builder.KieFileSystem; 38 | import org.kie.api.builder.Message.Level; 39 | import org.kie.api.definition.KiePackage; 40 | import org.kie.api.definition.rule.Rule; 41 | import org.kie.api.runtime.KieContainer; 42 | import org.kie.api.runtime.KieSession; 43 | import org.kie.internal.conf.ConstraintJittingThresholdOption; 44 | import org.kie.internal.io.ResourceFactory; 45 | import org.springframework.beans.factory.annotation.Autowired; 46 | import org.springframework.beans.factory.annotation.Value; 47 | import org.springframework.stereotype.Component; 48 | 49 | @Component 50 | public class RuleEngine { 51 | 52 | private static final org.edgexfoundry.support.logging.client.EdgeXLogger logger = 53 | org.edgexfoundry.support.logging.client.EdgeXLoggerFactory.getEdgeXLogger(RuleEngine.class); 54 | 55 | @Value("${rules.default.path}") 56 | private String resourceFilePath; 57 | 58 | @Value("${rules.packagename}") 59 | private String packageName; 60 | 61 | @Value("${rules.fileextension}") 62 | private String ruleFileExtension; 63 | 64 | @Autowired 65 | private CommandExecutor executor; 66 | 67 | private KieBase kbase; 68 | private KieFileSystem kfs; 69 | 70 | @PostConstruct 71 | public void init() { 72 | logger.debug("initializing Drools Kies"); 73 | initKie(); 74 | } 75 | 76 | public void execute(Object object) { 77 | try { 78 | KieSession ksession = kbase.newKieSession(); 79 | if (!getRulenames().isEmpty()) { 80 | if (executor != null) { 81 | ksession.setGlobal("executor", executor); 82 | ksession.setGlobal("logger", logger); 83 | ksession.insert(object); 84 | int rulesFired = ksession.fireAllRules(); 85 | logger.debug("Number of rules fired on event: " + rulesFired); 86 | if (rulesFired > 0) { 87 | logger.info("Event triggered " + rulesFired + "rules: " + (Event) object); 88 | } 89 | } else 90 | logger.error("Command Executor not available - no command sent for event: " + object); 91 | } else { 92 | logger.debug("No rules in the system - skipping firing rules"); 93 | } 94 | ksession.dispose(); 95 | } catch (Exception e) { 96 | logger.error("Error during rules enging processing: " + e.getMessage()); 97 | } 98 | } 99 | 100 | public void addRule(String newRule, String rulename) throws IOException { 101 | String filename = getFileName(rulename); 102 | writeRule(newRule, filename); 103 | loadRule(filename); 104 | logger.info("new rule: " + rulename + " added."); 105 | initKie(); 106 | } 107 | 108 | public boolean removeRule(String rulename) throws IOException { 109 | String filename = getFileName(rulename); 110 | if (kbase.getRule(packageName, rulename) != null) 111 | kbase.removeRule(packageName, rulename); 112 | kfs.delete(filename); 113 | // goofey - but the file won't delete but will allow to be overwritten 114 | // with nothing this allows the rule to go away 115 | boolean success = writeRule("", filename); 116 | logger.info("rule: " + rulename + " removed."); 117 | return success; 118 | } 119 | 120 | public List getRulenames() { 121 | List result = new ArrayList<>(); 122 | try { 123 | KiePackage kpkg = kbase.getKiePackage(packageName); 124 | if (kpkg != null) { 125 | Collection rules = kpkg.getRules(); 126 | if (rules != null) { 127 | for (Rule rule : rules) { 128 | result.add(rule.getName()); 129 | } 130 | } 131 | } 132 | return result; 133 | } catch (Exception ex) { 134 | logger.error(ex.getMessage()); 135 | throw new ServiceException(ex); 136 | } 137 | } 138 | 139 | public String getResourceFilePath() { 140 | return resourceFilePath; 141 | } 142 | 143 | public String getPackageName() { 144 | return packageName; 145 | } 146 | 147 | public String getRuleFileExtension() { 148 | return ruleFileExtension; 149 | } 150 | 151 | private String getFileName(String rulename) { 152 | createDirectory(); 153 | return resourceFilePath + "/" + rulename + ruleFileExtension; 154 | } 155 | 156 | private void createDirectory() { 157 | File ruleDirectory = new File(resourceFilePath); 158 | if (!ruleDirectory.exists()) 159 | ruleDirectory.mkdir(); 160 | } 161 | 162 | private boolean writeRule(String rule, String filename) throws IOException { 163 | try (FileWriter fileWriter = new FileWriter(new File(filename)); 164 | BufferedWriter writer = new BufferedWriter(fileWriter)) { 165 | writer.write(rule); 166 | writer.flush(); 167 | writer.close(); 168 | return true; 169 | } catch (IOException e) { 170 | logger.error("Problem writing file: " + filename); 171 | throw e; 172 | } 173 | } 174 | 175 | private void loadRule(String fileName) { 176 | kfs.write(ResourceFactory.newFileResource(fileName)); 177 | } 178 | 179 | private void uploadDroolFiles() { 180 | logger.info("Starting Drools with drl files from: " + resourceFilePath); 181 | File directory = new File(resourceFilePath); 182 | File[] fList = directory.listFiles(); 183 | logger.info("Uploading Drool rules..."); 184 | if (fList != null && fList.length > 0) { 185 | for (File file : fList) { 186 | kfs.write(ResourceFactory.newFileResource(resourceFilePath + "/" + file.getName())); 187 | logger.info("... " + file.getName()); 188 | } 189 | } else { 190 | logger.info("...no rules found to upload"); 191 | } 192 | } 193 | 194 | private void initKie() { 195 | KieServices ks = KieServices.Factory.get(); 196 | kfs = ks.newKieFileSystem(); 197 | uploadDroolFiles(); 198 | KieBuilder kbuilder = ks.newKieBuilder(kfs); 199 | kbuilder.buildAll(); 200 | if (kbuilder.getResults().hasMessages(Level.ERROR)) { 201 | throw new IllegalArgumentException(kbuilder.getResults().toString()); 202 | } 203 | KieContainer kcontainer = ks.newKieContainer(kbuilder.getKieModule().getReleaseId()); 204 | KieBaseConfiguration kbConfig = KieServices.Factory.get().newKieBaseConfiguration(); 205 | kbConfig.setOption(ConstraintJittingThresholdOption.get(-1)); 206 | kbase = kcontainer.newKieBase(kbConfig); 207 | } 208 | } 209 | -------------------------------------------------------------------------------- /src/main/java/org/edgexfoundry/export/registration/ExportClient.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2017 Dell Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | * 14 | * @microservice: support-rulesengine 15 | * @author: Jim White, Dell 16 | * @version: 1.0.0 17 | *******************************************************************************/ 18 | 19 | package org.edgexfoundry.export.registration; 20 | 21 | import javax.ws.rs.Consumes; 22 | import javax.ws.rs.DELETE; 23 | import javax.ws.rs.GET; 24 | import javax.ws.rs.POST; 25 | import javax.ws.rs.Path; 26 | import javax.ws.rs.PathParam; 27 | 28 | import org.edgexfoundry.domain.export.ExportRegistration; 29 | 30 | public interface ExportClient { 31 | 32 | @GET 33 | @Path("/registration/name/{name}") 34 | ExportRegistration exportRegistrationByName(@PathParam("name") String name); 35 | 36 | @POST 37 | @Path("/registration") 38 | @Consumes("application/json") 39 | String register(ExportRegistration registration); 40 | 41 | @DELETE 42 | @Path("/registration/name/{name}") 43 | boolean deleteByName(@PathParam("name") String name); 44 | 45 | @DELETE 46 | @Path("/registration/id/{id}") 47 | boolean delete(@PathParam("id") String id); 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/org/edgexfoundry/export/registration/ExportClientImpl.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2017 Dell Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | * 14 | * @microservice: support-rulesengine 15 | * @author: Jim White, Dell 16 | * @version: 1.0.0 17 | *******************************************************************************/ 18 | 19 | package org.edgexfoundry.export.registration; 20 | 21 | import javax.annotation.PostConstruct; 22 | import javax.ws.rs.NotFoundException; 23 | 24 | import org.edgexfoundry.domain.export.ExportDestination; 25 | import org.edgexfoundry.domain.export.ExportFormat; 26 | import org.edgexfoundry.domain.export.ExportRegistration; 27 | import org.edgexfoundry.domain.meta.Addressable; 28 | import org.edgexfoundry.domain.meta.Protocol; 29 | import org.jboss.resteasy.client.jaxrs.ResteasyClient; 30 | import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder; 31 | import org.jboss.resteasy.client.jaxrs.ResteasyWebTarget; 32 | import org.springframework.beans.factory.annotation.Value; 33 | import org.springframework.stereotype.Component; 34 | 35 | @Component 36 | public class ExportClientImpl implements ExportClient { 37 | 38 | private static final org.edgexfoundry.support.logging.client.EdgeXLogger logger = 39 | org.edgexfoundry.support.logging.client.EdgeXLoggerFactory 40 | .getEdgeXLogger(ExportClientImpl.class); 41 | 42 | @Value("${export.client}") 43 | private boolean exportClient; 44 | 45 | @Value("${export.client.registration.url}") 46 | private String url; 47 | 48 | @Value("${export.client.registration.name}") 49 | private String clientName; 50 | 51 | @Value("${export.client.registration.retry.time}") 52 | private int retryTime; 53 | 54 | @Value("${export.client.registration.retry.attempts}") 55 | private int retryAttempts; 56 | 57 | @PostConstruct 58 | public void init() throws InterruptedException { 59 | if (exportClient) { 60 | int tries = 0; 61 | do { 62 | tries++; 63 | try { 64 | if (isRegistered()) { 65 | logger.info("Already registered with export service"); 66 | return; 67 | } 68 | logger.debug("Attempting to register with export service"); 69 | if (registerRulesEngine()) { 70 | logger.info("Export client registration complete"); 71 | return; 72 | } 73 | } catch (Exception e) { 74 | logger.debug("Problem while connecting to export client service: " + e.getMessage()); 75 | logger.info("Export Client registration try# : " + tries); 76 | } 77 | retrySleep(retryTime); 78 | } while (tries < retryAttempts); 79 | logger.error("Trouble connecting to export service. Exiting.\n"); 80 | System.exit(1); 81 | } else 82 | logger.info("Direct receiver of messages from core. No export client registration"); 83 | } 84 | 85 | private void retrySleep(int time) throws InterruptedException { 86 | try { 87 | Thread.sleep(time); 88 | } catch (InterruptedException e) { 89 | logger.error("Problem sleeping between registration retries"); 90 | throw e; 91 | } 92 | } 93 | 94 | public boolean isRegistered() { 95 | try { 96 | return (exportRegistrationByName(clientName) != null); 97 | } catch (NotFoundException nfE) { 98 | return false; 99 | } 100 | } 101 | 102 | public boolean registerRulesEngine() { 103 | logger.debug("Registering rules engine service as export client"); 104 | String id = register(getExportRegistration()); 105 | if (id != null && id != "") 106 | return true; 107 | logger.error("Problems registering rules engine service as export client"); 108 | return false; 109 | } 110 | 111 | @Override 112 | public ExportRegistration exportRegistrationByName(String name) { 113 | return getClient().exportRegistrationByName(name); 114 | } 115 | 116 | @Override 117 | public String register(ExportRegistration registration) { 118 | return getClient().register(registration); 119 | } 120 | 121 | @Override 122 | public boolean deleteByName(String name) { 123 | try { 124 | return getClient().deleteByName(name); 125 | } catch (javax.ws.rs.NotFoundException notFound) { 126 | return false; 127 | } 128 | } 129 | 130 | @Override 131 | public boolean delete(String id) { 132 | try { 133 | return getClient().delete(id); 134 | } catch (javax.ws.rs.NotFoundException notFound) { 135 | return false; 136 | } 137 | } 138 | 139 | private ExportRegistration getExportRegistration() { 140 | ExportRegistration registration = new ExportRegistration(); 141 | registration.setName(clientName); 142 | registration.setFormat(ExportFormat.SERIALIZED); 143 | registration.setDestination(ExportDestination.ZMQ_TOPIC); 144 | registration.setEnable(true); 145 | Addressable addressable = 146 | new Addressable("EdgeXRulesEngineAddressable", Protocol.ZMQ, "", "", 0); 147 | registration.setAddressable(addressable); 148 | return registration; 149 | } 150 | 151 | private ExportClient getClient() { 152 | ResteasyClient client = new ResteasyClientBuilder().build(); 153 | ResteasyWebTarget target = client.target(url); 154 | return target.proxy(ExportClient.class); 155 | } 156 | 157 | } 158 | -------------------------------------------------------------------------------- /src/main/java/org/edgexfoundry/messaging/ZeroMQEventSubscriber.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2017 Dell Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | * 14 | * @microservice: support-rulesengine 15 | * @author: Jim White, Dell 16 | * @version: 1.0.0 17 | *******************************************************************************/ 18 | 19 | package org.edgexfoundry.messaging; 20 | 21 | import java.io.IOException; 22 | 23 | import org.edgexfoundry.domain.core.Event; 24 | import org.edgexfoundry.engine.RuleEngine; 25 | import org.springframework.beans.factory.annotation.Autowired; 26 | import org.springframework.beans.factory.annotation.Value; 27 | import org.springframework.stereotype.Component; 28 | import org.zeromq.SocketType; 29 | import org.zeromq.ZFrame; 30 | import org.zeromq.ZMQ; 31 | import org.zeromq.ZMsg; 32 | 33 | import com.fasterxml.jackson.core.JsonProcessingException; 34 | import com.fasterxml.jackson.databind.JsonNode; 35 | import com.fasterxml.jackson.databind.ObjectMapper; 36 | import com.google.gson.Gson; 37 | 38 | /** 39 | * Export data message ingestion bean - gets messages out of ZeroMQ from export 40 | * service. 41 | */ 42 | @Component 43 | public class ZeroMQEventSubscriber { 44 | 45 | private static final org.edgexfoundry.support.logging.client.EdgeXLogger logger = org.edgexfoundry.support.logging.client.EdgeXLoggerFactory 46 | .getEdgeXLogger(ZeroMQEventSubscriber.class); 47 | 48 | public static final String NO_ENVELOPE = "no_envelope"; 49 | public static final String JSON = "application/json"; 50 | public static final String CBOR = "application/cbor"; 51 | public static final String CONTENT_TYPE = "ContentType"; 52 | 53 | @Value("${export.zeromq.port}") 54 | private String zeromqAddressPort; 55 | @Value("${export.zeromq.host}") 56 | private String zeromqAddress; 57 | @Value("${export.client}") 58 | private boolean exportClient; 59 | @Value("${expect.serializedjava}") 60 | private boolean serializedJava; 61 | 62 | @Autowired 63 | RuleEngine engine; 64 | 65 | private ZMQ.Socket subscriber; 66 | private ZMQ.Context context; 67 | private ObjectMapper mapper = new ObjectMapper(); 68 | 69 | { 70 | context = ZMQ.context(1); 71 | } 72 | 73 | public void receive() { 74 | getSubscriber(); 75 | JsonNode node; 76 | ZMsg zmsg; 77 | ZFrame[] parts; 78 | logger.info("Watching for new exported Event messages..."); 79 | try { 80 | while (!Thread.currentThread().isInterrupted()) { 81 | zmsg = ZMsg.recvMsg(subscriber); 82 | parts = new ZFrame[zmsg.size()]; 83 | zmsg.toArray(parts); 84 | logger.debug("Message has " + parts.length + " parts."); 85 | 86 | if (parts.length < 2) {// if the message is not a multi-part message 87 | try { 88 | node = mapper.readTree(parts[0].getData()); 89 | } catch (JsonProcessingException jsonE) { // if can't parse the data from the message, assume it is CBOR 90 | processCborEvent(parts[0]); 91 | break; 92 | } 93 | } else // if the message is multi-part message 94 | node = mapper.readTree(parts[1].getData()); 95 | switch (payloadType(node)) { 96 | case NO_ENVELOPE: 97 | processEvent(node); 98 | break; 99 | case JSON: 100 | processJsonEvent(node); 101 | break; 102 | case CBOR: 103 | processCborEvent(node); 104 | break; 105 | default: 106 | logger.error("Unknown payload type received"); 107 | break; 108 | } 109 | } 110 | } catch (Exception e) { 111 | logger.error("Unable to receive messages via ZMQ: " + e.getMessage()); 112 | } 113 | logger.error("Shutting off Event message watch due to error!"); 114 | if (subscriber != null) 115 | subscriber.close(); 116 | subscriber = null; 117 | // try to restart 118 | logger.debug("Attempting restart of Event message watch."); 119 | 120 | receive(); 121 | 122 | } 123 | 124 | private String payloadType(JsonNode node) throws JsonProcessingException, IOException { 125 | JsonNode contentType = node.get(CONTENT_TYPE); 126 | if (contentType == null) 127 | return NO_ENVELOPE; 128 | else 129 | return node.get(CONTENT_TYPE).asText(); 130 | } 131 | 132 | public String getZeromqAddress() { 133 | return zeromqAddress; 134 | } 135 | 136 | public void setZeromqAddress(String zeromqAddress) { 137 | this.zeromqAddress = zeromqAddress; 138 | } 139 | 140 | public String getZeromqAddressPort() { 141 | return zeromqAddressPort; 142 | } 143 | 144 | public void setZeromqAddressPort(String zeromqAddressPort) { 145 | this.zeromqAddressPort = zeromqAddressPort; 146 | } 147 | 148 | private ZMQ.Socket getSubscriber() { 149 | if (subscriber == null) { 150 | try { 151 | subscriber = context.socket(SocketType.SUB); 152 | subscriber.connect(zeromqAddress + ":" + zeromqAddressPort); 153 | subscriber.subscribe("".getBytes()); 154 | } catch (Exception e) { 155 | logger.error("Unable to get a ZMQ subscriber. Error: " + e); 156 | subscriber = null; 157 | } 158 | } 159 | return subscriber; 160 | } 161 | 162 | private void processJsonEvent(JsonNode node) throws IOException { 163 | logger.info("JSON event received"); 164 | Event event = toEvent(node.get("Payload").binaryValue()); 165 | logger.debug("Event: " + event); 166 | executeOnEvent(event); 167 | } 168 | 169 | private void processEvent(JsonNode node) { 170 | logger.info("Event received"); 171 | Event event = mapper.convertValue(node, Event.class); 172 | logger.debug("Event: " + event); 173 | executeOnEvent(event); 174 | } 175 | 176 | private void executeOnEvent(Event event) { 177 | engine.execute(event); 178 | logger.info("Event sent to rules engine for device id: " + event.getDevice()); 179 | } 180 | 181 | private void processCborEvent(Object data) { 182 | logger.info("CBOR received. CBOR is unsupported in the rules engine at this time; message being ignored"); 183 | } 184 | 185 | private static Event toEvent(byte[] eventBytes) throws IOException { 186 | Gson gson = new Gson(); 187 | String json = new String(eventBytes); 188 | return gson.fromJson(json, Event.class); 189 | } 190 | } 191 | -------------------------------------------------------------------------------- /src/main/java/org/edgexfoundry/rule/domain/Action.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2017 Dell Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | * 14 | * @microservice: support-rulesengine 15 | * @author: Jim White, Dell 16 | * @version: 1.0.0 17 | *******************************************************************************/ 18 | 19 | package org.edgexfoundry.rule.domain; 20 | 21 | public class Action { 22 | 23 | private String device; 24 | private String command; 25 | private String body; 26 | 27 | public String getDevice() { 28 | return device; 29 | } 30 | 31 | public void setDevice(String device) { 32 | this.device = device; 33 | } 34 | 35 | public String getCommand() { 36 | return command; 37 | } 38 | 39 | public void setCommand(String command) { 40 | this.command = command; 41 | } 42 | 43 | public String getBody() { 44 | return body; 45 | } 46 | 47 | public void setBody(String body) { 48 | this.body = body; 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/org/edgexfoundry/rule/domain/Condition.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2017 Dell Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | * 14 | * @microservice: support-rulesengine 15 | * @author: Jim White, Dell 16 | * @version: 1.0.0 17 | *******************************************************************************/ 18 | 19 | package org.edgexfoundry.rule.domain; 20 | 21 | import java.util.ArrayList; 22 | import java.util.List; 23 | 24 | public class Condition { 25 | 26 | private String device; 27 | private List checks; 28 | 29 | public String getDevice() { 30 | return device; 31 | } 32 | 33 | public void setDevice(String device) { 34 | this.device = device; 35 | } 36 | 37 | public List getChecks() { 38 | return checks; 39 | } 40 | 41 | public void setChecks(List checks) { 42 | this.checks = checks; 43 | } 44 | 45 | public void addCheck(ValueCheck check) { 46 | if (checks == null) 47 | checks = new ArrayList<>(); 48 | checks.add(check); 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/org/edgexfoundry/rule/domain/Rule.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2017 Dell Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | * 14 | * @microservice: support-rulesengine 15 | * @author: Jim White, Dell 16 | * @version: 1.0.0 17 | *******************************************************************************/ 18 | 19 | package org.edgexfoundry.rule.domain; 20 | 21 | public class Rule { 22 | 23 | private String name; 24 | private Condition condition; 25 | private Action action; 26 | private String log; 27 | 28 | public String getName() { 29 | return name; 30 | } 31 | 32 | public void setName(String name) { 33 | this.name = name; 34 | } 35 | 36 | public Condition getCondition() { 37 | return condition; 38 | } 39 | 40 | public void setCondition(Condition condition) { 41 | this.condition = condition; 42 | } 43 | 44 | public Action getAction() { 45 | return action; 46 | } 47 | 48 | public void setAction(Action action) { 49 | this.action = action; 50 | } 51 | 52 | public String getLog() { 53 | return log; 54 | } 55 | 56 | public void setLog(String log) { 57 | this.log = log; 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/org/edgexfoundry/rule/domain/ValueCheck.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2017 Dell Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | * 14 | * @microservice: support-rulesengine 15 | * @author: Jim White, Dell 16 | * @version: 1.0.0 17 | *******************************************************************************/ 18 | 19 | package org.edgexfoundry.rule.domain; 20 | 21 | public class ValueCheck { 22 | 23 | private String parameter; 24 | private String operand1; 25 | private String operation; 26 | private String operand2; 27 | 28 | public String getParameter() { 29 | return parameter; 30 | } 31 | 32 | public void setParameter(String parameter) { 33 | this.parameter = parameter; 34 | } 35 | 36 | public String getOperand1() { 37 | return operand1; 38 | } 39 | 40 | public void setOperand1(String operand1) { 41 | this.operand1 = operand1; 42 | } 43 | 44 | public String getOperation() { 45 | return operation; 46 | } 47 | 48 | public void setOperation(String operation) { 49 | this.operation = operation; 50 | } 51 | 52 | public String getOperand2() { 53 | return operand2; 54 | } 55 | 56 | public void setOperand2(String operand2) { 57 | this.operand2 = operand2; 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Copyright 2017 Dell Inc. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | # @microservice: support-rulesengine 17 | # @author: Jim White, Dell 18 | # @version: 1.0.0 19 | ############################################################################### 20 | #-----------------General Config----------------------------------------------- 21 | #every 5 minutes (in milliseconds) 22 | heart.beat.time=300000 23 | #messages 24 | heart.beat.msg=Support Rules Engine data heart beat 25 | app.open.msg=This is the Support Rules Engine Microservice. 26 | # set port (override Spring boot default port 8080 ) 27 | server.port=48075 28 | #-----------------App Service Configurable Rules Config---------------------------------------- 29 | #Turn on/off registration of rules engine as app-service-configurable client. 30 | #Set to false to receive messages directly from core data 31 | export.client=false 32 | expect.serializedjava=false 33 | export.client.registration.url=http://localhost:48071/api/v1 34 | #export.client.registration.url=http://edgex-export-client:48071/api/v1 35 | export.client.registration.name=EdgeXRulesEngine 36 | #use port 5566 when connected to app-service-configurable 37 | #use port 5563 when connected to core data directly 38 | export.zeromq.port=5566 39 | #export.zeromq.port=5563 40 | export.zeromq.host=tcp://localhost 41 | #export.zeromq.host=tcp://edgex-app-service-configurable-rules 42 | #how long to wait to retry registration 43 | export.client.registration.retry.time=10000 44 | #how many times to try registration before exiting 45 | export.client.registration.retry.attempts=100 46 | #-----------------Logging Config----------------------------------------------- 47 | #logging levels (used to control log4j entries) 48 | logging.level.org.springframework=ERROR 49 | logging.level.org.apache=ERROR 50 | logging.level.org.edgexfoundry=INFO 51 | #log files are rotated after 10MB by default in Spring boot 52 | logging.file=edgex-support-rulesengine.log 53 | #print stack traces with errors on REST calls 54 | print.stacktrace=true 55 | #-----------------Drools Config----------------------------------------------- 56 | #Drools drl resource path 57 | rules.default.path=edgex/rules 58 | #rules.default.path=/edgex/edgex-support-rulesengine/rules 59 | rules.packagename=org.edgexfoundry.rules 60 | rules.fileextension=.drl 61 | rules.template.path=./src/main/resources 62 | #rules.template.path=edgex/templates 63 | #rules.template.path=/edgex/edgex-support-rulesengine/templates 64 | rules.template.name=rule-template.drl 65 | rules.template.encoding=UTF-8 66 | #IOT core data database service connection information 67 | core.db.command.url=http://localhost:48082/api/v1/device 68 | #core.db.command.url=http://edgex-core-command:48082/api/v1/device 69 | #IOT metadata database service connection information 70 | meta.db.addressable.url=http://localhost:48081/api/v1/addressable 71 | meta.db.deviceservice.url=http://localhost:48081/api/v1/deviceservice 72 | meta.db.deviceprofile.url=http://localhost:48081/api/v1/deviceprofile 73 | meta.db.device.url=http://localhost:48081/api/v1/device 74 | meta.db.devicereport.url=http://localhost:48081/api/v1/devicereport 75 | meta.db.command.url=http://localhost:48081/api/v1/command 76 | meta.db.event.url=http://localhost:48081/api/v1/event 77 | meta.db.schedule.url=http://localhost:48081/api/v1/schedule 78 | meta.db.provisionwatcher.url=http://localhost:48081/api/v1/provisionwatcher 79 | #meta.db.addressable.url=http://edgex-core-metadata:48081/api/v1/addressable 80 | #meta.db.deviceservice.url=http://edgex-core-metadata:48081/api/v1/deviceservice 81 | #meta.db.deviceprofile.url=http://edgex-core-metadata:48081/api/v1/deviceprofile 82 | #meta.db.device.url=http://edgex-core-metadata:48081/api/v1/device 83 | #meta.db.devicereport.url=http://edgex-core-metadata:48081/api/v1/devicereport 84 | #meta.db.command.url=http://edgex-core-metadata:48081/api/v1/command 85 | #meta.db.event.url=http://edgex-core-metadata:48081/api/v1/event 86 | #meta.db.schedule.url=http://edgex-core-metadata:48081/api/v1/schedule 87 | #meta.db.provisionwatcher.url=http://edgex-core-metadata:48081/api/v1/provisionwatcher 88 | #-----------------Remote Logging Config------------------------------------------ 89 | logging.remote.enable=false 90 | logging.remote.url=http://localhost:48061/api/v1/logs 91 | #logging.remote.url=http://edgex-support-logging:48061/api/v1/logs 92 | -------------------------------------------------------------------------------- /src/main/resources/banner.txt: -------------------------------------------------------------------------------- 1 | ___ _ __ __ ___ _ ___ _ 2 | | __|__| |__ _ ___\ \/ / ___ | _ \_ _| |___ ___ | __|_ _ __ _(_)_ _ ___ 3 | | _|/ _` / _` / -_)> < |___| | / || | / -_|_-< | _|| ' \/ _` | | ' \/ -_) 4 | |___\__,_\__, \___/_/\_\ |_|_\\_,_|_\___/__/ |___|_||_\__, |_|_||_\___| 5 | |___/ |___/ 6 | /******************************************************************************* 7 | * Copyright 2016-2017, Dell, Inc. All Rights Reserved. 8 | ******************************************************************************/ 9 | -------------------------------------------------------------------------------- /src/main/resources/bootstrap.properties: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Copyright 2017 Dell Inc. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | # @microservice: support-rulesengine 17 | # @author: Jim White, Dell 18 | # @version: 1.0.0 19 | ############################################################################### 20 | spring.application.name=edgex-support-rulesengine 21 | spring.cloud.consul.host=localhost 22 | spring.cloud.consul.config.profileSeparator=; 23 | spring.cloud.consul.enabled=false 24 | -------------------------------------------------------------------------------- /src/main/resources/rule-template.drl: -------------------------------------------------------------------------------- 1 | package org.edgexfoundry.rules; 2 | global org.edgexfoundry.engine.CommandExecutor executor; 3 | global org.edgexfoundry.support.logging.client.EdgeXLogger logger; 4 | import org.edgexfoundry.domain.core.Event; 5 | import org.edgexfoundry.domain.core.Reading; 6 | import java.util.Map; 7 | rule "${rulename}" 8 | when 9 | $e:Event($rlist: readings && device=="${conddeviceid}") 10 | <#if valuechecks??> 11 | <#assign idx = 0> 12 | <#list valuechecks as valuecheck> 13 | $r${idx}:Reading(name=="${valuecheck.parameter}" && ${valuecheck.operand1} ${valuecheck.operation} ${valuecheck.operand2}) from $rlist 14 | <#assign idx = idx + 1> 15 | 16 | 17 | then 18 | executor.fireCommand("${actiondeviceid}", "${actioncommandid}", "${commandbody}"); 19 | logger.info("${log}"); 20 | end -------------------------------------------------------------------------------- /src/test/java/org/edgexfoundry/controller/PingControllerTest.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2017 Dell Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | * 14 | * @microservice: support-rulesengine 15 | * @author: Jim White, Dell 16 | * @version: 1.0.0 17 | *******************************************************************************/ 18 | 19 | package org.edgexfoundry.controller; 20 | 21 | import static org.junit.Assert.assertEquals; 22 | 23 | import org.edgexfoundry.controller.impl.PingControllerImpl; 24 | import org.edgexfoundry.test.category.RequiresNone; 25 | import org.junit.Before; 26 | import org.junit.Test; 27 | import org.junit.experimental.categories.Category; 28 | 29 | @Category(RequiresNone.class) 30 | public class PingControllerTest { 31 | 32 | private static final String PING_RESP = "pong"; 33 | 34 | private PingControllerImpl controller; 35 | 36 | @Before 37 | public void setup() { 38 | controller = new PingControllerImpl(); 39 | } 40 | 41 | @Test 42 | public void testPing() { 43 | assertEquals("Ping controller ping test responded incorrectly", PING_RESP, controller.ping()); 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/test/java/org/edgexfoundry/controller/RuleEngineControllerTest.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2017 Dell Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | * 14 | * @microservice: support-rulesengine 15 | * @author: Jim White, Dell 16 | * @version: 1.0.0 17 | *******************************************************************************/ 18 | 19 | package org.edgexfoundry.controller; 20 | 21 | import static org.junit.Assert.assertEquals; 22 | import static org.junit.Assert.assertTrue; 23 | 24 | import java.io.IOException; 25 | import java.util.ArrayList; 26 | import java.util.List; 27 | 28 | import org.edgexfoundry.controller.impl.RuleEngineControllerImpl; 29 | import org.edgexfoundry.engine.RuleCreator; 30 | import org.edgexfoundry.engine.RuleEngine; 31 | import org.edgexfoundry.exception.controller.ServiceException; 32 | import org.edgexfoundry.rule.domain.Rule; 33 | import org.edgexfoundry.rule.domain.data.RuleData; 34 | import org.edgexfoundry.test.category.RequiresNone; 35 | import org.junit.Before; 36 | import org.junit.Test; 37 | import org.junit.experimental.categories.Category; 38 | import org.mockito.InjectMocks; 39 | import org.mockito.Mock; 40 | import org.mockito.Mockito; 41 | import org.mockito.MockitoAnnotations; 42 | 43 | import freemarker.template.TemplateException; 44 | 45 | @Category({RequiresNone.class}) 46 | public class RuleEngineControllerTest { 47 | 48 | private static final String TEST_RULE1 = "Rule1"; 49 | private static final String TEST_RULE2 = "Rule2"; 50 | 51 | @InjectMocks 52 | private RuleEngineControllerImpl controller; 53 | 54 | @Mock 55 | private RuleEngine engine; 56 | 57 | @Mock 58 | private RuleCreator creator; 59 | 60 | 61 | @Before 62 | public void setup() { 63 | MockitoAnnotations.initMocks(this); 64 | } 65 | 66 | @Test 67 | public void testGetRuleNames() { 68 | List ruleNames = new ArrayList<>(); 69 | ruleNames.add(TEST_RULE1); 70 | ruleNames.add(TEST_RULE2); 71 | Mockito.when(engine.getRulenames()).thenReturn(ruleNames); 72 | assertEquals("Rule names not returned as expected", ruleNames, controller.ruleNames()); 73 | } 74 | 75 | @Test(expected = ServiceException.class) 76 | public void testGetRuleNamesException() { 77 | Mockito.when(engine.getRulenames()).thenThrow(new RuntimeException()); 78 | controller.ruleNames(); 79 | } 80 | 81 | @Test 82 | public void testAddRule() { 83 | assertTrue("Rule was not added as expected", controller.addRule(RuleData.newTestInstance())); 84 | } 85 | 86 | @Test(expected = ServiceException.class) 87 | public void testAddRuleException() throws TemplateException, IOException { 88 | Rule rule = RuleData.newTestInstance(); 89 | Mockito.when(creator.createDroolRule(rule)).thenThrow(new RuntimeException()); 90 | controller.addRule(rule); 91 | } 92 | 93 | @Test 94 | public void testRemoveRule() { 95 | assertTrue("Rule was not removed as expected", controller.removeRule(TEST_RULE1)); 96 | } 97 | 98 | @Test(expected = ServiceException.class) 99 | public void testRemoveRuleException() throws IOException { 100 | Mockito.when(engine.removeRule(TEST_RULE1)).thenThrow(new RuntimeException()); 101 | controller.removeRule(TEST_RULE1); 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/test/java/org/edgexfoundry/controller/integration/RuleEngineControllerTest.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2017 Dell Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | * 14 | * @microservice: support-rulesengine 15 | * @author: Jim White, Dell 16 | * @version: 1.0.0 17 | *******************************************************************************/ 18 | 19 | package org.edgexfoundry.controller.integration; 20 | 21 | import static org.junit.Assert.assertEquals; 22 | import static org.junit.Assert.assertTrue; 23 | 24 | import java.io.IOException; 25 | import java.lang.reflect.Field; 26 | import java.nio.file.Files; 27 | import java.nio.file.Paths; 28 | import java.util.List; 29 | 30 | import org.edgexfoundry.Application; 31 | import org.edgexfoundry.controller.impl.RuleEngineControllerImpl; 32 | import org.edgexfoundry.engine.RuleEngine; 33 | import org.edgexfoundry.exception.controller.ServiceException; 34 | import org.edgexfoundry.rule.domain.Action; 35 | import org.edgexfoundry.rule.domain.Condition; 36 | import org.edgexfoundry.test.category.RequiresExportClientRunning; 37 | import org.edgexfoundry.test.category.RequiresMongoDB; 38 | import org.edgexfoundry.test.category.RequiresSpring; 39 | import org.edgexfoundry.test.category.RequiresWeb; 40 | import org.junit.After; 41 | import org.junit.Before; 42 | import org.junit.Test; 43 | import org.junit.experimental.categories.Category; 44 | import org.junit.runner.RunWith; 45 | import org.springframework.beans.factory.annotation.Autowired; 46 | import org.springframework.boot.test.SpringApplicationConfiguration; 47 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 48 | import org.springframework.test.context.web.WebAppConfiguration; 49 | 50 | /** 51 | * note: Make sure the /edgex/rules folder contains no drl files (or just the testname.drl file) 52 | * before starting this test 53 | */ 54 | @RunWith(SpringJUnit4ClassRunner.class) 55 | @SpringApplicationConfiguration(classes = Application.class) 56 | @WebAppConfiguration("src/test/resources") 57 | @Category({RequiresSpring.class, RequiresWeb.class, RequiresMongoDB.class, 58 | RequiresExportClientRunning.class}) 59 | public class RuleEngineControllerTest { 60 | 61 | private static final String TEST_RULE_NAME = "testname"; 62 | 63 | private static final String TEST_LOG = "testlog"; 64 | private static final String TEST_NAME = "testname"; 65 | private static final String TEST_BODY = "testbody"; 66 | private static final String TEST_CMD = "testcommand"; 67 | private static final String TEST_DEVICE = "testdevice"; 68 | 69 | @Autowired 70 | RuleEngineControllerImpl controller; 71 | 72 | @Autowired 73 | RuleEngine engine; 74 | 75 | @Before 76 | public void setup() throws IOException { 77 | String ruleContent = new String(Files.readAllBytes(Paths.get("./src/test/resources/rule.txt"))); 78 | engine.addRule(ruleContent, TEST_RULE_NAME); 79 | } 80 | 81 | @After 82 | public void cleanup() throws Exception { 83 | Class clazz = controller.getClass(); 84 | Field eng = clazz.getDeclaredField("engine"); 85 | eng.setAccessible(true); 86 | eng.set(controller, engine); 87 | 88 | List names = engine.getRulenames(); 89 | for (String name : names) { 90 | engine.removeRule(name); 91 | } 92 | } 93 | 94 | @Test 95 | public void testGetRuleNames() throws Exception { 96 | List names = controller.ruleNames(); 97 | assertEquals("Rule names not returning list with rule name", 1, names.size()); 98 | assertEquals("Rule name not in list of rule names", TEST_RULE_NAME, names.get(0)); 99 | } 100 | 101 | @Test(expected = ServiceException.class) 102 | public void testGetRuleNamesException() throws Exception { 103 | Class clazz = controller.getClass(); 104 | Field eng = clazz.getDeclaredField("engine"); 105 | eng.setAccessible(true); 106 | eng.set(controller, null); 107 | controller.ruleNames(); 108 | } 109 | 110 | @Test 111 | public void testAddRule() { 112 | assertTrue("New rule did not get added correctly", controller.addRule(createRule())); 113 | } 114 | 115 | @Test(expected = ServiceException.class) 116 | public void testAddRuleException() throws Exception { 117 | Class clazz = controller.getClass(); 118 | Field eng = clazz.getDeclaredField("engine"); 119 | eng.setAccessible(true); 120 | eng.set(controller, null); 121 | controller.addRule(createRule()); 122 | } 123 | 124 | @Test 125 | public void testRemoveRule() { 126 | assertTrue("Rule did not get removed correctly", controller.removeRule(TEST_RULE_NAME)); 127 | } 128 | 129 | @Test(expected = ServiceException.class) 130 | public void testRemoveRuleException() throws Exception { 131 | Class clazz = controller.getClass(); 132 | Field eng = clazz.getDeclaredField("engine"); 133 | eng.setAccessible(true); 134 | eng.set(controller, null); 135 | controller.removeRule(TEST_RULE_NAME); 136 | } 137 | 138 | private org.edgexfoundry.rule.domain.Rule createRule() { 139 | org.edgexfoundry.rule.domain.Rule rule = new org.edgexfoundry.rule.domain.Rule(); 140 | rule.setLog(TEST_LOG); 141 | rule.setName(TEST_NAME); 142 | Action action = new Action(); 143 | action.setBody(TEST_BODY); 144 | action.setCommand(TEST_CMD); 145 | action.setDevice(TEST_DEVICE); 146 | rule.setAction(action); 147 | Condition cond = new Condition(); 148 | cond.setDevice(TEST_DEVICE); 149 | rule.setCondition(cond); 150 | return rule; 151 | } 152 | 153 | } 154 | -------------------------------------------------------------------------------- /src/test/java/org/edgexfoundry/engine/CommandExecutorTest.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2017 Dell Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | * 14 | * @microservice: support-rulesengine 15 | * @author: Jim White, Dell 16 | * @version: 1.0.0 17 | *******************************************************************************/ 18 | 19 | package org.edgexfoundry.engine; 20 | 21 | import org.apache.commons.lang3.reflect.FieldUtils; 22 | import org.edgexfoundry.controller.CmdClient; 23 | import org.edgexfoundry.test.category.RequiresNone; 24 | import org.junit.Before; 25 | import org.junit.Test; 26 | import org.junit.experimental.categories.Category; 27 | import org.mockito.InjectMocks; 28 | import org.mockito.Mock; 29 | import org.mockito.Mockito; 30 | import org.mockito.MockitoAnnotations; 31 | 32 | @Category(RequiresNone.class) 33 | public class CommandExecutorTest { 34 | 35 | private static final String TEST_DEVICE = "test_device_id"; 36 | private static final String TEST_CMD = "test_command_id"; 37 | private static final String TEST_BODY = "test body"; 38 | 39 | @InjectMocks 40 | private CommandExecutor executor; 41 | 42 | @Mock 43 | private CmdClient client; 44 | 45 | @Before 46 | public void setup() { 47 | MockitoAnnotations.initMocks(this); 48 | } 49 | 50 | @Test 51 | public void testFireCommand() { 52 | executor.fireCommand(TEST_DEVICE, TEST_CMD, TEST_BODY); 53 | } 54 | 55 | @Test 56 | public void testFireCommandException() { 57 | Mockito.when(client.put(TEST_DEVICE, TEST_CMD, TEST_BODY)).thenThrow(new RuntimeException()); 58 | executor.fireCommand(TEST_DEVICE, TEST_CMD, TEST_BODY); 59 | } 60 | 61 | @Test 62 | public void testFireCommandNoClient() throws IllegalAccessException { 63 | FieldUtils.writeField(executor, "client", null, true); 64 | executor.fireCommand(TEST_DEVICE, TEST_CMD, TEST_BODY); 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /src/test/java/org/edgexfoundry/engine/RuleCreatorTest.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2017 Dell Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | * 14 | * @microservice: support-rulesengine 15 | * @author: Jim White, Dell 16 | * @version: 1.0.0 17 | *******************************************************************************/ 18 | 19 | package org.edgexfoundry.engine; 20 | 21 | import static org.junit.Assert.assertEquals; 22 | 23 | import java.io.IOException; 24 | import java.nio.file.Files; 25 | import java.nio.file.Paths; 26 | 27 | import org.apache.commons.lang3.reflect.FieldUtils; 28 | import org.edgexfoundry.rule.domain.Rule; 29 | import org.edgexfoundry.rule.domain.data.RuleData; 30 | import org.edgexfoundry.test.category.RequiresNone; 31 | import org.junit.Before; 32 | import org.junit.Test; 33 | import org.junit.experimental.categories.Category; 34 | import org.mockito.InjectMocks; 35 | import org.mockito.MockitoAnnotations; 36 | 37 | import freemarker.template.TemplateException; 38 | 39 | @Category(RequiresNone.class) 40 | public class RuleCreatorTest { 41 | 42 | private static final String FIELD_LOC = "templateLocation"; 43 | private static final String FIELD_NAME = "templateName"; 44 | private static final String FIELD_ENC = "templateEncoding"; 45 | private static final String TEMP_LOC = "./src/test/resources"; 46 | private static final String TEMP_NAME = "rule-template.drl"; 47 | private static final String TEMP_ENC = "UTF-8"; 48 | 49 | @InjectMocks 50 | private RuleCreator creator; 51 | 52 | private Rule rule; 53 | 54 | @Before 55 | public void setup() throws IllegalAccessException, IOException { 56 | MockitoAnnotations.initMocks(this); 57 | FieldUtils.writeField(creator, FIELD_LOC, TEMP_LOC, true); 58 | FieldUtils.writeField(creator, FIELD_NAME, TEMP_NAME, true); 59 | FieldUtils.writeField(creator, FIELD_ENC, TEMP_ENC, true); 60 | creator.init(); 61 | rule = RuleData.newTestInstance(); 62 | } 63 | 64 | @Test(expected = IOException.class) 65 | public void testInitException() throws NoSuchFieldException, SecurityException, 66 | IllegalArgumentException, IllegalAccessException, IOException { 67 | FieldUtils.writeField(creator, FIELD_LOC, "foobar", true); 68 | creator.init(); 69 | } 70 | 71 | @Test 72 | public void testCreateDroolRule() throws TemplateException, IOException { 73 | String ruleContent = new String(Files.readAllBytes(Paths.get("./src/test/resources/rule.txt"))); 74 | assertEquals("Drool file not created properly", ruleContent, creator.createDroolRule(rule)); 75 | } 76 | 77 | @Test(expected = IOException.class) 78 | public void testCreateDroolRuleIOException() 79 | throws IllegalAccessException, TemplateException, IOException { 80 | FieldUtils.writeField(creator, FIELD_NAME, "foobar", true); 81 | creator.createDroolRule(rule); 82 | } 83 | 84 | @Test(expected = TemplateException.class) 85 | public void testCreateDroolRuleTemplateException() throws TemplateException, IOException, 86 | NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException { 87 | rule.getAction().setDevice(null); 88 | creator.createDroolRule(rule); 89 | } 90 | 91 | @Test(expected = Exception.class) 92 | public void testCreateDroolRuleException() 93 | throws IllegalAccessException, TemplateException, IOException { 94 | FieldUtils.writeField(creator, "cfg", null, true); 95 | creator.createDroolRule(rule); 96 | } 97 | 98 | } 99 | -------------------------------------------------------------------------------- /src/test/java/org/edgexfoundry/engine/RunEngineTest.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2017 Dell Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | * 14 | * @microservice: support-rulesengine 15 | * @author: Jim White, Dell 16 | * @version: 1.0.0 17 | *******************************************************************************/ 18 | 19 | package org.edgexfoundry.engine; 20 | 21 | import org.apache.commons.lang3.reflect.FieldUtils; 22 | import org.edgexfoundry.test.category.RequiresNone; 23 | import org.junit.Before; 24 | import org.junit.experimental.categories.Category; 25 | import org.mockito.InjectMocks; 26 | import org.mockito.Mock; 27 | import org.mockito.MockitoAnnotations; 28 | 29 | @Category({RequiresNone.class}) 30 | public class RunEngineTest { 31 | 32 | private static final String TEST_RESOURCE_FILE_PATH = "./src/test/resources"; 33 | private static final String TEST_PACKAGE_NAME ="org.edgexfoundry.rules"; 34 | private static final String TEST_RULE_FILE_EXT=".drl"; 35 | 36 | @InjectMocks 37 | private RuleEngine engine; 38 | 39 | @Mock 40 | private CommandExecutor executor; 41 | 42 | @Before 43 | public void setup() throws IllegalAccessException { 44 | MockitoAnnotations.initMocks(this); 45 | FieldUtils.writeField(engine, "resourceFilePath", TEST_RESOURCE_FILE_PATH, true); 46 | FieldUtils.writeField(engine, "packageName", TEST_PACKAGE_NAME, true); 47 | FieldUtils.writeField(engine, "ruleFileExtension", TEST_RULE_FILE_EXT, true); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/test/java/org/edgexfoundry/engine/integration/RuleEngineTest.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2017 Dell Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | * 14 | * @microservice: support-rulesengine 15 | * @author: Jim White, Dell 16 | * @version: 1.0.0 17 | *******************************************************************************/ 18 | 19 | package org.edgexfoundry.engine.integration; 20 | 21 | import static org.junit.Assert.assertEquals; 22 | import static org.junit.Assert.assertTrue; 23 | 24 | import java.io.IOException; 25 | import java.nio.file.Files; 26 | import java.nio.file.Paths; 27 | import java.util.List; 28 | 29 | import org.edgexfoundry.Application; 30 | import org.edgexfoundry.domain.core.Event; 31 | import org.edgexfoundry.engine.RuleEngine; 32 | import org.edgexfoundry.test.category.RequiresExportClientRunning; 33 | import org.edgexfoundry.test.category.RequiresMongoDB; 34 | import org.edgexfoundry.test.category.RequiresSpring; 35 | import org.edgexfoundry.test.category.RequiresWeb; 36 | import org.edgexfoundry.test.data.EventData; 37 | import org.junit.After; 38 | import org.junit.Before; 39 | import org.junit.Test; 40 | import org.junit.experimental.categories.Category; 41 | import org.junit.runner.RunWith; 42 | import org.springframework.beans.factory.annotation.Autowired; 43 | import org.springframework.boot.test.SpringApplicationConfiguration; 44 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 45 | import org.springframework.test.context.web.WebAppConfiguration; 46 | 47 | /** 48 | * note: Make sure the /edgex/rules folder contains no drl files (or just the testname.drl file) 49 | * before starting this test 50 | */ 51 | @RunWith(SpringJUnit4ClassRunner.class) 52 | @SpringApplicationConfiguration(classes = Application.class) 53 | @WebAppConfiguration("src/test/resources") 54 | @Category({RequiresSpring.class, RequiresWeb.class, RequiresMongoDB.class, 55 | RequiresExportClientRunning.class}) 56 | public class RuleEngineTest { 57 | 58 | private static final String TEST_RULE_NAME = "testname"; 59 | private String ruleContent; 60 | 61 | @Autowired 62 | private RuleEngine engine; 63 | 64 | @Before 65 | public void setup() throws IOException { 66 | ruleContent = new String(Files.readAllBytes(Paths.get("./src/test/resources/rule.txt"))); 67 | engine.addRule(ruleContent, TEST_RULE_NAME); 68 | } 69 | 70 | @After 71 | public void cleanup() throws Exception { 72 | List names = engine.getRulenames(); 73 | for (String name : names) { 74 | engine.removeRule(name); 75 | } 76 | } 77 | 78 | @Test 79 | public void testAddRule() throws Exception { 80 | engine.addRule(ruleContent, TEST_RULE_NAME); 81 | String droolfile = engine.getResourceFilePath() + "/" + TEST_RULE_NAME + ".drl"; 82 | String content = new String(Files.readAllBytes(Paths.get(droolfile))); 83 | assertTrue("Rule did not get added properly", content.length() > 1); 84 | } 85 | 86 | @Test 87 | public void testRemoveRule() throws IOException { 88 | engine.removeRule(TEST_RULE_NAME); 89 | String droolfile = engine.getResourceFilePath() + "/" + TEST_RULE_NAME + ".drl"; 90 | String content = new String(Files.readAllBytes(Paths.get(droolfile))); 91 | assertTrue("Rule did not get removed properly", content.length() == 0); 92 | } 93 | 94 | @Test 95 | public void testGetRuleNames() throws Exception { 96 | assertTrue("No rules should exist", !engine.getRulenames().isEmpty()); 97 | assertEquals("Existing rule name not found", TEST_RULE_NAME, engine.getRulenames().get(0)); 98 | } 99 | 100 | @Test 101 | public void testExcecute() { 102 | Event event = EventData.newTestInstance(); 103 | engine.execute(event); 104 | } 105 | 106 | } 107 | -------------------------------------------------------------------------------- /src/test/java/org/edgexfoundry/export/registration/integration/web/ExportClientImplTest.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2017 Dell Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | * 14 | * @microservice: support-rulesengine 15 | * @author: Jim White, Dell 16 | * @version: 1.0.0 17 | *******************************************************************************/ 18 | 19 | package org.edgexfoundry.export.registration.integration.web; 20 | 21 | import static org.junit.Assert.assertFalse; 22 | import static org.junit.Assert.assertNotNull; 23 | import static org.junit.Assert.assertNull; 24 | import static org.junit.Assert.assertTrue; 25 | 26 | import org.edgexfoundry.Application; 27 | import org.edgexfoundry.domain.export.ExportFormat; 28 | import org.edgexfoundry.domain.export.ExportRegistration; 29 | import org.edgexfoundry.domain.meta.Addressable; 30 | import org.edgexfoundry.domain.meta.Protocol; 31 | import org.edgexfoundry.export.registration.ExportClientImpl; 32 | import org.edgexfoundry.test.category.RequiresExportClientRunning; 33 | import org.edgexfoundry.test.category.RequiresMongoDB; 34 | import org.edgexfoundry.test.category.RequiresSpring; 35 | import org.edgexfoundry.test.category.RequiresWeb; 36 | import org.junit.Test; 37 | import org.junit.experimental.categories.Category; 38 | import org.junit.runner.RunWith; 39 | import org.springframework.beans.factory.annotation.Autowired; 40 | import org.springframework.beans.factory.annotation.Value; 41 | import org.springframework.boot.test.SpringApplicationConfiguration; 42 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 43 | import org.springframework.test.context.web.WebAppConfiguration; 44 | 45 | @RunWith(SpringJUnit4ClassRunner.class) 46 | @SpringApplicationConfiguration(classes = Application.class) 47 | @WebAppConfiguration("src/test/resources") 48 | @Category({RequiresSpring.class, RequiresWeb.class, RequiresMongoDB.class, 49 | RequiresExportClientRunning.class}) 50 | public class ExportClientImplTest { 51 | 52 | private static final String TEST_CLIENT_NAME = "testclient"; 53 | private static final ExportFormat TEST_FORMAT = ExportFormat.SERIALIZED; 54 | private static final boolean TEST_ENABLE = true; 55 | private static final Addressable TEST_ADDR = 56 | new Addressable("testaddress", Protocol.ZMQ, "", "", 0); 57 | 58 | @Autowired 59 | private ExportClientImpl client; 60 | 61 | @Value("${export.client.registration.name}") 62 | private String clientName; 63 | 64 | @Test 65 | public void testIsRegistered() { 66 | assertTrue(client.isRegistered()); 67 | } 68 | 69 | @Test 70 | public void testRegisterRulesEngine() { 71 | assertTrue(client.deleteByName(clientName)); 72 | assertTrue(client.registerRulesEngine()); 73 | } 74 | 75 | @Test 76 | public void testExportRegistrationByNameNoneFound() { 77 | assertNull(client.exportRegistrationByName("foo")); 78 | } 79 | 80 | @Test 81 | public void testExportRegistrationByName() { 82 | assertNotNull(client.exportRegistrationByName(clientName)); 83 | } 84 | 85 | @Test 86 | // also tests delete by id 87 | public void testRegister() { 88 | String id = client.register(newInstance()); 89 | assertNotNull(id); 90 | assertTrue(client.delete(id)); 91 | } 92 | 93 | @Test 94 | public void testDeleteByIdNoneFound() { 95 | assertFalse(client.delete("foobar")); 96 | } 97 | 98 | @Test 99 | public void testDeleteByName() { 100 | client.register(newInstance()); 101 | assertTrue(client.deleteByName(TEST_CLIENT_NAME)); 102 | } 103 | 104 | @Test 105 | public void testDeleteByNameNotFound() { 106 | assertFalse(client.deleteByName("foo")); 107 | } 108 | 109 | private ExportRegistration newInstance() { 110 | ExportRegistration registration = new ExportRegistration(); 111 | registration.setName(TEST_CLIENT_NAME); 112 | registration.setFormat(TEST_FORMAT); 113 | registration.setEnable(TEST_ENABLE); 114 | registration.setAddressable(TEST_ADDR); 115 | return registration; 116 | } 117 | 118 | } 119 | -------------------------------------------------------------------------------- /src/test/java/org/edgexfoundry/export/registration/integration/web/LocalErrorControllerTest.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2017 Dell Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | * 14 | * @microservice: support-rulesengine 15 | * @author: Jim White, Dell 16 | * @version: 1.0.0 17 | *******************************************************************************/ 18 | 19 | package org.edgexfoundry.export.registration.integration.web; 20 | 21 | import static org.junit.Assert.assertEquals; 22 | 23 | import org.edgexfoundry.Application; 24 | import org.edgexfoundry.controller.impl.LocalErrorController; 25 | import org.edgexfoundry.test.category.RequiresExportClientRunning; 26 | import org.edgexfoundry.test.category.RequiresMongoDB; 27 | import org.edgexfoundry.test.category.RequiresSpring; 28 | import org.edgexfoundry.test.category.RequiresWeb; 29 | import org.junit.Before; 30 | import org.junit.Test; 31 | import org.junit.experimental.categories.Category; 32 | import org.junit.runner.RunWith; 33 | import org.springframework.beans.factory.annotation.Autowired; 34 | import org.springframework.boot.test.SpringApplicationConfiguration; 35 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 36 | import org.springframework.test.context.web.WebAppConfiguration; 37 | 38 | @RunWith(SpringJUnit4ClassRunner.class) 39 | @SpringApplicationConfiguration(classes = Application.class) 40 | @WebAppConfiguration("src/test/resources") 41 | @Category({RequiresSpring.class, RequiresWeb.class, RequiresMongoDB.class, 42 | RequiresExportClientRunning.class}) 43 | public class LocalErrorControllerTest { 44 | 45 | @Autowired 46 | private LocalErrorController controller; 47 | 48 | @Before 49 | public void setup() { 50 | // controller = new LocalErrorController(); 51 | } 52 | 53 | @Test 54 | public void testGetErrorPath() { 55 | assertEquals("/error", controller.getErrorPath()); 56 | } 57 | 58 | @Test 59 | public void testError() { 60 | TestHttpServletRequest request = new TestHttpServletRequest(); 61 | TestHttpServletResponse response = new TestHttpServletResponse(); 62 | controller.error(request, response); 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /src/test/java/org/edgexfoundry/export/registration/integration/web/TestHttpServletRequest.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2017 Dell Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | * 14 | * @microservice: support-rulesengine 15 | * @author: Jim White, Dell 16 | * @version: 1.0.0 17 | *******************************************************************************/ 18 | 19 | package org.edgexfoundry.export.registration.integration.web; 20 | 21 | import java.io.BufferedReader; 22 | import java.io.IOException; 23 | import java.io.UnsupportedEncodingException; 24 | import java.security.Principal; 25 | import java.util.Collection; 26 | import java.util.Enumeration; 27 | import java.util.Locale; 28 | import java.util.Map; 29 | 30 | import javax.servlet.AsyncContext; 31 | import javax.servlet.DispatcherType; 32 | import javax.servlet.RequestDispatcher; 33 | import javax.servlet.ServletContext; 34 | import javax.servlet.ServletException; 35 | import javax.servlet.ServletInputStream; 36 | import javax.servlet.ServletRequest; 37 | import javax.servlet.ServletResponse; 38 | import javax.servlet.http.Cookie; 39 | import javax.servlet.http.HttpServletRequest; 40 | import javax.servlet.http.HttpServletResponse; 41 | import javax.servlet.http.HttpSession; 42 | import javax.servlet.http.HttpUpgradeHandler; 43 | import javax.servlet.http.Part; 44 | 45 | public class TestHttpServletRequest implements HttpServletRequest { 46 | 47 | @Override 48 | public AsyncContext getAsyncContext() { 49 | return null; 50 | } 51 | 52 | @Override 53 | public Object getAttribute(String arg0) { 54 | return null; 55 | } 56 | 57 | @Override 58 | public Enumeration getAttributeNames() { 59 | return null; 60 | } 61 | 62 | @Override 63 | public String getCharacterEncoding() { 64 | return null; 65 | } 66 | 67 | @Override 68 | public int getContentLength() { 69 | return 0; 70 | } 71 | 72 | @Override 73 | public long getContentLengthLong() { 74 | return 0; 75 | } 76 | 77 | @Override 78 | public String getContentType() { 79 | return null; 80 | } 81 | 82 | @Override 83 | public DispatcherType getDispatcherType() { 84 | return null; 85 | } 86 | 87 | @Override 88 | public ServletInputStream getInputStream() throws IOException { 89 | return null; 90 | } 91 | 92 | @Override 93 | public String getLocalAddr() { 94 | return null; 95 | } 96 | 97 | @Override 98 | public String getLocalName() { 99 | return null; 100 | } 101 | 102 | @Override 103 | public int getLocalPort() { 104 | return 0; 105 | } 106 | 107 | @Override 108 | public Locale getLocale() { 109 | return null; 110 | } 111 | 112 | @Override 113 | public Enumeration getLocales() { 114 | return null; 115 | } 116 | 117 | @Override 118 | public String getParameter(String arg0) { 119 | return null; 120 | } 121 | 122 | @Override 123 | public Map getParameterMap() { 124 | return null; 125 | } 126 | 127 | @Override 128 | public Enumeration getParameterNames() { 129 | return null; 130 | } 131 | 132 | @Override 133 | public String[] getParameterValues(String arg0) { 134 | return null; 135 | } 136 | 137 | @Override 138 | public String getProtocol() { 139 | return null; 140 | } 141 | 142 | @Override 143 | public BufferedReader getReader() throws IOException { 144 | return null; 145 | } 146 | 147 | @Override 148 | public String getRealPath(String arg0) { 149 | return null; 150 | } 151 | 152 | @Override 153 | public String getRemoteAddr() { 154 | return null; 155 | } 156 | 157 | @Override 158 | public String getRemoteHost() { 159 | return null; 160 | } 161 | 162 | @Override 163 | public int getRemotePort() { 164 | return 0; 165 | } 166 | 167 | @Override 168 | public RequestDispatcher getRequestDispatcher(String arg0) { 169 | return null; 170 | } 171 | 172 | @Override 173 | public String getScheme() { 174 | return null; 175 | } 176 | 177 | @Override 178 | public String getServerName() { 179 | return null; 180 | } 181 | 182 | @Override 183 | public int getServerPort() { 184 | return 0; 185 | } 186 | 187 | @Override 188 | public ServletContext getServletContext() { 189 | return null; 190 | } 191 | 192 | @Override 193 | public boolean isAsyncStarted() { 194 | return false; 195 | } 196 | 197 | @Override 198 | public boolean isAsyncSupported() { 199 | return false; 200 | } 201 | 202 | @Override 203 | public boolean isSecure() { 204 | return false; 205 | } 206 | 207 | @Override 208 | public void removeAttribute(String arg0) { 209 | 210 | } 211 | 212 | @Override 213 | public void setAttribute(String arg0, Object arg1) { 214 | 215 | } 216 | 217 | @Override 218 | public void setCharacterEncoding(String arg0) throws UnsupportedEncodingException { 219 | 220 | } 221 | 222 | @Override 223 | public AsyncContext startAsync() throws IllegalStateException { 224 | return null; 225 | } 226 | 227 | @Override 228 | public AsyncContext startAsync(ServletRequest arg0, ServletResponse arg1) 229 | throws IllegalStateException { 230 | return null; 231 | } 232 | 233 | @Override 234 | public boolean authenticate(HttpServletResponse arg0) throws IOException, ServletException { 235 | return false; 236 | } 237 | 238 | @Override 239 | public String changeSessionId() { 240 | return null; 241 | } 242 | 243 | @Override 244 | public String getAuthType() { 245 | return null; 246 | } 247 | 248 | @Override 249 | public String getContextPath() { 250 | return null; 251 | } 252 | 253 | @Override 254 | public Cookie[] getCookies() { 255 | return null; 256 | } 257 | 258 | @Override 259 | public long getDateHeader(String arg0) { 260 | return 0; 261 | } 262 | 263 | @Override 264 | public String getHeader(String arg0) { 265 | return null; 266 | } 267 | 268 | @Override 269 | public Enumeration getHeaderNames() { 270 | return null; 271 | } 272 | 273 | @Override 274 | public Enumeration getHeaders(String arg0) { 275 | return null; 276 | } 277 | 278 | @Override 279 | public int getIntHeader(String arg0) { 280 | return 0; 281 | } 282 | 283 | @Override 284 | public String getMethod() { 285 | return null; 286 | } 287 | 288 | @Override 289 | public Part getPart(String arg0) throws IOException, ServletException { 290 | return null; 291 | } 292 | 293 | @Override 294 | public Collection getParts() throws IOException, ServletException { 295 | return null; 296 | } 297 | 298 | @Override 299 | public String getPathInfo() { 300 | return null; 301 | } 302 | 303 | @Override 304 | public String getPathTranslated() { 305 | return null; 306 | } 307 | 308 | @Override 309 | public String getQueryString() { 310 | return null; 311 | } 312 | 313 | @Override 314 | public String getRemoteUser() { 315 | return null; 316 | } 317 | 318 | @Override 319 | public String getRequestURI() { 320 | return null; 321 | } 322 | 323 | @Override 324 | public StringBuffer getRequestURL() { 325 | return null; 326 | } 327 | 328 | @Override 329 | public String getRequestedSessionId() { 330 | return null; 331 | } 332 | 333 | @Override 334 | public String getServletPath() { 335 | return null; 336 | } 337 | 338 | @Override 339 | public HttpSession getSession() { 340 | return null; 341 | } 342 | 343 | @Override 344 | public HttpSession getSession(boolean arg0) { 345 | return null; 346 | } 347 | 348 | @Override 349 | public Principal getUserPrincipal() { 350 | return null; 351 | } 352 | 353 | @Override 354 | public boolean isRequestedSessionIdFromCookie() { 355 | return false; 356 | } 357 | 358 | @Override 359 | public boolean isRequestedSessionIdFromURL() { 360 | return false; 361 | } 362 | 363 | @Override 364 | public boolean isRequestedSessionIdFromUrl() { 365 | return false; 366 | } 367 | 368 | @Override 369 | public boolean isRequestedSessionIdValid() { 370 | return false; 371 | } 372 | 373 | @Override 374 | public boolean isUserInRole(String arg0) { 375 | return false; 376 | } 377 | 378 | @Override 379 | public void login(String arg0, String arg1) throws ServletException { 380 | 381 | } 382 | 383 | @Override 384 | public void logout() throws ServletException { 385 | 386 | } 387 | 388 | @Override 389 | public T upgrade(Class arg0) 390 | throws IOException, ServletException { 391 | return null; 392 | } 393 | 394 | } 395 | -------------------------------------------------------------------------------- /src/test/java/org/edgexfoundry/export/registration/integration/web/TestHttpServletResponse.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2017 Dell Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | * 14 | * @microservice: support-rulesengine 15 | * @author: Jim White, Dell 16 | * @version: 1.0.0 17 | *******************************************************************************/ 18 | 19 | package org.edgexfoundry.export.registration.integration.web; 20 | 21 | import java.io.IOException; 22 | import java.io.PrintWriter; 23 | import java.util.Collection; 24 | import java.util.Locale; 25 | 26 | import javax.servlet.ServletOutputStream; 27 | import javax.servlet.http.Cookie; 28 | import javax.servlet.http.HttpServletResponse; 29 | 30 | public class TestHttpServletResponse implements HttpServletResponse { 31 | 32 | @Override 33 | public void flushBuffer() throws IOException {} 34 | 35 | @Override 36 | public int getBufferSize() { 37 | return 0; 38 | } 39 | 40 | @Override 41 | public String getCharacterEncoding() { 42 | return null; 43 | } 44 | 45 | @Override 46 | public String getContentType() { 47 | return null; 48 | } 49 | 50 | @Override 51 | public Locale getLocale() { 52 | return null; 53 | } 54 | 55 | @Override 56 | public ServletOutputStream getOutputStream() throws IOException { 57 | return null; 58 | } 59 | 60 | @Override 61 | public PrintWriter getWriter() throws IOException { 62 | return null; 63 | } 64 | 65 | @Override 66 | public boolean isCommitted() { 67 | return false; 68 | } 69 | 70 | @Override 71 | public void reset() {} 72 | 73 | @Override 74 | public void resetBuffer() { 75 | 76 | } 77 | 78 | @Override 79 | public void setBufferSize(int arg0) { 80 | 81 | } 82 | 83 | @Override 84 | public void setCharacterEncoding(String arg0) { 85 | 86 | } 87 | 88 | @Override 89 | public void setContentLength(int arg0) { 90 | 91 | } 92 | 93 | @Override 94 | public void setContentLengthLong(long arg0) { 95 | 96 | } 97 | 98 | @Override 99 | public void setContentType(String arg0) { 100 | 101 | } 102 | 103 | @Override 104 | public void setLocale(Locale arg0) {} 105 | 106 | @Override 107 | public void addCookie(Cookie arg0) {} 108 | 109 | @Override 110 | public void addDateHeader(String arg0, long arg1) {} 111 | 112 | @Override 113 | public void addHeader(String arg0, String arg1) {} 114 | 115 | @Override 116 | public void addIntHeader(String arg0, int arg1) {} 117 | 118 | @Override 119 | public boolean containsHeader(String arg0) { 120 | return false; 121 | } 122 | 123 | @Override 124 | public String encodeRedirectURL(String arg0) { 125 | return null; 126 | } 127 | 128 | @Override 129 | public String encodeRedirectUrl(String arg0) { 130 | return null; 131 | } 132 | 133 | @Override 134 | public String encodeURL(String arg0) { 135 | return null; 136 | } 137 | 138 | @Override 139 | public String encodeUrl(String arg0) { 140 | return null; 141 | } 142 | 143 | @Override 144 | public String getHeader(String arg0) { 145 | return null; 146 | } 147 | 148 | @Override 149 | public Collection getHeaderNames() { 150 | return null; 151 | } 152 | 153 | @Override 154 | public Collection getHeaders(String arg0) { 155 | return null; 156 | } 157 | 158 | @Override 159 | public int getStatus() { 160 | return 0; 161 | } 162 | 163 | @Override 164 | public void sendError(int arg0) throws IOException { 165 | 166 | } 167 | 168 | @Override 169 | public void sendError(int arg0, String arg1) throws IOException { 170 | 171 | } 172 | 173 | @Override 174 | public void sendRedirect(String arg0) throws IOException { 175 | 176 | } 177 | 178 | @Override 179 | public void setDateHeader(String arg0, long arg1) { 180 | 181 | } 182 | 183 | @Override 184 | public void setHeader(String arg0, String arg1) { 185 | 186 | } 187 | 188 | @Override 189 | public void setIntHeader(String arg0, int arg1) { 190 | 191 | } 192 | 193 | @Override 194 | public void setStatus(int arg0) { 195 | 196 | } 197 | 198 | @Override 199 | public void setStatus(int arg0, String arg1) { 200 | 201 | } 202 | 203 | } 204 | -------------------------------------------------------------------------------- /src/test/java/org/edgexfoundry/messaging/ZeroMQEventSubscriberTest.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2017 Dell Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | * 14 | * @microservice: support-rulesengine 15 | * @author: Jim White, Dell 16 | * @version: 1.0.0 17 | *******************************************************************************/ 18 | 19 | package org.edgexfoundry.messaging; 20 | 21 | import static org.junit.Assert.assertEquals; 22 | 23 | import org.edgexfoundry.test.category.RequiresNone; 24 | import org.junit.Before; 25 | import org.junit.Test; 26 | import org.junit.experimental.categories.Category; 27 | 28 | @Category({RequiresNone.class}) 29 | public class ZeroMQEventSubscriberTest { 30 | 31 | private ZeroMQEventSubscriber subscriber; 32 | 33 | @Before 34 | public void setup() { 35 | subscriber = new ZeroMQEventSubscriber(); 36 | } 37 | 38 | @Test 39 | public void testSetters() { 40 | subscriber.setZeromqAddressPort("foobar"); 41 | subscriber.setZeromqAddress("foobar"); 42 | assertEquals("foobar", subscriber.getZeromqAddress()); 43 | assertEquals("foobar", subscriber.getZeromqAddressPort()); 44 | } 45 | 46 | // when it cant recieve it will keep trying and eventually overflow 47 | @Test(expected = StackOverflowError.class) 48 | public void testRecieve() { 49 | subscriber.setZeromqAddressPort("foobar"); 50 | subscriber.setZeromqAddress("foobar"); 51 | subscriber.receive(); 52 | 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/test/java/org/edgexfoundry/rule/domain/data/ActionData.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2017 Dell Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | * 14 | * @microservice: support-rulesengine 15 | * @author: Jim White, Dell 16 | * @version: 1.0.0 17 | *******************************************************************************/ 18 | 19 | package org.edgexfoundry.rule.domain.data; 20 | 21 | import org.edgexfoundry.rule.domain.Action; 22 | 23 | public interface ActionData { 24 | 25 | static final String TEST_BODY = "{\\\"value\\\":\\\"300\\\"}"; 26 | static final String TEST_CMD = "12345edf"; 27 | static final String TEST_DEVICE = "56789abc"; 28 | 29 | 30 | static Action newTestInstance() { 31 | Action action = new Action(); 32 | action.setBody(TEST_BODY); 33 | action.setCommand(TEST_CMD); 34 | action.setDevice(TEST_DEVICE); 35 | return action; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/test/java/org/edgexfoundry/rule/domain/data/ConditionData.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2017 Dell Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | * 14 | * @microservice: support-rulesengine 15 | * @author: Jim White, Dell 16 | * @version: 1.0.0 17 | *******************************************************************************/ 18 | 19 | package org.edgexfoundry.rule.domain.data; 20 | 21 | import java.util.ArrayList; 22 | import java.util.List; 23 | 24 | import org.edgexfoundry.rule.domain.Condition; 25 | import org.edgexfoundry.rule.domain.ValueCheck; 26 | 27 | public interface ConditionData { 28 | 29 | static final String TEST_DEVICE = "56789abc"; 30 | 31 | static Condition newTestCondition() { 32 | Condition condition = new Condition(); 33 | List checks = new ArrayList<>(); 34 | checks.add(ValueCheckData.newTestInstance()); 35 | condition.setChecks(checks); 36 | condition.setDevice(TEST_DEVICE); 37 | return condition; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/test/java/org/edgexfoundry/rule/domain/data/RuleData.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2017 Dell Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | * 14 | * @microservice: support-rulesengine 15 | * @author: Jim White, Dell 16 | * @version: 1.0.0 17 | *******************************************************************************/ 18 | 19 | package org.edgexfoundry.rule.domain.data; 20 | 21 | import org.edgexfoundry.rule.domain.Rule; 22 | 23 | public interface RuleData { 24 | 25 | static final String TEST_RULE1 = "Rule1"; 26 | static final String TEST_RULE2 = "Rule2"; 27 | static final String TEST_LOG = "slow motor down"; 28 | 29 | static Rule newTestInstance() { 30 | Rule rule = new Rule(); 31 | rule.setAction(ActionData.newTestInstance()); 32 | rule.setCondition(ConditionData.newTestCondition()); 33 | rule.setLog(TEST_LOG); 34 | rule.setName(TEST_RULE1); 35 | return rule; 36 | } 37 | 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/test/java/org/edgexfoundry/rule/domain/data/ValueCheckData.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2017 Dell Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | * 14 | * @microservice: support-rulesengine 15 | * @author: Jim White, Dell 16 | * @version: 1.0.0 17 | *******************************************************************************/ 18 | 19 | package org.edgexfoundry.rule.domain.data; 20 | 21 | import org.edgexfoundry.rule.domain.ValueCheck; 22 | 23 | public interface ValueCheckData { 24 | 25 | static final String TEST_PARAM = "rpm"; 26 | static final String TEST_OP1 = "Integer.parseInt(value)"; 27 | static final String TEST_OP2 = "900"; 28 | static final String TEST_OPERATION = ">"; 29 | 30 | static ValueCheck newTestInstance() { 31 | ValueCheck check = new ValueCheck(); 32 | check.setOperand1(TEST_OP1); 33 | check.setOperand2(TEST_OP2); 34 | check.setOperation(TEST_OPERATION); 35 | check.setParameter(TEST_PARAM); 36 | return check; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/test/resources/bad-rule-template.drl: -------------------------------------------------------------------------------- 1 | package com.foo.bar; 2 | package org.edgexfoundry.rules; 3 | global org.edgexfoundry.engine.CommandExecutor executor; 4 | global org.slf4j.Logger logger; 5 | import org.edgexfoundry.domain.core.Event; 6 | import org.edgexfoundry.domain.core.Reading; 7 | import java.util.Map; 8 | rule "${name}" 9 | when 10 | $e:Event($rlist: readings && device=="${conddevice}") 11 | then 12 | executor.fireCommand("${actiondevice}", "${command}", "${body}"); 13 | logger.info("${log}"); 14 | end -------------------------------------------------------------------------------- /src/test/resources/raml/support-rulesengine.raml: -------------------------------------------------------------------------------- 1 | #%RAML 0.8 2 | title: support-rulesengine 3 | version: "1.0.0" 4 | baseUri: "http://localhost:48075/api/v1" 5 | schemas: 6 | - 7 | rule: '{"type":"object","$schema":"http://json-schema.org/draft-03/schema#","description":"EdgeX Support Rules Engine rule","title":"rule","properties":{"name":{"type":"string","required":true,"title":"name"}, "action":{"type":"object","properties":{"device":{"type":"string","required":true,"title":"device"},"command":{"type":"string","required":true,"title":"command"},"body":{"type":"string","required":true,"title":"body"}}}, "condition":{"type":"object","properties":{"device":{"type":"string","required":true,"title":"device"},"checks":{"type":"array","required":false,"title":"checks","items":{"type":"object","properties":{"parameter":{"type":"string","required":false,"title":"parameter"},"operand1":{"type":"string","required":false,"title":"operand1"},"operation":{"type":"string","required":false,"title":"operation"},"operand2":{"type":"string","required":false,"title":"operand2"}}},"uniqueItems":false}}}, "log":{"type":"string","required":false,"title":"log"}}}' 8 | /rule: 9 | displayName: rules 10 | description: example - http://localhost:48075/api/v1/rule 11 | post: 12 | description: Add a new rule. ServcieException (HTTP 503) for unknown or unanticipated issues. 13 | displayName: add a rule 14 | body: 15 | application/json: 16 | schema: rule 17 | example: '{"name":"motortoofastsignal", "condition": {"device":"562114e9e4b0385849b96cd8","checks":[ {"parameter":"RPM", "operand1":"Integer.parseInt(value)", "operation":">","operand2":"1200" } ] }, "action" : {"device":"56325f7ee4b05eaae5a89ce1","command":"56325f6de4b05eaae5a89cdc","body":"{\\\"value\\\":\\\"3\\\"}"},"log":"Patlite warning triggered for engine speed too high" }' 18 | responses: 19 | "200": 20 | description: boolean indicating success of adding the new rule 21 | "503": 22 | description: for unknown or unanticipated issues 23 | get: 24 | description: Return all rule names. ServcieException (HTTP 503) for unknown or unanticipated issues. 25 | displayName: get all rule names 26 | responses: 27 | "200": 28 | description: list of strings 29 | body: 30 | application/json: 31 | example: '["motortoofastsignal"]' 32 | "503": 33 | description: for unknown or unanticipated issues. 34 | /rule/name/{rulename}: 35 | displayName: rule (by name) 36 | description: example - http://localhost:48075/api/v1/rule/name/temptoohi (where temptoohi is the name of a rule) 37 | uriParameters: 38 | rulename: 39 | displayName: rulename 40 | description: Unique name of the rule 41 | type: string 42 | required: true 43 | repeat: false 44 | delete: 45 | description: Remove the rule designated by name. ServcieException (HTTP 503) for unknown or unanticipated issues. 46 | displayName: remove a rule by name 47 | responses: 48 | "200": 49 | description: boolean indicating success of the remove operation 50 | "503": 51 | description: for unknown or unanticipated issues. 52 | /ping: 53 | displayName: Ping Resource 54 | description: example - http://localhost:48075/api/v1/ping 55 | get: 56 | description: Test service providing an indication that the service is available. 57 | displayName: service up check 58 | responses: 59 | "200": 60 | description: return value of "pong" 61 | "503": 62 | description: for unknown or unanticipated issues 63 | -------------------------------------------------------------------------------- /src/test/resources/rule-template.drl: -------------------------------------------------------------------------------- 1 | package org.edgexfoundry.rules; 2 | global org.edgexfoundry.engine.CommandExecutor executor; 3 | global org.slf4j.Logger logger; 4 | import org.edgexfoundry.domain.core.Event; 5 | import org.edgexfoundry.domain.core.Reading; 6 | import java.util.Map; 7 | rule "${rulename}" 8 | when 9 | $e:Event($rlist: readings && device=="${conddeviceid}") 10 | <#if valuechecks??> 11 | <#assign idx = 0> 12 | <#list valuechecks as valuecheck> 13 | $r${idx}:Reading(name=="${valuecheck.parameter}" && ${valuecheck.operand1} ${valuecheck.operation} ${valuecheck.operand2}) from $rlist 14 | <#assign idx = idx + 1> 15 | 16 | 17 | then 18 | executor.fireCommand("${actiondeviceid}", "${actioncommandid}", "${commandbody}"); 19 | logger.info("${log}"); 20 | end -------------------------------------------------------------------------------- /src/test/resources/rule.txt: -------------------------------------------------------------------------------- 1 | package org.edgexfoundry.rules; 2 | global org.edgexfoundry.engine.CommandExecutor executor; 3 | global org.slf4j.Logger logger; 4 | import org.edgexfoundry.domain.core.Event; 5 | import org.edgexfoundry.domain.core.Reading; 6 | import java.util.Map; 7 | rule "Rule1" 8 | when 9 | $e:Event($rlist: readings && device=="56789abc") 10 | $r0:Reading(name=="rpm" && Integer.parseInt(value) > 900) from $rlist 11 | then 12 | executor.fireCommand("56789abc", "12345edf", "{\"value\":\"300\"}"); 13 | logger.info("slow motor down"); 14 | end --------------------------------------------------------------------------------