Update the Drools Engine to Version 6.5.0
[holmes/engine-management.git] / engine-d / src / main / java / org / onap / holmes / engine / manager / DroolsEngine.java
1 /**\r
2  * Copyright 2017 ZTE Corporation.\r
3  *\r
4  * Licensed under the Apache License, Version 2.0 (the "License");\r
5  * you may not use this file except in compliance with the License.\r
6  * You may obtain a copy of the License at\r
7  *\r
8  * http://www.apache.org/licenses/LICENSE-2.0\r
9  *\r
10  * Unless required by applicable law or agreed to in writing, software\r
11  * distributed under the License is distributed on an "AS IS" BASIS,\r
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
13  * See the License for the specific language governing permissions and\r
14  * limitations under the License.\r
15  */\r
16 package org.onap.holmes.engine.manager;\r
17 import java.io.StringReader;\r
18 import java.util.ArrayList;\r
19 import java.util.HashSet;\r
20 import java.util.List;\r
21 import java.util.Locale;\r
22 import java.util.Set;\r
23 import javax.annotation.PostConstruct;\r
24 import javax.annotation.PreDestroy;\r
25 import javax.inject.Inject;\r
26 import lombok.extern.slf4j.Slf4j;\r
27 import org.drools.compiler.kie.builder.impl.InternalKieModule;\r
28 import org.jvnet.hk2.annotations.Service;\r
29 import org.kie.api.KieBase;\r
30 import org.kie.api.KieServices;\r
31 import org.kie.api.builder.KieBuilder;\r
32 import org.kie.api.builder.KieFileSystem;\r
33 import org.kie.api.builder.KieRepository;\r
34 import org.kie.api.builder.Message;\r
35 import org.kie.api.builder.Message.Level;\r
36 import org.kie.api.builder.model.KieBaseModel;\r
37 import org.kie.api.builder.model.KieModuleModel;\r
38 import org.kie.api.builder.model.KieSessionModel;\r
39 import org.kie.api.conf.EqualityBehaviorOption;\r
40 import org.kie.api.conf.EventProcessingOption;\r
41 import org.kie.api.definition.KiePackage;\r
42 import org.kie.api.io.KieResources;\r
43 import org.kie.api.io.ResourceType;\r
44 import org.kie.api.runtime.KieContainer;\r
45 import org.kie.api.runtime.KieSession;\r
46 import org.kie.api.runtime.conf.ClockTypeOption;\r
47 import org.kie.api.runtime.rule.FactHandle;\r
48 import org.onap.holmes.common.api.stat.VesAlarm;\r
49 import org.onap.holmes.common.dmaap.DmaapService;\r
50 import org.onap.holmes.engine.request.DeployRuleRequest;\r
51 import org.onap.holmes.common.api.entity.CorrelationRule;\r
52 import org.onap.holmes.common.exception.CorrelationException;\r
53 import org.onap.holmes.common.utils.ExceptionUtil;\r
54 import org.onap.holmes.engine.wrapper.RuleMgtWrapper;\r
55 \r
56 @Slf4j\r
57 @Service\r
58 public class DroolsEngine {\r
59 \r
60     private final static int ENABLE = 1;\r
61     private final Set<String> packageNames = new HashSet<String>();\r
62     @Inject\r
63     private RuleMgtWrapper ruleMgtWrapper;\r
64 \r
65     private KieBase kieBase;\r
66     private KieSession kieSession;\r
67     private KieContainer kieContainer;\r
68     private KieFileSystem kfs;\r
69     private KieServices ks;\r
70     private KieBuilder kieBuilder;\r
71     private KieResources resources;\r
72     private KieRepository kieRepository;\r
73 \r
74     @PostConstruct\r
75     private void init() {\r
76         try {\r
77             // start engine\r
78             start();\r
79         } catch (Exception e) {\r
80             log.error("Failed to start the service: " + e.getMessage(), e);\r
81             throw ExceptionUtil.buildExceptionResponse("Failed to start the drools engine!");\r
82         }\r
83     }\r
84 \r
85     private void start() throws CorrelationException {\r
86         log.info("Drools Engine Initialize Beginning...");\r
87 \r
88         initEngineParameter();\r
89         initDeployRule();\r
90 \r
91         log.info("Business Rule Engine Initialize Successfully.");\r
92     }\r
93 \r
94     public void stop() {\r
95         this.kieSession.dispose();\r
96     }\r
97 \r
98     public void initEngineParameter() {\r
99         this.ks = KieServices.Factory.get();\r
100         this.resources = ks.getResources();\r
101         this.kieRepository = ks.getRepository();\r
102         this.kfs = createKieFileSystemWithKProject(ks);\r
103 \r
104         this.kieBuilder = ks.newKieBuilder(kfs).buildAll();\r
105         this.kieContainer = ks.newKieContainer(kieRepository.getDefaultReleaseId());\r
106 \r
107         this.kieBase = kieContainer.getKieBase();\r
108         this.kieSession = kieContainer.newKieSession();\r
109     }\r
110 \r
111     private void initDeployRule() throws CorrelationException {\r
112         List<CorrelationRule> rules = ruleMgtWrapper.queryRuleByEnable(ENABLE);\r
113 \r
114         if (rules.isEmpty()) {\r
115             return;\r
116         }\r
117         for (CorrelationRule rule : rules) {\r
118             if (rule.getContent() != null) {\r
119                 deployRuleFromDB(rule.getContent());\r
120                 DmaapService.loopControlNames.put(rule.getPackageName(), rule.getClosedControlLoopName());\r
121             }\r
122         }\r
123     }\r
124 \r
125     private void deployRuleFromDB(String ruleContent) throws CorrelationException {\r
126         avoidDeployBug();\r
127         StringReader reader = new StringReader(ruleContent);\r
128         kfs.write("src/main/resources/rules/rule.drl",\r
129                 this.resources.newReaderResource(reader,"UTF-8").setResourceType(ResourceType.DRL));\r
130         kieBuilder = ks.newKieBuilder(kfs).buildAll();\r
131         try {\r
132             InternalKieModule internalKieModule = (InternalKieModule)kieBuilder.getKieModule();\r
133             kieContainer.updateToVersion(internalKieModule.getReleaseId());\r
134         } catch (Exception e) {\r
135             throw new CorrelationException(e.getMessage(), e);\r
136         }\r
137         kieSession.fireAllRules();\r
138     }\r
139 \r
140     public synchronized String deployRule(DeployRuleRequest rule, Locale locale)\r
141         throws CorrelationException {\r
142         avoidDeployBug();\r
143         StringReader reader = new StringReader(rule.getContent());\r
144         kfs.write("src/main/resources/rules/rule.drl",\r
145                 this.resources.newReaderResource(reader,"UTF-8").setResourceType(ResourceType.DRL));\r
146         kieBuilder = ks.newKieBuilder(kfs).buildAll();\r
147 \r
148         judgeRuleContent(locale, kieBuilder, true);\r
149 \r
150         InternalKieModule internalKieModule = (InternalKieModule)kieBuilder.getKieModule();;\r
151         String packageName = internalKieModule.getKnowledgePackagesForKieBase("KBase").iterator().next().getName();\r
152         try {\r
153             kieContainer.updateToVersion(internalKieModule.getReleaseId());\r
154         } catch (Exception e) {\r
155             throw new CorrelationException("Failed to deploy the rule.", e);\r
156         }\r
157         packageNames.add(packageName);\r
158         kieSession.fireAllRules();\r
159         return packageName;\r
160     }\r
161 \r
162     public synchronized void undeployRule(String packageName, Locale locale)\r
163         throws CorrelationException {\r
164         KiePackage kiePackage = kieBase.getKiePackage(packageName);\r
165         if (null == kiePackage) {\r
166             throw new CorrelationException("The rule " + packageName + " does not exist!");\r
167         }\r
168         try {\r
169             kieBase.removeKiePackage(kiePackage.getName());\r
170         } catch (Exception e) {\r
171             throw new CorrelationException("Failed to delete the rule: " + packageName, e);\r
172         }\r
173         packageNames.remove(kiePackage.getName());\r
174     }\r
175 \r
176     public void compileRule(String content, Locale locale)\r
177         throws CorrelationException {\r
178         StringReader reader = new StringReader(content);\r
179 \r
180         kfs.write("src/main/resources/rules/rule.drl",\r
181                 this.resources.newReaderResource(reader,"UTF-8").setResourceType(ResourceType.DRL));\r
182 \r
183         kieBuilder = ks.newKieBuilder(kfs).buildAll();\r
184 \r
185         judgeRuleContent(locale, kieBuilder, false);\r
186     }\r
187 \r
188     private void judgeRuleContent(Locale locale, KieBuilder kbuilder, boolean judgePackageName)\r
189         throws CorrelationException {\r
190         if (kbuilder.getResults().hasMessages(Message.Level.ERROR)) {\r
191             String errorMsg = "There are errors in the rule: " + kbuilder.getResults()\r
192                     .getMessages(Level.ERROR).toString();\r
193             log.error(errorMsg);\r
194             throw new CorrelationException(errorMsg);\r
195         }\r
196         InternalKieModule internalKieModule = null;\r
197         try {\r
198             internalKieModule = (InternalKieModule) kbuilder.getKieModule();\r
199         } catch (Exception e) {\r
200             throw new CorrelationException("There are errors in the rule!" + e.getMessage(), e);\r
201         }\r
202         if (internalKieModule == null) {\r
203             throw new CorrelationException("There are errors in the rule!");\r
204         }\r
205         String packageName = internalKieModule.getKnowledgePackagesForKieBase("KBase").iterator().next().getName();\r
206 \r
207         if (queryAllPackage().contains(packageName) && judgePackageName) {\r
208             throw new CorrelationException("The rule " + packageName + " already exists in the drools engine.");\r
209         }\r
210     }\r
211 \r
212     public void putRaisedIntoStream(VesAlarm raiseAlarm) {\r
213         FactHandle factHandle = this.kieSession.getFactHandle(raiseAlarm);\r
214         if (factHandle != null) {\r
215             Object obj = this.kieSession.getObject(factHandle);\r
216             if (obj != null && obj instanceof VesAlarm) {\r
217                 raiseAlarm.setRootFlag(((VesAlarm) obj).getRootFlag());\r
218             }\r
219             this.kieSession.delete(factHandle);\r
220         }\r
221         this.kieSession.insert(raiseAlarm);\r
222         this.kieSession.fireAllRules();\r
223     }\r
224 \r
225     public List<String> queryAllPackage() {\r
226         List<KiePackage> kiePackages = (List<KiePackage>)kieBase.getKiePackages();\r
227         List<String> list = new ArrayList<>();\r
228         for(KiePackage kiePackage : kiePackages) {\r
229             list.add(kiePackage.getName());\r
230         }\r
231         return list;\r
232     }\r
233 \r
234     private KieFileSystem createKieFileSystemWithKProject(KieServices ks) {\r
235         KieModuleModel kieModuleModel = ks.newKieModuleModel();\r
236         KieBaseModel kieBaseModel = kieModuleModel.newKieBaseModel("KBase")\r
237                 .addPackage("rules")\r
238                 .setDefault(true)\r
239                 .setEqualsBehavior(EqualityBehaviorOption.EQUALITY)\r
240                 .setEventProcessingMode(EventProcessingOption.STREAM);\r
241         KieSessionModel kieSessionModel = kieBaseModel.newKieSessionModel("KSession")\r
242                 .setDefault( true )\r
243                 .setType( KieSessionModel.KieSessionType.STATEFUL )\r
244                 .setClockType( ClockTypeOption.get("realtime") );\r
245         KieFileSystem kfs = ks.newKieFileSystem();\r
246         kfs.writeKModuleXML(kieModuleModel.toXML());\r
247         return kfs;\r
248     }\r
249 \r
250     private void avoidDeployBug() {\r
251         String tmp = Math.random() + "";\r
252         String rule = "package justInOrderToAvoidDeployBug" + tmp.substring(2);\r
253         kfs.write("src/main/resources/rules/rule.drl", rule);\r
254         kieBuilder = ks.newKieBuilder(kfs).buildAll();\r
255         InternalKieModule internalKieModule = (InternalKieModule)kieBuilder.getKieModule();\r
256         String packageName = internalKieModule.getKnowledgePackagesForKieBase("KBase").iterator().next().getName();\r
257         kieRepository.addKieModule(internalKieModule);\r
258         kieContainer.updateToVersion(internalKieModule.getReleaseId());\r
259 \r
260         KiePackage kiePackage = kieBase.getKiePackage(packageName);\r
261         kieBase.removeKiePackage(kiePackage.getName());\r
262     }\r
263 \r
264 }\r