Jess Rule Engine og JSR 94

1. Oversigt

Brug af en regelmotor er en fantastisk måde at adskille forretningslogikken fra vores kedelpladekode og beskytte vores applikationskode mod forretningsændringer.

I en tidligere artikel om Java Rule Engines nævnte vi JSR 94-specifikationen. Jess Rule Engine har særlig betydningsom reference regler driverimplementering for JSR 94, så lad os se på det.

2. Jess regel motor

Jess er en af ​​de tidligste regelmotorer, der let kan integreres med Java. Jess bruger en forbedret implementering af den meget effektive Rete-algoritme, hvilket gør den meget hurtigere end en simpel Java-loop i de fleste scenarier.

Regler kan udføres fra regelsæt skrevet på det oprindelige Jess Rules Language, en udvidet Lisp-baseret syntaks, eller fra et mere detaljeret XML-format. Vi bruger det oprindelige format.

Der er en Eclipse-baseret IDE til udvikling (til ældre versioner af Eclipse) og noget fremragende dokumentation om brug og integration af Jess med Java. Der er endda en REPL kommandolinjegrænseflade, hvor vi kan prøve vores ideer, inden vi opretter en reglerfil.

Som referenceregelmotor for JSR 94 er Jess pr. Definition JSR 94-kompatibel, selvom den ikke længere er under aktiv udvikling.

2.1. Et hurtigt ord om JSR 94

JSR 94 giver en API, som vi kan bruge til at give os uafhængighed af, hvilken regelmotor vi vælger. Vi kan tilslutte en hvilken som helst JSR 94-kompatibel regelmotor til vores kode og køre nogle regler uden at skulle ændre den måde, vi interagerer med regelmotoren på i vores applikation.

Dette betyder ikke, at regelmotorens underliggende regler vil se ens ud - vi bliver muligvis nødt til at omskrive dem, hvis vi ændrer regelmotoren, men det betyder, at vi ikke behøver at omskrive dele af vores applikation for at bruge den nye regelmotor. De eneste kodeændringer, vi har brug for, er at opdatere navnet på driveren og nogle regelfilnavne.

2.2. Jess JSR 94 Driver

Selvom der er en referenceregelmotor chauffør for Jess inkluderet til JSR 94, er Jess selv ikke inkluderet, da det er et licenseret kommercielt produkt. Referencedriveren kommer i org.jcp.jsr94.jess pakke, men en nyere driver er tilgængelig i jess.jsr94 pakke, når vi downloader Jess.

Lad os starte med at se på Jess's native Java-integration, inden vi går videre for at se, hvordan JSR 94-laget ændrer dette.

3. Tilvejebragte eksempler

Før vi begynder at integrere Jess i vores kode, skal vi sørge for, at vi har downloadet den og gjort den tilgængelig på vores klassesti. Vi bliver nødt til at registrere os til den gratis 30-dages prøveversion, medmindre vi allerede har en licens.

Så lad os downloade Jess, pakke den downloadede ud Jess71p2.jar, og kør et af eksemplerne for at sikre, at vi har en fungerende version.

3.1. Frittstående Jess

Lad os se i Jess71p2 / eksempler bibliotek, hvor jess katalog indeholder nogle eksempler på regelsæt. Det prissætning_motor katalog viser en integration, der kan udføres via en myre build.xml manuskript. Lad os ændre vores mappe til prissætningseksemplet og køre programmet via myretest:

cd Jess71p2 / eksempler / pricing_engine ant test

Dette bygger og kører et eksempel på prisregelsæt:

Buildfile: Jess71p2 \ examples \ pricing_engine \ build.xml ... test: [java] Varer til ordre 123: [java] 1 CD Writer: 199,99 ... [java] Varer til ordre 666: [java] 1 Incredibles DVD: 29.99 [java] Tilbud til ordre 666: [java] BYG SUCCESFULT Samlet tid: 1 sekund

3.2. Jess med JSR 94

Nu hvor vi har Jess i gang, lad os downloade JSR 94 og derefter pakke den ud for at oprette en jsr94-1.0-mappe med ant, doc, lib og src-mapper inde.

unzip jreng-1_0a-fr-spec-api.zip

Dette giver os JSR 94 API og Jess-referencedriveren, men det følger ikke med den licenserede Jess-implementering, så hvis vi prøver at køre et eksempel nu, får vi følgende fejl:

Fejl: Referenceimplementeringen Jess kunne ikke findes.

Så lad os tilføje Jess-referenceimplementeringen, jess.jar, der kom som en del af Jess71p2, vi downloadede tidligere, og kopierede den til JSR 94 lib-biblioteket, og kør derefter eksemplet:

cp Jess71p2 / lib / jess.jar jsr94-1.0 / lib / java -jar jsr94-1.0 / lib / jsr94-eksempel.jar

Eksemplet kører nogle regler for at bestemme en kundes resterende kredit, når fakturaer betales:

Administration API Erhvervet regel Administrator: [e-mail-beskyttet] ... Runtime API Erhvervet RuleRuntime: [e-mail-beskyttet] Resultat af kundekreditgrænse: 3000 ... Fakturabeløb 2: 1750 status: betalt Udgivet Stateful Rule Session.

4. Integrering af Jess med Java

Nu hvor vi har downloadet Jess og JSR 94 og har kørt nogle regler både indfødt og via JSR, lad os se på, hvordan man integrerer et Jess-regelsæt i et Java-program.

I vores eksempel starter vi med at udføre en simpel Jess-reglerfil, hellojess.clp, fra Java-kode, og se derefter på en anden reglerfil, bonus.clp, der vil bruge og ændre nogle af vores objekter.

4.1. Maven afhængighed

Der er ingen Maven-afhængighed tilgængelig for Jess, så hvis vi ikke allerede har gjort det, lad os downloade og pakke Jess-krukken ud (jess.jar) og mvn installere det til vores lokale Maven-arkiv:

mvn install: install-file -Dfile = jess.jar -DgroupId = gov.sandia -DartifactId = jess -Dversion = 7.1p2 -Dpackaging = jar -DgeneratePom = true

Vi kan derefter tilføje det som en afhængighed på den sædvanlige måde:

 gov.sandia jess 7.1p2 

4.2. Hej Jess-regler

Lad os derefter oprette de enkleste reglerfiler til at udskrive en besked. Vi gemmer reglerfilen som hellojess.clp:

(udskrift t "Hej fra Jess!" crlf)

4.3. Jess Rule Engine

Lad os nu oprette en forekomst af Jess Rete regelmotor, Nulstil() den til sin oprindelige tilstand skal du indlæse reglerne i hellojess.clp, og kør dem:

offentlig klasse HelloJess {offentlig statisk ugyldig hoved (String [] args) kaster JessException {Rete motor = ny Rete (); engine.reset (); engine.batch ("hellojess.clp"); engine.run (); }

Til dette enkle eksempel har vi lige tilføjet potentialet JessException til vores vigtigste metoder kaster klausul.

Når vi kører vores program, ser vi output:

Hej fra Jess!

5. Integrering af Jess til Java med data

Nu hvor alt er installeret korrekt, og vi kan køre regler, lad os se, hvordan vi tilføjer data til regelmotoren, der skal behandles, og hvordan vi henter resultaterne.

Først skal vi bruge nogle Java-klasser til at arbejde med, og derefter et nyt regelsæt, der bruger dem.

5.1. Model

Lad os oprette nogle enkle Spørgsmål og Svar klasser:

offentlig klasse Spørgsmål {privat String spørgsmål; privat int balance  // getters og setters  offentligt spørgsmål (streng spørgsmål, int balance) {dette.spørgsmål = spørgsmål; dette. balance = balance; }} offentlig klasse Svar {privat streng svar; privat int newBalance;  // getters og setters  offentligt svar (streng svar, int newBalance) {this.answer = svar; this.newBalance = newBalance; }}

5.2 Jess-regel med input og output

Lad os nu oprette et simpelt Jess-regelsæt kaldet bonus.clp at vi passerer en Spørgsmål til og modtage en Svar fra.

Først vi importere vores Spørgsmål og Svar og derefter bruge Jess's deftemplate funktion til at gøre dem tilgængelige for regelmotoren:

(import com.baeldung.rules.jsr94.jess.model. *) (deftemplate Question (erklær (fra klasse spørgsmål))) (deftemplate Answer (erklær (fra klasse svar))))

Bemærk brugen af ​​parenteser, som betegner Jess-funktionskald.

Lad os nu bruge det defrule for at tilføje en enkelt regel undgå overtræk i Jess's udvidede Lisp-format, der giver os en bonus på $ 50, hvis saldoen i vores Spørgsmål er under nul:

(defrule undgå overtræk "Giv $ 50 til enhver overdrevet"? q <- (Spørgsmål {balance (tilføj (nyt svar "Overtrukket bonus" (+? q. balance 50))))

Her er “?” binder et objekt til en variabel q når forholdene på højre side af “<-“ match. I dette tilfælde er det, når regelmotoren finder en Spørgsmål der har en balance mindre end 0.

Når det sker, så handlinger til højre for “=>” udløses, så motoren tilføjes a nyt svar modsætter sig arbejdshukommelsen. Vi giver det de to krævede konstruktørargumenter: "Overtrukket bonus" for svar parameter og a (+) funktion til at beregne newAmount parameter.

5.3. Manipulering af data med Jess Rule Engine

Vi kan bruge tilføje() at tilføje et enkelt objekt ad gangen til vores regelmotors arbejdshukommelse, eller tilføjAlle () for at tilføje en samling af data. Lad os bruge tilføje() for at tilføje et enkelt spørgsmål:

Spørgsmålsspørgsmål = nyt spørgsmål ("Kan jeg få en bonus?", -5); engine.add (data);

Med alle vores data på plads, lad os udføre vores regler:

engine.run ();

Jess Rete motoren vil arbejde med sin magi og vende tilbage, når alle relevante regler er udført. I vores tilfælde har vi en Svar at inspicere.

Lad os bruge en jess. filter at udtrække vores Svar fra regelmotoren til en Iterabel resultat objekt:

Iteratorresultater = engine.getObjects (ny jess.Filter.ByClass (Answer.class)); mens (results.hasNext ()) {Answer answer = (Answer) results.next (); // behandle vores svar}

Vi har ikke nogen referencedata i vores enkle eksempel, men når vi gør det, kan vi bruge en WorkingMemoryMarker og engine.mark () for at markere tilstanden for regelmotorens arbejdshukommelse efter tilføjelse af data. Så kan vi ringe motor.resetToMark med vores markør for at nulstille arbejdshukommelsen til vores "indlæste" tilstand og effektivt genbruge regelmotoren til et andet sæt objekter:

WorkingMemoryMarker markør; // belastningsreferencedatamarkør = engine.mark (); // indlæse specifikke data og køre regler engine.resetToMark (markør);

Lad os nu se på, hvordan vi kører det samme regelsæt ved hjælp af JSR 94.

6. Brug af JSR 94 til at integrere Jess Rule Engine

JSR 94 standardiserer, hvordan vores kode interagerer med en regelmotor. Dette gør det lettere at ændre vores regelmotor uden at ændre vores applikation markant, hvis der kommer et bedre alternativ.

JSR 94 API kommer i to hovedpakker:

  • javax.rules.admin - til indlæsning af chauffører og regler
  • javax.regler - at køre reglerne og udtrække resultater

Vi ser på, hvordan man bruger klasserne i begge disse.

6.1. Maven afhængighed

Lad os først tilføje en Maven-afhængighed for jsr94:

 jsr94 jsr94 1.1 

6.2. Administration API

For at begynde at bruge JSR 94 er vi nødt til at starte en RuleServiceProvider. Lad os oprette en og give den vores Jess-regler driver:

Streng RULE_SERVICE_PROVIDER = "jess.jsr94"; Class.forName (RULE_SERVICE_PROVIDER + ".RuleServiceProviderImpl"); RuleServiceProvider ruleServiceProvider = RuleServiceProviderManager.getRuleServiceProvider (RULE_SERVICE_PROVIDER);

Lad os nu få Jess's JSR 94 Regeladministrator, indlæs vores eksempel regelsæt i en JSR 94 RuleExecutionSet, og registrer det til udførelse med en URI efter eget valg:

RuleAdministrator ruleAdministrator = serviceProvider.getRuleAdministrator (); InputStream ruleInput = JessRunner.class.getResourceAsStream (rulesFile); HashMap vendorProperties = ny HashMap (); RuleExecutionSet ruleExecutionSet = ruleAdministrator .getLocalRuleExecutionSetProvider (vendorProperties) .createRuleExecutionSet (ruleInput, vendorProperties); String rulesURI = "regler: // com / baeldung / regler / bonus"; ruleAdministrator.registerRuleExecutionSet (rulesURI, ruleExecutionSet, vendorProperties);

Jess-chaufføren har ikke brug for sælgerEjendomme kort vi leverede til Regeladministrator, men det er en del af grænsefladen, og andre leverandører kan kræve det.

Nu hvor vores regelmotorudbyder, Jess, er blevet initialiseret, og vores regelsæt er blevet registreret, er vi næsten klar til at køre vores regler.

Før vi kan køre dem, har vi brug for en runtime-forekomst og en session til at køre dem i. Lad os også tilføje en pladsholder, calcResults (), for hvor magien vil ske, og slip sessionen:

RuleRuntime ruleRuntime = ruleServiceProvider.getRuleRuntime (); StatelessRuleSession statelessRuleSession = (StatelessRuleSession) ruleRuntime.createRuleSession (rulesURI, ny HashMap (), RuleRuntime.STATELESS_SESSION_TYPE); CalcResults (statelessRuleSession); statelessRuleSession.release ();

6.3. API til udførelse

Nu hvor vi har alt på plads, lad os implementere det beregne resultater for at levere vores oprindelige data, udføre vores regler i en statsløs session og udtrække resultaterne:

Listedata = ny ArrayList (); data.add (nyt spørgsmål ("Kan jeg få en bonus?", -5)); Listeresultater = statelessRuleSession.executeRules (data);

Da JSR 94 blev skrevet før JDK 5 kom, bruger API ikke generiske produkter, så lad os bare bruge en Iterator for at se resultaterne:

Iterator itr = results.iterator (); mens (itr.hasNext ()) {Objekt obj = itr.next (); if (obj instanceof Answer) {int answerBalance = ((Answer) obj) .getCalculatedBalance ()); }}

Vi har brugt en statsløs session i vores eksempel, men vi kan også oprette en StatefuleRuleSession hvis vi ønsker at opretholde staten mellem påkaldelser.

7. Konklusion

I denne artikel lærte vi, hvordan vi integrerer Jess-regelmotoren i vores applikation ved at bruge Jess's native klasser og med lidt mere indsats ved at bruge JSR 94. Vi har set, hvordan forretningsregler kan opdeles i separate filer, der bliver behandlet af regelmotoren, når vores applikation kører.

Hvis vi har regler for den samme forretningslogik, skrevet til en anden JSR 94-kompatibel regelmotor, kan vi simpelthen tilføje driveren til vores alternative regelmotor og opdatere drivernavnet, som vores applikation skal bruge, og ingen yderligere kodeændringer skal være nødvendig.

Der er flere detaljer på jess.sandia.gov til indlejring af Jess i en Java-applikation, og Oracle har en nyttig guide til Kom godt i gang med Java Rule Engine API (JSR 94).

Som sædvanlig er koden, vi kiggede på i denne artikel, tilgængelig på GitHub.


$config[zx-auto] not found$config[zx-overlay] not found