/* * Claudia Project * http://claudia.morfeo-project.org * * (C) Copyright 2010 Telefonica Investigacion y Desarrollo * S.A.Unipersonal (Telefonica I+D) * * See CREDITS file for info about members and contributors. * * This program is free software; you can redistribute it and/or modify * it under the terms of the Affero GNU General Public License (AGPL) as * published by the Free Software Foundation; either version 3 of the License, * or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the Affero GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * If you want to use this software an plan to distribute a * proprietary application in any way, and you are not licensing and * distributing your source code under AGPL, you probably need to * purchase a commercial license of the product. Please contact * claudia-support@lists.morfeo-project.org for more information. */ package com.telefonica.claudia.slm.rulesEngine; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.util.HashSet; import java.util.Iterator; import java.util.Properties; import java.util.Set; import java.util.logging.Level; import org.apache.log4j.Logger; import org.drools.RuleBase; import org.drools.RuleBaseFactory; import org.drools.StatefulSession; import org.drools.WorkingMemory; import org.drools.compiler.DroolsParserException; import org.drools.compiler.PackageBuilder; import org.drools.compiler.PackageBuilderConfiguration; import org.drools.event.DebugWorkingMemoryEventListener; import org.drools.rule.Package; import com.telefonica.claudia.slm.deployment.Rule; import com.telefonica.claudia.slm.deployment.ServiceApplication; import com.telefonica.claudia.slm.deployment.ServiceKPI; import com.telefonica.claudia.slm.deployment.VEE; import com.telefonica.claudia.slm.lifecyclemanager.FSM; import com.telefonica.claudia.slm.lifecyclemanager.LifecycleController; public class RulesEngine { private static Logger logger = Logger.getLogger(RulesEngine.class); private StatefulSession rulesEngineSession = null; @SuppressWarnings("unused") private String rulesFileName = null; @SuppressWarnings("unused") private EventsReceptor erecept; private PackageBuilderConfiguration builderConf; private PackageBuilder builder; private Package pkg; private RuleBase ruleBase; private HashSet<String> ruleSet= new HashSet<String>(); public ServiceApplication sap; private LifecycleController lcc; private final static String paramOpener="@{"; private final static String paramCloser="}"; private String ruleBaseDir="./ruleHome/"; private String ruleExtension=".drl"; public RulesEngine(String rulesFileName) { this.rulesFileName = rulesFileName; } public RulesEngine(LifecycleController lcc) { this.lcc=lcc; } public void run() { // To avoid eclipse dependencies, we set the java compiler to janino. logger.info("Preparing package builder"); Properties properties = new Properties(); //properties.setProperty( "drools.dialect.java.compiler", "JANINO" ); properties.setProperty( "drools.dialect.java.compiler", "ECLIPSE" ); builderConf = new PackageBuilderConfiguration(properties); builder = new PackageBuilder(builderConf); initRules(); } protected void executeRules(WorkingEnvironmentCallback callBack) { logger.info("Starting rules engine stateful session"); if (ruleBase==null) { logger.error("Rule base not found for Service [" + sap + "]. This event may be lost from a previously deleted service."); return; } WorkingMemory workingMemory = ruleBase.newStatefulSession(); workingMemory.addEventListener(new DebugWorkingMemoryEventListener()); callBack.initEnvironment(workingMemory); logger.info("Firing rules"); workingMemory.fireAllRules(); } /** * init the first rule to be evaluated and loaded */ public void startRule(String startRule){ // add Rule to a Set to load it System.out.println ("add rule " + startRule); ruleSet.add(startRule); } /** * Configures the rule engine with the required data * @param sap * @param fsm */ public void configure(FSM fsm) { this.sap=fsm.getServiceApplication(); erecept=new EventsReceptor(this, fsm, sap, lcc); } /** * Load all the rules in the ruleSet */ public void initRules(){ String ruleFile; Iterator <String> it=ruleSet.iterator(); while (it.hasNext()){ ruleFile=it.next(); System.out.println ("rule example " + ruleFile); addRule(ruleFile); } } /** * Call only after run or startRule have been invoked: method to update the set of running rules * @param rulesFile */ public void addRule(String rulesFile){ //Read from an input stream BufferedInputStream rf; InputStreamReader source; logger.info("Adding rule [" + rulesFile + "] to the rules base"); try { rf = new BufferedInputStream(new FileInputStream(rulesFile)); // Read in the rules source file source = new InputStreamReader(rf); // This will parse and compile in one step builder.addPackageFromDrl(source); } catch (FileNotFoundException ex) { java.util.logging.Logger.getLogger(RulesEngine.class.getName()).log(Level.SEVERE, null, ex); logger.error("File not found "+ex.getMessage()); } catch (DroolsParserException ex) { java.util.logging.Logger.getLogger(RulesEngine.class.getName()).log(Level.SEVERE, null, ex); logger.error("Parse exception "+ex.getMessage()); } catch (IOException ex) { java.util.logging.Logger.getLogger(RulesEngine.class.getName()).log(Level.SEVERE, null, ex); logger.error("IOException "+ex.getMessage()); } logger.info("Building package"); pkg = builder.getPackage(); logger.info("Creating rules base (container of rules packages)"); // Add the package to a rulebase (deploy the rule package). ruleBase = RuleBaseFactory.newRuleBase(); try { logger.info("Adding rules package to rule base"); ruleBase.addPackage(pkg); } catch (Exception ex) { java.util.logging.Logger.getLogger(RulesEngine.class.getName()).log(Level.SEVERE, null, ex); logger.error("Exception caught when trying to add package", ex); System.out.println(ex.getMessage()); } } public void close() { logger.info("Removing rules from rules engine"); rulesEngineSession.dispose(); } /** * convert this VEE rules into Drools-compatible rules */ public void rules2Drools(){ String header, body, condition, function,action; CharSequence target,replacement,targetAction,replacementAction; int locatorInit,locatorEnd; PrintWriter out ; Rule rule; ServiceKPI kpi; VEE vee; int occurence,occurenceAction; header="package es.tid.reservoir.serviceManager.rulesEngine;"+"\n"+"// Imports for all types of events should be here..."+"\n"+"import es.tid.reservoir.serviceManager.eventsBus.events.VeeHwMeasureEvent;"+"\n"+"import es.tid.reservoir.serviceManager.eventsBus.events.AgentMeasureEvent;"+"\n"+"import es.tid.reservoir.serviceManager.eventsBus.events.ProbeMeasureEvent;"+"\n"+"global es.tid.reservoir.serviceManager.rulesEngine.Actions actions; \n"; Iterator<ServiceKPI> kpiIterator; Iterator<VEE> veeIterator; Iterator<Rule> ruleIterator=sap.getServiceRules().iterator(); while(ruleIterator.hasNext()){ rule=((Rule)ruleIterator.next()); // add rule name body="rule"+" \""+rule.getFQN().toString(); // add other headers body=body+"\""+"\n"+"lock-on-active true"+"\n"+"salience 100"+"\n"+"when"+"\n"; // add when part of the rule condition=rule.getCondition(); action=rule.getAction(); // replace KPIs with their FQN kpiIterator=sap.getServiceKPIs().iterator(); String kpiName = null; while(kpiIterator.hasNext()){ kpi=((ServiceKPI)kpiIterator.next()); target=kpi.getKPIName(); target.toString(); //assume naming convention target=paramOpener+"kpis."+target+paramCloser; occurence=(condition.indexOf(target.toString())); if(!(occurence<0)){ // the KPI name is included in this rule, //the parameter is the KPI replacement="value"; kpiName=kpi.getFQN().toString(); // then, we must substitute it condition=condition.replace(target, replacement); } } // replace VEEs with their FQN veeIterator= sap.getVEEs().iterator(); while(veeIterator.hasNext()){ vee=(VEE)veeIterator.next(); target=vee.getVEEName(); target=paramOpener+"components."+target+".replicas."; occurence=(condition.indexOf(target.toString())); if(!(occurence<0)){ // the VEE name is included in this rule // Find the function we are dealing with (amount in this case) to map it to a Drools global object // assume amount is a known parameter (a set of allowed parameters must be defined and checked here in the future: TBD), locatorInit=occurence+target.length(); locatorEnd=condition.indexOf(paramCloser,occurence); function=condition.substring(locatorInit, locatorEnd); if(function.equals("amount")){ target=target+function+paramCloser; replacement="actions.getAmount(\""+vee.getFQN().toString()+"\")"; // then, we must substitute it condition=condition.replace(target, replacement); } } targetAction=vee.getVEEName(); targetAction="components."+targetAction; occurenceAction=(action.indexOf(targetAction.toString())); if(!(occurenceAction<0)){ targetAction=action; replacementAction="actions."+action.substring(0,occurenceAction)+"\""+vee.getFQN().toString()+"\")" ; // then, we must substitute it action=action.replace(targetAction, replacementAction); } } // add then part of the rule body=body+" event : "+rule.getEventType().toString()+" (measure == \""+kpiName+"\" , "+"eval("+condition+")); \n"+"then \n"; body=body+action+";\n"+"end"; // System.out.println(header+body); //write to Drools try { File norma=new File(ruleBaseDir+rule.getFQN().toString()+ruleExtension); logger.info("Storing new Drools rule in file " + norma.getAbsolutePath()); norma.createNewFile(); out = new PrintWriter(new FileWriter(norma)); out.write(header+body); out.close(); }catch (IOException ex){ logger.error("IOException caught when trying to create rule file " + ex); } // load rules into drools startRule(ruleBaseDir+rule.getFQN().toString()+ruleExtension); } } /** * convert this VEE rules into Drools-compatible rules * @param type of rules employed that should be converted */ public void claudiaRules2Drools(){ String ruleUp, ruleDown; boolean up=true; PrintWriter out ; Rule rule; Iterator<Rule> ruleIterator; Set<Rule> ruleVector = sap.getServiceRules(); System.out.println ("numero de reglas " + ruleVector.size()); for(ruleIterator=ruleVector.iterator();ruleIterator.hasNext();){ rule=((Rule)ruleIterator.next()); // IN Y2 a rule is associated with a single KPI: univocal association // build upscaling rule first ruleUp=rule.buildRule(up); // build donwscaling rule System.out.println ("ruling down"); ruleDown=rule.buildRule(!up); //write to Drools try { // write upscaling rule to file File norma=new File(ruleBaseDir+rule.getFQN().toString()+ruleExtension); norma.createNewFile(); out = new PrintWriter(new FileWriter(norma)); out.write(ruleUp); out.close(); // write downscaling rule to file norma=new File(ruleBaseDir+rule.getFQN().toString()+"b"+ruleExtension); norma.createNewFile(); out = new PrintWriter(new FileWriter(norma)); out.write(ruleDown); out.close(); }catch (IOException ex){ //log.debug("IOException caught when trying to createrule file " + ex); } // load rules into drools startRule(ruleBaseDir+rule.getFQN().toString()+ruleExtension); startRule(ruleBaseDir+rule.getFQN().toString()+"b"+ruleExtension); } } }