Integration von Business Rules in eine Standardapplikation
Inhaltsverzeichnis
Abbildungsverzeichnis
Tabellenverzeichnis
Beispiele
Vorwort
Kapitel 1. Einleitung 1.1. Problemstellung 1.2. Aufgabenstellung und Zielsetzung 1.3. Lösungsansatz
1.4. Gliederung der Arbeit
Kapitel 2. Business Rules 2.1. Definition
2.2. Darstellung von Business Rules 2.2.1. Einleitung
2.2.2. Ontologie
2.2.3. Allgemeiner Aufbau einer Business Rule IF the value of all transactions of a customer is more than 100 $ in one year THEN he qualifies for a discount of 10%.
2.2.4. RuleML - XML Sprache zur Repräsentation von Fakten/Regeln 2.2.4.1. Allgemein 2.2.4.2. RuleML Design
rules / \ 1. / \ 2. / \ reaction rules transformation rules 3. derivation rules 4. 5. facts queries 6. integrity constraints Wenn eine Aktie x um mehr als 5 % verliert Dann verkaufe Aktie x und schicke eine Info per Email
Hier die Darstellung in RuleML: <imp> <_body> <atom> <_opr><rel>eine Aktie x um mehr als 5 % verliert</rel></_opr> </atom> </_body> <_head> <and> <atom> <_opr><rel>verkaufe Aktie x</rel></_opr> </atom> <atom> <_opr><rel>schicke eine Info per Email</rel></_opr> </atom> </and> </_head> </imp> Wenn eine Aktie x um mehr als 5 % verliert Dann verkaufe Aktie x Wenn eine Aktie x um mehr als 5 % verliert Dann schicke eine Info per Email <imp> <_body> <atom> <_opr><rel>eine Aktie x um mehr als 5 % verliert</rel></_opr> </atom> </_body> <_head> <atom> <_opr><rel>verkaufe Aktie x</rel></_opr> </atom> </_head> </imp> <imp> <_body> <atom> <_opr><rel>eine Aktie x um mehr als 5 % verliert</rel></_opr> </atom> </_body> <_head> <atom> <_opr><rel>schicke eine Info per Email</rel></_opr> </atom> </_head>
</imp> 2.2.4.3. Das Beispiel if medium(abwasser) then ort(rostock)
<?xml version="1.0" encoding="utf-8"?> <rulebase> <imp> <_head> <atom> <_opr> <rel>orte</rel> </_opr> <ind>rostock</ind> </atom> </_head> <_body> <and> <atom> <_opr> <rel>medium</rel> </_opr> <ind>abwasser</ind> </atom> </and> </_body> </imp> </rulebase> if medium(abwasser) and not ort(rostock) then send("message") 2.2.5. Zusammenfassung
Kapitel 3. Busines - Rule - Managment - Systeme 3.1. Einführung
3.2. Auswahl
3.3. ILog - JRules 3.3.1. Allgemein 3.3.2. ILOG`s Rule Engine
A(x) ^ B(x) ^ C(y) ) add D(x) A(x) ^ B(y) ^ D(x) ) add E(x) A(x) ^ B(x) ^ E(y) ) delete A(x) Arbeitsspeicher(WM): {A(1); A(2); B(2); B(3); B(4); C(5)}
3.3.3. ILOG`s JRules - Das Business-Rule-Management-System
3.3.4. ILOG's - Business Rule Language
BAL Wenn Dann das abzurechnende Medium ist : Abfall und nicht der Abrechnungsort : Rostock Sende diese Nachricht : "Die Abrechnung von Abfall ist nur in Rostock gestattet!" TRL When Then there is a [ ] Abrechnung [ ] [ called?abrechnung] [where] such that Medium equals Abfall and not Abrechnungsort equals Rostock modify [ ]?abrechnung so that Nachricht = "Die Abrechnung von Abfall ist nur in Rostock gestattet!" IRL when {?abrechnung1: Abrechnung(Medium equals "Abfall" ;! (Ort equals "Rostock")); } then { modify?abrechnung } { Nachricht = "Die Abrechnung von Abfall ist nur in Rostock erlaubt!"; }
3.3.5. Repository
3.3.6. Zusammenfassung
3.4. Mandarax und Oryx 3.4.1. Allgemein 3.4.2. Mandarax
If the value of all transactions of a customer is more than 100 $ in one year then he qualifies for a discount of 10%.
LogicFactory factory = LogicFactory.getDefaultFactory(); Term term1 = factory.createvariableterm("a customer", Customer.class); Discount discount = new Discount(5); Term term2 = factory.createconstantterm(discount); Term[] terms = {terms1,term2}; Class[] predicatestructure = {Customer.class,Discount.class}; Predicate predicate = new SimplePredicate("gets discount", predicatestructure); Fact fact = factory.createfact(predicate,terms); org.mandarax.example.crm org.mandarax.kernel.kowledgebase public Discount getdiscount (Customer customer) { //Erzeuge Anfrage(Parameter sind die Klassen des Objektmodells) Class[] parameters = {Customer.class, Discount.class}; Predicate getsdiscount = new SimplePredicate ("get discount", parameters); Fact query = factorysupport.fact (getsdiscount, customer, "a discount"); // Anfrage stellen InferenceEngine ie = new ResolutionInferenceEngine (); KnowledgeBase kb =...; // hier sind die Regeln gespeichert Result result = ie.query (query, kb);
Replacement replaced = result.getreplacements ()[0]; Discount discount4customer = (Discount) replaced.replacement.getobject (); return discount4customer; } org.mandarax.kernel.inferenceengine org.mandarax.kernel.resultset Derivation getproof();
clauses nextclause(); next(); java.util.iterator
String[] struct = {String.class}; DataSource datasource =..; SQLFunction function = new SQLFunction(); function.setdatasource(datasource); function.setquery( "SELECT COUNT(*) FROM CUSTOMER_TRANSACTIONS WHERE CUSTOMER=?" ); function.setobjectrelationalmapping(new OneColumnMapping (Integer.class) ); function.setname("number of all transactions of a customer"); function.setstructure(struct);
3.4.3. Oryx 2 - Knowledge Editor/Repository 3.4.3.1. Allgemein /plugins /plugins com.jbdietrich.oryx.gui.plugin.plugin
plugins/joi.zip plugins/pluginviewer.jar plugins/log4jconfig.jar plugins/lfconfig.jar plugins/sysinfo.jar 3.4.3.2. Knowledge Editor
ExtendedKnowledgeBase 3.4.3.3. Repository
3.5. Fazit
Kapitel 4. Implementation 4.1. Die Standardapplikation kvasy
4.2. Prototyp 4.2.1. Voraussetzungen
Wenn das abzurechnende Medium Abwasser ist und der Abrechnungsort nicht Rostock ist Dann sende die Nachricht: "Abwasser kann nur in Rostock abgerechnet werden!" Wenn der abzurechnende Tarif Abfallentsorgung ist und der Abrechnungsort nicht Rostock ist Dann sende die Nachricht: "Die Abfallentsorgung existiert nur in Rostock!"
4.2.2. Clientseitige Integration Abrechnung
Abrechnung
addinfo(string arg) comparemedium(balmedium arg) compareort(balort arg) comparetarif(baltarif arg)
Regelmaschine.java public static int processabrechnung(abrechnung a) (1) { if (handler == null) { System.err.println("generateContext aufgerufen" ); handler = new RegelMaschine("Abrechnung.irl"); (2) } context.insert(a); (3) int i = context.fireallrules(); (4) context.retractall(); return i; } processabrechnung(abrechnung a)
Abrechnung Regelmaschine declare lv_fire number; lv_obj_a ORA_JAVA.JOBJECT; lv_error ORA_JAVA.JEXCEPTION; begin al_id Alert; al_button Number; lv_obj_a:= abrechnung.new(:sweiss_rule.kund_kunden_nr, (1) :sweiss_rule.kund_name1, :sweiss_rule.ort_o_name, :sweiss_rule.abzu_bezeichnung, :sweiss_rule.prei_bezeichnung); lv_fire:= REGELMASCHINE.processAbrechnung(lv_obj_a); (2) message('fire? :' lv_fire); if lv_fire > 0 (3) then al_id := Find_Alert('Alert'); Set_Alert_Property(al_id, ALERT_MESSAGE_TEXT, abrechnung.getnachricht(lv_obj_a)); al_button := Show_Alert(al_id); end if; exception when ORA_JAVA.EXCEPTION_THROWN then lv_error:= ORA_JAVA.LAST_EXCEPTION; ORA_JAVA.CLEAR_EXCEPTION; when ORA_JAVA.JAVA_ERROR then message(ora_java.last_error); end; Abrechnung processabrechnung(lv_obj_a) processabrechnung(lv_obj_a)
Wenn das abzurechnende Medium ist: Abwasser ist und der Abrechnungsort ist nicht: Rostock Dann sende die Nachricht: "Abwasser kann nur in Rostock abgerechnet werden!" 4.2.3. Weiterentwicklung der clientseitigen Integration
4.2.4. Serverseitige Integration
when {?boe_debitorenv: Boe_debitorenv(); } then { System.out.println(?boe_debitorenv + "gefunden"); }
Kapitel 5. Zusammenfassung und Ausblick 5.1. Zusammenfassung
5.2. Ausblick
Anhang A. RuleML-DTD Version 0.8 <!-- An XML DTD for a Datalog RuleML Sublanguage: Monolith Version --> <!-- Last Modification: 2001-07-07 --> <!-- ELEMENT Declarations --> <!-- 'rulebase' root element uses 'imp' rules and 'fact' assertions as top-level elements --> <!ELEMENT rulebase ((imp fact)*)> <!-- 'imp' rules are usable as general implications on the top-level --> <!-- 'imp' element uses a conclusion role _head followed by a premise role _body, or equivalently --> <!-- (since roles constitute unordered elements), uses a premise role _body followed by a conclusion role _head --> <!-- "<imp>_head _body</imp>" stands for "_head is implied by _body", i.e., "_head is true is implied by _body is true", or equivalently, --> <!-- "<imp>_body _head</imp>" stands for "_body implies _head", i.e., "_body is true implies _head is true" --> <!ELEMENT imp ((_head, _body) (_body, _head))> <!-- 'fact' assertions are usable as degenerate rules on the top-level --> <!-- 'fact' element uses just a conclusion role _head --> <!-- "<fact>_head</fact>" stands for "_head is implied by true", i.e., "_head is true" --> <!ELEMENT fact (_head) > <!-- _head role is usable within 'imp' rules and 'fact' assertions --> <!-- _body role is usable within 'imp' rules --> <!-- _head uses an atomic formula --> <!-- _body uses an atomic formula or an 'and' --> <!ELEMENT _head (atom)> <!ELEMENT _body (atom and)> <!-- an 'and' is usable within _body's --> <!-- 'and' uses zero or more atomic formulas --> <!-- "<and>atom</and>" is equivalent to "atom"--> <!-- "<and></and>" is equivalent to "true"--> <!ELEMENT and (atom*)> <!-- atomic formulas are usable within _head's, _body's, and 'and's --> <!-- atom element uses an: --> <!-- _opr ("operator of relations") role followed by a sequence of zero or more arguments, or similarly --> <!-- (since roles constitute unordered elements, and
the zero-argument case must not cause ambiguity), --> <!-- a sequence of one or more arguments followed by an _opr role --> <!-- the arguments may be ind(ividual)s or var(iable)s --> <!ELEMENT atom ((_opr, (ind var)*) ((ind var)+, _opr))> <!-- _opr is usable within atoms --> <!-- _opr uses rel(ation) symbol --> <!ELEMENT _opr (rel)> <!-- there is one kind of fixed argument --> <!-- individual constant, as in predicate logic --> <!ELEMENT ind (#PCDATA)> <!-- there is one kind of variable argument --> <!-- logical variable, as in logic programming --> <!ELEMENT var (#PCDATA)> <!-- there are only fixed (first-order) relations --> <!-- relation or predicate symbol --> <!ELEMENT rel (#PCDATA)>
Anhang B. Performancevergleich von Rules Engine
Anhang C. Prototyp - Quellcode Abrechnung.java public class Abrechnung { public String KundenNummer; public String KundenName; public String Ort; public String Medium; public String Tarif; public String Nachricht = ""; public Abrechnung(String knr, String kn,string o,string m, String t) { KundenNummer = knr; } KundenName = kn; Ort = o; Medium = m; Tarif = t; public void addinfo(string text) { this.nachricht += text+"\n"; } } Regelmaschine.java import java.io.*; import java.util.*; import ilog.rules.engine.*; import ilog.rules.tools.*; import ilog.rules.util.logging.*; import ilog.rules.repository.brm.*; import ilog.rules.repository.model.*; import ilog.rules.repository.facility.*; import ilog.rules.util.ilroperationexception; public class RegelMaschine { private static RegelMaschine handler = null; private static IlrContext context; public RegelMaschine(String rulefile) { IlrRuleset ruleset = new IlrRuleset(); ruleset.parsefilename( rulefile ); context = new IlrContext( ruleset ); System.err.println( "Constr. aufgerufen" );
} public static int processabrechnung(abrechnung a) { if (handler == null) { System.err.println("generateContext aufgerufen" ); handler = new RegelMaschine("PATH/Abrechnung.irl"); } context.insert(a); int i = context.fireallrules(); context.retractall(); return i; } }
Anhang D. Oracle Form Builder - Start.bat set CLASSPATH=$HOME\jbproject\Abrechnung\classes; \ D:\ILOG\JRules45\lib\jrulesall.jar; \ F:\oracle\orant\FORMS60\java; \ F:\oracle\orant\TOOLS\COMMON60\JAVA\IMPORTER.JAR; \ F:\oracle\orant\jdk\lib\classes.zip; \ D:\ILOG\JRules45\lib\*.jar set path=c:\j2sdk1.4.1\bin;c:\j2sdk1.4.1\jre\bin\client;%path% set NLS_NUMERIC_CHARACTERS=,. set NLS_SORT=BINARY F:\oracle\orant\BIN\ifbld60.EXE '' kvasy/kvasy@local
Anhang E. Glossar
Literaturverzeichnis