├── .classpath ├── .gitignore ├── .project ├── .settings └── .gitignore ├── LICENSE ├── README.md ├── pom.xml ├── reference ├── rule-mysql.sql ├── rule-oracle.sql ├── table-1.png └── table-2.png └── src └── main ├── java └── tech │ └── kiwa │ └── engine │ ├── EngineService.java │ ├── component │ ├── AbstractCommand.java │ ├── AbstractComparisonOperator.java │ ├── AbstractResultLogRecorder.java │ ├── AbstractRuleItem.java │ ├── AbstractRuleReader.java │ ├── drools │ │ ├── ConstraintCreator.java │ │ ├── DeclareCreator.java │ │ ├── DeclareInterface.java │ │ ├── DroolsBuilder.java │ │ ├── DroolsPartsCreator.java │ │ ├── DroolsPartsObject.java │ │ ├── FunctionCreator.java │ │ ├── GlobalCreator.java │ │ ├── ImportCreator.java │ │ ├── LocalCreator.java │ │ ├── PackageCreator.java │ │ ├── QueryCreator.java │ │ └── RuleCreator.java │ └── impl │ │ ├── ComplexRuleExecutor.java │ │ ├── DBRuleReader.java │ │ ├── DefaultRuleExecutor.java │ │ ├── DroolsRuleExecutor.java │ │ ├── DroolsRuleReader.java │ │ └── XMLRuleReader.java │ ├── entity │ ├── EngineRunResult.java │ ├── ItemExecutedResult.java │ ├── RESULT.java │ └── RuleItem.java │ ├── exception │ ├── EmptyResultSetException.java │ └── RuleEngineException.java │ ├── framework │ ├── Component.java │ ├── DBAccesser.java │ ├── FactoryMethod.java │ ├── OperatorFactory.java │ └── ResultLogFactory.java │ ├── sample │ ├── BlackListShow.java │ └── Student.java │ └── utility │ ├── DirectDBAccesser.java │ ├── JavaStringCompiler.java │ ├── MemoryClassLoader.java │ ├── MemoryJavaFileManager.java │ ├── PropertyUtil.java │ ├── SpringContextHelper.java │ └── SpringDBAccesser.java └── resources ├── druid.properties ├── ruleEngine.properties ├── ruleconfig.xml ├── sample.drl └── studentrule.xml /.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | /.setttings/ 3 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | RuleEngine 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.wst.common.project.facet.core.builder 10 | 11 | 12 | 13 | 14 | org.eclipse.jdt.core.javabuilder 15 | 16 | 17 | 18 | 19 | org.eclipse.wst.validation.validationbuilder 20 | 21 | 22 | 23 | 24 | org.eclipse.m2e.core.maven2Builder 25 | 26 | 27 | 28 | 29 | 30 | org.eclipse.jem.workbench.JavaEMFNature 31 | org.eclipse.wst.common.modulecore.ModuleCoreNature 32 | org.eclipse.jdt.core.javanature 33 | org.eclipse.m2e.core.maven2Nature 34 | org.eclipse.wst.common.project.facet.core.nature 35 | 36 | 37 | -------------------------------------------------------------------------------- /.settings/.gitignore: -------------------------------------------------------------------------------- 1 | /org.eclipse.core.resources.prefs 2 | /org.eclipse.jdt.core.prefs 3 | /org.eclipse.m2e.core.prefs 4 | /org.eclipse.wst.common.component 5 | /org.eclipse.wst.common.project.facet.core.xml 6 | /org.eclipse.wst.validation.prefs 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 |   Copyright [Hale.Li] [hale2000@163.com] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### RuleEngine 2 | one of the best simple rule engine, easy to use, can define different format of the rule, such as xml, drools, database. 3 | 4 | ###使用方法 5 | 6 | #1, 在POM.XML文件中添加下面的内容. 7 | 8 | 9 | com.github.hale-lee 10 | RuleEngine 11 | 0.2.0 12 | 13 | 14 | 15 | #2, 配置ruleEngine.properties文件 16 | 17 | rule.reader=xml/drools/database 18 | 19 |   -2.1 若选择xml格式的规则文件,那么rule.reader=xml,此时需要设置xml.rule.filename=ruleconfig.xml 20 |    
21 |   -2.2 若选择将规则文件定义存放在数据库中,那么设置rule.reader=database,此时需要设置db.rule.table=表名  (存放规则定义的表格,其格式可以参考SQL文件夹下的rule-mysql.sql或rule-oracle.sql)同时需要配置或者引用现有框架的jdbc配置, RuleEngine支持直接的jdbc数据库,也支持druid的数据库连接池,还可以直接引用外部框架的的数据库链接,比如spring-mvc的数据库链接。 22 |      
23 |   -2.3 若选择使用drools格式的规则文件,则设置rule.reader=drools,同时需要设置drools.rule.filename=sample.drl 24 |
25 | 26 | #3,引用调用 27 | 28 |   直接import EngineService类,生成EngineService对象,同时将需要校验的bean作为Object传入给EngineService对象的Start方法。 29 |   如下所示: 30 | 31 | EngineService service = new EngineService(); 32 | 33 | try { 34 | 35 | Student st = new Student(); 36 | st.setAge(5); 37 | st.name = "tom"; 38 | st.sex = 1; 39 | 40 | EngineRunResult result = service.start(st); 41 | System.out.println(result.getResult().getName()); 42 | 43 | System.out.println(st.getAge()); 44 | } catch (RuleEngineException e) { 45 | 46 | e.printStackTrace(); 47 | } 48 | 49 | 50 |     #4,编写规则 51 |       52 |
53 | 54 |        -4.1 若2.1选择了xml格式的规则,则需要配置xml.rule.filename项目,这个地方填写规则的文件名,需要指定为xml文件格式。 55 | 典型的规则项目为: 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 |        -4.2 若2.2选择了drools格式的规则,则需要配置drools.rule.filename项目,这个地方填写规则的文件名,需要指定为drl文件格式。 66 | 典型的规则项目为: 67 |      
68 | 69 | rule "ageUp12" 70 | salience 400 71 | when 72 | $student: Student(age < 8) 73 | /* antoher rule */ 74 | then 75 | System.out.println("I was called, my name is : " + $student.name); 76 | ageUp($student,12); 77 | //callOver($student); 78 | end 79 |   80 |
81 |       -4.3 若2.3选择database格式的规则,则需要配置db.rule.table项目,这个地方填写规则的数据库表结构,其表生成的结构可以参考SQL目录下的2个文件。典型 的规则描述如下: 82 |  
83 | 84 | item_no|content|exe_sql|exe_class|param_name|param_type|comparison_code|comparison_value|baseline|result|executor|priority|continue_flag|parent_item_no|group_express|remark|comments|enable_flag|create_time|update_time 85 | 11|黑名单|select count(1) as cnt from tl_blacklist where customer_no = ? and delete_flag = 1|customer_no|java.lang.String|01|==|0|PASSED|100|1|1|2018-02-26 12:40:15.000000|2018-02-26 12:40:18.000000 86 | 87 |
88 |      数据库连接方式时,需要同时设置db.accesser,如果是直接使用druid的数据库连接池,可以设置成db.accesser=tech.kiwa.engine.utility.DirectDBAccesser,DirectDBAccesser提供了开关变量UseDruid,如果设置成true就是使用了druid连接池,如果设置成false则是直接地jdbc。 89 |
     如果使用Spring的数据库连接,可以设置成db.accesser=tech.kiwa.engine.utility.SpringDBAccesser. 90 | 91 | 92 | 93 | 94 | 95 | 96 | https://github.com/Hale-Lee/RuleEngine/wiki 97 | 98 | 微信: woyishixinghren 99 | 100 | 加微信请注明:规则引擎 101 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | com.github.hale-lee 5 | RuleEngine 6 | 0.2.0 7 | Hale 8 | 9 | org.sonatype.oss 10 | oss-parent 11 | 8 12 | 13 | 14 | 15 | 16 | The Apache Software License, Version 2.0 17 | http://www.apache.org/licenses/LICENSE-2.0.txt 18 | repo 19 | 20 | 21 | 22 | 23 | https://github.com/Hale-Lee/RuleEngine 24 | https://github.com/Hale-Lee/RuleEngine.git 25 | https://www.kiwa.tech 26 | 27 | 28 | 29 | 30 | hale 31 | hale2000@163.com 32 | http://www.kiwa.tech 33 | 34 | 35 | 36 | 37 | UTF-8 38 | 1.2.3 39 | 1.7.25 40 | 4.3.1.RELEASE 41 | 42 | 43 | 44 | 52 | 53 | 59 | 60 | 61 | org.springframework 62 | spring-context 63 | ${spring.version} 64 | 65 | 66 | 72 | 73 | 74 | ch.qos.logback 75 | logback-classic 76 | ${logback.version} 77 | 78 | 79 | ch.qos.logback 80 | logback-access 81 | ${logback.version} 82 | 83 | 84 | org.slf4j 85 | jcl-over-slf4j 86 | ${org.slf4j.version} 87 | 88 | 89 | 90 | 91 | com.alibaba 92 | druid 93 | 1.1.22 94 | 95 | 96 | 97 | commons-lang 98 | commons-lang 99 | 2.5 100 | 101 | 102 | 109 | 110 | 111 | ojdbc 112 | ojdbc 113 | 14 114 | 115 | 116 | 117 | mysql 118 | mysql-connector-java 119 | 8.0.20 120 | 121 | 122 | 123 | 124 | 125 | 126 | src/main/resources 127 | true 128 | 136 | 137 | 138 | RuleEngine 139 | 140 | 141 | 142 | maven-compiler-plugin 143 | 3.6.0 144 | 145 | 1.8 146 | 1.8 147 | 148 | 149 | 150 | org.apache.maven.plugins 151 | maven-dependency-plugin 152 | 2.10 153 | 154 | 155 | copy-dependencies 156 | package 157 | 158 | copy-dependencies 159 | 160 | 161 | /target 162 | 163 | 164 | 165 | 166 | 167 | 168 | org.apache.maven.plugins 169 | maven-jar-plugin 170 | 2.4 171 | 172 | 173 | 174 | true 175 | 176 | 177 | 178 | 179 | 180 | org.apache.maven.plugins 181 | maven-gpg-plugin 182 | 1.6 183 | 184 | 185 | sign-artifacts 186 | verify 187 | 188 | sign 189 | 190 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | www.kiwa.tech 202 | 203 | 204 | 205 | 206 | -------------------------------------------------------------------------------- /reference/rule-mysql.sql: -------------------------------------------------------------------------------- 1 | 2 | 3 | SET FOREIGN_KEY_CHECKS=0; 4 | 5 | -- ---------------------------- 6 | -- Table structure for TL_RULE_DEFINE 7 | -- ---------------------------- 8 | DROP TABLE IF EXISTS `TL_RULE_DEFINE`; 9 | CREATE TABLE `TL_RULE_DEFINE` ( 10 | `item_no` varchar(32) NOT NULL, 11 | `content` varchar(128) DEFAULT NULL COMMENT '中文的内容说明', 12 | `exe_sql` varchar(512) DEFAULT NULL COMMENT '执行检查的SQL语句', 13 | `exe_class` varchar(128) DEFAULT NULL COMMENT '执行检查的java类名, 与exe_sql二者只填写一项', 14 | `param_name` varchar(128) DEFAULT NULL COMMENT 'exe_sql或者exe_class的参数,多个参数用逗号(,)分割。', 15 | `param_type` varchar(255) DEFAULT NULL COMMENT 'exe_sql或者exe_class的参数类型,多个类型用逗号(,)分割,与param_name需一一对应。', 16 | `comparison_code` varchar(32) DEFAULT NULL COMMENT '01: == , 02: > , 03 : < , 04 != , 05 >= , 06: <= , 07 include , 08 exclude , 09: included by 10: excluded by 11: equal , 12 : not equal 13: euqalIngoreCase', 17 | `comparison_value` varchar(64) DEFAULT NULL COMMENT ' =,>,<,>=,<=, !=, include, exclude等内容。' , 18 | `baseline` varchar(64) DEFAULT NULL COMMENT '参数值,比较目标值', 19 | `result` varchar(6) DEFAULT NULL COMMENT '1 - 通过 2 - 关注 3 -拒绝 逻辑运算满足目标值的时候读取改内容。', 20 | `executor` varchar(128) DEFAULT NULL COMMENT '结果执行后的被执行体,从AbstractCommand中继承下来。', 21 | `priority` varchar(32) DEFAULT NULL COMMENT '执行的优先顺序,值大的优先执行.', 22 | `continue_flag` varchar(2) DEFAULT NULL COMMENT '1: 继续执行下一条 其他:中断执行', 23 | `parent_item_no` varchar(32) DEFAULT NULL COMMENT '如果是子规则,那么需要填写父规则的item_no', 24 | `group_express` varchar(256) DEFAULT NULL COMMENT '同一PARENT_ITEM的各个ITEM的运算表达式。 ( A AND B OR C)', 25 | `remark` varchar(128) DEFAULT NULL, 26 | `comments` varchar(128) DEFAULT NULL, 27 | `enable_flag` varchar(2) DEFAULT NULL COMMENT '是否有效,enable_flag = 1表示有效,其余: 无效', 28 | `create_time` datetime(6) DEFAULT NULL, 29 | `update_time` datetime(6) DEFAULT NULL, 30 | PRIMARY KEY (`item_no`) 31 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 32 | -------------------------------------------------------------------------------- /reference/rule-oracle.sql: -------------------------------------------------------------------------------- 1 | 2 | 3 | -- ---------------------------- 4 | -- Table structure for TL_RULE_DEFINE 5 | -- ---------------------------- 6 | DROP TABLE "TL_RULE_DEFINE"; 7 | CREATE TABLE "TL_RULE_DEFINE" ( 8 | "ITEM_NO" NVARCHAR2(32) NOT NULL , 9 | "CONTENT" NVARCHAR2(256) NULL , 10 | "EXE_SQL" NVARCHAR2(512) NULL , 11 | "EXE_CLASS" NVARCHAR2(128) NULL , 12 | "PARAM_NAME" NVARCHAR2(128) NULL , 13 | "PARAM_TYPE" NVARCHAR2(128) NULL , 14 | "COMPARISON_CODE" NVARCHAR2(32) NULL , 15 | "COMPARISON_VALUE" NVARCHAR2(64) NULL , 16 | "BASELINE" NVARCHAR2(64) NULL , 17 | "RESULT" NVARCHAR2(6) NULL , 18 | "PRIORITY" NVARCHAR2(32) NULL , 19 | "CONTINUE_FLAG" NVARCHAR2(2) NULL , 20 | "PARENT_ITEM_NO" NVARCHAR2(2) NULL , 21 | "PARENT_EXPRESS" NVARCHAR2(256) NULL , 22 | "EXECUTOR" NVARCHAR2(64) NULL , 23 | "REMARK" NVARCHAR2(64) NULL , 24 | "COMMENTS" NVARCHAR2(64) NULL , 25 | "ENABLE_FLAG" NVARCHAR2(2) NULL , 26 | "CREATE_TIME" TIMESTAMP(6) NULL , 27 | "UPDATE_TIME" TIMESTAMP(6) NULL 28 | ) 29 | LOGGING 30 | NOCOMPRESS 31 | NOCACHE 32 | 33 | ; 34 | COMMENT ON TABLE "TL_RULE_DEFINE" IS '规则引擎定义表'; 35 | COMMENT ON COLUMN "TL_RULE_DEFINE"."ITEM_NO" IS '主key'; 36 | COMMENT ON COLUMN "TL_RULE_DEFINE"."CONTENT" IS '中文的内容说明'; 37 | COMMENT ON COLUMN "TL_RULE_DEFINE"."EXE_SQL" IS '执行的SQL语句'; 38 | COMMENT ON COLUMN "TL_RULE_DEFINE"."EXE_CLASS" IS '执行检查的java类名, 与exe_sql二者只填写一项'; 39 | COMMENT ON COLUMN "TL_RULE_DEFINE"."PARAM_NAME" IS 'SQL语句的参数,多个参数用,分割,读值时需要完成和继承DefaultCustomerCheck类。'; 40 | COMMENT ON COLUMN "TL_RULE_DEFINE"."PARAM_TYPE" IS 'exe_sql或者exe_class的参数类型,多个类型用逗号(,)分割,与param_name需一一对应。'; 41 | COMMENT ON COLUMN "TL_RULE_DEFINE"."COMPARISON_CODE" IS '01: = , 02: > , 03 : < , 04 != , 05 >= , 06: <= , 07 include , 08 exclude , 09: included by 10: excluded by 11: equal , 12 : not equal 13: euqalIngoreCase 15: matches 16: NOT MATCHES'; 42 | COMMENT ON COLUMN "TL_RULE_DEFINE"."COMPARISON_VALUE" IS '=,>,<,>=,<=, !=, include, exclude等内容。'; 43 | COMMENT ON COLUMN "TL_RULE_DEFINE"."BASELINE" IS '参数值,比较目标值'; 44 | COMMENT ON COLUMN "TL_RULE_DEFINE"."RESULT" IS '1 - 通过 2 - 关注 3 -拒绝 逻辑运算满足目标值的时候读取改内容。'; 45 | COMMENT ON COLUMN "TL_RULE_DEFINE"."PRIORITY" IS '执行的优先顺序,值大的优先执行.'; 46 | COMMENT ON COLUMN "TL_RULE_DEFINE"."CONTINUE_FLAG" IS '是否继续执行下一条,如果某条规则满足中断的话,那么就设置为 2. 1 -- 继续 2 -- 中断'; 47 | COMMENT ON COLUMN "TL_RULE_DEFINE"."PARENT_ITEM_NO" IS '如果是子规则,那么需要填写父规则的item_no'; 48 | COMMENT ON COLUMN "TL_RULE_DEFINE"."PARENT_EXPRESS" IS '同一PARENT_ITEM的各个ITEM的运算表达式。 ( A AND B OR C)'; 49 | COMMENT ON COLUMN "TL_RULE_DEFINE"."EXECUTOR" IS '结果执行后的被执行体,从AbstractCommand中继承下来。'; 50 | COMMENT ON COLUMN "TL_RULE_DEFINE"."ENABLE_FLAG" IS '是否使用 1 - 有效 2 - 失效'; 51 | 52 | -- ---------------------------- 53 | -- Checks structure for table TL_RULE_DEFINE 54 | -- ---------------------------- 55 | ALTER TABLE "TL_RULE_DEFINE" ADD CHECK ("ITEM_NO" IS NOT NULL); 56 | -------------------------------------------------------------------------------- /reference/table-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hale-Lee/RuleEngine/bb9d019dd52bb45a8ceb2ae178f378a8322aad85/reference/table-1.png -------------------------------------------------------------------------------- /reference/table-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hale-Lee/RuleEngine/bb9d019dd52bb45a8ceb2ae178f378a8322aad85/reference/table-2.png -------------------------------------------------------------------------------- /src/main/java/tech/kiwa/engine/EngineService.java: -------------------------------------------------------------------------------- 1 | //Copyright Hale [hale2000@163.com] 2 | // 3 | //Licensed under the Apache License, Version 2.0 (the "License"); 4 | //you may not use this file except in compliance with the License. 5 | //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 10 | //distributed under the License is distributed on an "AS IS" BASIS, 11 | //WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | //See the License for the specific language governing permissions and 13 | //limitations under the License. 14 | 15 | package tech.kiwa.engine; 16 | 17 | import java.util.List; 18 | import java.util.Map; 19 | import java.util.Random; 20 | 21 | import org.apache.commons.lang.StringUtils; 22 | import org.slf4j.Logger; 23 | import org.slf4j.LoggerFactory; 24 | 25 | import tech.kiwa.engine.component.AbstractRuleItem; 26 | import tech.kiwa.engine.component.AbstractRuleReader; 27 | import tech.kiwa.engine.component.impl.ComplexRuleExecutor; 28 | import tech.kiwa.engine.component.impl.DBRuleReader; 29 | import tech.kiwa.engine.component.impl.DefaultRuleExecutor; 30 | import tech.kiwa.engine.component.impl.DroolsRuleReader; 31 | import tech.kiwa.engine.component.impl.XMLRuleReader; 32 | import tech.kiwa.engine.entity.EngineRunResult; 33 | import tech.kiwa.engine.entity.ItemExecutedResult; 34 | import tech.kiwa.engine.entity.RESULT; 35 | import tech.kiwa.engine.entity.RuleItem; 36 | import tech.kiwa.engine.exception.RuleEngineException; 37 | import tech.kiwa.engine.framework.ResultLogFactory; 38 | import tech.kiwa.engine.sample.Student; 39 | import tech.kiwa.engine.utility.PropertyUtil; 40 | 41 | /** 42 | * 入口类,所有的执行,必须从该类中开始。 43 | * @author Hale.Li 44 | * @since 2018-01-28 45 | * @version 0.1 46 | */ 47 | public class EngineService { 48 | 49 | 50 | private AbstractRuleReader itemService = loadService(); 51 | 52 | private Logger log = LoggerFactory.getLogger(EngineService.class); 53 | 54 | private String seq = null; 55 | 56 | @SuppressWarnings("unchecked") 57 | private AbstractRuleReader loadService(){ 58 | 59 | if(itemService != null){ 60 | return itemService; 61 | } 62 | 63 | AbstractRuleReader reader = null; 64 | 65 | String serviceName = PropertyUtil.getProperty("rule.reader"); 66 | switch(serviceName.toLowerCase()){ 67 | case "database": 68 | reader = new DBRuleReader(); 69 | break; 70 | case "xml": 71 | reader = new XMLRuleReader(); 72 | break; 73 | case "drools": 74 | reader = new DroolsRuleReader(); 75 | break; 76 | default: 77 | Class ServiceClass; 78 | try { 79 | ServiceClass = (Class) Class.forName(serviceName); 80 | reader = ServiceClass.newInstance(); 81 | } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) { 82 | log.debug(e.getMessage()); 83 | } 84 | 85 | break; 86 | } 87 | 88 | itemService = reader; 89 | return reader; 90 | } 91 | 92 | /** 93 | * 启动函数,传入一个对象进来就可以比较了。 94 | * @param object 95 | * @return 96 | * @throws RuleEngineException 97 | */ 98 | public EngineRunResult start(Object object ) throws RuleEngineException{ 99 | return this.start(object, null); 100 | } 101 | 102 | public EngineRunResult start(Map object ) throws RuleEngineException{ 103 | return this.start((String)object.get("Id"), null); 104 | } 105 | 106 | /** 107 | * 启动函数,传入对象和系列号作比较。 108 | * @param object 109 | * @param sequence 110 | * @return 111 | * @throws RuleEngineException 112 | */ 113 | @SuppressWarnings("unchecked") 114 | public EngineRunResult start(Object object , String sequence) throws RuleEngineException{ 115 | 116 | List itemList = itemService.readRuleItemList(); 117 | 118 | itemList = itemService.filterItem(itemList, null); 119 | itemList = itemService.sortItem(itemList, null); 120 | 121 | this.seq = sequence; 122 | 123 | EngineRunResult ret_Result = new EngineRunResult(); 124 | ret_Result.setResult(RESULT.PASSED); 125 | ret_Result.setResult_desc("PASSED"); 126 | 127 | for(RuleItem item : itemList){ 128 | 129 | log.debug("started to execute the rule item check. item = {}, ObjectId ={}", item.getItemNo(), object); 130 | 131 | if(StringUtils.isNotEmpty(item.getGroupExpress())){ 132 | 133 | ComplexRuleExecutor executor = new ComplexRuleExecutor(); 134 | executor.setObject(object); 135 | ItemExecutedResult result = null; 136 | //如果是重复执行. 137 | do{ 138 | result = executor.doCheck(item); 139 | if(result == null) break; 140 | 141 | seq = this.writeExecutedLog(object,item, result); 142 | if(result.getResult().compare(ret_Result.getResult()) > 0 ){ 143 | ret_Result.setResult(result.getResult()); 144 | ret_Result.setResult_desc(result.getRemark()); 145 | } 146 | ret_Result.setSequence(seq); 147 | if(!result.canBeContinue()){ 148 | break; 149 | } 150 | 151 | }while(result != null && result.shouldLoop()); 152 | 153 | if(!result.canBeContinue()){ 154 | break; 155 | } 156 | 157 | 158 | }else{ 159 | 160 | String className= item.getExeClass(); 161 | 162 | Class auditClass = null; 163 | AbstractRuleItem auditInstance = null; 164 | 165 | if(StringUtils.isNotEmpty(className)){ 166 | try { 167 | //auditInstance = CglibCaller.newInstance(AbstractRuleItem.class); 168 | 169 | auditClass = (Class) Class.forName(className); 170 | if(null != auditClass){ 171 | auditInstance = auditClass.newInstance(); 172 | } 173 | } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) { 174 | throw new RuleEngineException(e.getMessage()); 175 | } 176 | } 177 | 178 | if(null == auditInstance){ 179 | auditInstance = new DefaultRuleExecutor(); 180 | } 181 | 182 | //直接地调用doCheck的函数。 183 | auditInstance.setObject(object); 184 | 185 | ItemExecutedResult result = null; 186 | //如果是重复执行. 187 | do{ 188 | 189 | //CglibCaller caller = new CglibCaller(); 190 | 191 | //caller.intercept(caller, method, args, caller); 192 | 193 | result = auditInstance.doCheck(item); 194 | if(result == null){ 195 | break; 196 | } 197 | seq = this.writeExecutedLog(object,item, result); 198 | if(result.getResult().compare(ret_Result.getResult()) > 0 ){ 199 | ret_Result.setResult(result.getResult()); 200 | ret_Result.setResult_desc(result.getRemark()); 201 | } 202 | ret_Result.setSequence(seq); 203 | 204 | if(!result.canBeContinue()){ 205 | break; 206 | } 207 | } while(result != null && result.shouldLoop()); 208 | 209 | if(!result.canBeContinue()){ 210 | break; 211 | } 212 | 213 | } 214 | } 215 | 216 | this.afterExecuted(ret_Result); 217 | 218 | return ret_Result; 219 | } 220 | 221 | protected void afterExecuted(EngineRunResult result){ 222 | 223 | } 224 | 225 | protected String writeExecutedLog(Object object, RuleItem item , ItemExecutedResult result ) throws RuleEngineException{ 226 | 227 | 228 | if(StringUtils.isEmpty(seq)){ 229 | seq = String.valueOf(System.currentTimeMillis()); 230 | seq = seq + String.valueOf(new Random(1000).nextInt()); 231 | } 232 | 233 | try { 234 | ResultLogFactory.getInstance().writeLog(object, item, result); 235 | } catch (RuleEngineException e) { 236 | log.debug("write log error."); 237 | throw e; 238 | } 239 | 240 | return seq; 241 | } 242 | 243 | 244 | /** 245 | * 这是一个例子,通过Student类来说明规则引擎的实际应用。Student定义在TL_STUDENT中(参考数据库) 246 | * 在本例子中,我们构建了一组student对象, 同时配置一个简单的规则,如果学生年龄>7岁,或者学生年龄<3岁,则认为不可以读幼儿园, 这个时候在显示出来。 247 | * 规则配置文件时studentrule.xml,这个文件需要在ruleEngine.properties中配置。 248 | * @param args 249 | */ 250 | public static void main(String[] args){ 251 | 252 | EngineService service = new EngineService(); 253 | 254 | try { 255 | 256 | Random rand = new Random (1); 257 | 258 | for(int id =2 ; id <=4; id++){ 259 | // Student st = new Student(); 260 | // st.setAge(rand.nextInt(10)); 261 | // st.name = "tom"; 262 | // st.sex = rand.nextInt(1); 263 | 264 | EngineRunResult result = service.start(id); 265 | 266 | System.out.println(result.getResult().getName()); 267 | if(result.getResult() == RESULT.PASSED) { 268 | service.log.error("学生{} 不能入读本幼儿园,年龄不符合要求。",id); 269 | }else { 270 | service.log.info("学生{} 没有年龄不符合条件的情况。",id); 271 | } 272 | } 273 | } catch (RuleEngineException e) { 274 | 275 | e.printStackTrace(); 276 | } 277 | 278 | } 279 | } 280 | 281 | 282 | 283 | 284 | -------------------------------------------------------------------------------- /src/main/java/tech/kiwa/engine/component/AbstractCommand.java: -------------------------------------------------------------------------------- 1 | //Copyright Hale [hale2000@163.com] 2 | // 3 | //Licensed under the Apache License, Version 2.0 (the "License"); 4 | //you may not use this file except in compliance with the License. 5 | //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 10 | //distributed under the License is distributed on an "AS IS" BASIS, 11 | //WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | //See the License for the specific language governing permissions and 13 | //limitations under the License. 14 | 15 | package tech.kiwa.engine.component; 16 | 17 | import tech.kiwa.engine.entity.ItemExecutedResult; 18 | import tech.kiwa.engine.entity.RuleItem; 19 | /** 20 | * 命令接口,如果需要自定义Rule地执行部分,那么该部分必须从这个父类继承。 21 | * @author Hale.Li 22 | * @since 2018-01-28 23 | * @version 0.1 24 | */ 25 | public abstract class AbstractCommand { 26 | 27 | public abstract void execute(RuleItem item, ItemExecutedResult result); 28 | 29 | public abstract void SetObject(Object obj); 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/tech/kiwa/engine/component/AbstractComparisonOperator.java: -------------------------------------------------------------------------------- 1 | //Copyright Hale [hale2000@163.com] 2 | // 3 | //Licensed under the Apache License, Version 2.0 (the "License"); 4 | //you may not use this file except in compliance with the License. 5 | //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 10 | //distributed under the License is distributed on an "AS IS" BASIS, 11 | //WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | //See the License for the specific language governing permissions and 13 | //limitations under the License. 14 | 15 | package tech.kiwa.engine.component; 16 | 17 | import tech.kiwa.engine.exception.RuleEngineException; 18 | import tech.kiwa.engine.framework.Component; 19 | import tech.kiwa.engine.framework.OperatorFactory; 20 | 21 | /** 22 | * @author Hale.Li 23 | * @since 2018-01-28 24 | * @version 0.1 25 | */ 26 | public abstract class AbstractComparisonOperator implements Component { 27 | 28 | private String comparisonCode ; 29 | 30 | // auto register. 31 | public AbstractComparisonOperator( String comparison_code) throws Exception{ 32 | 33 | 34 | comparisonCode = comparison_code; 35 | this.register(); 36 | 37 | } 38 | 39 | public void register() throws RuleEngineException{ 40 | 41 | OperatorFactory optMgr = OperatorFactory.getInstance(); 42 | 43 | if(OperatorFactory.OPR_CODE.isReserved(comparisonCode) ){ 44 | throw new RuleEngineException("cannot use reserved logic key."); 45 | } 46 | 47 | optMgr.acceptRegister(this); 48 | } 49 | 50 | public abstract boolean run(String subject, String baseline); 51 | 52 | public String getComparisonCode(){ 53 | return comparisonCode; 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/tech/kiwa/engine/component/AbstractResultLogRecorder.java: -------------------------------------------------------------------------------- 1 | //Copyright Hale [hale2000@163.com] 2 | // 3 | //Licensed under the Apache License, Version 2.0 (the "License"); 4 | //you may not use this file except in compliance with the License. 5 | //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 10 | //distributed under the License is distributed on an "AS IS" BASIS, 11 | //WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | //See the License for the specific language governing permissions and 13 | //limitations under the License. 14 | 15 | package tech.kiwa.engine.component; 16 | 17 | import tech.kiwa.engine.entity.ItemExecutedResult; 18 | import tech.kiwa.engine.entity.RuleItem; 19 | import tech.kiwa.engine.exception.RuleEngineException; 20 | import tech.kiwa.engine.framework.Component; 21 | import tech.kiwa.engine.framework.ResultLogFactory; 22 | 23 | /** 24 | * @author Hale.Li 25 | * @since 2018-01-28 26 | * @version 0.1 27 | */ 28 | public abstract class AbstractResultLogRecorder implements Component { 29 | 30 | public AbstractResultLogRecorder( ) { 31 | } 32 | 33 | // explicit register. 34 | public void register() throws RuleEngineException{ 35 | 36 | ResultLogFactory optMgr = ResultLogFactory.getInstance(); 37 | optMgr.acceptRegister(this); 38 | } 39 | 40 | public abstract boolean writeLog(Object object, RuleItem item , ItemExecutedResult result ); 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/tech/kiwa/engine/component/AbstractRuleItem.java: -------------------------------------------------------------------------------- 1 | //Copyright Hale [hale2000@163.com] 2 | // 3 | //Licensed under the Apache License, Version 2.0 (the "License"); 4 | //you may not use this file except in compliance with the License. 5 | //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 10 | //distributed under the License is distributed on an "AS IS" BASIS, 11 | //WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | //See the License for the specific language governing permissions and 13 | //limitations under the License. 14 | 15 | package tech.kiwa.engine.component; 16 | 17 | import java.math.BigDecimal; 18 | import java.util.Map; 19 | import java.util.Set; 20 | 21 | import org.springframework.beans.BeansException; 22 | 23 | import tech.kiwa.engine.entity.ItemExecutedResult; 24 | import tech.kiwa.engine.entity.RuleItem; 25 | import tech.kiwa.engine.exception.EmptyResultSetException; 26 | import tech.kiwa.engine.exception.RuleEngineException; 27 | import tech.kiwa.engine.framework.OperatorFactory; 28 | import tech.kiwa.engine.utility.SpringContextHelper; 29 | 30 | /** 31 | * @author Hale.Li 32 | * @since 2018-01-28 33 | * @version 0.1 34 | */ 35 | public abstract class AbstractRuleItem { 36 | 37 | protected Object object; 38 | 39 | public void setObject(Object object) { 40 | this.object = object; 41 | } 42 | 43 | /** 44 | * 获取SpringMVC中的Service对象,如果未使用SpringMVC,则返回null. 45 | * 46 | * @param seriveName 47 | * Service名称, 48 | * @return 返回的Serivce对象。 49 | */ 50 | protected Object getService(String seriveName) { 51 | 52 | Object objRet = null; 53 | 54 | try { 55 | objRet = SpringContextHelper.getBean(seriveName); 56 | } catch (BeansException e) { 57 | 58 | } 59 | 60 | return objRet; 61 | } 62 | 63 | /** 64 | * 获取SpringMVC中的Service对象。 如果未使用SpringMVC,则返回null. 65 | * 66 | * @param 参数类型的模板类 67 | * @param requiredType 68 | * Serivce的类型,即具体的类。 69 | * @return 返回的Serivce对象。 70 | */ 71 | protected T getService(Class requiredType) { 72 | 73 | T objRet = null; 74 | try { 75 | objRet = SpringContextHelper.getBean(requiredType); 76 | } catch (BeansException e) { 77 | 78 | } 79 | return objRet; 80 | 81 | } 82 | 83 | public abstract ItemExecutedResult doCheck(RuleItem item) throws RuleEngineException; 84 | 85 | /** 86 | * analyze the data of when condition. 87 | * 88 | * @param resultSet 89 | * 返回的结果集,从数据库读出来的 90 | * @param item 91 | * 规则定义体 92 | * @return 运行是成功还是失败 true or false. 93 | * @throws EmptyResultSetException 94 | * 结果集是空时的的返回. 95 | * @throws RuleEngineException 96 | * 其他的异常 97 | */ 98 | protected boolean analyze(Map resultSet, RuleItem item) 99 | throws EmptyResultSetException, RuleEngineException { 100 | 101 | String retValue = null; 102 | 103 | // 104 | if (resultSet.containsKey("cnt")) { 105 | 106 | retValue = resultSet.get("cnt").toString(); 107 | 108 | } else if (resultSet.size() == 1) { 109 | 110 | Set keySet = (Set) resultSet.keySet(); 111 | for (String key : keySet) { 112 | 113 | if (null == resultSet.get(key)) { 114 | retValue = null; 115 | } else if (resultSet.get(key) instanceof String) { 116 | retValue = (String) resultSet.get(key); 117 | } else { 118 | retValue = resultSet.get(key).toString(); 119 | } 120 | 121 | } 122 | 123 | } else if (resultSet.size() > 1) { 124 | // read the first data. 125 | Set keySet = (Set) resultSet.keySet(); 126 | for (String key : keySet) { 127 | 128 | if (null == resultSet.get(key)) { 129 | retValue = null; 130 | } else if (resultSet.get(key) instanceof String) { 131 | retValue = (String) resultSet.get(key); 132 | } else { 133 | retValue = resultSet.get(key).toString(); 134 | } 135 | break; 136 | } 137 | 138 | // 如果数据返回为空,那么默认为审核通过 139 | } else if (resultSet.isEmpty()) { 140 | 141 | throw new EmptyResultSetException("resultset is empty."); 142 | // return true; 143 | } else { 144 | throw new RuleEngineException("unknow resultset."); 145 | } 146 | 147 | boolean bRet = false; 148 | 149 | // try { 150 | bRet = comparisonOperate(retValue, item.getComparisonCode(), item.getBaseline()); 151 | // } catch (RuleEngineException e) { 152 | // throw e; 153 | // } 154 | 155 | return bRet; 156 | } 157 | 158 | /** 159 | * 比较运算操作,将执行的结果和RuleItem中的baseline作比较。 160 | * 161 | * @param subject 162 | * 比较对象(运行结果) 163 | * @param comparisonCode 164 | * 比较操作符号,在OperationFactory中定义。 165 | * @param baseline 166 | * 比较基线,用于比较的对象。 167 | * @return 根据ComparisonCode运行的结果。 true or flase。 168 | * @throws RuleEngineException 169 | * 参数不合法,或者比较操作符不合法。 170 | */ 171 | public static boolean comparisonOperate(String subject, String comparisonCode, String baseline) 172 | throws RuleEngineException { 173 | 174 | boolean bRet = false; 175 | 176 | if (null == subject || null == baseline || null == comparisonCode) { 177 | throw new RuleEngineException("null pointer error of subject or baseline or comparison code."); 178 | } 179 | 180 | BigDecimal bdSubject = null; 181 | BigDecimal object = null; 182 | 183 | switch (comparisonCode) { 184 | 185 | case OperatorFactory.OPR_CODE.EQUAL: 186 | try { 187 | bdSubject = new BigDecimal(subject); 188 | object = new BigDecimal(baseline); 189 | bRet = (bdSubject.compareTo(object) == 0); 190 | } catch (Exception e) { 191 | bRet = subject.equals(baseline); 192 | } 193 | break; 194 | case OperatorFactory.OPR_CODE.GREATER: 195 | try { 196 | bdSubject = new BigDecimal(subject); 197 | object = new BigDecimal(baseline); 198 | bRet = (bdSubject.compareTo(object) > 0); 199 | } catch (Exception e1) { 200 | bRet = (subject.compareTo(baseline) > 0); 201 | } 202 | break; 203 | case OperatorFactory.OPR_CODE.LESS: 204 | try { 205 | bdSubject = new BigDecimal(subject); 206 | object = new BigDecimal(baseline); 207 | bRet = (bdSubject.compareTo(object) < 0); 208 | } catch (Exception e1) { 209 | bRet = (subject.compareTo(baseline) < 0); 210 | } 211 | break; 212 | case OperatorFactory.OPR_CODE.NOT_EQUAL: 213 | try { 214 | bdSubject = new BigDecimal(subject); 215 | object = new BigDecimal(baseline); 216 | bRet = (bdSubject.compareTo(object) != 0); 217 | } catch (Exception e) { 218 | bRet = !subject.equals(baseline); 219 | } 220 | break; 221 | case OperatorFactory.OPR_CODE.GREATER_EQUAL: 222 | try { 223 | bdSubject = new BigDecimal(subject); 224 | object = new BigDecimal(baseline); 225 | bRet = (bdSubject.compareTo(object) >= 0); 226 | } catch (Exception e) { 227 | bRet = (subject.compareTo(baseline) >= 0); 228 | } 229 | break; 230 | case OperatorFactory.OPR_CODE.LESS_EQUAL: 231 | try { 232 | bdSubject = new BigDecimal(subject); 233 | object = new BigDecimal(baseline); 234 | bRet = (bdSubject.compareTo(object) <= 0); 235 | } catch (Exception e) { 236 | bRet = (subject.compareTo(baseline) <= 0); 237 | } 238 | break; 239 | case OperatorFactory.OPR_CODE.INCLUDE: 240 | bRet = subject.contains(baseline); 241 | break; 242 | case OperatorFactory.OPR_CODE.NOT_INCLUDE: 243 | bRet = !subject.contains(baseline); 244 | break; 245 | case OperatorFactory.OPR_CODE.INCLUDED_BY: 246 | bRet = baseline.contains(subject); 247 | break; 248 | case OperatorFactory.OPR_CODE.NOT_INCLUDED_BY: 249 | bRet = !baseline.contains(subject); 250 | break; 251 | case OperatorFactory.OPR_CODE.EQUAL_IGNORE_CASE: 252 | bRet = subject.equalsIgnoreCase(baseline); 253 | break; 254 | case OperatorFactory.OPR_CODE.NOT_EQUAL_IGNORE_CASE: 255 | bRet = !subject.equalsIgnoreCase(baseline); 256 | break; 257 | case OperatorFactory.OPR_CODE.MATCH: 258 | bRet = subject.matches(baseline); 259 | break; 260 | case OperatorFactory.OPR_CODE.UNMATCH: 261 | bRet = !subject.matches(baseline); 262 | break; 263 | default: 264 | bRet = extendComparisonOperate(subject, comparisonCode, baseline); 265 | break; 266 | } 267 | 268 | return bRet; 269 | } 270 | 271 | private static boolean extendComparisonOperate(String subject, String comparisonCode, String baseline) 272 | throws RuleEngineException { 273 | 274 | OperatorFactory optMgr = OperatorFactory.getInstance(); 275 | return optMgr.runOperator(subject, comparisonCode, baseline); 276 | 277 | } 278 | } 279 | -------------------------------------------------------------------------------- /src/main/java/tech/kiwa/engine/component/AbstractRuleReader.java: -------------------------------------------------------------------------------- 1 | //Copyright Hale [hale2000@163.com] 2 | // 3 | //Licensed under the Apache License, Version 2.0 (the "License"); 4 | //you may not use this file except in compliance with the License. 5 | //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 10 | //distributed under the License is distributed on an "AS IS" BASIS, 11 | //WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | //See the License for the specific language governing permissions and 13 | //limitations under the License. 14 | 15 | package tech.kiwa.engine.component; 16 | 17 | import java.util.ArrayList; 18 | import java.util.List; 19 | 20 | import org.apache.commons.lang.StringUtils; 21 | import org.slf4j.Logger; 22 | import org.slf4j.LoggerFactory; 23 | 24 | import tech.kiwa.engine.entity.RESULT; 25 | import tech.kiwa.engine.entity.RuleItem; 26 | import tech.kiwa.engine.exception.RuleEngineException; 27 | 28 | 29 | /** 30 | * @author Hale.Li 31 | * @since 2018-01-28 32 | * @version 0.1 33 | */ 34 | public abstract class AbstractRuleReader { 35 | 36 | public abstract List readRuleItemList() throws RuleEngineException ; 37 | public abstract Long getRuleItemCount() throws RuleEngineException; 38 | public abstract RuleItem getRuleItem(String ruleId) throws RuleEngineException; 39 | 40 | protected volatile List ruleItemCache = new ArrayList(); 41 | 42 | private static Logger log = LoggerFactory.getLogger(AbstractRuleReader.class); 43 | 44 | /** 45 | * Sort the same level rule item, and filter the items not in the same level. 46 | * @param itemList 排序的对象列表 47 | * @param parentItem 父级规则 48 | * @return 排好序的规则列表 49 | */ 50 | public List sortItem(List itemList, String parentItem){ 51 | 52 | List retItemList = new ArrayList(); 53 | List tempItemList = new ArrayList(); 54 | 55 | //同一层级的item, 56 | for(RuleItem item: itemList){ 57 | if(StringUtils.isEmpty(parentItem)){ 58 | 59 | if(StringUtils.isEmpty(item.getParentItemNo())){ 60 | tempItemList.add(item); 61 | } 62 | 63 | }else if(parentItem.equals(item.getParentItemNo())){ 64 | tempItemList.add(item); 65 | } 66 | } 67 | 68 | while(!tempItemList.isEmpty()){ 69 | /* 70 | int minIndex = queryMiniumPriority(tempItemList); 71 | retItemList.add(tempItemList.get(minIndex)); 72 | tempItemList.remove(minIndex); 73 | */ 74 | int maxIndex = queryMaxiumPriority(tempItemList); 75 | retItemList.add(tempItemList.get(maxIndex)); 76 | tempItemList.remove(maxIndex); 77 | } 78 | 79 | return retItemList; 80 | 81 | } 82 | 83 | /** 84 | * 在规则列表中查找最小的优先级 85 | * @param itemList 查找的对象列表 86 | * @return 最小的优先级 87 | */ 88 | @SuppressWarnings("unused") 89 | private int queryMiniumPriority( List itemList){ 90 | 91 | int priority = Integer.MAX_VALUE; 92 | int minIndex = Integer.MAX_VALUE; 93 | 94 | for(int iLoop = 0 ;iLoop < itemList.size(); iLoop++){ 95 | 96 | try{ 97 | int current = Integer.valueOf(itemList.get(iLoop).getPriority()); 98 | 99 | if( priority > current ){ 100 | priority = current; 101 | minIndex = iLoop; 102 | } 103 | }catch (java.lang.NumberFormatException e){ 104 | log.debug(e.getLocalizedMessage()); 105 | } 106 | } 107 | 108 | return minIndex; 109 | 110 | } 111 | 112 | /** 113 | * 在规则列表中查找最大的优先级 114 | * @param itemList 查找的对象列表 115 | * @return 最大的优先级 116 | */ 117 | private int queryMaxiumPriority( List itemList){ 118 | 119 | int priority = Integer.MIN_VALUE; 120 | int minIndex = Integer.MIN_VALUE; 121 | 122 | for(int iLoop = 0 ;iLoop < itemList.size(); iLoop++){ 123 | 124 | try{ 125 | int current = Integer.valueOf(itemList.get(iLoop).getPriority()); 126 | 127 | if( priority < current ){ 128 | priority = current; 129 | minIndex = iLoop; 130 | } 131 | }catch (java.lang.NumberFormatException e){ 132 | log.debug(e.getLocalizedMessage()); 133 | } 134 | } 135 | 136 | return minIndex; 137 | 138 | } 139 | 140 | /** 141 | * 查找同层级的规则列表 142 | * @param itemList 要查找的对象 143 | * @param parentItemNo 父级规则 144 | * @return 同层级的规则列表 145 | */ 146 | public List filterItem(List itemList, String parentItemNo){ 147 | 148 | List newItemList = new ArrayList(); 149 | 150 | for(int iLoop = 0 ;iLoop < itemList.size(); iLoop++){ 151 | 152 | RuleItem item= itemList.get(iLoop); 153 | if(StringUtils.isEmpty(parentItemNo)){ 154 | if(StringUtils.isEmpty(item.getParentItemNo())){ 155 | newItemList.add(item); 156 | } 157 | }else{ 158 | if(parentItemNo.equalsIgnoreCase(item.getParentItemNo())){ 159 | newItemList.add(item); 160 | } 161 | } 162 | } 163 | 164 | return newItemList; 165 | 166 | } 167 | 168 | /** 169 | * 检查规则的格式是否正确 170 | * @param item 规则定义体 171 | * @return true -- 合法 false -- 不合法 172 | */ 173 | public boolean preCompile(RuleItem item){ 174 | 175 | boolean bRet = true; 176 | if(StringUtils.isEmpty(item.getItemNo())){ 177 | log.debug("ruleId cannot be empty."); 178 | bRet = false; 179 | } 180 | 181 | // single normal item. 182 | if(StringUtils.isEmpty(item.getParentItemNo()) && StringUtils.isEmpty(item.getGroupExpress())){ 183 | 184 | if(StringUtils.isEmpty(item.getPriority())){ 185 | log.debug("priority cannot be empty and must be numberic if it's free-running rule. ruleid ={}" , item.getItemNo()); 186 | bRet = false; 187 | } 188 | 189 | if(!StringUtils.isNumeric(item.getPriority())){ 190 | log.debug("priority cannot be empty and must be numberic if it's free-running rule. ruleid ={}" , item.getItemNo()); 191 | bRet = false; 192 | } 193 | 194 | if(!StringUtils.isNumeric(item.getContinueFlag())){ 195 | log.debug("continue flag cannot be empty and must be numberic if it's free-running rule. ruleid ={}" , item.getItemNo()); 196 | bRet = false; 197 | } 198 | 199 | if(!StringUtils.isNumeric(item.getResult())){ 200 | RESULT result = RESULT.EMPTY ; 201 | if(!result.parse(item.getResult())){ 202 | log.debug("result cannot be empty and must be numberic if it's free-running rule. ruleid ={}" , item.getItemNo()); 203 | bRet = false; 204 | } 205 | } 206 | 207 | if(StringUtils.isEmpty(item.getExeClass()) && StringUtils.isEmpty(item.getExeSql())){ 208 | log.debug("either exe_class or exe_sql must be inputted. ruleid ={}" , item.getItemNo()); 209 | bRet = false; 210 | } 211 | 212 | if(StringUtils.isEmpty(item.getBaseline())){ 213 | log.debug("baseline must be inputted. ruleid ={}" , item.getItemNo()); 214 | bRet = false; 215 | } 216 | 217 | if(StringUtils.isEmpty(item.getComparisonCode())){ 218 | log.debug("comparison code must be inputted. ruleid ={}" , item.getItemNo()); 219 | bRet = false; 220 | } 221 | 222 | if(StringUtils.isNotEmpty(item.getExeSql())){ 223 | String sql = item.getExeSql(); 224 | if(sql.contains("?")){ 225 | if(StringUtils.isEmpty(item.getParamName())){ 226 | 227 | log.debug("param name must be inputted since your exe_sql has parameters. ruleid ={}" , item.getItemNo()); 228 | bRet = false; 229 | } 230 | } 231 | } 232 | } 233 | // group check, parent group. 234 | if( StringUtils.isNotEmpty(item.getGroupExpress()) ){ 235 | 236 | if(StringUtils.isEmpty(item.getPriority())){ 237 | log.debug("priority cannot be empty and must be numberic if it's free-running rule. ruleid ={}" , item.getItemNo()); 238 | bRet = false; 239 | } 240 | 241 | if(!StringUtils.isNumeric(item.getPriority())){ 242 | log.debug("priority cannot be empty and must be numberic if it's free-running rule. ruleid ={}" , item.getItemNo()); 243 | bRet = false; 244 | } 245 | 246 | if(!StringUtils.isNumeric(item.getContinueFlag())){ 247 | log.debug("continue flag cannot be empty and must be numberic if it's free-running rule. ruleid ={}" , item.getItemNo()); 248 | bRet = false; 249 | } 250 | 251 | if(!StringUtils.isNumeric(item.getResult())){ 252 | RESULT result = RESULT.EMPTY ; 253 | if(!result.parse(item.getResult())){ 254 | log.debug("result cannot be empty and must be numberic if it's free-running rule. ruleid ={}" , item.getItemNo()); 255 | bRet = false; 256 | } 257 | } 258 | 259 | } 260 | 261 | //sub item check, simple rule , without complex express. 262 | if(StringUtils.isNotEmpty(item.getParentItemNo())){ 263 | 264 | if(StringUtils.isEmpty(item.getExeClass()) && StringUtils.isEmpty(item.getExeSql())){ 265 | log.debug("either java_class or exe_sql must be inputted. ruleid ={}" , item.getItemNo()); 266 | bRet = false; 267 | } 268 | 269 | if(StringUtils.isEmpty(item.getBaseline())){ 270 | log.debug("baseline must be inputted. ruleid ={}" , item.getItemNo()); 271 | bRet = false; 272 | } 273 | 274 | if(StringUtils.isEmpty(item.getComparisonCode())){ 275 | log.debug("comparison code must be inputted. ruleid ={}" , item.getItemNo()); 276 | bRet = false; 277 | } 278 | 279 | if(StringUtils.isNotEmpty(item.getExeSql())){ 280 | String sql = item.getExeSql(); 281 | if(sql.contains("?")){ 282 | if(StringUtils.isEmpty(item.getParamName())){ 283 | 284 | log.debug("param name must be inputted since your exe_sql has parameters. ruleid ={}" , item.getItemNo()); 285 | bRet = false; 286 | } 287 | } 288 | } 289 | } 290 | 291 | return bRet; 292 | } 293 | 294 | /** 295 | * 缓存清除的接口。 296 | */ 297 | public void clearRuleItemCache(){ 298 | 299 | synchronized(ruleItemCache){ 300 | ruleItemCache.clear(); 301 | } 302 | 303 | } 304 | 305 | public void updateRuleItem(RuleItem item){ 306 | 307 | for(int iLoop =0; iLoop < ruleItemCache.size(); iLoop++){ 308 | 309 | RuleItem element = ruleItemCache.get(iLoop); 310 | 311 | if(element.getItemNo().equalsIgnoreCase(item.getItemNo())){ 312 | synchronized(ruleItemCache){ 313 | ruleItemCache.set(iLoop, item); 314 | } 315 | } 316 | } 317 | } 318 | } 319 | -------------------------------------------------------------------------------- /src/main/java/tech/kiwa/engine/component/drools/DeclareCreator.java: -------------------------------------------------------------------------------- 1 | //Copyright Hale [hale2000@163.com] 2 | // 3 | //Licensed under the Apache License, Version 2.0 (the "License"); 4 | //you may not use this file except in compliance with the License. 5 | //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 10 | //distributed under the License is distributed on an "AS IS" BASIS, 11 | //WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | //See the License for the specific language governing permissions and 13 | //limitations under the License. 14 | 15 | package tech.kiwa.engine.component.drools; 16 | 17 | import java.util.HashMap; 18 | import java.util.Map; 19 | import java.util.Set; 20 | 21 | import com.alibaba.druid.util.StringUtils; 22 | 23 | import tech.kiwa.engine.component.drools.ImportCreator; 24 | /** 25 | * @author Hale.Li 26 | * @since 2018-01-28 27 | * @version 0.1 28 | */ 29 | public class DeclareCreator implements DroolsPartsCreator { 30 | 31 | private String name; 32 | private Map attributes; 33 | 34 | public String getName() { 35 | return name; 36 | } 37 | 38 | public Map getAttributes() { 39 | return attributes; 40 | } 41 | 42 | private DroolsBuilder builder = null; 43 | 44 | private DeclareCreator(){ 45 | 46 | } 47 | public static DeclareCreator create(String content, DroolsBuilder builder){ 48 | 49 | 50 | 51 | if(StringUtils.isEmpty(content)){ 52 | return null; 53 | } 54 | 55 | if(!content.startsWith("declare")){ 56 | return null; 57 | } 58 | 59 | content = content.trim(); 60 | 61 | DeclareCreator creator = new DeclareCreator(); 62 | creator.builder = builder; 63 | 64 | String[] lines = content.split("\\n|\\r"); 65 | String title = lines[0].trim(); 66 | 67 | String[] sections = title.split("\\s+|\\t|\\(|,|\\)"); 68 | 69 | 70 | if(sections.length >= 2){ 71 | 72 | creator.name = sections[1]; 73 | 74 | creator.attributes = new HashMap(); 75 | for(int iLoop =1 ; iLoop < lines.length -1 ; iLoop++){ 76 | 77 | String line = lines[iLoop]; 78 | if(StringUtils.isEmpty(line)){ 79 | continue; 80 | } 81 | line = line.trim(); 82 | if(line.endsWith(";")){ 83 | line = line.substring(0, line.length()-1); 84 | } 85 | sections = line.split(":"); 86 | //ASSERT sections.length = 2; 87 | if(creator.attributes == null){ 88 | creator.attributes = new HashMap(); 89 | } 90 | creator.attributes.put(sections[0].trim(), sections[1].trim()); 91 | } 92 | } 93 | 94 | return creator; 95 | 96 | } 97 | 98 | public String toJavaString(){ 99 | 100 | StringBuffer javaBuffer = new StringBuffer(); 101 | javaBuffer.append(builder.getPackage().toJavaString()); 102 | for(ImportCreator impt : builder.getImportList()){ 103 | javaBuffer.append(impt.toJavaString()); 104 | } 105 | 106 | javaBuffer.append("import tech.kiwa.engine.component.drools.DeclareInterface;\n"); 107 | 108 | javaBuffer.append("\n"); 109 | javaBuffer.append("public class ").append(name); 110 | javaBuffer.append(" implements DeclareInterface"); 111 | javaBuffer.append(" {").append("\n"); 112 | javaBuffer.append("\n"); 113 | 114 | for(GlobalCreator global : builder.getGlobalList()){ 115 | javaBuffer.append(global.toJavaString()); 116 | } 117 | javaBuffer.append("\n"); 118 | 119 | Set nameSet = attributes.keySet(); 120 | for(String name : nameSet){ 121 | String type = attributes.get(name); 122 | javaBuffer.append("public "); 123 | javaBuffer.append(type); 124 | javaBuffer.append(" "); 125 | javaBuffer.append(name); 126 | javaBuffer.append(";\n"); 127 | } 128 | javaBuffer.append("\n"); 129 | //Implement the getValue function. 130 | javaBuffer.append(" public Object getValue(String name){ \n"); 131 | javaBuffer.append("\n"); 132 | javaBuffer.append(" Object value = null;\n"); 133 | for(String name : nameSet){ 134 | javaBuffer.append(" if(name.equals(\""+name+"\")){\n"); 135 | javaBuffer.append(" value = this."+ name +";\n"); 136 | javaBuffer.append(" }\n"); 137 | } 138 | 139 | javaBuffer.append("\n"); 140 | javaBuffer.append(" return value;\n"); 141 | 142 | javaBuffer.append(" }"); 143 | javaBuffer.append("\n"); 144 | 145 | //Implement the setValue function. 146 | javaBuffer.append(" public void setValue(String name, Object value){ \n"); 147 | javaBuffer.append("\n"); 148 | for(String name : nameSet){ 149 | String type = attributes.get(name); 150 | javaBuffer.append(" if(name.equals(\""+name+"\")){\n"); 151 | javaBuffer.append(" this."+ name +" = ("+ type +") value;\n"); 152 | javaBuffer.append(" }\n"); 153 | } 154 | 155 | javaBuffer.append("\n"); 156 | javaBuffer.append(" return ;\n"); 157 | 158 | javaBuffer.append(" }"); 159 | javaBuffer.append("\n"); 160 | 161 | javaBuffer.append("}"); 162 | 163 | return javaBuffer.toString(); 164 | } 165 | 166 | public DeclareInterface createObject(){ 167 | 168 | DeclareInterface declare = (DeclareInterface) builder.createObject(this.name, this.toJavaString()); 169 | 170 | return declare; 171 | } 172 | 173 | 174 | } 175 | -------------------------------------------------------------------------------- /src/main/java/tech/kiwa/engine/component/drools/DeclareInterface.java: -------------------------------------------------------------------------------- 1 | //Copyright Hale [hale2000@163.com] 2 | // 3 | //Licensed under the Apache License, Version 2.0 (the "License"); 4 | //you may not use this file except in compliance with the License. 5 | //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 10 | //distributed under the License is distributed on an "AS IS" BASIS, 11 | //WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | //See the License for the specific language governing permissions and 13 | //limitations under the License. 14 | 15 | package tech.kiwa.engine.component.drools; 16 | 17 | /** 18 | * @author Hale.Li 19 | * @since 2018-01-28 20 | * @version 0.1 21 | */ 22 | public interface DeclareInterface extends DroolsPartsObject { 23 | 24 | public Object getValue(String name); 25 | 26 | public void setValue(String name, Object value); 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/tech/kiwa/engine/component/drools/DroolsBuilder.java: -------------------------------------------------------------------------------- 1 | //Copyright Hale [hale2000@163.com] 2 | // 3 | //Licensed under the Apache License, Version 2.0 (the "License"); 4 | //you may not use this file except in compliance with the License. 5 | //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 10 | //distributed under the License is distributed on an "AS IS" BASIS, 11 | //WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | //See the License for the specific language governing permissions and 13 | //limitations under the License. 14 | 15 | package tech.kiwa.engine.component.drools; 16 | 17 | import java.io.IOException; 18 | import java.util.ArrayList; 19 | import java.util.List; 20 | import java.util.Map; 21 | 22 | import org.slf4j.Logger; 23 | import org.slf4j.LoggerFactory; 24 | 25 | import tech.kiwa.engine.entity.RuleItem; 26 | import tech.kiwa.engine.utility.JavaStringCompiler; 27 | /** 28 | * @author Hale.Li 29 | * @since 2018-01-28 30 | * @version 0.1 31 | */ 32 | public class DroolsBuilder { 33 | 34 | 35 | //private static DroolsBuilder instance = new DroolsBuilder(); 36 | 37 | public DroolsBuilder(){ 38 | 39 | } 40 | 41 | //public static DroolsBuilder getInstance(){ 42 | // return instance; 43 | //} 44 | 45 | private Logger log = LoggerFactory.getLogger(DroolsBuilder.class); 46 | 47 | private List functionList = new ArrayList(); 48 | private List globalList = new ArrayList(); 49 | private List importList = new ArrayList(); 50 | private List queryList = new ArrayList(); 51 | private List ruleList = new ArrayList(); 52 | private List declareList = new ArrayList(); 53 | 54 | //private ClassFileManager fileManager = null;// new ClassFileManager(compiler.getStandardFileManager(null, null, null)); 55 | //private List fileList = new ArrayList(); 56 | private JavaStringCompiler compiler = new JavaStringCompiler(); 57 | 58 | private PackageCreator pack = null; 59 | 60 | public List getImportList(){ 61 | return importList; 62 | } 63 | 64 | public PackageCreator getPackage(){ 65 | return pack; 66 | } 67 | 68 | public List getFunctionList() { 69 | return functionList; 70 | } 71 | 72 | public List getGlobalList() { 73 | return globalList; 74 | } 75 | 76 | public List getQueryList() { 77 | return queryList; 78 | } 79 | 80 | public List getRuleList() { 81 | return ruleList; 82 | } 83 | 84 | public List getDeclareList() { 85 | return declareList; 86 | } 87 | 88 | 89 | 90 | public void build(List phases) { 91 | 92 | for(String item : phases){ 93 | 94 | item = item.trim(); 95 | if(item.startsWith("rule")){ 96 | ruleList.add(RuleCreator.create(item, this)); 97 | 98 | }else if(item.startsWith("function")){ 99 | 100 | functionList.add(FunctionCreator.create(item, this)); 101 | 102 | }else if(item.startsWith("global")){ 103 | 104 | this.globalList.add(GlobalCreator.create(item, this)); 105 | 106 | } else if(item.startsWith("import")){ 107 | 108 | this.importList.add(ImportCreator.create(item, this)); 109 | 110 | }else if(item.startsWith("query")){ 111 | 112 | this.queryList.add(QueryCreator.create(item, this)); 113 | 114 | }else if(item.startsWith("package")){ 115 | 116 | this.pack = PackageCreator.create(item, this); 117 | 118 | }else if(item.startsWith("declare")){ 119 | this.declareList.add(DeclareCreator.create(item, this)); 120 | } 121 | 122 | } 123 | 124 | } 125 | 126 | // public ClassFileManager getFileManager(){ 127 | // return this.fileManager; 128 | // } 129 | 130 | public List getRuleItemList(){ 131 | 132 | List retList = new ArrayList(); 133 | for(RuleCreator creator: ruleList){ 134 | retList.add(creator.getItem()); 135 | } 136 | 137 | return retList; 138 | } 139 | /* 140 | public Class queryClass(String className) throws ClassNotFoundException{ 141 | 142 | return compiler.queryLoadedClass(className); 143 | 144 | //return compiler.loadClass(className, classBytes); 145 | } 146 | */ 147 | private boolean compiled = false; 148 | 149 | public boolean compile(){ 150 | 151 | if(compiled){ 152 | return compiled; 153 | } 154 | 155 | for (DeclareCreator declare : declareList){ 156 | 157 | // 生成源代码的JavaFileObject 158 | //SimpleJavaFileObject fileObject = new JavaSourceFromString(declare.getName(), declare.toJavaString()); 159 | //fileList.add(fileObject); 160 | try { 161 | 162 | //String clsName = this.getPackage().getName() + "." + declare.getName(); 163 | String fileName = declare.getName() + ".java"; 164 | compiler.compile(fileName, declare.toJavaString()); 165 | } catch (IOException e) { 166 | 167 | } 168 | 169 | } 170 | if(!functionList.isEmpty()){ 171 | //String clsName = this.getPackage().getName() + ".DroolsFunctions" ; 172 | String fileName = "DroolsFunctions.java"; 173 | //SimpleJavaFileObject fileObject = new JavaSourceFromString(clsName, functionList.get(0).toJavaString()); 174 | //fileList.add(fileObject); 175 | try { 176 | compiler.compile(fileName, functionList.get(0).toJavaString()); 177 | } catch (IOException e) { 178 | // TODO Auto-generated catch block 179 | log.debug(e.getMessage()); 180 | e.printStackTrace(); 181 | } 182 | } 183 | 184 | return compiled; 185 | 186 | 187 | } 188 | 189 | 190 | @SuppressWarnings({ "unchecked" }) 191 | public DroolsPartsObject createObject(String className, String javaContent) { 192 | 193 | try { 194 | String fileName = ""; 195 | int pos = className.lastIndexOf('.'); 196 | if(pos > 0){ 197 | fileName = className.substring(pos+1) + ".java"; 198 | }else{ 199 | fileName = className + ".java"; 200 | } 201 | 202 | Map clsMap = compiler.compile(fileName, javaContent); 203 | 204 | Class cls = (Class) compiler.loadClass(className, clsMap); 205 | DroolsPartsObject obj = (DroolsPartsObject) cls.newInstance(); 206 | 207 | return obj; 208 | } catch (ClassNotFoundException | IOException | InstantiationException | IllegalAccessException e) { 209 | log.debug(e.getMessage()); 210 | e.printStackTrace(); 211 | } 212 | 213 | return null; 214 | 215 | } 216 | 217 | } 218 | -------------------------------------------------------------------------------- /src/main/java/tech/kiwa/engine/component/drools/DroolsPartsCreator.java: -------------------------------------------------------------------------------- 1 | //Copyright Hale [hale2000@163.com] 2 | // 3 | //Licensed under the Apache License, Version 2.0 (the "License"); 4 | //you may not use this file except in compliance with the License. 5 | //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 10 | //distributed under the License is distributed on an "AS IS" BASIS, 11 | //WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | //See the License for the specific language governing permissions and 13 | //limitations under the License. 14 | 15 | package tech.kiwa.engine.component.drools; 16 | /** 17 | * @author Hale.Li 18 | * @since 2018-01-28 19 | * @version 0.1 20 | */ 21 | public interface DroolsPartsCreator { 22 | 23 | public String toJavaString(); 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/tech/kiwa/engine/component/drools/DroolsPartsObject.java: -------------------------------------------------------------------------------- 1 | //Copyright Hale [hale2000@163.com] 2 | // 3 | //Licensed under the Apache License, Version 2.0 (the "License"); 4 | //you may not use this file except in compliance with the License. 5 | //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 10 | //distributed under the License is distributed on an "AS IS" BASIS, 11 | //WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | //See the License for the specific language governing permissions and 13 | //limitations under the License. 14 | 15 | package tech.kiwa.engine.component.drools; 16 | /** 17 | * @author Hale.Li 18 | * @since 2018-01-28 19 | * @version 0.1 20 | */ 21 | public interface DroolsPartsObject { 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/tech/kiwa/engine/component/drools/FunctionCreator.java: -------------------------------------------------------------------------------- 1 | //Copyright Hale [hale2000@163.com] 2 | // 3 | //Licensed under the Apache License, Version 2.0 (the "License"); 4 | //you may not use this file except in compliance with the License. 5 | //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 10 | //distributed under the License is distributed on an "AS IS" BASIS, 11 | //WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | //See the License for the specific language governing permissions and 13 | //limitations under the License. 14 | 15 | package tech.kiwa.engine.component.drools; 16 | 17 | import java.util.ArrayList; 18 | import java.util.HashMap; 19 | import java.util.List; 20 | import java.util.Map; 21 | 22 | import com.alibaba.druid.util.StringUtils; 23 | /** 24 | * @author Hale.Li 25 | * @since 2018-01-28 26 | * @version 0.1 27 | */ 28 | public class FunctionCreator implements DroolsPartsCreator { 29 | 30 | private String functionName; 31 | private String reference; 32 | private Map params = new HashMap(); 33 | private List paramTypes = new ArrayList(); 34 | private List paramNames = new ArrayList(); 35 | 36 | private String content; 37 | 38 | public String getFunctionName() { 39 | return functionName; 40 | } 41 | 42 | public String getReference() { 43 | return reference; 44 | } 45 | 46 | public Map getParams() { 47 | return params; 48 | } 49 | 50 | public String getContent() { 51 | return content; 52 | } 53 | 54 | @Override 55 | public String toJavaString() { 56 | 57 | StringBuffer javaBuffer = new StringBuffer(); 58 | 59 | 60 | javaBuffer.append(builder.getPackage().toJavaString()); 61 | javaBuffer.append("\n"); 62 | 63 | for(ImportCreator impt : builder.getImportList()){ 64 | javaBuffer.append(impt.toJavaString()); 65 | } 66 | 67 | for(DeclareCreator decl : builder.getDeclareList()){ 68 | javaBuffer.append("import " + builder.getPackage().getName() +"."); 69 | javaBuffer.append(decl.getName()); 70 | javaBuffer.append(";\n"); 71 | } 72 | 73 | javaBuffer.append("\n"); 74 | javaBuffer.append("public class ").append("DroolsFunctions"); 75 | javaBuffer.append(" {").append("\n"); 76 | javaBuffer.append("\n"); 77 | 78 | for(FunctionCreator fun: builder.getFunctionList()){ 79 | 80 | javaBuffer.append(" public "); 81 | javaBuffer.append(fun.reference); 82 | javaBuffer.append(" "); 83 | javaBuffer.append(fun.functionName); 84 | javaBuffer.append(" "); 85 | javaBuffer.append(" ("); 86 | 87 | //Set nameSet = fun.params.keySet(); 88 | for(int iLoop =0; iLoop < fun.paramNames.size(); iLoop++){ 89 | String name = fun.paramNames.get(iLoop); 90 | String type = fun.paramTypes.get(iLoop); 91 | javaBuffer.append( type ); 92 | javaBuffer.append(" "); 93 | javaBuffer.append(name); 94 | javaBuffer.append(" , "); 95 | } 96 | if(!fun.paramNames.isEmpty()){ 97 | int pos = javaBuffer.lastIndexOf(","); 98 | javaBuffer.deleteCharAt(pos); 99 | } 100 | 101 | javaBuffer.append(")"); 102 | 103 | javaBuffer.append(fun.content); 104 | javaBuffer.append("\n"); 105 | } 106 | 107 | javaBuffer.append("\n"); 108 | 109 | javaBuffer.append("}"); 110 | return javaBuffer.toString(); 111 | 112 | } 113 | 114 | private FunctionCreator(){ 115 | 116 | } 117 | 118 | private DroolsBuilder builder = null; 119 | 120 | public static FunctionCreator create(String content,DroolsBuilder builder ){ 121 | 122 | if(StringUtils.isEmpty(content)){ 123 | return null; 124 | } 125 | 126 | if(!content.startsWith("function")){ 127 | return null; 128 | } 129 | 130 | content = content.trim(); 131 | 132 | FunctionCreator creator = new FunctionCreator(); 133 | creator.builder = builder; 134 | 135 | String[] lines = content.split("\\n|\\r"); 136 | String title = lines[0].trim(); 137 | 138 | String[] sections = title.split("\\s+|\\t|\\(|,|\\)\\{"); 139 | 140 | if(sections.length >= 3){ 141 | 142 | creator.reference = sections[1]; 143 | creator.functionName = sections[2]; 144 | 145 | if(title.endsWith("{")){ 146 | title = title.substring(0, title.length()-1); 147 | } 148 | 149 | if(title.endsWith(")")){ 150 | 151 | String type = null, name =null; 152 | for(int iLoop = 3; iLoop < sections.length; iLoop ++){ 153 | if(StringUtils.isEmpty(sections[iLoop])){ 154 | continue; 155 | } 156 | if(type == null){ 157 | type = sections[iLoop]; 158 | }else{ 159 | name = sections[iLoop]; 160 | } 161 | if(type != null && name != null){ 162 | creator.params.put(name,type); 163 | creator.paramTypes.add(type); 164 | creator.paramNames.add(name); 165 | type = null; 166 | name = null; 167 | } 168 | } 169 | } 170 | int pos = content.indexOf('{'); 171 | creator.content = content.substring(pos); 172 | } 173 | 174 | return creator; 175 | 176 | } 177 | 178 | } 179 | -------------------------------------------------------------------------------- /src/main/java/tech/kiwa/engine/component/drools/GlobalCreator.java: -------------------------------------------------------------------------------- 1 | //Copyright Hale [hale2000@163.com] 2 | // 3 | //Licensed under the Apache License, Version 2.0 (the "License"); 4 | //you may not use this file except in compliance with the License. 5 | //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 10 | //distributed under the License is distributed on an "AS IS" BASIS, 11 | //WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | //See the License for the specific language governing permissions and 13 | //limitations under the License. 14 | 15 | package tech.kiwa.engine.component.drools; 16 | 17 | import com.alibaba.druid.util.StringUtils; 18 | /** 19 | * @author Hale.Li 20 | * @since 2018-01-28 21 | * @version 0.1 22 | */ 23 | public class GlobalCreator implements DroolsPartsCreator { 24 | 25 | private String name = null; 26 | private String reference = null; 27 | 28 | private Object value = null; 29 | 30 | 31 | public Object getValue() { 32 | return value; 33 | } 34 | 35 | public void setValue(Object value) { 36 | this.value = value; 37 | } 38 | 39 | public String getName() { 40 | return name; 41 | } 42 | 43 | public String getReference() { 44 | return reference; 45 | } 46 | 47 | @Override 48 | public String toJavaString() { 49 | StringBuffer sbf = new StringBuffer(); 50 | sbf.append("public static "); 51 | sbf.append(reference); 52 | sbf.append(" "); 53 | sbf.append(name); 54 | sbf.append(" ;\n"); 55 | 56 | return sbf.toString(); 57 | } 58 | 59 | private GlobalCreator(){ 60 | 61 | } 62 | 63 | @SuppressWarnings("unused") 64 | private DroolsBuilder builder = null; 65 | 66 | public static GlobalCreator create(String content, DroolsBuilder builder ){ 67 | 68 | if(StringUtils.isEmpty(content)){ 69 | return null; 70 | } 71 | 72 | if(!content.startsWith("global")){ 73 | return null; 74 | } 75 | 76 | content = content.trim(); 77 | GlobalCreator creator = new GlobalCreator(); 78 | creator.builder = builder; 79 | 80 | String[] sections = content.split("\\s+|\\t|\\n|\\r"); 81 | if(sections.length >=3){ 82 | 83 | creator.name = sections[2].trim(); 84 | creator.reference = sections[1].trim(); 85 | } 86 | 87 | return creator; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/main/java/tech/kiwa/engine/component/drools/ImportCreator.java: -------------------------------------------------------------------------------- 1 | //Copyright Hale [hale2000@163.com] 2 | // 3 | //Licensed under the Apache License, Version 2.0 (the "License"); 4 | //you may not use this file except in compliance with the License. 5 | //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 10 | //distributed under the License is distributed on an "AS IS" BASIS, 11 | //WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | //See the License for the specific language governing permissions and 13 | //limitations under the License. 14 | 15 | package tech.kiwa.engine.component.drools; 16 | 17 | import com.alibaba.druid.util.StringUtils; 18 | /** 19 | * @author Hale.Li 20 | * @since 2018-01-28 21 | * @version 0.1 22 | */ 23 | public class ImportCreator implements DroolsPartsCreator { 24 | 25 | String fullName; 26 | String simpleName; 27 | 28 | public String getFullName() { 29 | return fullName; 30 | } 31 | 32 | 33 | public String getSimpleName() { 34 | return simpleName; 35 | } 36 | 37 | 38 | public String toString() { 39 | return "import " + fullName + ";\n"; 40 | } 41 | 42 | 43 | @Override 44 | public String toJavaString() { 45 | return "import " + fullName + ";\n"; 46 | } 47 | 48 | private ImportCreator(){ 49 | 50 | } 51 | 52 | @SuppressWarnings("unused") 53 | private DroolsBuilder builder = null; 54 | 55 | public static ImportCreator create(String content, DroolsBuilder builder){ 56 | 57 | if(StringUtils.isEmpty(content)){ 58 | return null; 59 | } 60 | 61 | if(!content.startsWith("import")){ 62 | return null; 63 | } 64 | 65 | content = content.trim(); 66 | ImportCreator creator = new ImportCreator(); 67 | creator.builder = builder; 68 | 69 | String[] sections = content.split("\\s+|\\t|\\n|\\r"); 70 | if(sections.length >=2){ 71 | creator.fullName = sections[1].trim(); 72 | if(creator.fullName.endsWith(";")){ 73 | creator.fullName = creator.fullName.substring(0,creator.fullName.length()-1); 74 | } 75 | 76 | int pos = creator.fullName.lastIndexOf('.'); 77 | if(pos > 0){ 78 | creator.simpleName = creator.fullName.substring(pos+1); 79 | } 80 | } 81 | 82 | return creator; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/main/java/tech/kiwa/engine/component/drools/LocalCreator.java: -------------------------------------------------------------------------------- 1 | //Copyright Hale [hale2000@163.com] 2 | // 3 | //Licensed under the Apache License, Version 2.0 (the "License"); 4 | //you may not use this file except in compliance with the License. 5 | //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 10 | //distributed under the License is distributed on an "AS IS" BASIS, 11 | //WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | //See the License for the specific language governing permissions and 13 | //limitations under the License. 14 | 15 | package tech.kiwa.engine.component.drools; 16 | 17 | /** 18 | * @author Hale.Li 19 | * @since 2018-01-28 20 | * @version 0.1 21 | */ 22 | public class LocalCreator implements DroolsPartsCreator { 23 | 24 | 25 | private String name = null; 26 | private String reference = null; 27 | private Object value = null; 28 | 29 | 30 | public Object getValue() { 31 | return value; 32 | } 33 | 34 | public void setValue(Object value) { 35 | this.value = value; 36 | } 37 | 38 | public String getName() { 39 | return name; 40 | } 41 | 42 | public String getReference() { 43 | return reference; 44 | } 45 | 46 | public void setName(String name) { 47 | if(null != name){ 48 | this.name = name.trim(); 49 | } 50 | } 51 | 52 | public void setReference(String reference) { 53 | if(null != reference){ 54 | this.reference = reference.trim(); 55 | } 56 | } 57 | 58 | 59 | @Override 60 | public String toJavaString() { 61 | StringBuffer sbf = new StringBuffer(); 62 | sbf.append("private "); 63 | sbf.append(reference); 64 | sbf.append(" "); 65 | sbf.append(name); 66 | sbf.append(" ;\n"); 67 | 68 | return sbf.toString(); 69 | } 70 | 71 | public LocalCreator(String name, String reference){ 72 | if(null != name){ 73 | this.name = name.trim(); 74 | } 75 | if(null != reference){ 76 | this.reference = reference.trim(); 77 | } 78 | } 79 | 80 | public LocalCreator(){ 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/tech/kiwa/engine/component/drools/PackageCreator.java: -------------------------------------------------------------------------------- 1 | //Copyright Hale [hale2000@163.com] 2 | // 3 | //Licensed under the Apache License, Version 2.0 (the "License"); 4 | //you may not use this file except in compliance with the License. 5 | //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 10 | //distributed under the License is distributed on an "AS IS" BASIS, 11 | //WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | //See the License for the specific language governing permissions and 13 | //limitations under the License. 14 | 15 | package tech.kiwa.engine.component.drools; 16 | 17 | import com.alibaba.druid.util.StringUtils; 18 | 19 | /** 20 | * @author Hale.Li 21 | * @since 2018-01-28 22 | * @version 0.1 23 | */ 24 | public class PackageCreator implements DroolsPartsCreator { 25 | 26 | /* (non-Javadoc) 27 | * @see tech.kiwa.engine.component.drools.DroolsPartsCreator#toJavaString() 28 | */ 29 | 30 | private String packageName = null; 31 | 32 | @Override 33 | public String toJavaString() { 34 | 35 | StringBuffer javaBuffer = new StringBuffer(); 36 | javaBuffer.append("package "); 37 | javaBuffer.append(packageName); 38 | javaBuffer.append(";\n"); 39 | 40 | return javaBuffer.toString(); 41 | } 42 | 43 | public String getName(){ 44 | return packageName; 45 | } 46 | 47 | private PackageCreator(){ 48 | 49 | } 50 | 51 | @SuppressWarnings("unused") 52 | private DroolsBuilder builder = null; 53 | 54 | public static PackageCreator create(String content, DroolsBuilder builder){ 55 | 56 | if(StringUtils.isEmpty(content)){ 57 | return null; 58 | } 59 | 60 | if(!content.startsWith("package")){ 61 | return null; 62 | } 63 | 64 | content = content.trim(); 65 | 66 | PackageCreator creator = new PackageCreator(); 67 | creator.builder = builder; 68 | 69 | String[] sections = content.split("\\s+|\\t|\\n|\\r"); 70 | if(sections.length >=2){ 71 | 72 | if(sections[1].endsWith(";")){ 73 | sections[1] = sections[1].substring(0, sections[1].length()-1); 74 | } 75 | creator.packageName = sections[1].trim(); 76 | }else{ 77 | 78 | creator.packageName = null; 79 | } 80 | 81 | return creator; 82 | } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /src/main/java/tech/kiwa/engine/component/drools/QueryCreator.java: -------------------------------------------------------------------------------- 1 | //Copyright Hale [hale2000@163.com] 2 | // 3 | //Licensed under the Apache License, Version 2.0 (the "License"); 4 | //you may not use this file except in compliance with the License. 5 | //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 10 | //distributed under the License is distributed on an "AS IS" BASIS, 11 | //WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | //See the License for the specific language governing permissions and 13 | //limitations under the License. 14 | 15 | package tech.kiwa.engine.component.drools; 16 | 17 | import java.lang.reflect.Field; 18 | import java.lang.reflect.InvocationTargetException; 19 | import java.lang.reflect.Method; 20 | import java.util.HashMap; 21 | import java.util.Map; 22 | 23 | import org.slf4j.Logger; 24 | import org.slf4j.LoggerFactory; 25 | 26 | import com.alibaba.druid.util.StringUtils; 27 | 28 | import tech.kiwa.engine.component.AbstractRuleItem; 29 | import tech.kiwa.engine.exception.RuleEngineException; 30 | 31 | /** 32 | * @author Hale.Li 33 | * @since 2018-01-28 34 | * @version 0.1 35 | */ 36 | public class QueryCreator implements DroolsPartsCreator { 37 | 38 | private String name; 39 | private String content; 40 | private Map params = null; 41 | private LocalCreator result = null; 42 | private ConstraintCreator condition = null; 43 | 44 | private Logger log = LoggerFactory.getLogger(QueryCreator.class); 45 | 46 | //private Object object = null; 47 | private DroolsBuilder builder = null; 48 | 49 | public ConstraintCreator getCondition() { 50 | return condition; 51 | } 52 | 53 | public DroolsBuilder getBuilder(){ 54 | return builder; 55 | } 56 | 57 | public String getName() { 58 | return name; 59 | } 60 | 61 | public String getContent() { 62 | return content; 63 | } 64 | 65 | 66 | public Map getParams() { 67 | return params; 68 | } 69 | 70 | public LocalCreator getResult() { 71 | return result; 72 | } 73 | 74 | private QueryCreator(){ 75 | 76 | } 77 | 78 | 79 | 80 | public static QueryCreator create(String content, DroolsBuilder builder){ 81 | 82 | if(StringUtils.isEmpty(content)){ 83 | return null; 84 | } 85 | 86 | if(!content.startsWith("query")){ 87 | return null; 88 | } 89 | 90 | content = content.trim(); 91 | 92 | QueryCreator creator = new QueryCreator(); 93 | creator.builder = builder; 94 | 95 | String[] lines = content.split("\\n|\\r"); 96 | String title = lines[0].trim(); 97 | 98 | String[] sections = title.split("\\s+|\\t|\\(|,|\\)"); 99 | 100 | if(sections.length >= 2){ 101 | 102 | creator.name = sections[1]; 103 | if(creator.name.startsWith("\"") && creator.name.endsWith("\"")){ 104 | creator.name = creator.name.substring(1, creator.name.length()-1); 105 | } 106 | 107 | if(title.endsWith(")")){ 108 | creator.params = new HashMap(); 109 | 110 | String type = null, name =null; 111 | for(int iLoop = 2; iLoop < sections.length; iLoop ++){ 112 | if(StringUtils.isEmpty(sections[iLoop])){ 113 | continue; 114 | } 115 | if(type == null){ 116 | type = sections[iLoop]; 117 | }else{ 118 | name = sections[iLoop]; 119 | } 120 | if(type != null && name != null){ 121 | creator.params.put(name,type); 122 | type = null; 123 | name = null; 124 | } 125 | } 126 | } 127 | 128 | int pos = title.length() + "\\n".length(); 129 | 130 | creator.content = content.substring(pos ); 131 | creator.content = creator.content.trim(); 132 | if(creator.content.endsWith("end")){ 133 | creator.content = creator.content.substring(0, creator.content.length()-"end".length()); 134 | creator.content = creator.content.trim(); 135 | } 136 | 137 | if(creator.content.contains(":")){ 138 | sections = creator.content.split(":"); 139 | creator.result = new LocalCreator(); 140 | creator.result.setName(sections[0].trim()); 141 | pos = sections[1].indexOf("("); 142 | //sections = sections[1].split("\\("); 143 | creator.result.setReference(sections[1].substring(0, pos)); 144 | 145 | if( sections[1].endsWith(")")){ 146 | sections[1] = sections[1].substring(pos, sections[1].length() ); 147 | sections[1] = sections[1].trim(); 148 | } 149 | creator.condition = ConstraintCreator.create(sections[1], creator); 150 | } 151 | } 152 | 153 | return creator; 154 | 155 | } 156 | 157 | public boolean run(Object object) throws RuleEngineException { 158 | 159 | boolean bRet = false; 160 | 161 | //this.object = object; 162 | 163 | String className = result.getReference(); 164 | 165 | if (object.getClass().getName().equals(className)) { 166 | 167 | try { 168 | bRet = condition.executeExpress(object); 169 | } catch (RuleEngineException e) { 170 | log.debug(e.getMessage()); 171 | throw e; 172 | } 173 | 174 | } 175 | 176 | return bRet; 177 | } 178 | 179 | public boolean operateCallback(String leftValue , String comparisonCode ,String baseValue, Object object) throws RuleEngineException{ 180 | 181 | boolean bRet = false; 182 | 183 | try { 184 | 185 | Class retClass = object.getClass(); 186 | Field field = retClass.getDeclaredField(leftValue); 187 | Object value = null; 188 | if(field!=null && field.isAccessible()){ 189 | value = field.get(object); 190 | }else { 191 | String methodName = "get"+ leftValue.substring(0,1).toUpperCase() + leftValue.substring(1); 192 | Method method = retClass.getMethod(methodName,(Class[])null); 193 | if(method != null ){ 194 | value = method.invoke(object, (Object[]) null); 195 | } 196 | } 197 | 198 | if(value != null){ 199 | bRet = AbstractRuleItem.comparisonOperate(value.toString(), comparisonCode, baseValue); 200 | } 201 | } catch (IllegalAccessException | NoSuchFieldException | SecurityException | NoSuchMethodException | IllegalArgumentException | InvocationTargetException e ) { 202 | 203 | throw new RuleEngineException(e.getCause()); 204 | } 205 | 206 | return bRet; 207 | } 208 | 209 | @Override 210 | public String toJavaString() { 211 | 212 | StringBuffer java = new StringBuffer(); 213 | java.append("boolean bResult = false;\n"); 214 | java.append("bResult = ("); 215 | 216 | String constraint = condition.toJavaString(); 217 | constraint.replace("?", result.getName()); 218 | 219 | java.append(constraint); 220 | 221 | java.append(")"); 222 | 223 | return java.toString(); 224 | 225 | } 226 | } 227 | -------------------------------------------------------------------------------- /src/main/java/tech/kiwa/engine/component/impl/DBRuleReader.java: -------------------------------------------------------------------------------- 1 | //Copyright Hale [hale2000@163.com] 2 | // 3 | //Licensed under the Apache License, Version 2.0 (the "License"); 4 | //you may not use this file except in compliance with the License. 5 | //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 10 | //distributed under the License is distributed on an "AS IS" BASIS, 11 | //WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | //See the License for the specific language governing permissions and 13 | //limitations under the License. 14 | 15 | package tech.kiwa.engine.component.impl; 16 | 17 | import java.sql.Connection; 18 | import java.sql.PreparedStatement; 19 | import java.sql.ResultSet; 20 | import java.sql.SQLException; 21 | import java.sql.Statement; 22 | import java.util.ArrayList; 23 | import java.util.List; 24 | 25 | import org.slf4j.Logger; 26 | import org.slf4j.LoggerFactory; 27 | 28 | import tech.kiwa.engine.component.AbstractRuleReader; 29 | import tech.kiwa.engine.entity.RuleItem; 30 | import tech.kiwa.engine.exception.RuleEngineException; 31 | import tech.kiwa.engine.framework.DBAccesser; 32 | import tech.kiwa.engine.utility.PropertyUtil; 33 | 34 | /** 35 | * @author Hale.Li 36 | * @since 2018-01-28 37 | * @version 0.1 38 | */ 39 | public class DBRuleReader extends AbstractRuleReader { 40 | 41 | private static Logger log = LoggerFactory.getLogger(DBRuleReader.class); 42 | 43 | private static volatile DBAccesser accesser = null; //数据库访问类。 44 | 45 | @SuppressWarnings("unchecked") 46 | private DBAccesser loadDBAccesser() throws ClassNotFoundException, InstantiationException, IllegalAccessException{ 47 | 48 | if(accesser == null){ 49 | 50 | String className = PropertyUtil.getProperty("db.accesser"); 51 | Class DBClass = (Class) Class.forName(className); 52 | 53 | synchronized(DBAccesser.class){ 54 | if(accesser == null){ 55 | accesser = DBClass.newInstance(); 56 | } 57 | } 58 | } 59 | 60 | return accesser; 61 | } 62 | 63 | @Override 64 | public List readRuleItemList() throws RuleEngineException { 65 | 66 | 67 | Statement stmt = null; 68 | ResultSet res = null; 69 | 70 | //缓存加载 71 | if(!ruleItemCache.isEmpty()){ 72 | return ruleItemCache; 73 | } 74 | 75 | List retList = new ArrayList(); 76 | 77 | String sqlStr = " select * from "+ PropertyUtil.getProperty("db.rule.table") +" where ENABLE_FLAG = 1 order by PRIORITY desc "; 78 | try { 79 | 80 | loadDBAccesser(); 81 | Connection conn = accesser.getConnection(); 82 | 83 | stmt = conn.prepareStatement(sqlStr); 84 | //stmt = conn.createStatement(); 85 | res = stmt.executeQuery(sqlStr); 86 | while(res.next()) 87 | { 88 | RuleItem rule = new RuleItem(); 89 | rule.setItemNo(res.getString("ITEM_NO")); 90 | rule.setContent(res.getString("content")); 91 | rule.setExeSql(res.getString("EXE_SQL")); 92 | rule.setExeClass(res.getString("exe_class")); 93 | rule.setParamType(res.getString("param_type")); 94 | rule.setParamName(res.getString("PARAM_NAME")); 95 | rule.setComparisonCode(res.getString("comparison_code")); 96 | rule.setComparisonValue(res.getString("comparison_value")); 97 | rule.setBaseline(res.getString("BASELINE")); 98 | rule.setResult(res.getString("result")); 99 | rule.setExecutor(res.getString("EXECUTOR")); 100 | rule.setPriority(res.getString("PRIORITY")); 101 | rule.setParentItemNo(res.getString("PARENT_ITEM_NO")); 102 | rule.setGroupExpress(res.getString("group_express")); 103 | rule.setContinueFlag(res.getString("CONTINUE_FLAG")); 104 | rule.setRemark(res.getString("REMARK")); 105 | rule.setComments(res.getString("COMMENTS")); 106 | rule.setEnableFlag(res.getString("ENABLE_FLAG")); 107 | rule.setCreateTime(res.getDate("CREATE_TIME")); 108 | rule.setUpdateTime(res.getDate("UPDATE_TIME")); 109 | if(!preCompile(rule)){ 110 | log.debug("database rule format error."); 111 | throw new RuleEngineException("rule format error."); 112 | //return null; 113 | } 114 | 115 | retList.add(rule); 116 | } 117 | 118 | res.close(); 119 | stmt.close(); 120 | 121 | 122 | //accesser.closeConnection(conn); 123 | 124 | } catch (SQLException e) { 125 | log.debug(e.getMessage()); 126 | throw new RuleEngineException(e.getCause()); 127 | } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e){ 128 | log.debug(e.getMessage()); 129 | throw new RuleEngineException(e.getCause()); 130 | } catch (Exception e) { 131 | log.debug(e.getMessage()); 132 | throw new RuleEngineException(e.getCause()); 133 | } 134 | 135 | //添加到缓存中。 136 | synchronized(ruleItemCache){ 137 | ruleItemCache.addAll(retList); 138 | } 139 | 140 | return ruleItemCache; 141 | 142 | } 143 | 144 | @Override 145 | public Long getRuleItemCount() throws RuleEngineException { 146 | 147 | 148 | Statement stmt = null; 149 | ResultSet res = null; 150 | 151 | long count = 0; 152 | 153 | String sqlStr = " select count(*) from "+ PropertyUtil.getProperty("db.rule.table") +" where ENABLE_FLAG = 1 "; 154 | try { 155 | 156 | loadDBAccesser(); 157 | Connection conn = accesser.getConnection(); 158 | 159 | stmt = conn.prepareStatement(sqlStr); 160 | //stmt = conn.createStatement(); 161 | res = stmt.executeQuery(sqlStr); 162 | res.next(); 163 | count = res.getLong(1); 164 | 165 | res.close(); 166 | stmt.close(); 167 | 168 | //accesser.closeConnection(conn); 169 | 170 | } catch (SQLException e) { 171 | log.debug(e.getMessage()); 172 | throw new RuleEngineException(e.getCause()); 173 | } catch (Exception e) { 174 | log.debug(e.getMessage()); 175 | throw new RuleEngineException(e.getCause()); 176 | } 177 | 178 | 179 | return count; 180 | } 181 | 182 | @Override 183 | public RuleItem getRuleItem(String ruleId) throws RuleEngineException { 184 | 185 | 186 | PreparedStatement stmt = null; 187 | ResultSet res = null; 188 | 189 | List retList = new ArrayList(); 190 | 191 | String sqlStr = " select * from "+ PropertyUtil.getProperty("db.rule.table") +" where ENABLE_FLAG = 1 and ITEM_NO = ? "; 192 | try { 193 | 194 | loadDBAccesser(); 195 | Connection conn = accesser.getConnection(); 196 | 197 | stmt = conn.prepareStatement(sqlStr); 198 | stmt.setString(1, ruleId); 199 | res = stmt.executeQuery(); 200 | 201 | while(res.next()) 202 | { 203 | RuleItem rule = new RuleItem(); 204 | rule.setItemNo(res.getString("ITEM_NO")); 205 | rule.setContent(res.getString("content")); 206 | rule.setExeSql(res.getString("EXE_SQL")); 207 | rule.setExeClass(res.getString("exe_class")); 208 | rule.setParamType(res.getString("param_type")); 209 | rule.setParamName(res.getString("PARAM_NAME")); 210 | rule.setComparisonCode(res.getString("comparison_code")); 211 | rule.setComparisonValue(res.getString("comparison_value")); 212 | rule.setBaseline(res.getString("BASELINE")); 213 | rule.setResult(res.getString("result")); 214 | rule.setExecutor(res.getString("EXECUTOR")); 215 | rule.setPriority(res.getString("PRIORITY")); 216 | rule.setParentItemNo(res.getString("PARENT_ITEM_NO")); 217 | rule.setGroupExpress(res.getString("group_express")); 218 | rule.setContinueFlag(res.getString("CONTINUE_FLAG")); 219 | rule.setRemark(res.getString("REMARK")); 220 | rule.setComments(res.getString("COMMENTS")); 221 | rule.setEnableFlag(res.getString("ENABLE_FLAG")); 222 | rule.setCreateTime(res.getDate("CREATE_TIME")); 223 | rule.setUpdateTime(res.getDate("UPDATE_TIME")); 224 | if(!preCompile(rule)){ 225 | log.debug("database rule format error."); 226 | throw new RuleEngineException("rule format error."); 227 | //return null; 228 | } 229 | 230 | retList.add(rule); 231 | //只读一条记录。 232 | break; 233 | } 234 | 235 | res.close(); 236 | stmt.close(); 237 | 238 | //accesser.closeConnection(conn); 239 | 240 | } catch (SQLException e) { 241 | log.debug(e.getMessage()); 242 | throw new RuleEngineException(e.getCause()); 243 | } catch (Exception e) { 244 | log.debug(e.getMessage()); 245 | throw new RuleEngineException(e.getCause()); 246 | } 247 | 248 | if(retList.isEmpty()){ 249 | return null; 250 | } 251 | 252 | return retList.get(0); 253 | 254 | } 255 | 256 | 257 | 258 | public static void main(String[] args){ 259 | DBRuleReader reader = new DBRuleReader(); 260 | 261 | try { 262 | reader.getRuleItem("3"); 263 | reader.readRuleItemList(); 264 | } catch (RuleEngineException e) { 265 | // TODO Auto-generated catch block 266 | e.printStackTrace(); 267 | } 268 | 269 | } 270 | 271 | } 272 | 273 | -------------------------------------------------------------------------------- /src/main/java/tech/kiwa/engine/component/impl/DefaultRuleExecutor.java: -------------------------------------------------------------------------------- 1 | //Copyright Hale [hale2000@163.com] 2 | // 3 | //Licensed under the Apache License, Version 2.0 (the "License"); 4 | //you may not use this file except in compliance with the License. 5 | //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 10 | //distributed under the License is distributed on an "AS IS" BASIS, 11 | //WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | //See the License for the specific language governing permissions and 13 | //limitations under the License. 14 | 15 | package tech.kiwa.engine.component.impl; 16 | 17 | import java.math.BigDecimal; 18 | import java.sql.Connection; 19 | import java.sql.PreparedStatement; 20 | import java.sql.ResultSet; 21 | import java.sql.ResultSetMetaData; 22 | import java.sql.SQLException; 23 | import java.text.SimpleDateFormat; 24 | import java.util.ArrayList; 25 | import java.util.Date; 26 | import java.util.HashMap; 27 | import java.util.List; 28 | import java.util.Map; 29 | 30 | import org.apache.commons.lang.StringUtils; 31 | import org.slf4j.Logger; 32 | import org.slf4j.LoggerFactory; 33 | 34 | import tech.kiwa.engine.component.AbstractCommand; 35 | import tech.kiwa.engine.component.AbstractRuleItem; 36 | import tech.kiwa.engine.entity.ItemExecutedResult; 37 | import tech.kiwa.engine.entity.RESULT; 38 | import tech.kiwa.engine.entity.RuleItem; 39 | import tech.kiwa.engine.exception.RuleEngineException; 40 | import tech.kiwa.engine.framework.DBAccesser; 41 | import tech.kiwa.engine.utility.PropertyUtil; 42 | 43 | 44 | /** 45 | * @author Hale.Li 46 | * @since 2018-01-28 47 | * @version 0.1 48 | */ 49 | public class DefaultRuleExecutor extends AbstractRuleItem { 50 | 51 | private Logger log = LoggerFactory.getLogger(DefaultRuleExecutor.class); 52 | 53 | private static volatile DBAccesser accesser = null; //数据库访问类。 54 | 55 | @SuppressWarnings("unchecked") 56 | private DBAccesser loadDBAccesser() throws ClassNotFoundException, InstantiationException, IllegalAccessException{ 57 | 58 | if(accesser == null){ 59 | 60 | String className = PropertyUtil.getProperty("db.accesser"); 61 | Class DBClass = (Class) Class.forName(className); 62 | synchronized(DBAccesser.class){ 63 | if(null == accesser){ 64 | accesser = DBClass.newInstance(); 65 | } 66 | } 67 | } 68 | 69 | return accesser; 70 | } 71 | 72 | 73 | @Override 74 | public ItemExecutedResult doCheck(RuleItem item) throws RuleEngineException { 75 | 76 | String sqlStr = item.getExeSql(); 77 | 78 | if(StringUtils.isEmpty(sqlStr)){ 79 | log.debug("This function must be called when the sql statement is not empty."); 80 | throw new RuleEngineException("This function must be called when the sql statement is not empty."); 81 | } 82 | 83 | // add tailed space. 84 | if(sqlStr.endsWith("?")){ 85 | sqlStr = sqlStr + " "; 86 | } 87 | 88 | String paramName = item.getParamName(); 89 | List paramList = null ; 90 | if(!StringUtils.isEmpty(paramName)){ 91 | 92 | String[] params = paramName.split(","); 93 | String[] sqlSection = sqlStr.split("\\?"); 94 | 95 | if(sqlSection.length != params.length + 1){ 96 | log.debug("the parameters count must be equal to the count of the question mark.item_no = {}, item.desc = {}", item.getItemNo(), item.getContent()); 97 | throw new RuleEngineException("the parameters count must be equal to the count of the question mark."); 98 | } 99 | 100 | if(StringUtils.isEmpty(item.getParamType())){ 101 | log.debug("the cannot be empty if param is assigned. item_no = {}, item.desc = {}", item.getItemNo(), item.getContent()); 102 | throw new RuleEngineException("the cannot be empty if param is assigned."); 103 | } 104 | 105 | String[] paramTypes = item.getParamType().split(","); 106 | if(params.length != paramTypes.length){ 107 | log.debug("the parameters count must be equal to the count of the question mark. item_no = {}, item.desc = {}", item.getItemNo(), item.getContent()); 108 | throw new RuleEngineException("the parameters count must be equal to the count of the question mark."); 109 | } 110 | 111 | paramList =new ArrayList(); 112 | for(int iLoop =0 ; iLoop < paramTypes.length; iLoop++){ 113 | String type = paramTypes[iLoop]; 114 | paramList.add(getParamValue(params[iLoop],type)); 115 | } 116 | 117 | } 118 | 119 | 120 | Map resultSet = null; 121 | resultSet = executeSQL(sqlStr, paramList); 122 | boolean bRet = false; 123 | 124 | bRet = super.analyze(resultSet, item); 125 | 126 | ItemExecutedResult checkResult = new ItemExecutedResult(); 127 | 128 | //默认做法时可以继续执行下一条规则。 129 | checkResult.setContinue(ItemExecutedResult.CONTINUE); 130 | checkResult.setReturnValue(bRet); 131 | 132 | if(bRet){ 133 | checkResult.setResult(RESULT.PASSED); 134 | checkResult.setRemark(RESULT.PASSED.getName()); 135 | //checkResult.setContinue( Integer.parseInt(item.getContinueFlag())); 136 | }else{ 137 | checkResult.setResult(RESULT.REJECTED); 138 | checkResult.setRemark(RESULT.REJECTED.getName()); 139 | //checkResult.setContinue( Integer.parseInt(item.getContinueFlag())); 140 | // add false result return. 141 | } 142 | 143 | this.executeCommand(item, checkResult); 144 | 145 | return checkResult; 146 | } 147 | 148 | @SuppressWarnings("unchecked") 149 | private void executeCommand(RuleItem item, ItemExecutedResult result){ 150 | Class commandClass; 151 | try { 152 | if(StringUtils.isNotEmpty(item.getExecutor())){ 153 | commandClass = (Class) Class.forName(item.getExecutor()); 154 | AbstractCommand command = commandClass.newInstance(); 155 | command.execute(item, result); 156 | } 157 | } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) { 158 | log.debug(e.getMessage()); 159 | } 160 | } 161 | 162 | //TODO: 该函数可以被覆盖,可以实现不同的参数传入效果 163 | 164 | /** 165 | * 根据Param的类型和名称,把Object对象转换成实际的值。 166 | * @param param 167 | * @param type 168 | * @return 169 | */ 170 | protected Object getParamValue( String param, String type){ 171 | 172 | Object value = ""; 173 | switch(type.toLowerCase()){ 174 | 175 | case "object": 176 | value = this.object.toString(); 177 | break; 178 | 179 | case "java.lang.integer": 180 | case "integer": 181 | value = Integer.parseInt(this.object.toString()); 182 | break; 183 | case "java.lang.long": 184 | case "long": 185 | value = Long.parseLong(this.object.toString()); 186 | break; 187 | case "java.lang.boolean": 188 | case "boolean": 189 | value = Boolean.parseBoolean(this.object.toString()); 190 | break; 191 | case "java.lang.byte": 192 | case "byte": 193 | value = Byte.parseByte(this.object.toString()); 194 | break; 195 | case "java.lang.double": 196 | case "dobule": 197 | value = Double.parseDouble(this.object.toString()); 198 | break; 199 | case "java.lang.float": 200 | case "float": 201 | value = Float.parseFloat(this.object.toString()); 202 | break; 203 | case "java.lang.date": 204 | case "date": 205 | SimpleDateFormat sdf = new SimpleDateFormat(PropertyUtil.getProperty("dateFormat")); 206 | value = sdf.format(this.object); 207 | break; 208 | case "java.math.bigdecimal": 209 | case "bigdecimal": 210 | value = new BigDecimal(this.object.toString()); 211 | break; 212 | case "java.lang.character": 213 | case "char": 214 | case "character": 215 | value = Character.valueOf(this.object.toString().charAt(0)); 216 | break; 217 | default: 218 | value = this.object.toString(); 219 | break; 220 | } 221 | 222 | return value; 223 | } 224 | 225 | 226 | /** 227 | * 228 | * @param sqlStr 229 | * @return 230 | * @throws SQLException 231 | * @throws ReflectiveOperationException 232 | * @throws RuleEngineException 233 | */ 234 | private Map executeSQL(String sqlStr, List paramList ) throws RuleEngineException { 235 | 236 | PreparedStatement stmt = null; 237 | ResultSet res = null; 238 | 239 | Map retMap = new HashMap(); 240 | 241 | try { 242 | 243 | loadDBAccesser(); 244 | Connection conn = accesser.getConnection(); 245 | 246 | stmt = conn.prepareStatement(sqlStr); 247 | if(null != paramList && !paramList.isEmpty()){ 248 | for(int iLoop=0; iLoop < paramList.size(); iLoop++){ 249 | 250 | Object param = paramList.get(iLoop); 251 | //从1开始计数。 252 | if(param instanceof String){ 253 | stmt.setString(iLoop + 1 , param.toString()); 254 | } else if(param instanceof Integer){ 255 | stmt.setInt(iLoop+1, ((Integer) param).intValue()); 256 | } else if (param instanceof Long){ 257 | stmt.setLong(iLoop+1 , ((Long) param).longValue()); 258 | // java.util.Date类型对应于timestamp结构了类型。 259 | } else if (param instanceof Date){ 260 | stmt.setTimestamp(iLoop + 1, new java.sql.Timestamp(((Date) param).getTime())); 261 | } else if (param instanceof java.sql.Date){ 262 | stmt.setDate(iLoop + 1, (java.sql.Date) param); 263 | } else if (param instanceof java.sql.Time){ 264 | stmt.setTime(iLoop + 1, (java.sql.Time) param); 265 | } else if (param instanceof java.sql.Timestamp){ 266 | stmt.setTimestamp(iLoop + 1, (java.sql.Timestamp) param); 267 | } else if (param instanceof Double){ 268 | stmt.setDouble(iLoop +1, ((Double) param).doubleValue()); 269 | } else if (param instanceof BigDecimal){ 270 | stmt.setBigDecimal(iLoop + 1, (BigDecimal)param); 271 | } else if (param instanceof Boolean){ 272 | stmt.setBoolean(iLoop+1, ((Boolean) param).booleanValue()); 273 | } else if (param instanceof Byte){ 274 | stmt.setByte(iLoop+1, ((Byte) param).byteValue()); 275 | } else { 276 | stmt.setObject(iLoop+1, param); 277 | } 278 | } 279 | } 280 | 281 | //stmt = conn.createStatement(); 282 | res = stmt.executeQuery(); 283 | ResultSetMetaData columnInfo = res.getMetaData(); 284 | 285 | while(res.next()) 286 | { 287 | int columnCount = columnInfo.getColumnCount(); 288 | for(int iLoop =1; iLoop <= columnCount; iLoop++){ 289 | String colName = columnInfo.getColumnName(iLoop); 290 | retMap.put(colName, res.getObject(iLoop)); 291 | } 292 | 293 | //无条件break.只读取第一行记录。 294 | break; 295 | } 296 | 297 | res.close(); 298 | stmt.close(); 299 | 300 | 301 | 302 | } catch (SQLException e) { 303 | log.debug(e.getMessage()); 304 | throw new RuleEngineException(e.getCause()); 305 | 306 | } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e){ 307 | log.debug(e.getMessage()); 308 | throw new RuleEngineException(e.getCause()); 309 | 310 | } catch (Exception e) { 311 | log.debug(e.getMessage()); 312 | throw new RuleEngineException(e.getCause()); 313 | } 314 | 315 | 316 | return retMap; 317 | } 318 | 319 | 320 | } 321 | -------------------------------------------------------------------------------- /src/main/java/tech/kiwa/engine/component/impl/DroolsRuleExecutor.java: -------------------------------------------------------------------------------- 1 | //Copyright Hale [hale2000@163.com] 2 | // 3 | //Licensed under the Apache License, Version 2.0 (the "License"); 4 | //you may not use this file except in compliance with the License. 5 | //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 10 | //distributed under the License is distributed on an "AS IS" BASIS, 11 | //WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | //See the License for the specific language governing permissions and 13 | //limitations under the License. 14 | 15 | package tech.kiwa.engine.component.impl; 16 | 17 | import org.apache.commons.lang.StringUtils; 18 | import org.slf4j.Logger; 19 | import org.slf4j.LoggerFactory; 20 | 21 | import tech.kiwa.engine.component.AbstractCommand; 22 | import tech.kiwa.engine.component.AbstractRuleItem; 23 | import tech.kiwa.engine.component.drools.DroolsBuilder; 24 | import tech.kiwa.engine.component.drools.LocalCreator; 25 | import tech.kiwa.engine.component.drools.RuleCreator; 26 | import tech.kiwa.engine.entity.ItemExecutedResult; 27 | import tech.kiwa.engine.entity.RESULT; 28 | import tech.kiwa.engine.entity.RuleItem; 29 | import tech.kiwa.engine.exception.RuleEngineException; 30 | 31 | /** 32 | * @author Hale.Li 33 | * @since 2018-01-28 34 | * @version 0.1 35 | */ 36 | public class DroolsRuleExecutor extends AbstractRuleItem { 37 | 38 | private Logger log = LoggerFactory.getLogger(this.getClass()); 39 | 40 | /* (non-Javadoc) 41 | * @see tech.kiwa.engine.component.AbstractRuleItem#doCheck(tech.kiwa.engine.entity.RuleItem) 42 | */ 43 | @Override 44 | public ItemExecutedResult doCheck(RuleItem item) throws RuleEngineException { 45 | 46 | 47 | RuleCreator creator = (RuleCreator) item.getAttach(); 48 | DroolsBuilder builder = creator.getBuilder(); 49 | builder.compile(); 50 | 51 | boolean bRet = creator.runCondition(this.object); 52 | 53 | ItemExecutedResult checkResult = new ItemExecutedResult(); 54 | 55 | //缺省认为是 passed 56 | checkResult.setResult(RESULT.EMPTY); //通过 57 | checkResult.setRemark(RESULT.EMPTY.getName()); 58 | checkResult.setContinue(ItemExecutedResult.CONTINUE); 59 | 60 | checkResult.setReturnValue(bRet); 61 | if(bRet){ 62 | checkResult.setResult(item.getResult()); 63 | checkResult.setRemark(checkResult.getResult().getName()); 64 | checkResult.setContinue( Integer.parseInt(item.getContinueFlag())); 65 | }else{ 66 | // add false result return. 67 | } 68 | 69 | this.executeCommand(item, checkResult); 70 | 71 | return checkResult; 72 | } 73 | 74 | 75 | private void executeCommand(RuleItem item, ItemExecutedResult result){ 76 | 77 | if(!result.getReturnValue()){ 78 | return; 79 | } 80 | 81 | try { 82 | 83 | if(StringUtils.isNotEmpty(item.getExecutor())){ 84 | 85 | RuleCreator rule = (RuleCreator)item.getAttach(); 86 | 87 | DroolsBuilder builder = rule.getBuilder(); 88 | 89 | builder.compile(); 90 | 91 | 92 | AbstractCommand command = (AbstractCommand)builder.createObject(item.getExecutor(), rule.toJavaString()); 93 | 94 | //if(command != null){ 95 | for(LocalCreator result_value: rule.getResultList()){ 96 | if(result_value != null && result_value.getValue() != null){ 97 | command.SetObject(result_value.getValue()); 98 | } 99 | } 100 | 101 | 102 | command.execute(item, result); 103 | //} 104 | } 105 | 106 | } catch (Exception e) { 107 | log.debug(e.getMessage()); 108 | e.printStackTrace(); 109 | } 110 | } 111 | 112 | } 113 | -------------------------------------------------------------------------------- /src/main/java/tech/kiwa/engine/component/impl/DroolsRuleReader.java: -------------------------------------------------------------------------------- 1 | //Copyright Hale [hale2000@163.com] 2 | // 3 | //Licensed under the Apache License, Version 2.0 (the "License"); 4 | //you may not use this file except in compliance with the License. 5 | //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 10 | //distributed under the License is distributed on an "AS IS" BASIS, 11 | //WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | //See the License for the specific language governing permissions and 13 | //limitations under the License. 14 | 15 | package tech.kiwa.engine.component.impl; 16 | 17 | import java.io.File; 18 | import java.io.FileInputStream; 19 | import java.io.FileNotFoundException; 20 | import java.io.IOException; 21 | import java.util.ArrayList; 22 | import java.util.List; 23 | 24 | import org.slf4j.Logger; 25 | import org.slf4j.LoggerFactory; 26 | 27 | import tech.kiwa.engine.component.AbstractRuleReader; 28 | import tech.kiwa.engine.component.drools.DroolsBuilder; 29 | import tech.kiwa.engine.entity.RuleItem; 30 | import tech.kiwa.engine.utility.PropertyUtil; 31 | 32 | 33 | /** 34 | * @author Hale.Li 35 | * @since 2018-01-28 36 | * @version 0.1 37 | */ 38 | public class DroolsRuleReader extends AbstractRuleReader { 39 | 40 | 41 | /* 42 | private static String[] RULE_KEYWORDS = new String[] {"salience", 43 | "when","then","end","agenda-group","auto-focus", "no-loop", 44 | "activation-group","dialect","date-effective","date-exptires","lock-on-active","duration"}; 45 | */ 46 | private Logger log = LoggerFactory.getLogger(DefaultRuleExecutor.class); 47 | 48 | private DroolsBuilder builder = null; 49 | 50 | private String removeComments(String contents){ 51 | 52 | 53 | StringBuffer element = new StringBuffer(); 54 | 55 | for(int iLoop = 0; iLoop < contents.length(); iLoop++){ 56 | 57 | char alphabet = contents.charAt(iLoop); 58 | String keywords = ""; 59 | if(iLoop> 0){ 60 | char preAlpha = contents.charAt(iLoop-1); 61 | keywords = ""+ preAlpha + alphabet; 62 | }else{ 63 | keywords = ""+ alphabet; 64 | } 65 | 66 | int jLoop = iLoop; 67 | switch(keywords){ 68 | 69 | case "//": 70 | element.deleteCharAt(element.length()-1); 71 | case "#": 72 | 73 | //读到行末 74 | for(jLoop = iLoop +1; jLoop < contents.length(); jLoop++){ 75 | alphabet = contents.charAt(jLoop); 76 | 77 | if(alphabet == '\n'){ 78 | element.append(alphabet); 79 | iLoop = jLoop; 80 | break; 81 | } 82 | } 83 | 84 | 85 | break; 86 | 87 | case "/*": 88 | element.deleteCharAt(element.length()-1); 89 | for(jLoop = iLoop +1; jLoop < contents.length(); jLoop++){ 90 | alphabet = contents.charAt(jLoop); 91 | //element.append(alphabet); 92 | String compare = "" + contents.charAt(jLoop-1) + alphabet; 93 | if(compare.equals("*/")){ 94 | iLoop = jLoop; 95 | break; 96 | } 97 | } 98 | break; 99 | 100 | default: 101 | element.append(alphabet); 102 | break; 103 | } // end case 104 | 105 | } // end first for. 106 | 107 | return element.toString(); 108 | } 109 | 110 | private List analyzeTopPhase(String contents){ 111 | 112 | StringBuffer element = new StringBuffer(); 113 | 114 | List thePhases = new ArrayList(); 115 | for(int iLoop = 0; iLoop < contents.length(); iLoop++){ 116 | 117 | char alphabet = contents.charAt(iLoop); 118 | 119 | //去除空行。 120 | if(element.length() == 0 && (alphabet == '\r' || alphabet =='\n')){ 121 | continue; 122 | }else{ 123 | element.append(alphabet); 124 | } 125 | 126 | int jLoop = iLoop; 127 | switch(element.toString()){ 128 | case "package ": 129 | case "package\t": 130 | case "import ": 131 | case "import\t": 132 | case "globals ": 133 | case "globals\t": 134 | case "global ": 135 | case "global\t": 136 | if(iLoop >= element.length()){ 137 | 138 | char preAlpha = contents.charAt(iLoop-element.length()); 139 | if(preAlpha != ' ' && preAlpha != '\t' && preAlpha != '\r' && preAlpha != '\n'){ 140 | break; 141 | } 142 | } 143 | //这里没有break. 144 | //读到行末 145 | for(jLoop = iLoop +1; jLoop < contents.length(); jLoop++){ 146 | alphabet = contents.charAt(jLoop); 147 | element.append(alphabet); 148 | if(alphabet == '\n'){ 149 | thePhases.add(element.toString().trim()); 150 | iLoop = jLoop; 151 | element = new StringBuffer(); 152 | break; 153 | } 154 | } 155 | 156 | break; 157 | case "function ": 158 | case "function\t": 159 | //防止前黏连。 160 | if(iLoop >= element.length()){ 161 | char preAlpha = contents.charAt(iLoop-element.length()); 162 | if(preAlpha != ' ' && preAlpha != '\t' && preAlpha != '\r' && preAlpha != '\n'){ 163 | break; 164 | } 165 | } 166 | int level = 1 , count = 0; 167 | for(jLoop = iLoop +1; jLoop < contents.length(); jLoop++){ 168 | alphabet = contents.charAt(jLoop); 169 | element.append(alphabet); 170 | if(alphabet == '{' ){ 171 | count ++; 172 | level = count; 173 | } 174 | if(alphabet == '}'){ 175 | level --; 176 | } 177 | if(level == 0){ 178 | thePhases.add(element.toString().trim()); 179 | iLoop = jLoop; 180 | element = new StringBuffer(); 181 | break; 182 | } 183 | } 184 | 185 | break; 186 | case "query ": 187 | case "query\t": 188 | case "declare ": 189 | case "declare\t": 190 | case "rule ": 191 | case "rule\t": 192 | case "rule\r": 193 | case "rule\n": 194 | //防止前黏连。 195 | if(iLoop >= element.length()){ 196 | char preAlpha = contents.charAt(iLoop-element.length()); 197 | if(preAlpha != ' ' && preAlpha != '\t' && preAlpha != '\r' && preAlpha != '\n'){ 198 | break; 199 | } 200 | } 201 | 202 | //查找对应的end关键字 203 | for(jLoop = iLoop +1; jLoop < contents.length(); jLoop++){ 204 | alphabet = contents.charAt(jLoop); 205 | element.append(alphabet); 206 | 207 | //防止前黏连 208 | if(contents.charAt(jLoop-3) == ' ' || contents.charAt(jLoop-3) == '\n' 209 | ||contents.charAt(jLoop-3) == '\r'||contents.charAt(jLoop-3) == '\t'){ 210 | //防止后黏连 211 | if(jLoop == contents.length() -1 || contents.charAt(jLoop+1) == '\r' 212 | || contents.charAt(jLoop+1) == ' '|| contents.charAt(jLoop+1) == '\t' 213 | || contents.charAt(jLoop+1) == '\n'){ 214 | 215 | String compare = "" + contents.charAt(jLoop-2) + contents.charAt(jLoop-1) + alphabet; 216 | if(compare.equals("end")){ 217 | thePhases.add(element.toString().trim()); 218 | iLoop = jLoop; 219 | element = new StringBuffer(); 220 | break; 221 | } 222 | } 223 | } 224 | } 225 | break; 226 | default: 227 | if(alphabet == '\r' || alphabet =='\n'){ 228 | log.debug("unknown keyword:" + element.toString()); 229 | element = new StringBuffer(); 230 | } 231 | break; 232 | } // end case 233 | 234 | } // end first for. 235 | 236 | return thePhases; 237 | } 238 | 239 | 240 | 241 | 242 | 243 | /* 244 | private List parseCondition(RuleItem rule){ 245 | 246 | String content = rule.getExeClass(); 247 | if(StringUtils.isEmpty(content)){ 248 | return null; 249 | } 250 | content = content.trim(); 251 | 252 | String[] lines = content.split("\\n|\\r"); 253 | 254 | List queryList = new ArrayList(); 255 | 256 | rule.setRemark(queryList); 257 | 258 | for(int iLoop =0 ; iLoop < lines.length; iLoop ++){ 259 | String line = lines[iLoop].trim(); 260 | 261 | 262 | Query query = new Query(); 263 | String[] sections = line.split(":"); 264 | Local local = new Local(); 265 | 266 | if(sections.length >= 2){ 267 | local.name = sections[0]; 268 | 269 | int pos = sections[1].indexOf("("); 270 | //sections = sections[1].split("\\("); 271 | local.reference = sections[1].substring(0, pos); 272 | 273 | if( sections[1].endsWith(")")){ 274 | sections[1] = sections[1].substring(pos+1, sections[1].length()-1 ); 275 | sections[1] = sections[1].trim(); 276 | } 277 | query.content = sections[1]; 278 | 279 | }else{ 280 | 281 | int pos = line.indexOf("("); 282 | //sections = sections[1].split("\\("); 283 | local.reference = line.substring(0, pos); 284 | 285 | if( line.endsWith(")")){ 286 | line = line.substring(pos+1, line.length()-1 ); 287 | line = line.trim(); 288 | } 289 | query.content = line; 290 | rule.setExeClass(line); 291 | } 292 | 293 | query.result = local; 294 | queryList.add(query); 295 | 296 | } 297 | 298 | return null; 299 | } 300 | 301 | */ 302 | public static void main(String[] args) { 303 | 304 | DroolsRuleReader reader = new DroolsRuleReader(); 305 | reader.readFile(); 306 | } 307 | 308 | private void readFile(){ 309 | 310 | 311 | String ruleEngineFile = PropertyUtil.getProperty("drools.rule.filename"); 312 | if(!ruleEngineFile.startsWith(File.separator)){ 313 | File dir = new File(PropertyUtil.class.getClassLoader().getResource("").getPath()); 314 | ruleEngineFile = dir + File.separator + ruleEngineFile; 315 | } 316 | File file = new File(ruleEngineFile); 317 | 318 | byte[] fileContent = new byte[(int) file.length()]; 319 | 320 | try { 321 | FileInputStream fisRule = new FileInputStream(file); 322 | fisRule.read(fileContent); 323 | fisRule.close(); 324 | } catch (FileNotFoundException e) { 325 | e.printStackTrace(); 326 | } catch (IOException e) { 327 | e.printStackTrace(); 328 | } 329 | 330 | String noComments = removeComments(new String(fileContent)); 331 | 332 | //System.out.println("-------------------------------------------"); 333 | List phases = analyzeTopPhase(noComments); 334 | if(builder == null){ 335 | builder = new DroolsBuilder(); 336 | } 337 | builder.build(phases); 338 | } 339 | 340 | 341 | 342 | @Override 343 | public List readRuleItemList() { 344 | 345 | //缓存加载 346 | if(!ruleItemCache.isEmpty()){ 347 | return ruleItemCache; 348 | } 349 | 350 | if(builder == null){ 351 | readFile(); 352 | } 353 | 354 | synchronized(ruleItemCache){ 355 | ruleItemCache.addAll(builder.getRuleItemList()); 356 | } 357 | 358 | return ruleItemCache; 359 | } 360 | 361 | @Override 362 | public Long getRuleItemCount() { 363 | 364 | if(builder == null){ 365 | readFile(); 366 | } 367 | int count = builder.getRuleItemList().size(); 368 | return new Long(count); 369 | 370 | } 371 | 372 | @Override 373 | public RuleItem getRuleItem(String ruleId) { 374 | 375 | if(builder == null){ 376 | readFile(); 377 | } 378 | 379 | List list = builder.getRuleItemList(); 380 | for(RuleItem item :list){ 381 | if(item.getItemNo().equals(ruleId)){ 382 | return item; 383 | } 384 | } 385 | 386 | return null; 387 | } 388 | 389 | public void convertToXml(String drlFile, String xmlFile){ 390 | 391 | } 392 | 393 | } 394 | -------------------------------------------------------------------------------- /src/main/java/tech/kiwa/engine/component/impl/XMLRuleReader.java: -------------------------------------------------------------------------------- 1 | //Copyright Hale [hale2000@163.com] 2 | // 3 | //Licensed under the Apache License, Version 2.0 (the "License"); 4 | //you may not use this file except in compliance with the License. 5 | //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 10 | //distributed under the License is distributed on an "AS IS" BASIS, 11 | //WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | //See the License for the specific language governing permissions and 13 | //limitations under the License. 14 | 15 | package tech.kiwa.engine.component.impl; 16 | 17 | import java.io.File; 18 | import java.util.ArrayList; 19 | import java.util.List; 20 | 21 | import javax.xml.parsers.DocumentBuilder; 22 | import javax.xml.parsers.DocumentBuilderFactory; 23 | 24 | import org.slf4j.Logger; 25 | import org.slf4j.LoggerFactory; 26 | import org.w3c.dom.Document; 27 | import org.w3c.dom.NamedNodeMap; 28 | import org.w3c.dom.Node; 29 | import org.w3c.dom.NodeList; 30 | 31 | import tech.kiwa.engine.component.AbstractRuleReader; 32 | import tech.kiwa.engine.entity.RuleItem; 33 | import tech.kiwa.engine.exception.RuleEngineException; 34 | import tech.kiwa.engine.utility.PropertyUtil; 35 | 36 | /** 37 | * @author Hale.Li 38 | * @since 2018-01-28 39 | * @version 0.1 40 | */ 41 | public class XMLRuleReader extends AbstractRuleReader { 42 | 43 | private static Logger log = LoggerFactory.getLogger(XMLRuleReader.class); 44 | 45 | private List itemList = null; 46 | 47 | @Override 48 | public List readRuleItemList() throws RuleEngineException { 49 | 50 | 51 | //缓存加载 52 | if(!ruleItemCache.isEmpty()){ 53 | return ruleItemCache; 54 | } 55 | 56 | itemList = new ArrayList(); 57 | 58 | try { 59 | // 创建DOM文档对象 60 | DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance(); 61 | DocumentBuilder builder = dFactory.newDocumentBuilder(); 62 | Document doc; 63 | 64 | String configFile = PropertyUtil.getProperty("xml.rule.filename"); 65 | if(!configFile.startsWith(File.separator)){ 66 | File dir = new File(PropertyUtil.class.getClassLoader().getResource("").getPath()); 67 | configFile = dir + File.separator + configFile; 68 | } 69 | 70 | doc = builder.parse(new File(configFile)); 71 | 72 | // 获取包含类名的文本节点 73 | NodeList ruleList = doc.getElementsByTagName("rule"); 74 | for(int iLoop =0; iLoop < ruleList.getLength();iLoop++){ 75 | 76 | RuleItem item = new RuleItem(); 77 | 78 | Node rule = ruleList.item(iLoop); 79 | NamedNodeMap attributes = rule.getAttributes(); 80 | if(null == attributes || attributes.getNamedItem("id") == null){ 81 | log.debug("rule id must not be null. rule.context = {}", rule.getTextContent()); 82 | return null; 83 | } 84 | 85 | String xmlRuleId = attributes.getNamedItem("id").getNodeValue(); 86 | 87 | item.setItemNo(xmlRuleId); 88 | for(int jLoop =0 ; jLoop < attributes.getLength(); jLoop++){ 89 | Node node = attributes.item(jLoop); 90 | item.setMappedValue(node.getNodeName(), node.getNodeValue()); 91 | } 92 | 93 | // alias of attribute name. 94 | if(attributes.getNamedItem("class") != null){ 95 | item.setExeClass(attributes.getNamedItem("class").getNodeValue()); 96 | } 97 | if(attributes.getNamedItem("method") != null){ 98 | item.setExecutor(rule.getAttributes().getNamedItem("method").getNodeValue()); 99 | } 100 | if(attributes.getNamedItem("parent") != null){ 101 | item.setParentItemNo(rule.getAttributes().getNamedItem("parent").getNodeValue()); 102 | } 103 | 104 | if(rule.hasChildNodes()){ 105 | Node child = rule.getFirstChild(); 106 | while(child != null){ 107 | 108 | if("property".equalsIgnoreCase(child.getNodeName())){ 109 | NamedNodeMap childAttrs = child.getAttributes(); 110 | Node nameNode = childAttrs.getNamedItem("name"); 111 | Node valueNode = childAttrs.getNamedItem("value"); 112 | if(valueNode == null || nameNode == null){ 113 | throw new RuleEngineException("rule format error, attribute value or name must existed."); 114 | } 115 | Node typeNode = childAttrs.getNamedItem("type"); 116 | item.setMappedValue(nameNode.getNodeValue(), valueNode.getNodeValue()); 117 | 118 | if("param".equalsIgnoreCase(nameNode.getNodeValue())){ 119 | item.setParamName(valueNode.getNodeValue()); 120 | item.setParamType(typeNode.getNodeValue()); 121 | } 122 | if("comparison".equalsIgnoreCase(nameNode.getNodeValue())){ 123 | Node codeNode = childAttrs.getNamedItem("code"); 124 | item.setComparisonCode(codeNode.getNodeValue()); 125 | item.setComparisonValue(valueNode.getNodeValue()); 126 | } 127 | 128 | } 129 | 130 | child = child.getNextSibling(); 131 | } 132 | } // endif hasChildNodes. 133 | 134 | if(!preCompile(item)){ 135 | log.debug("xml rule format error."); 136 | throw new RuleEngineException("rule format error."); 137 | //return null; 138 | } 139 | 140 | itemList.add(item); 141 | 142 | } // end for 143 | 144 | 145 | } catch (Exception e) { 146 | log.debug(e.getMessage()); 147 | throw new RuleEngineException(e.getCause()); 148 | //return null; 149 | } 150 | 151 | synchronized(ruleItemCache){ 152 | ruleItemCache.addAll(itemList); 153 | } 154 | 155 | return ruleItemCache; 156 | 157 | } 158 | 159 | @Override 160 | public Long getRuleItemCount() throws RuleEngineException { 161 | 162 | if(itemList == null){ 163 | this.readRuleItemList(); 164 | return (long) itemList.size(); 165 | } 166 | 167 | return 0L; 168 | } 169 | 170 | @Override 171 | public RuleItem getRuleItem(String ruleId) throws RuleEngineException { 172 | 173 | if(itemList == null){ 174 | this.readRuleItemList(); 175 | } 176 | 177 | for(RuleItem rule: itemList){ 178 | if(rule.getItemNo().equalsIgnoreCase(ruleId)){ 179 | return rule; 180 | } 181 | } 182 | 183 | 184 | RuleItem item = new RuleItem(); 185 | try { 186 | // 创建DOM文档对象 187 | DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance(); 188 | DocumentBuilder builder = dFactory.newDocumentBuilder(); 189 | Document doc; 190 | 191 | String configFile = PropertyUtil.getProperty("xml.rule.filename"); 192 | if(!configFile.startsWith(File.separator)){ 193 | File dir = new File(PropertyUtil.class.getClassLoader().getResource("").getPath()); 194 | configFile = dir + File.separator + configFile; 195 | } 196 | 197 | doc = builder.parse(new File(configFile)); 198 | 199 | // 获取包含类名的文本节点 200 | NodeList ruleList = doc.getElementsByTagName("rule"); 201 | for(int iLoop =0; iLoop < ruleList.getLength();iLoop++){ 202 | 203 | Node rule = ruleList.item(iLoop); 204 | NamedNodeMap attributes = rule.getAttributes(); 205 | if(null == attributes || attributes.getNamedItem("id") == null){ 206 | log.debug("rule id must not be null."); 207 | return null; 208 | } 209 | 210 | String xmlRuleId = attributes.getNamedItem("id").getNodeValue(); 211 | 212 | 213 | if(!ruleId.equalsIgnoreCase(xmlRuleId)){ 214 | continue; 215 | } 216 | 217 | item.setItemNo(xmlRuleId); 218 | for(int jLoop =0 ; jLoop < attributes.getLength(); jLoop++){ 219 | Node node = attributes.item(jLoop); 220 | item.setMappedValue(node.getNodeName(), node.getNodeValue()); 221 | } 222 | 223 | // alias attribute name. 224 | if(attributes.getNamedItem("class") != null){ 225 | item.setExeClass(attributes.getNamedItem("class").getNodeValue()); 226 | } 227 | if(attributes.getNamedItem("method") != null){ 228 | item.setExecutor(rule.getAttributes().getNamedItem("method").getNodeValue()); 229 | } 230 | if(attributes.getNamedItem("parent") != null){ 231 | item.setParentItemNo(rule.getAttributes().getNamedItem("parent").getNodeValue()); 232 | } 233 | 234 | if(rule.hasChildNodes()){ 235 | Node child = rule.getFirstChild(); 236 | while(child != null){ 237 | 238 | if("property".equalsIgnoreCase(child.getNodeName())){ 239 | NamedNodeMap childAttrs = child.getAttributes(); 240 | Node nameNode = childAttrs.getNamedItem("name"); 241 | Node valueNode = childAttrs.getNamedItem("value"); 242 | item.setMappedValue(nameNode.getNodeValue(), valueNode.getNodeValue()); 243 | } 244 | 245 | child = child.getNextSibling(); 246 | } 247 | } 248 | 249 | if(!preCompile(item)){ 250 | log.debug("xml rule format error."); 251 | throw new RuleEngineException("rule format error."); 252 | //return null; 253 | } 254 | 255 | // found , then return. 256 | if(ruleId.equalsIgnoreCase(xmlRuleId)){ 257 | return item; 258 | //break; 259 | } 260 | } 261 | 262 | 263 | } catch (Exception e) { 264 | log.debug(e.getMessage()); 265 | throw new RuleEngineException(e.getCause()); 266 | //return null; 267 | } 268 | 269 | return null; 270 | } 271 | 272 | 273 | 274 | 275 | public static void main(String[] args){ 276 | XMLRuleReader reader = new XMLRuleReader(); 277 | try { 278 | reader.getRuleItem("blacklist"); 279 | } catch (RuleEngineException e) { 280 | // TODO Auto-generated catch block 281 | e.printStackTrace(); 282 | } 283 | } 284 | } 285 | -------------------------------------------------------------------------------- /src/main/java/tech/kiwa/engine/entity/EngineRunResult.java: -------------------------------------------------------------------------------- 1 | //Copyright Hale [hale2000@163.com] 2 | // 3 | //Licensed under the Apache License, Version 2.0 (the "License"); 4 | //you may not use this file except in compliance with the License. 5 | //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 10 | //distributed under the License is distributed on an "AS IS" BASIS, 11 | //WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | //See the License for the specific language governing permissions and 13 | //limitations under the License. 14 | 15 | package tech.kiwa.engine.entity; 16 | /** 17 | * @author Hale.Li 18 | * @since 2018-01-28 19 | * @version 0.1 20 | */ 21 | public class EngineRunResult { 22 | 23 | private RESULT result = RESULT.EMPTY; 24 | 25 | private String result_desc; 26 | 27 | private String sequence; 28 | 29 | public RESULT getResult() { 30 | return result; 31 | } 32 | 33 | public void setResult(RESULT result) { 34 | this.result = result; 35 | } 36 | 37 | public void setResult(String result) { 38 | 39 | boolean bRet = this.result.parse(result); 40 | if(!bRet){ 41 | try { 42 | this.result.setValue(Integer.parseInt(result)); 43 | } catch (NumberFormatException e) { 44 | 45 | } 46 | } 47 | } 48 | 49 | public void setResult(int result) { 50 | 51 | this.result.setValue(result); 52 | } 53 | 54 | public String getResult_desc() { 55 | return result_desc; 56 | } 57 | 58 | public void setResult_desc(String result_desc) { 59 | 60 | this.result_desc = result_desc; 61 | this.result.parse(result_desc); 62 | 63 | } 64 | 65 | public String getSequence() { 66 | return sequence; 67 | } 68 | 69 | public void setSequence(String sequence) { 70 | this.sequence = sequence; 71 | } 72 | 73 | 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/tech/kiwa/engine/entity/ItemExecutedResult.java: -------------------------------------------------------------------------------- 1 | //Copyright Hale [hale2000@163.com] 2 | // 3 | //Licensed under the Apache License, Version 2.0 (the "License"); 4 | //you may not use this file except in compliance with the License. 5 | //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 10 | //distributed under the License is distributed on an "AS IS" BASIS, 11 | //WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | //See the License for the specific language governing permissions and 13 | //limitations under the License. 14 | 15 | package tech.kiwa.engine.entity; 16 | 17 | /** 18 | * @author Hale.Li 19 | * @since 2018-01-28 20 | * @version 0.1 21 | */ 22 | public class ItemExecutedResult { 23 | 24 | public static final int CONTINUE = 1; 25 | public static final int LOOP = 2; 26 | public static final int BROKEN = 3; 27 | 28 | private RESULT result =RESULT.EMPTY; 29 | private String remark; 30 | 31 | private boolean returnValue ; 32 | 33 | public boolean getReturnValue() { 34 | return returnValue; 35 | } 36 | 37 | public void setReturnValue(boolean returnValue) { 38 | this.returnValue = returnValue; 39 | } 40 | 41 | private int continueFlag = CONTINUE; //默认可以继续 42 | 43 | public RESULT getResult() { 44 | return result; 45 | } 46 | 47 | public void setResult(RESULT result) { 48 | 49 | this.result = result; 50 | if(this.result == RESULT.WAIT){ 51 | continueFlag = BROKEN; 52 | } 53 | //continueFlag = ( this.result != RESULT.WAIT); //非中断状态 54 | } 55 | 56 | public void setResult(String result) { 57 | 58 | int iResult = Integer.parseInt(result); 59 | this.setResult(iResult); 60 | 61 | } 62 | 63 | public void setResult(int result) { 64 | 65 | this.result.setValue(result); 66 | if(this.result == RESULT.WAIT){ 67 | continueFlag = BROKEN; 68 | } 69 | //continueFlag = ( this.result != RESULT.WAIT); //非中断状态 70 | } 71 | 72 | 73 | public String getRemark() { 74 | return remark; 75 | } 76 | 77 | public void setRemark(String remark) { 78 | this.remark = remark; 79 | } 80 | 81 | public boolean canBeContinue(){ 82 | 83 | return continueFlag == CONTINUE; 84 | } 85 | 86 | public void setContinue(int contin){ 87 | this.continueFlag = contin; 88 | } 89 | 90 | public boolean shouldLoop(){ 91 | 92 | return continueFlag == LOOP; 93 | 94 | } 95 | } 96 | 97 | -------------------------------------------------------------------------------- /src/main/java/tech/kiwa/engine/entity/RESULT.java: -------------------------------------------------------------------------------- 1 | //Copyright Hale [hale2000@163.com] 2 | // 3 | //Licensed under the Apache License, Version 2.0 (the "License"); 4 | //you may not use this file except in compliance with the License. 5 | //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 10 | //distributed under the License is distributed on an "AS IS" BASIS, 11 | //WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | //See the License for the specific language governing permissions and 13 | //limitations under the License. 14 | 15 | package tech.kiwa.engine.entity; 16 | /** 17 | * @author Hale.Li 18 | * @since 2018-01-28 19 | * @version 0.1 20 | */ 21 | public enum RESULT { 22 | 23 | EMPTY(0), PASSED(1), CONCERNED(2), REJECTED(3) , WAIT(4), SELFDEFINE(5); 24 | 25 | RESULT(){ 26 | 27 | } 28 | private RESULT(int value){ 29 | this.setValue(value); 30 | } 31 | 32 | private int value = 0; 33 | public void setValue(int value){ 34 | switch (value){ 35 | case 1: 36 | defaultDesc= "PASSED"; 37 | break; 38 | case 2: 39 | defaultDesc= "CONCERNED"; 40 | break; 41 | case 3: 42 | defaultDesc= "REJECTED"; 43 | break; 44 | case 4: 45 | defaultDesc= "WAIT"; 46 | break; 47 | case 5: 48 | defaultDesc= "SELFDEFINE"; 49 | break; 50 | default: 51 | break; 52 | } 53 | 54 | this.value = value; 55 | } 56 | 57 | public int compare(RESULT target){ 58 | return this.value - target.value; 59 | } 60 | 61 | public static RESULT valueOf(int value) { 62 | 63 | RESULT result = RESULT.EMPTY; 64 | result.setValue(value); 65 | return result; 66 | 67 | } 68 | 69 | /* 70 | @Override 71 | public int compareTo(RESULT o){ 72 | return 0; 73 | } 74 | */ 75 | public int getValue(){ 76 | return value; 77 | } 78 | 79 | private String defaultDesc = ""; 80 | public String getName() { 81 | return defaultDesc; 82 | } 83 | 84 | public void setName(String defaultDesc) { 85 | this.defaultDesc = defaultDesc; 86 | this.parse(defaultDesc); 87 | } 88 | 89 | public boolean parse(String value ){ 90 | 91 | boolean bRet = true; 92 | value = value.toUpperCase(); 93 | switch (value){ 94 | case "PASSED": 95 | case "RESULT.PASSED": 96 | this.value = 1; 97 | this.defaultDesc = "PASSED"; 98 | break; 99 | case "CONCERNED": 100 | case "RESULT.CONCERNED": 101 | this.value = 2; 102 | this.defaultDesc= "CONCERNED"; 103 | break; 104 | case "REJECTED": 105 | case "RESULT.REJECTED": 106 | this.value = 3; 107 | this.defaultDesc = "REJECTED"; 108 | break; 109 | case "WAIT": 110 | case "RESULT.WAIT": 111 | this.value = 4; 112 | this.defaultDesc="WAIT"; 113 | break; 114 | case "SELFDEFINE": 115 | case "RESULT.SELFDEFINE": 116 | this.value = 5; 117 | this.defaultDesc = "SELFDEFINE"; 118 | break; 119 | default: 120 | bRet = false; 121 | break; 122 | } 123 | 124 | return bRet; 125 | } 126 | 127 | } -------------------------------------------------------------------------------- /src/main/java/tech/kiwa/engine/entity/RuleItem.java: -------------------------------------------------------------------------------- 1 | //Copyright Hale [hale2000@163.com] 2 | // 3 | //Licensed under the Apache License, Version 2.0 (the "License"); 4 | //you may not use this file except in compliance with the License. 5 | //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 10 | //distributed under the License is distributed on an "AS IS" BASIS, 11 | //WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | //See the License for the specific language governing permissions and 13 | //limitations under the License. 14 | 15 | package tech.kiwa.engine.entity; 16 | 17 | import java.io.Serializable; 18 | import java.util.Date; 19 | 20 | import tech.kiwa.engine.framework.OperatorFactory; 21 | /** 22 | * @author Hale.Li 23 | * @since 2018-01-28 24 | * @version 0.1 25 | */ 26 | 27 | public class RuleItem implements Serializable { 28 | 29 | private static final long serialVersionUID = -4129428406038157150L; 30 | 31 | private String itemNo; 32 | private String content; 33 | private String exeSql; 34 | private String exeClass; 35 | private String paramName; 36 | private String paramType; 37 | private String comparisonCode; 38 | private String comparisonValue; 39 | private String baseline; 40 | private String result; 41 | private String executor; 42 | private String priority; 43 | private String continueFlag; 44 | private String parentItemNo; 45 | private String groupExpress; 46 | private Object attach; 47 | private String comments; 48 | private String enableFlag; 49 | private Date createTime; 50 | private Date updateTime; 51 | 52 | 53 | public void setMappedValue(String name, String value){ 54 | switch(name.toLowerCase()){ 55 | case "itemno": 56 | case "ruleid": 57 | case "id": 58 | this.itemNo = value; 59 | break; 60 | case "auditdesc": 61 | case "content": 62 | this.content = value; 63 | break; 64 | case "exe_sql": 65 | this.exeSql = value; 66 | break; 67 | case "param_name": 68 | this.paramName = value; 69 | break; 70 | case "param_type": 71 | this.paramType = value; 72 | break; 73 | case "java_class": 74 | case "exe_class": 75 | this.exeClass = value; 76 | break; 77 | case "executor": 78 | case "command": 79 | this.executor = value; 80 | break; 81 | case "comments": 82 | this.comments = value; 83 | break; 84 | case "attach": 85 | this.attach = value; 86 | break; 87 | case "logic_key": 88 | case "comparison_code": 89 | this.comparisonCode = value; 90 | if(null != value && comparisonValue == null){ 91 | this.comparisonValue = OperatorFactory.OPR_CODE.getValue(value); 92 | } 93 | break; 94 | case "logic_value": 95 | case "comparison_value": 96 | this.comparisonValue = value; 97 | if(null != value && comparisonCode == null){ 98 | this.comparisonCode = OperatorFactory.OPR_CODE.getCode(value); 99 | } 100 | break; 101 | case "baseline": 102 | this.baseline = value; 103 | break; 104 | case "result_key": 105 | case "result": 106 | this.result = value; 107 | break; 108 | 109 | case "priority": 110 | this.priority = value; 111 | break; 112 | case "enable_flag": 113 | this.enableFlag = value; 114 | break; 115 | case "continue_flag": 116 | this.continueFlag = value; 117 | break; 118 | case "parent_item_no": 119 | case "parent": 120 | this.parentItemNo = value; 121 | break; 122 | case "group_express": 123 | case "parent_express": 124 | this.groupExpress = value; 125 | break; 126 | default: 127 | break; 128 | } 129 | } 130 | 131 | public Object getValue(String name){ 132 | 133 | Object value = null; 134 | if(name.equals("itemno")){ 135 | value = this.itemNo; 136 | } 137 | 138 | return value; 139 | } 140 | 141 | public String getItemNo() { 142 | return itemNo; 143 | } 144 | public void setItemNo(String itemNo) { 145 | this.itemNo = (itemNo == null ? null : itemNo.trim()); 146 | } 147 | public String getContent() { 148 | return content; 149 | } 150 | public void setContent(String content) { 151 | this.content = (content == null ? null : content.trim()); 152 | } 153 | public String getExeSql() { 154 | return exeSql; 155 | } 156 | public void setExeSql(String exeSql) { 157 | this.exeSql = (exeSql == null ? null : exeSql.trim()); 158 | } 159 | public String getExeClass() { 160 | return exeClass; 161 | } 162 | public void setExeClass(String exeClass) { 163 | this.exeClass = (exeClass == null ? null : exeClass.trim()); 164 | } 165 | public String getParamName() { 166 | return paramName; 167 | } 168 | public void setParamName(String paramName) { 169 | this.paramName = (paramName == null ? null : paramName.trim()); 170 | } 171 | public String getParamType() { 172 | return paramType; 173 | } 174 | public void setParamType(String paramType) { 175 | this.paramType = (paramType == null ? null : paramType.trim()); 176 | } 177 | public String getComparisonCode() { 178 | return comparisonCode; 179 | } 180 | public void setComparisonCode(String comparisonCode) { 181 | this.comparisonCode = (comparisonCode == null ? null : comparisonCode.trim()); 182 | } 183 | public String getComparisonValue() { 184 | return comparisonValue; 185 | } 186 | public void setComparisonValue(String comparisonValue) { 187 | this.comparisonValue = (comparisonValue == null ? null : comparisonValue.trim()); 188 | } 189 | public String getBaseline() { 190 | return baseline; 191 | } 192 | public void setBaseline(String baseline) { 193 | this.baseline = (baseline == null ? null : baseline.trim()); 194 | } 195 | public String getResult() { 196 | return result; 197 | } 198 | public void setResult(String result) { 199 | this.result = (result == null ? null : result.trim()); 200 | } 201 | public String getExecutor() { 202 | return executor; 203 | } 204 | public void setExecutor(String executor) { 205 | this.executor = (executor == null ? null : executor.trim()); 206 | } 207 | public String getPriority() { 208 | return priority; 209 | } 210 | public void setPriority(String priority) { 211 | this.priority = (priority == null ? null : priority.trim()); 212 | } 213 | public String getContinueFlag() { 214 | return continueFlag; 215 | } 216 | public void setContinueFlag(String continueFlag) { 217 | this.continueFlag = (continueFlag == null ? null : continueFlag.trim()); 218 | } 219 | public String getParentItemNo() { 220 | return parentItemNo; 221 | } 222 | public void setParentItemNo(String parentItemNo) { 223 | this.parentItemNo = (parentItemNo == null ? null : parentItemNo.trim()); 224 | } 225 | public String getGroupExpress() { 226 | return groupExpress; 227 | } 228 | public void setGroupExpress(String groupExpress) { 229 | this.groupExpress = (groupExpress == null ? null : groupExpress.trim()); 230 | } 231 | public Object getAttach() { 232 | return attach; 233 | } 234 | public void setAttach(Object attachment) { 235 | if(attachment instanceof String){ 236 | this.attach = (attachment == null ? null : ((String)attachment).trim()); 237 | }else{ 238 | this.attach = attachment; 239 | } 240 | } 241 | 242 | public void setRemark(String remark) { 243 | this.attach = (remark == null ? null : remark.trim()); 244 | } 245 | 246 | public String getComments() { 247 | return comments; 248 | } 249 | public void setComments(String comments) { 250 | this.comments = (comments == null ? null : comments.trim()); 251 | } 252 | public String getEnableFlag() { 253 | return enableFlag; 254 | } 255 | public void setEnableFlag(String enableFlag) { 256 | this.enableFlag = (enableFlag == null ? null : enableFlag.trim()); 257 | } 258 | 259 | public void setEnableFlag(boolean enableFlag) { 260 | this.enableFlag = (enableFlag ? "1" : "2"); 261 | } 262 | 263 | public Date getCreateTime() { 264 | return createTime; 265 | } 266 | public void setCreateTime(Date createTime) { 267 | this.createTime = createTime; 268 | } 269 | public Date getUpdateTime() { 270 | return updateTime; 271 | } 272 | public void setUpdateTime(Date updateTime) { 273 | this.updateTime = updateTime; 274 | } 275 | 276 | 277 | } 278 | -------------------------------------------------------------------------------- /src/main/java/tech/kiwa/engine/exception/EmptyResultSetException.java: -------------------------------------------------------------------------------- 1 | //Copyright Hale [hale2000@163.com] 2 | // 3 | //Licensed under the Apache License, Version 2.0 (the "License"); 4 | //you may not use this file except in compliance with the License. 5 | //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 10 | //distributed under the License is distributed on an "AS IS" BASIS, 11 | //WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | //See the License for the specific language governing permissions and 13 | //limitations under the License. 14 | 15 | package tech.kiwa.engine.exception; 16 | /** 17 | * @author Hale.Li 18 | * @since 2018-01-28 19 | * @version 0.1 20 | */ 21 | public class EmptyResultSetException extends RuleEngineException { 22 | 23 | /** 24 | * 25 | */ 26 | private static final long serialVersionUID = -2247544711821509687L; 27 | 28 | public EmptyResultSetException() { 29 | super(); 30 | } 31 | 32 | public EmptyResultSetException(String message) { 33 | super(message); 34 | } 35 | 36 | public EmptyResultSetException(Throwable cause) { 37 | super(cause); 38 | } 39 | 40 | public EmptyResultSetException(String message,Throwable cause) { 41 | super(message, cause); 42 | } 43 | 44 | 45 | public EmptyResultSetException(String message, Throwable cause, 46 | boolean enableSuppression, 47 | boolean writableStackTrace) { 48 | super(message, cause, enableSuppression, writableStackTrace); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/tech/kiwa/engine/exception/RuleEngineException.java: -------------------------------------------------------------------------------- 1 | //Copyright Hale [hale2000@163.com] 2 | // 3 | //Licensed under the Apache License, Version 2.0 (the "License"); 4 | //you may not use this file except in compliance with the License. 5 | //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 10 | //distributed under the License is distributed on an "AS IS" BASIS, 11 | //WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | //See the License for the specific language governing permissions and 13 | //limitations under the License. 14 | 15 | package tech.kiwa.engine.exception; 16 | 17 | /** 18 | * @author Hale.Li 19 | * @since 2018-01-28 20 | * @version 0.1 21 | */ 22 | public class RuleEngineException extends Exception { 23 | 24 | private static final long serialVersionUID = -2312238642591378363L; 25 | 26 | public RuleEngineException() { 27 | super(); 28 | } 29 | 30 | public RuleEngineException(String message) { 31 | super(message); 32 | } 33 | 34 | public RuleEngineException(Throwable cause) { 35 | super(cause); 36 | } 37 | 38 | public RuleEngineException(String message,Throwable cause) { 39 | super(message, cause); 40 | } 41 | 42 | 43 | public RuleEngineException(String message, Throwable cause, 44 | boolean enableSuppression, 45 | boolean writableStackTrace) { 46 | super(message, cause, enableSuppression, writableStackTrace); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/tech/kiwa/engine/framework/Component.java: -------------------------------------------------------------------------------- 1 | //Copyright Hale [hale2000@163.com] 2 | // 3 | //Licensed under the Apache License, Version 2.0 (the "License"); 4 | //you may not use this file except in compliance with the License. 5 | //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 10 | //distributed under the License is distributed on an "AS IS" BASIS, 11 | //WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | //See the License for the specific language governing permissions and 13 | //limitations under the License. 14 | 15 | package tech.kiwa.engine.framework; 16 | 17 | import tech.kiwa.engine.exception.RuleEngineException; 18 | /** 19 | * @author Hale.Li 20 | * @since 2018-01-28 21 | * @version 0.1 22 | */ 23 | public interface Component { 24 | 25 | public void register() throws RuleEngineException; 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/tech/kiwa/engine/framework/DBAccesser.java: -------------------------------------------------------------------------------- 1 | //Copyright Hale [hale2000@163.com] 2 | // 3 | //Licensed under the Apache License, Version 2.0 (the "License"); 4 | //you may not use this file except in compliance with the License. 5 | //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 10 | //distributed under the License is distributed on an "AS IS" BASIS, 11 | //WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | //See the License for the specific language governing permissions and 13 | //limitations under the License. 14 | 15 | package tech.kiwa.engine.framework; 16 | 17 | import java.sql.Connection; 18 | /** 19 | * @author Hale.Li 20 | * @since 2018-01-28 21 | * @version 0.1 22 | */ 23 | public interface DBAccesser { 24 | 25 | public Connection getConnection(); 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/tech/kiwa/engine/framework/FactoryMethod.java: -------------------------------------------------------------------------------- 1 | //Copyright Hale [hale2000@163.com] 2 | // 3 | //Licensed under the Apache License, Version 2.0 (the "License"); 4 | //you may not use this file except in compliance with the License. 5 | //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 10 | //distributed under the License is distributed on an "AS IS" BASIS, 11 | //WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | //See the License for the specific language governing permissions and 13 | //limitations under the License. 14 | 15 | package tech.kiwa.engine.framework; 16 | 17 | /** 18 | * @author Hale.Li 19 | * @since 2018-01-28 20 | * @version 0.1 21 | */ 22 | public interface FactoryMethod { 23 | 24 | public void acceptRegister(Component component); 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/tech/kiwa/engine/framework/OperatorFactory.java: -------------------------------------------------------------------------------- 1 | //Copyright Hale [hale2000@163.com] 2 | // 3 | //Licensed under the Apache License, Version 2.0 (the "License"); 4 | //you may not use this file except in compliance with the License. 5 | //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 10 | //distributed under the License is distributed on an "AS IS" BASIS, 11 | //WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | //See the License for the specific language governing permissions and 13 | //limitations under the License. 14 | 15 | package tech.kiwa.engine.framework; 16 | 17 | import java.util.HashMap; 18 | 19 | import tech.kiwa.engine.component.AbstractComparisonOperator; 20 | import tech.kiwa.engine.exception.RuleEngineException; 21 | 22 | 23 | /** 24 | * @author Hale.Li 25 | * @since 2018-01-28 26 | * @version 0.1 27 | */ 28 | public class OperatorFactory implements FactoryMethod{ 29 | 30 | private static OperatorFactory instance = new OperatorFactory(); 31 | 32 | private static HashMap operatorMap = new HashMap(); 33 | 34 | public final static class OPR_CODE { 35 | 36 | public static final String EQUAL = "01" ; 37 | public static final String GREATER = "02" ; 38 | public static final String LESS = "03" ; 39 | public static final String NOT_EQUAL = "04" ; 40 | public static final String GREATER_EQUAL = "05" ; 41 | public static final String LESS_EQUAL = "06" ; 42 | public static final String INCLUDE = "07" ; 43 | public static final String NOT_INCLUDE = "08" ; 44 | public static final String INCLUDED_BY = "09" ; 45 | public static final String NOT_INCLUDED_BY = "10" ; 46 | public static final String STRING_EQUAL = "11" ; 47 | public static final String NOTSTRING_EQUAL = "12" ; 48 | public static final String EQUAL_IGNORE_CASE = "13" ; 49 | public static final String NOT_EQUAL_IGNORE_CASE = "14" ; 50 | public static final String MATCH = "15" ; 51 | public static final String UNMATCH = "16" ; 52 | 53 | // alias 54 | public static final String CONTAINS = INCLUDE; 55 | public static final String NOT_CONTAINS = NOT_INCLUDE; 56 | public static final String MEMBER_OF = INCLUDED_BY; 57 | public static final String NOT_MEMBER_OF = NOT_INCLUDED_BY; 58 | 59 | private static final String RESERVED_CODES[] = new String[] {EQUAL,GREATER,LESS,NOT_EQUAL,GREATER_EQUAL,LESS_EQUAL,INCLUDE,NOT_INCLUDE, 60 | INCLUDED_BY,NOT_INCLUDED_BY,STRING_EQUAL,NOTSTRING_EQUAL,EQUAL_IGNORE_CASE,NOT_EQUAL_IGNORE_CASE,MATCH,UNMATCH,"17","18","19","20"}; 61 | 62 | private static final String RESERVED_VALUES[] = new String[] {"EQUAL","GREATER","LESS","NOT_EQUAL","GREATER_EQUAL","LESS_EQUAL","INCLUDE", 63 | "NOT_INCLUDE","INCLUDED_BY","NOT_INCLUDED_BY","STRING_EQUAL","NOTSTRING_EQUAL","EQUAL_IGNORE_CASE", 64 | "NOT_EQUAL_IGNORE_CASE","MATCH,UNMATCH","17","18","19","20"}; 65 | 66 | private static final String RESERVIED_ALIAS_CODES[] = new String[]{CONTAINS,NOT_CONTAINS,MEMBER_OF,NOT_MEMBER_OF,MATCH,UNMATCH}; 67 | private static final String RESERVIED_ALIAS_VALUES[] = new String[]{"CONTAINS","NOT CONTAINS","MEMBEROF","NOT MEMBEROF","MATCHES", "NOT MATCHES"}; 68 | 69 | private static final String RESERVED_LOGIC_ALIAS_VALUES[] = new String[]{"==",">","<","!=",">=","<="}; 70 | 71 | public static boolean isReserved(String code){ 72 | 73 | for(int iLoop =0 ; iLoop < RESERVED_CODES.length; iLoop++){ 74 | if(RESERVED_CODES[iLoop].equals(code)){ 75 | return true; 76 | } 77 | } 78 | return false; 79 | } 80 | 81 | public static String getCode(String value){ 82 | 83 | String temp = null; 84 | for(int iLoop = 0; iLoop < RESERVED_VALUES.length; iLoop++){ 85 | if(RESERVED_VALUES[iLoop].equalsIgnoreCase(value)){ 86 | temp = RESERVED_CODES[iLoop]; 87 | break; 88 | } 89 | } 90 | 91 | if(null == temp){ 92 | for(int iLoop = 0; iLoop < RESERVIED_ALIAS_VALUES.length; iLoop++){ 93 | if(RESERVIED_ALIAS_VALUES[iLoop].equalsIgnoreCase(value)){ 94 | temp = RESERVIED_ALIAS_CODES[iLoop]; 95 | break; 96 | } 97 | } 98 | } 99 | 100 | if(null == temp){ 101 | for(int iLoop = 0; iLoop < RESERVED_LOGIC_ALIAS_VALUES.length; iLoop++){ 102 | if(RESERVED_LOGIC_ALIAS_VALUES[iLoop].equalsIgnoreCase(value)){ 103 | temp = RESERVED_CODES[iLoop]; 104 | break; 105 | } 106 | } 107 | } 108 | 109 | return temp; 110 | } 111 | 112 | public static String getValue(String code){ 113 | 114 | String temp = null; 115 | for(int iLoop = 0; iLoop < RESERVED_CODES.length; iLoop++){ 116 | if(RESERVED_CODES[iLoop].equalsIgnoreCase(code)){ 117 | temp = RESERVED_VALUES[iLoop]; 118 | break; 119 | } 120 | } 121 | 122 | return temp; 123 | } 124 | } 125 | 126 | 127 | 128 | private OperatorFactory(){ 129 | 130 | } 131 | 132 | public static OperatorFactory getInstance(){ 133 | return instance; 134 | } 135 | 136 | public void acceptRegister( Component opt){ 137 | AbstractComparisonOperator operator = (AbstractComparisonOperator)opt; 138 | operatorMap.put(operator.getComparisonCode(), operator); 139 | } 140 | 141 | public boolean runOperator(String subject, String comparison_code , String baseline) throws RuleEngineException{ 142 | 143 | AbstractComparisonOperator opter = operatorMap.get(comparison_code); 144 | if(null == opter){ 145 | throw new RuleEngineException("null pointer error on comparison operate execute."); 146 | } 147 | 148 | return opter.run(subject, baseline); 149 | } 150 | 151 | 152 | } 153 | -------------------------------------------------------------------------------- /src/main/java/tech/kiwa/engine/framework/ResultLogFactory.java: -------------------------------------------------------------------------------- 1 | //Copyright Hale [hale2000@163.com] 2 | // 3 | //Licensed under the Apache License, Version 2.0 (the "License"); 4 | //you may not use this file except in compliance with the License. 5 | //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 10 | //distributed under the License is distributed on an "AS IS" BASIS, 11 | //WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | //See the License for the specific language governing permissions and 13 | //limitations under the License. 14 | 15 | package tech.kiwa.engine.framework; 16 | 17 | import java.util.ArrayList; 18 | import java.util.List; 19 | 20 | import tech.kiwa.engine.component.AbstractResultLogRecorder; 21 | import tech.kiwa.engine.entity.ItemExecutedResult; 22 | import tech.kiwa.engine.entity.RuleItem; 23 | import tech.kiwa.engine.exception.RuleEngineException; 24 | 25 | 26 | /** 27 | * @author Hale.Li 28 | * @since 2018-01-28 29 | * @version 0.1 30 | */ 31 | public class ResultLogFactory implements FactoryMethod{ 32 | 33 | private static ResultLogFactory instance = new ResultLogFactory(); 34 | 35 | private static List logList = new ArrayList< AbstractResultLogRecorder>(); 36 | 37 | private ResultLogFactory(){ 38 | 39 | } 40 | 41 | public static ResultLogFactory getInstance(){ 42 | return instance; 43 | } 44 | 45 | public void acceptRegister(Component logger){ 46 | 47 | logList.add((AbstractResultLogRecorder)logger); 48 | } 49 | 50 | public boolean writeLog(Object object, RuleItem item , ItemExecutedResult result) throws RuleEngineException{ 51 | 52 | boolean bRet = true; 53 | for(AbstractResultLogRecorder logger:logList ){ 54 | bRet = bRet && logger.writeLog(object, item, result); 55 | } 56 | 57 | return bRet; 58 | } 59 | 60 | 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/tech/kiwa/engine/sample/BlackListShow.java: -------------------------------------------------------------------------------- 1 | package tech.kiwa.engine.sample; 2 | 3 | import tech.kiwa.engine.component.AbstractCommand; 4 | import tech.kiwa.engine.entity.ItemExecutedResult; 5 | import tech.kiwa.engine.entity.RuleItem; 6 | 7 | public class BlackListShow extends AbstractCommand { 8 | 9 | private Object obj = null; 10 | @Override 11 | public void execute(RuleItem item, ItemExecutedResult result) { 12 | // TODO Auto-generated method stub 13 | System.out.print(obj.toString() + "该用户已经在黑名单了。"); 14 | } 15 | 16 | @Override 17 | public void SetObject(Object obj) { 18 | // TODO Auto-generated method stub 19 | this.obj = obj; 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/tech/kiwa/engine/sample/Student.java: -------------------------------------------------------------------------------- 1 | //Copyright Hale [hale2000@163.com] 2 | // 3 | //Licensed under the Apache License, Version 2.0 (the "License"); 4 | //you may not use this file except in compliance with the License. 5 | //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 10 | //distributed under the License is distributed on an "AS IS" BASIS, 11 | //WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | //See the License for the specific language governing permissions and 13 | //limitations under the License. 14 | 15 | /** 16 | * 17 | */ 18 | package tech.kiwa.engine.sample; 19 | /** 20 | * 这个类是一个例子,简单的说明了学生的几个属性:年龄,性别,姓名。 21 | * @author Hale.Li 22 | * @since 2018-01-28 23 | * @version 0.1 24 | */ 25 | public class Student { 26 | 27 | private int age = 0; 28 | public String name; 29 | public int sex; 30 | 31 | public void setAge(int age){ 32 | this.age = age; 33 | } 34 | 35 | public int getAge(){ 36 | return this.age; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/tech/kiwa/engine/utility/DirectDBAccesser.java: -------------------------------------------------------------------------------- 1 | //Copyright Hale [hale2000@163.com] 2 | // 3 | //Licensed under the Apache License, Version 2.0 (the "License"); 4 | //you may not use this file except in compliance with the License. 5 | //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 10 | //distributed under the License is distributed on an "AS IS" BASIS, 11 | //WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | //See the License for the specific language governing permissions and 13 | //limitations under the License. 14 | 15 | package tech.kiwa.engine.utility; 16 | 17 | import java.sql.Connection; 18 | import java.sql.DriverManager; 19 | import java.sql.SQLException; 20 | import java.util.ArrayList; 21 | import java.util.Properties; 22 | 23 | import javax.sql.DataSource; 24 | 25 | import org.slf4j.Logger; 26 | import org.slf4j.LoggerFactory; 27 | 28 | import com.alibaba.druid.filter.config.ConfigTools; 29 | import com.alibaba.druid.pool.DruidDataSourceFactory; 30 | import com.alibaba.druid.util.StringUtils; 31 | 32 | import tech.kiwa.engine.framework.DBAccesser; 33 | 34 | /** 35 | * 工具类,是一个直接链接数据库的工具,对JDBC做了简单的封装,通过设置UseDruid字段可以选择是否使用Druid连接池。默认是使用Druid连接池。 36 | * @author Hale.Li 37 | * @since 2018-01-28 38 | * @version 0.1 39 | */ 40 | public class DirectDBAccesser implements DBAccesser{ 41 | 42 | private static Logger log = LoggerFactory.getLogger(DirectDBAccesser.class); 43 | 44 | private static boolean UseDruid = true; 45 | 46 | private static ArrayList connList = new ArrayList (); //只用了一个连接, 没有用到连接池。 47 | 48 | 49 | public static boolean isUseDruid() { 50 | return UseDruid; 51 | } 52 | 53 | public static void setUseDruid(boolean useDruid) { 54 | UseDruid = useDruid; 55 | } 56 | 57 | /** The druid source. */ 58 | private static volatile DataSource dataSource = null; 59 | 60 | 61 | 62 | /** 63 | * 根据类型获取数据源. 非线程安全的函数 64 | * 65 | * @return druid或者dbcp数据源 66 | * @throws Exception the exception 67 | */ 68 | public static final DataSource getDataSource() throws Exception { 69 | 70 | Properties prop = PropertyUtil.loadPropertFile("druid.properties"); 71 | if(prop == null){ 72 | throw new Exception("druid.properties file load error."); 73 | } 74 | 75 | String password = prop.getProperty("password"); 76 | String publicKey = prop.getProperty("publickey"); 77 | 78 | if(!StringUtils.isEmpty(publicKey)){ 79 | 80 | password = ConfigTools.decrypt(publicKey, password); 81 | prop.setProperty("password", password); 82 | } 83 | 84 | dataSource = DruidDataSourceFactory.createDataSource(prop); 85 | 86 | return dataSource; 87 | } 88 | 89 | /** 90 | * 打开一个数据库链接,数据库链接的属性和参数配置在druid.properites文件中。 91 | * @return Connection对象,如果失败,则返回null. 92 | */ 93 | private Connection openConnection(){ 94 | 95 | Connection conn = null; 96 | 97 | String driver = PropertyUtil.getProperty("jdbc.driver"); // "oracle.jdbc.driver.OracleDriver"; 98 | String url = PropertyUtil.getProperty("jdbc.url"); //"jdbc:Oracle:thin:@localhost:1521:orcl"; 99 | String userName = PropertyUtil.getProperty("jdbc.username"); 100 | String password = PropertyUtil.getProperty("jdbc.password"); 101 | String publicKey = PropertyUtil.getProperty("jdbc.publickey"); 102 | 103 | if(!StringUtils.isEmpty(publicKey)){ 104 | try { 105 | password = ConfigTools.decrypt(publicKey, password); 106 | 107 | Class.forName(driver); 108 | 109 | DriverManager.setLoginTimeout(30000); 110 | conn = DriverManager.getConnection(url, userName, password); 111 | 112 | }catch (ClassNotFoundException e) { 113 | log.debug(e.getMessage()); 114 | } catch (Exception e) { 115 | log.debug(e.getMessage()); 116 | } 117 | } 118 | 119 | if(null != conn){ 120 | connList.add(conn); 121 | } 122 | 123 | return conn; 124 | } 125 | 126 | /** 127 | * 获得一个数据库链接,如果使用了Druid连接池,那么就从连接池获取一个活动的链接对象, 128 | * 如果没有使用连接池,那么从链接列表中获取一个链接。 129 | * @return Connection对象,如果失败,则返回null. 130 | */ 131 | public Connection getConnection(){ 132 | 133 | if(UseDruid){ 134 | try { 135 | 136 | if(dataSource == null){ 137 | synchronized (DataSource.class){ 138 | if(dataSource == null){ 139 | dataSource = getDataSource(); 140 | } 141 | } 142 | } 143 | 144 | return dataSource.getConnection(); 145 | } catch (SQLException e) { 146 | log.error(e.getMessage()); 147 | } catch (Exception e) { 148 | log.error(e.getMessage()); 149 | } 150 | } 151 | 152 | //如果是直接连接,或者是druid读取失败的情况下。 153 | for(Connection conn : connList){ 154 | try { 155 | if(!conn.isClosed()){ 156 | return conn; 157 | } 158 | } catch (SQLException e) { 159 | log.debug(e.getMessage()); 160 | } 161 | } 162 | 163 | //if the proper connection is not found , create a new one. 164 | return openConnection(); 165 | } 166 | 167 | /** 168 | * 关闭数据库链接,如果存在没有使用的链接,则关闭它。 169 | * @param conn 170 | */ 171 | //@SuppressWarnings("unused") 172 | public void closeConnection(Connection conn){ 173 | 174 | if(UseDruid){ 175 | 176 | try { 177 | conn.close(); 178 | 179 | } catch (SQLException e) { 180 | log.debug(e.getMessage()); 181 | } 182 | } 183 | 184 | try { 185 | 186 | if(conn != null && !conn.isClosed()){ 187 | conn.close(); 188 | 189 | 190 | if(connList.contains(conn)){ 191 | 192 | synchronized (connList){ 193 | connList.remove(conn); 194 | } 195 | } 196 | } 197 | } catch (SQLException e) { 198 | log.debug(e.getMessage()); 199 | } 200 | } 201 | 202 | 203 | 204 | } 205 | -------------------------------------------------------------------------------- /src/main/java/tech/kiwa/engine/utility/JavaStringCompiler.java: -------------------------------------------------------------------------------- 1 | //Copyright Hale [hale2000@163.com] 2 | // 3 | //Licensed under the Apache License, Version 2.0 (the "License"); 4 | //you may not use this file except in compliance with the License. 5 | //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 10 | //distributed under the License is distributed on an "AS IS" BASIS, 11 | //WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | //See the License for the specific language governing permissions and 13 | //limitations under the License. 14 | 15 | package tech.kiwa.engine.utility; 16 | 17 | import java.io.IOException; 18 | import java.util.ArrayList; 19 | import java.util.List; 20 | import java.util.Map; 21 | 22 | import javax.tools.JavaCompiler; 23 | import javax.tools.JavaCompiler.CompilationTask; 24 | import javax.tools.StandardJavaFileManager; 25 | import javax.tools.ToolProvider; 26 | 27 | import tech.kiwa.engine.utility.MemoryJavaFileManager.MemoryInputJavaFileObject; 28 | /** 29 | * Java字符串编译器,将字符串对象的Java文件编译成class文件。 30 | * @author Hale.Li 31 | * @since 2018-01-28 32 | * @version 0.1 33 | */ 34 | public class JavaStringCompiler { 35 | 36 | private JavaCompiler compiler; 37 | private StandardJavaFileManager stdManager; 38 | private MemoryJavaFileManager fileManager = null; 39 | 40 | private MemoryClassLoader classLoader = null; 41 | 42 | private List javaList = new ArrayList(); 43 | 44 | public JavaStringCompiler() { 45 | this.compiler = ToolProvider.getSystemJavaCompiler(); 46 | this.stdManager = compiler.getStandardFileManager(null,null ,null ); 47 | } 48 | 49 | /** 50 | * Compile a Java source file in memory. 51 | * 52 | * @param fileName 53 | * Java file name, e.g. "Test.java" 54 | * @param source 55 | * The source code as String. 56 | * @return The compiled results as Map that contains class name as key, 57 | * class binary as value. 58 | * @throws IOException 59 | * If compile error. 60 | */ 61 | public Map compile(String fileName, String source) throws IOException { 62 | 63 | if(fileManager == null){ 64 | fileManager = new MemoryJavaFileManager(stdManager); 65 | } 66 | 67 | MemoryInputJavaFileObject javaFileObject = (MemoryInputJavaFileObject)fileManager.makeStringSource(fileName, source); 68 | boolean bFound = false; 69 | for(MemoryInputJavaFileObject java : javaList){ 70 | if(fileName.equals(java.getClassName())){ 71 | bFound = true; 72 | break; 73 | } 74 | } 75 | if(!bFound){ 76 | javaList.add(javaFileObject); 77 | } 78 | CompilationTask task = compiler.getTask(null, fileManager,null , null, null, javaList); 79 | 80 | Boolean result = task.call(); 81 | if (result == null || !result.booleanValue()) { 82 | throw new RuntimeException("Compilation failed."); 83 | } 84 | 85 | return fileManager.getClassBytes(); 86 | 87 | } 88 | 89 | /** 90 | * Load class from compiled classes. 91 | * 92 | * @param name 93 | * Full class name. 94 | * @param classBytes 95 | * Compiled results as a Map. 96 | * @return The Class instance. 97 | * @throws ClassNotFoundException 98 | * If class not found. 99 | * @throws IOException 100 | * If load error. 101 | */ 102 | public Class loadClass(String name, Map classBytes) throws ClassNotFoundException, IOException { 103 | 104 | if(classLoader == null){ 105 | classLoader = new MemoryClassLoader(classBytes); 106 | }else{ 107 | classLoader.appendClass(classBytes); 108 | } 109 | 110 | return classLoader.loadClass(name); 111 | } 112 | 113 | /** 114 | * 根据Java类名查找Java类。 115 | * @param name -- Java类名,简称/ 116 | * @return -- Class对象 117 | * @throws ClassNotFoundException 118 | */ 119 | public Class queryLoadedClass(String name) throws ClassNotFoundException{ 120 | 121 | //MemoryClassLoader classLoader = new MemoryClassLoader(); 122 | if(classLoader == null){ 123 | return classLoader.queryLoadedClass(name); 124 | } 125 | 126 | return null; 127 | 128 | } 129 | 130 | 131 | } -------------------------------------------------------------------------------- /src/main/java/tech/kiwa/engine/utility/MemoryClassLoader.java: -------------------------------------------------------------------------------- 1 | //Copyright Hale [hale2000@163.com] 2 | // 3 | //Licensed under the Apache License, Version 2.0 (the "License"); 4 | //you may not use this file except in compliance with the License. 5 | //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 10 | //distributed under the License is distributed on an "AS IS" BASIS, 11 | //WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | //See the License for the specific language governing permissions and 13 | //limitations under the License. 14 | 15 | package tech.kiwa.engine.utility; 16 | 17 | import java.util.HashMap; 18 | import java.util.Map; 19 | import java.util.Set; 20 | 21 | /** 22 | * 类加载器,把Java类加载到内存中。 23 | * @author Hale.Li 24 | * @since 2018-01-28 25 | * @version 0.1 26 | */ 27 | public class MemoryClassLoader extends ClassLoader { 28 | // class name to class bytes: 29 | private Map classBytes = new HashMap(); 30 | 31 | public MemoryClassLoader(Map classBytes) { 32 | super(MemoryClassLoader.class.getClassLoader()); 33 | this.classBytes.putAll(classBytes); 34 | } 35 | 36 | public MemoryClassLoader(){ 37 | 38 | } 39 | @Override 40 | protected Class findClass(String name) throws ClassNotFoundException { 41 | byte[] buf = classBytes.get(name); 42 | if (buf == null) { 43 | return super.findClass(name); 44 | } 45 | //classBytes.remove(name); 46 | return defineClass(name, buf, 0, buf.length); 47 | } 48 | 49 | public Class queryLoadedClass(String name) throws ClassNotFoundException { 50 | return super.findClass(name); 51 | } 52 | 53 | public void appendClass( Map classSet){ 54 | 55 | Set keySet = classSet.keySet(); 56 | for(String key: keySet){ 57 | if(!classBytes.containsKey(key)){ 58 | classBytes.put(key, classSet.get(key)); 59 | } 60 | } 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/tech/kiwa/engine/utility/MemoryJavaFileManager.java: -------------------------------------------------------------------------------- 1 | //Copyright Hale [hale2000@163.com] 2 | // 3 | //Licensed under the Apache License, Version 2.0 (the "License"); 4 | //you may not use this file except in compliance with the License. 5 | //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 10 | //distributed under the License is distributed on an "AS IS" BASIS, 11 | //WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | //See the License for the specific language governing permissions and 13 | //limitations under the License. 14 | 15 | package tech.kiwa.engine.utility; 16 | 17 | import java.io.ByteArrayOutputStream; 18 | import java.io.FilterOutputStream; 19 | import java.io.IOException; 20 | import java.io.OutputStream; 21 | import java.net.URI; 22 | import java.nio.CharBuffer; 23 | import java.util.HashMap; 24 | import java.util.Map; 25 | 26 | import javax.tools.FileObject; 27 | import javax.tools.ForwardingJavaFileManager; 28 | import javax.tools.JavaFileManager; 29 | import javax.tools.JavaFileObject; 30 | import javax.tools.JavaFileObject.Kind; 31 | import javax.tools.SimpleJavaFileObject; 32 | /** 33 | * @author Hale.Li 34 | * @since 2018-01-28 35 | * @version 0.1 36 | */ 37 | class MemoryJavaFileManager extends ForwardingJavaFileManager { 38 | 39 | // compiled classes in bytes: 40 | final Map classBytes = new HashMap(); 41 | 42 | MemoryJavaFileManager(JavaFileManager fileManager) { 43 | super(fileManager); 44 | } 45 | 46 | public Map getClassBytes() { 47 | return new HashMap(this.classBytes); 48 | } 49 | 50 | @Override 51 | public void flush() throws IOException { 52 | } 53 | 54 | @Override 55 | public void close() throws IOException { 56 | classBytes.clear(); 57 | } 58 | 59 | @Override 60 | public JavaFileObject getJavaFileForOutput(JavaFileManager.Location location, String className, Kind kind, 61 | FileObject sibling) throws IOException { 62 | if (kind == Kind.CLASS) { 63 | return new MemoryOutputJavaFileObject(className); 64 | } else { 65 | return super.getJavaFileForOutput(location, className, kind, sibling); 66 | } 67 | } 68 | 69 | JavaFileObject makeStringSource(String name, String code) { 70 | return new MemoryInputJavaFileObject(name, code); 71 | } 72 | 73 | static class MemoryInputJavaFileObject extends SimpleJavaFileObject { 74 | 75 | final String code; 76 | final String javaClassName; 77 | 78 | MemoryInputJavaFileObject(String name, String code) { 79 | super(URI.create("string:///" + name), Kind.SOURCE); 80 | this.javaClassName = name; 81 | this.code = code; 82 | } 83 | 84 | @Override 85 | public CharBuffer getCharContent(boolean ignoreEncodingErrors) { 86 | return CharBuffer.wrap(code); 87 | } 88 | 89 | public String getClassName(){ 90 | return this.javaClassName; 91 | } 92 | 93 | } 94 | 95 | class MemoryOutputJavaFileObject extends SimpleJavaFileObject { 96 | 97 | final String name; 98 | 99 | MemoryOutputJavaFileObject(String name) { 100 | super(URI.create("string:///" + name), Kind.CLASS); 101 | this.name = name; 102 | } 103 | 104 | @Override 105 | public OutputStream openOutputStream() { 106 | return new FilterOutputStream(new ByteArrayOutputStream()) { 107 | @Override 108 | public void close() throws IOException { 109 | out.close(); 110 | ByteArrayOutputStream bos = (ByteArrayOutputStream) out; 111 | classBytes.put(name, bos.toByteArray()); 112 | } 113 | }; 114 | } 115 | 116 | } 117 | } -------------------------------------------------------------------------------- /src/main/java/tech/kiwa/engine/utility/PropertyUtil.java: -------------------------------------------------------------------------------- 1 | //Copyright Hale [hale2000@163.com] 2 | // 3 | //Licensed under the Apache License, Version 2.0 (the "License"); 4 | //you may not use this file except in compliance with the License. 5 | //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 10 | //distributed under the License is distributed on an "AS IS" BASIS, 11 | //WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | //See the License for the specific language governing permissions and 13 | //limitations under the License. 14 | 15 | package tech.kiwa.engine.utility; 16 | 17 | import java.io.File; 18 | import java.io.FileInputStream; 19 | import java.io.FileNotFoundException; 20 | import java.io.IOException; 21 | import java.io.InputStream; 22 | import java.util.Properties; 23 | import java.util.Set; 24 | 25 | import org.apache.commons.lang.StringUtils; 26 | import org.slf4j.Logger; 27 | import org.slf4j.LoggerFactory; 28 | 29 | /** 30 | * 加载属性文件,同时写到内存中。 31 | * @author Hale.Li 32 | * @since 2018-01-28 33 | * @version 0.1 34 | */ 35 | public class PropertyUtil { 36 | 37 | private static Logger log = LoggerFactory.getLogger(PropertyUtil.class); 38 | 39 | /** 40 | * 获取配置属性,从内存中获取配置属性(key-value键值对),如果不存在,则尝试解析一下${}格式,再读一遍。 41 | * @param key 42 | * @return 43 | */ 44 | public static String getProperty(String key){ 45 | 46 | String value = directGetProperty(key); 47 | 48 | if(StringUtils.isNotEmpty(value)){ 49 | value = value.trim(); 50 | 51 | //${}格式化的数据,那么取括号里面的内容。 52 | if(value.startsWith("${") && value.endsWith("}")){ 53 | 54 | value = value.substring(2, value.length()-1); 55 | 56 | value = directGetProperty(value); 57 | if(StringUtils.isNotEmpty(value)){ 58 | value = value.trim(); 59 | // break; 60 | } 61 | } 62 | } 63 | 64 | 65 | return value; 66 | } 67 | 68 | /** 69 | * 加载配置文件,从配置文件中加载到内存中。 70 | * @param fileName 71 | * @return 72 | */ 73 | public static Properties loadPropertFile(String fileName){ 74 | Properties prop = null; 75 | 76 | if(fileName.contains(File.separator)){ 77 | try { 78 | File file = new File(fileName); 79 | 80 | prop = new Properties(); 81 | InputStream fisResource = new FileInputStream(file); 82 | prop.load(fisResource); 83 | fisResource.close(); 84 | } catch (FileNotFoundException e) { 85 | log.debug(e.getMessage()); 86 | } catch (IOException e) { 87 | log.debug(e.getMessage()); 88 | } 89 | }else{ 90 | try { 91 | File dir = new File(PropertyUtil.class.getClassLoader().getResource("").getPath()); 92 | File file = new File(dir.getAbsolutePath() + File.separator + fileName); 93 | 94 | prop = new Properties(); 95 | InputStream fisResource = new FileInputStream(file); 96 | prop.load(fisResource); 97 | fisResource.close(); 98 | } catch (FileNotFoundException e) { 99 | log.debug(e.getMessage()); 100 | } catch (IOException e) { 101 | log.debug(e.getMessage()); 102 | } 103 | } 104 | 105 | if(prop != null){ 106 | 107 | Set keySet = (Set) prop.keySet(); 108 | for(Object key : keySet){ 109 | 110 | //如果key不是字符串格式的,那么跳过。 111 | 112 | if(key instanceof String){ 113 | String value = prop.getProperty((String)key); 114 | //value 存在的情况下。 115 | if(null != value){ 116 | 117 | value = value.trim(); 118 | //如果是变量形式的值。 119 | if(value.startsWith("${") && value.endsWith("}")){ 120 | 121 | //那么再读取一遍。 122 | value = value.substring(2, value.length()-1); 123 | value = directGetProperty(value); 124 | if(StringUtils.isNotEmpty(value)){ 125 | value = value.trim(); 126 | prop.setProperty((String)key, value); 127 | } 128 | } 129 | } 130 | } //end if 131 | 132 | } //end for. 133 | } 134 | return prop; 135 | } 136 | 137 | private static Properties ruleEngineBuffer = new Properties(); 138 | private static String directGetProperty(String key){ 139 | 140 | final String ruleEngineFile = "ruleEngine.properties"; 141 | 142 | if(!ruleEngineBuffer.isEmpty()){ 143 | return ruleEngineBuffer.getProperty(key); 144 | } 145 | 146 | String value = null ; 147 | 148 | try { 149 | 150 | InputStream fisResource = PropertyUtil.class.getClassLoader().getResourceAsStream(ruleEngineFile); 151 | if(fisResource != null){ 152 | Properties prop = new Properties(); 153 | 154 | prop.load(fisResource); 155 | fisResource.close(); 156 | 157 | ruleEngineBuffer.putAll(prop); 158 | value = prop.getProperty(key); 159 | if(null != value){ 160 | return value; 161 | } 162 | } 163 | 164 | //read the resource file from the other property files. 165 | File dir = new File(PropertyUtil.class.getClassLoader().getResource("").getPath()); 166 | File[] propertyFiles = dir.listFiles(); 167 | 168 | for(int iLoop=0; iLoop < propertyFiles.length; iLoop++){ 169 | String propFile = propertyFiles[iLoop].getPath(); 170 | propFile = propFile.toLowerCase(); 171 | 172 | if(propFile.endsWith(".properties")){ 173 | FileInputStream fis = new FileInputStream(propFile); 174 | Properties prop = new Properties(); 175 | prop.load(fis); 176 | fisResource.close(); 177 | 178 | ruleEngineBuffer.putAll(prop); 179 | 180 | value = prop.getProperty(key); 181 | if(null != value){ 182 | return value; 183 | } 184 | } 185 | } 186 | 187 | } catch (FileNotFoundException e) { 188 | log.debug(e.getMessage()); 189 | } catch (IOException e) { 190 | log.debug(e.getMessage()); 191 | } catch (Exception e){ 192 | log.debug(e.getMessage()); 193 | } 194 | 195 | // read the value from system memory. 196 | if(null == value){ 197 | value = System.getProperty(key); 198 | } 199 | return value; 200 | } 201 | 202 | 203 | public static void main(String[] args){ 204 | PropertyUtil.getProperty("jdbc.pool"); 205 | } 206 | } 207 | -------------------------------------------------------------------------------- /src/main/java/tech/kiwa/engine/utility/SpringContextHelper.java: -------------------------------------------------------------------------------- 1 | //Copyright Hale [hale2000@163.com] 2 | // 3 | //Licensed under the Apache License, Version 2.0 (the "License"); 4 | //you may not use this file except in compliance with the License. 5 | //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 10 | //distributed under the License is distributed on an "AS IS" BASIS, 11 | //WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | //See the License for the specific language governing permissions and 13 | //limitations under the License. 14 | 15 | package tech.kiwa.engine.utility; 16 | 17 | import org.springframework.beans.BeansException; 18 | import org.springframework.beans.factory.NoSuchBeanDefinitionException; 19 | import org.springframework.context.ApplicationContext; 20 | //import org.springframework.web.context.WebApplicationContext; 21 | import org.springframework.context.ApplicationContextAware; 22 | import org.springframework.stereotype.Service; 23 | /** 24 | * 通过SpringContext获取Bean/Service等信息。 25 | * @author Hale.Li 26 | * @since 2018-01-28 27 | * @version 0.1 28 | */ 29 | @Service 30 | public class SpringContextHelper implements ApplicationContextAware { 31 | 32 | private static SpringContextHelper thisInstance = new SpringContextHelper(); 33 | 34 | private static ApplicationContext applicationContext = null; 35 | 36 | 37 | public static ApplicationContext getApplicationContext() { 38 | return applicationContext; 39 | } 40 | 41 | public static SpringContextHelper getInstance() { 42 | 43 | if (null == thisInstance) { 44 | return null; 45 | } 46 | 47 | return thisInstance; 48 | } 49 | 50 | /*** 51 | * 根据bean的id获取配置文件中相应的bean 52 | * 53 | * @param name 要取得的bean的名称 54 | * @return 返回service对象,或者是bean对象 55 | * @throws BeansException bean找不到等异常。 56 | */ 57 | public static Object getBean(String name) throws BeansException { 58 | 59 | return (applicationContext).getBean(name); 60 | } 61 | 62 | /*** 63 | * 类似于getBean(String name)只是在参数中提供了需要返回到的类型 64 | * 65 | * @param 参数类型的模板类 66 | * @param name 要取得的bean的名称 67 | * @param requiredType 要取得的bean的类型 68 | * @return 返回service对象,或者是bean对象 69 | * @throws BeansException bean找不到等异常。 70 | */ 71 | public static T getBean(String name, Class requiredType) throws BeansException { 72 | return applicationContext.getBean(name, requiredType); 73 | } 74 | 75 | /*** 76 | * 类似于getBean(String name)只是在参数中提供了需要返回到的类型 77 | * 78 | * @param 参数类型的模板类 79 | * @param requiredType 要取得的bean的类型 80 | * @return 返回service对象,或者是bean对象 81 | * @throws BeansException bean找不到等异常。 82 | */ 83 | public static T getBean( Class requiredType) throws BeansException { 84 | return applicationContext.getBean(requiredType); 85 | } 86 | 87 | 88 | /*** 89 | * 类似于getBean(String name)只是在参数中提供了需要返回到的类型 90 | * 91 | * @param name 要取得的bean的名称 92 | * @param args 要取得的bean的类型 93 | * @return 返回service对象,或者是bean对象 94 | * @throws BeansException bean找不到等异常。 95 | */ 96 | public static Object getBean(String name, Object... args) throws BeansException { 97 | return applicationContext.getBean(name, args); 98 | } 99 | 100 | 101 | /** 102 | * 如果BeanFactory包含与名称匹配的bean定义,则返回true 103 | * 104 | * @param name 是否包含bean的名称 105 | * @return boolean true--包含, false -- 不包含 106 | */ 107 | public static boolean containsBean(String name) { 108 | 109 | return applicationContext.containsBean(name); 110 | } 111 | 112 | /** 113 | * 判断以给定名字注册的bean定义是一个singleton还是多个prototype 114 | * 如果与给定名字相应的bean定义没有被找到,将会抛出一个个异常(NoSuchBeanDefinitionException 115 | * 116 | * @param name 是否是单一类,bean的名称 117 | * @return boolean true -- 是 false -- 否 118 | * @throws NoSuchBeanDefinitionException bean找不到等异常 119 | */ 120 | public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException { 121 | return applicationContext.isSingleton(name); 122 | } 123 | 124 | /** 125 | * @param name Bean对象名称。 126 | * @return Class 注册对象的类 127 | * @throws NoSuchBeanDefinitionException bean找不到等异常 128 | */ 129 | @SuppressWarnings("rawtypes") 130 | public static Class getType(String name) throws NoSuchBeanDefinitionException { 131 | return applicationContext.getType(name); 132 | } 133 | 134 | /** 135 | * 如果给定的bean名字在bean定义中有别名,则返回这些别名 136 | * 137 | * @param name bean的名称 138 | * @return bean的别名 139 | * @throws NoSuchBeanDefinitionException bean找不到等异常 140 | */ 141 | public static String[] getAliases(String name) throws NoSuchBeanDefinitionException { 142 | return applicationContext.getAliases(name); 143 | } 144 | 145 | /** 146 | * 设置上下文。 147 | */ 148 | @Override 149 | public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { 150 | SpringContextHelper.applicationContext = applicationContext; 151 | } 152 | 153 | 154 | } 155 | -------------------------------------------------------------------------------- /src/main/java/tech/kiwa/engine/utility/SpringDBAccesser.java: -------------------------------------------------------------------------------- 1 | //Copyright Hale [hale2000@163.com] 2 | // 3 | //Licensed under the Apache License, Version 2.0 (the "License"); 4 | //you may not use this file except in compliance with the License. 5 | //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 10 | //distributed under the License is distributed on an "AS IS" BASIS, 11 | //WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | //See the License for the specific language governing permissions and 13 | //limitations under the License. 14 | 15 | package tech.kiwa.engine.utility; 16 | 17 | import java.sql.Connection; 18 | import java.sql.SQLException; 19 | 20 | import javax.sql.DataSource; 21 | 22 | import org.springframework.beans.BeansException; 23 | import org.springframework.context.ApplicationContext; 24 | import org.springframework.context.ApplicationContextAware; 25 | import org.springframework.stereotype.Service; 26 | 27 | import tech.kiwa.engine.framework.DBAccesser; 28 | 29 | /** 30 | * 通过SpringContext获取数据库连接. 31 | * @author Hale.Li 32 | * @since 2018-01-28 33 | * @version 0.1 34 | */ 35 | @Service 36 | public class SpringDBAccesser implements ApplicationContextAware , DBAccesser { 37 | 38 | private static ApplicationContext applicationContext = null; 39 | 40 | public static ApplicationContext getApplicationContext() { 41 | return applicationContext; 42 | } 43 | 44 | @Override 45 | public Connection getConnection() { 46 | 47 | DataSource ds = (DataSource) applicationContext.getBean("dataSource"); 48 | 49 | try { 50 | return ds.getConnection(); 51 | } catch (SQLException e) { 52 | 53 | e.printStackTrace(); 54 | } 55 | 56 | return null; 57 | } 58 | 59 | @Override 60 | public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { 61 | 62 | SpringDBAccesser.applicationContext = applicationContext; 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /src/main/resources/druid.properties: -------------------------------------------------------------------------------- 1 | #\u8fd9\u4e2a\u6587\u4ef6\u4e5f\u53ef\u4ee5\u7528\u5176\u4ed6\u7684\u914d\u7f6e\u6587\u4ef6\u4ee3\u66ff\uff0c\u89c4\u5219\u5f15\u64ce\u672c\u8eab\u81ea\u52a8\u626b\u63cf\u6587\u4ef6\u5939\u4e2d\u6240\u6709\u7684.properites\u6587\u4ef6\u3002 2 | #\u8bfb\u53d6\u5230\u4e86url\u7b49\u5b57\u6bb5\u8fd9\u81ea\u52a8\u52a0\u8f7d 3 | #\u4e5f\u53ef\u4ee5\u901a\u8fc7\u53c2\u6570\u7684\u5f62\u5f0f\u6765\u914d\u7f6e\u6570\u636e\u5e93\u8fde\u63a5\u7684\u4fe1\u606f\u3002 4 | driver=${jdbc.driver} 5 | #com.mysql.cj.jdbc.Driver 6 | #driver=oracle.jdbc.driver.OracleDriver 7 | url=${jdbc.url} 8 | 9 | username=${jdbc.username} 10 | password=${jdbc.password} 11 | publickey=${jdbc.publickey} 12 | 13 | 14 | #\u5b9a\u4e49\u521d\u59cb\u8fde\u63a5\u6570 , \u4ece0\u6539\u621010 15 | initialSize=10 16 | #\u5b9a\u4e49\u6700\u5927\u8fde\u63a5\u6570 17 | maxActive=20 18 | #\u5b9a\u4e49\u6700\u5c0f\u7a7a\u95f2 19 | minIdle=1 20 | #\u5b9a\u4e49\u6700\u957f\u7b49\u5f85\u65f6\u95f4 21 | maxWait=60000 22 | timeBetweenEvictionRunsMillis=60000 23 | minEvictableIdleTimeMillis=30000 24 | testWhileIdle=true 25 | testOnBorrow=true 26 | testOnReturn=true 27 | filters=stat,wall 28 | removeAbandoned=true 29 | removeAbandonedTimeout=1200 30 | logAbandoned=true -------------------------------------------------------------------------------- /src/main/resources/ruleEngine.properties: -------------------------------------------------------------------------------- 1 | jdbc.driver=com.mysql.cj.jdbc.Driver 2 | #jdbc.driver=oracle.jdbc.driver.OracleDriver 3 | #jdbc.url=jdbc:mysql://127.0.0.1:3306/hosp?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=true 4 | #\u8FD9\u4E2A\u5730\u65B9\u914D\u7F6E\u7684\u662F\u6570\u636E\u5E93\u7684\u4FE1\u606F\uFF0C\uFF08\u53EF\u4EE5\u4E0D\u7528\uFF09 5 | jdbc.url=jdbc:mysql://122.51.249.97:3306/ruleEngine?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&allowPublicKeyRetrieval=true 6 | jdbc.username=devel 7 | jdbc.password=gavMtRcN/kx5B5DLqPJYGYu/VCMjeMctNSxrqmUKbFDxCTvjvqyVyab/NMZ5TxZHy1ZmpCoot/WQz+L2nblNuw== 8 | jdbc.publickey=MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAIiy9M4GEFKE+zxP5+KhgE4AHNmam0dZ+javOOmpJMmObkAnVtubRFoHDE5fq7NozFsWxf7CEIGdteobbxTSMhcCAwEAAQ== 9 | 10 | db.accesser=tech.kiwa.engine.utility.DirectDBAccesser 11 | 12 | #drools, database,xml 13 | #\u9009\u62E9\\u89C4\u5219\u5F15\u64CE\u7684\u914D\u7F6E\u65B9\u5F0F\u3002 14 | rule.reader=xml 15 | 16 | drools.rule.filename=sample.drl 17 | db.rule.table=TL_RULE_DEFINE 18 | xml.rule.filename=studentrule.xml -------------------------------------------------------------------------------- /src/main/resources/ruleconfig.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | www.kiwa.tech 5 | 6 | 7 | 8 | Configuration for the rule list which stores the rule information in-memory and executed by rule engine service. 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /src/main/resources/sample.drl: -------------------------------------------------------------------------------- 1 | #this is atest 2 | package tech.kiwa.engine.entity; 3 | globals java.util.List myGlobalList 4 | 5 | import tech.kiwa.engine.sample.Student; 6 | 7 | function void callOver(Student $student){ 8 | 9 | if($student != null){ 10 | System.out.println("student [" + $student.name + "] is called."); 11 | } 12 | 13 | } 14 | function void ageUp(Student $student, int age ){ 15 | 16 | if($student != null){ 17 | $student.setAge( $student.getAge() + age); 18 | } 19 | 20 | } 21 | 22 | declare teacher 23 | age : int 24 | name : String 25 | sex : int 26 | end 27 | 28 | query "juniorBoy" 29 | $student: Student( age <=14 && (age >10 || age !=12 , sex ==1 || sex == 2 ), name =="tony") 30 | end 31 | 32 | query "querymale"(int $gender) 33 | $student: Student(sex == $gender) 34 | end 35 | 36 | rule "ageUp12" 37 | salience 400 38 | when 39 | $student: Student(age < 8) 40 | /* antoher rule */ 41 | then 42 | System.out.println("I was called, my name is : " + $student.name); 43 | ageUp($student,12); 44 | //callOver($student); 45 | end 46 | 47 | rule "isTom" 48 | salience 30 49 | date-expires "2018-12-01" 50 | dialet "java" 51 | when 52 | $student: Student(name == tom) 53 | then 54 | $student.sex = 4; 55 | callOver($student); 56 | end 57 | 58 | rule "class" 59 | salience 10 60 | duration 30000 61 | enable true 62 | when 63 | $student:Student() 64 | then 65 | $student.toString(); 66 | callOver($student); 67 | end 68 | 69 | rule "testList" 70 | salience 20 71 | active-group "groupB" 72 | when 73 | $student : Student( age > 22) 74 | //not Student(age < $age) 75 | then 76 | System.out.println("age1 = " + $student.getAge()); 77 | callOver($student); //这里导致了LHS的变化 然后会重新触发规则的匹配慎用 这里只是为了展示排序的例子,然后这个rule可以排序。。。。 78 | end 79 | 80 | rule "testSimp" 81 | salience 80 82 | active-group "groupB" 83 | when 84 | $student : Student( age > 12) 85 | //not Student(age < $age) 86 | then 87 | System.out.println("age2 = " + $student.getAge()); 88 | callOver($student); //这里导致了LHS的变化 然后会重新触发规则的匹配慎用 这里只是为了展示排序的例子,然后这个rule可以排序。。。。 89 | end 90 | 91 | rule "agendaAge" 92 | salience 100 93 | agenda-group "groupA" 94 | auto-focus true 95 | when 96 | eval(true) 97 | $student : Student( age > 2) 98 | then 99 | System.out.println("age3 = " + $student.getAge()); 100 | callOver($student); //这里导致了LHS的变化 然后会重新触发规则的匹配慎用 这里只是为了展示排序的例子,然后这个rule可以排序。。。。 101 | end 102 | -------------------------------------------------------------------------------- /src/main/resources/studentrule.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | www.kiwa.tech 5 | 6 | 7 | 8 | Configuration for the rule list which stores the rule information in-memory and executed by rule engine service. 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | --------------------------------------------------------------------------------