IBM WebSphere ILOG JRules oferuje funkcjonalność potrzebną do budowania i wdrażania aplikacji działających w oparciu o reguły w środowiskach Java, mainframe i SOA. Programiści mogą w prosty sposób budować i wdrażać aplikacje, które w oparciu o reguły automatyzują podejmowanie decyzji w ramach szczegółowych, zmiennych procesów używanych przez systemy biznesowe. Narzędzie przyspiesza tworzenie i serwisowanie takich aplikacji oraz ogranicza pracochłonność i koszty takich prac.
Ogólny sposób wywoływania JRules za pomocą jPALIO przedstawia poniższy obrazek:
Przebieg wykonania reguły biznesowej z użyciem JRules wygląda następująco:
W procesie integracji JRules z jPALIO mogą brać udział osoby bez wiedzy programistycznej oraz ją posiadające nazywane dalej informatykami.
Ogólny zarys integracji JRules z jPALIO:
1. Informatyk tworzy projekt XOM w Rule Studio w którym definiuje:
2. Informatyk tworzy projekt reguł. W tym projekcie możliwe jest:
3. Informatyk tworzy projekt aplikacji z projektu reguł który będzie wysłany do serwera wykonawczego RES.
4. Informatyk tworzy projekt webservices z wcześniej zdefiniowanego projektu aplikacji.
5. Informatyk publikuje stworzone projekty na serwerze RTS oraz opcjonalnie umieszcza wykonywalne reguły na serwerze wykonawczym RES.
6. Informatyk lub osoba nie mająca wiedzy programistycznej projektuje reguły i przepływy.
7. Informatyk lub osoba nie mająca wiedzy programistycznej umieszcza zmiany na serwerze RTS oraz RES.
8. Programista jPALIO modyfikuje działanie portalu www w zależności od wyników reguł.
Podsumowując ogólny sposób projektowania systemów wykorzystujących JRules z pomocą jPALIO przedstawia poniższy rysunek:
Aby udostępnić JRules dla JPalio przez webservices należy:
package pl.com.torn.sncm;
import java.util.List;
public class Event {
private String eventDate;
private double amount;
private String organizationCode;
private String productCode;
private String eventTypeCode;
private String entityCode;
private List<Parameter> parameters;
public String getEventDate() {
return eventDate;
}
public void setEventDate(String eventDate) {
this.eventDate = eventDate;
}
public double getAmount() {
return amount;
}
public void setAmount(double amount) {
this.amount = amount;
}
public String getOrganizationCode() {
return organizationCode;
}
public void setOrganizationCode(String organizationCode) {
this.organizationCode = organizationCode;
}
public String getProductCode() {
return productCode;
}
public void setProductCode(String productCode) {
this.productCode = productCode;
}
public String getEventTypeCode() {
return eventTypeCode;
}
public void setEventTypeCode(String eventTypeCode) {
this.eventTypeCode = eventTypeCode;
}
public String getEntityCode() {
return entityCode;
}
public void setEntityCode(String entityCode) {
this.entityCode = entityCode;
}
public List<Parameter> getParameters() {
return parameters;
}
public void setParameters(List<Parameter> parameters) {
this.parameters = parameters;
}
}
orazpackage pl.com.torn.sncm;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlType;
/**
* <p>Java class for parameter complex type.
*
* <p>The following schema fragment specifies the expected content
contained within this class.
*
* <pre>
* <complexType name="parameter">
* <complexContent>
* <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* <sequence>
* <element name="code"
type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
* <element name="dateValue"
type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
* <element name="fractionalValue"
type="{http://www.w3.org/2001/XMLSchema}double"/>
* <element name="numericValue"
type="{http://www.w3.org/2001/XMLSchema}double"/>
* <element name="textValue"
type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
* </sequence>
* </restriction>
* </complexContent>
* </complexType>
* </pre>
*
*
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "parameter", propOrder = {
"code",
"dateValue",
"fractionalValue",
"numericValue",
"textValue"
})
public class Parameter {
protected String code;
protected String dateValue;
protected double fractionalValue;
protected double numericValue;
protected String textValue;
/**
* Gets the value of the code property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getCode() {
return code;
}
/**
* Sets the value of the code property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setCode(String value) {
this.code = value;
}
/**
* Gets the value of the dateValue property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getDateValue() {
return dateValue;
}
/**
* Sets the value of the dateValue property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setDateValue(String value) {
this.dateValue = value;
}
/**
* Gets the value of the fractionalValue property.
*
*/
public double getFractionalValue() {
return fractionalValue;
}
/**
* Sets the value of the fractionalValue property.
*
*/
public void setFractionalValue(double value) {
this.fractionalValue = value;
}
/**
* Gets the value of the numericValue property.
*
*/
public double getNumericValue() {
return numericValue;
}
/**
* Sets the value of the numericValue property.
*
*/
public void setNumericValue(double value) {
this.numericValue = value;
}
/**
* Gets the value of the textValue property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getTextValue() {
return textValue;
}
/**
* Sets the value of the textValue property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setTextValue(String value) {
this.textValue = value;
}
}
request.setTaskName(rulesetrequest.getFlow());
public SncmRulesResult executeSncmRules(SncmRulesRequest rulesetrequest) throws RulesetExecutionException {
if (SncmRulesListener.getMBean().isActivated()) {
try {
// create the request
IlrSessionFactory factory = getFactory();
IlrSessionRequest request = factory.createRequest();
request.setRulesetPath(IlrPath.parsePath("/SncmRuleApp/SncmRules"));
request.setUserData("SncmRuleApp.SncmWSRunnerImpl.executeSncmRules");
// prepare trace options
request.setTraceEnabled(true);
request.setTaskName(rulesetrequest.getFlow());
request.setInputParameter("eventItem", rulesetrequest.getEventItem());
request.setInputParameter("flow", rulesetrequest.getFlow());
IlrSessionResponse response;
IlrStatelessSession session = factory.createStatelessSession();
ExecutionHook hook = new ExecutionHook();
request = hook.preProcessing(request);
// Get current time
long start = System.currentTimeMillis();
response = session.execute(request);
// Get the duration
long duration = System.currentTimeMillis() - start;
// Add measurement
SncmRulesListener.getMBeanManager().addMeasurement(
response.getCanonicalRulesetPath().toString(), start,
duration);
response = hook.postProcessing(request, response);
SncmRulesResult SncmRulesresult = new SncmRulesResult();
SncmRulesresult.provision = (java.lang.Double) response
.getOutputParameters().get("provision");
return SncmRulesresult;
} catch (Exception e) {
SncmRulesListener.getMBeanManager().addError(
System.currentTimeMillis());
throw new RulesetExecutionException("SncmRules", e);
}
} else {
throw new RulesetExecutionException("Execution is not authorized");
}
}
Dzięki nowo dodanej linii jest możliwe wybieranie przepływu w jPalio poprzez webservices. Zmodyfikowaną usługę webservices należy umieścić na serwerze za pomocą wygenerowanych tasków ant'a w pliku build.xml. Wystawiona usługa webservices powinna być widoczna na stronie serwera wykonawczego RES oraz powinnien być dostępny dokument wsdl przez przeglądarkę.Aby wywołać regułę i otrzymać z niej wynik należy:
W tym momencie jest możliwe wywołanie reguły JRules. Należy zwrócić uwagę, że sposób tworzenia i zarządzania regułami za pomocą dokumentów pakietu Office jest możliwe dla klienta końcowego nie posiadającego wiedzy programistycznej. Użytkownik nie posiadający wiedzy programistycznej może także edytować reguły biznesowe bezpośrednio za pomocą strony teamserver. Jednak w tym podejściu nie możliwa jest edycja przepływów (ang. flow) między regułami.
Dla osób mających wiedzę informatyczną, możliwa jest edycja reguł i przepływów bezpośrednio w projektach programu eclipse z pluginem do JRules - ILOG Business Rule Studio. To środowisko może być przez takie osoby preferowane ponieważ istnieje dodatkowo możliwość wpływu na webservices.
Integracja JRules po stronie jPALIO wygląda następująco:
@WebServiceClient(name = "SncmWSRunnerImplService", targetNamespace = "http://SncmRuleApp/",
wsdlLocation = "http://192.168.1.210:8080/jaxws-SncmRuleApp/SncmWS?wsdl")
public class SncmWSRunnerImplService {....}
static {
URL url = null;
try {
url = new URL("http://192.168.1.210:8080/jaxws-SncmRuleApp/SncmWS?wsdl");
} catch (MalformedURLException e) {
e.printStackTrace();
}
SNCMWSRUNNERIMPLSERVICE_WSDL_LOCATION = url;
}
Wywołanie JRules w jDesignerze odbywa się przez wywołanie obiektu groovy. Przykładem takiego obiektu może być:
package application.jrules;
import java.util.LinkedList;
import java.util.List;
public class SncmWSRunnerClient {
public static Double getProvisionFromJRules(final String flow, final Event event) {
SncmWSRunner port = new SncmWSRunnerImplService().getSncmWSRunnerImplPort();
return port.sncmRules(event, flow);
}
public static Event createEvent(
final String entityCode, final double amount, final String eventDate,
final String eventTypeCode, final String organizationCode, final String productCode,
final List<String> parameterCodes, final List<String> parameterFieldType, final List<Object> parameterFieldValue) {
Event eventItem = new Event();
eventItem.setAmount(amount);
eventItem.setEntityCode(entityCode);
eventItem.setEventDate(eventDate);
eventItem.setEventTypeCode(eventTypeCode);
eventItem.setOrganizationCode(organizationCode);
eventItem.setProductCode(productCode);
List<Parameter> parameters = new LinkedList<Parameter>();
if ((parameterCodes.size() == parameterFieldType.size()) &&
(parameterCodes.size() == parameterFieldValue.size())) {
for (int i = 0; i < parameterCodes.size(); ++i) {
parameters.add(createParameter(parameterCodes.get(i), parameterFieldType.get(i), parameterFieldValue.get(i)));
}
} else {
System.out.println("\nWrong parameter initialization");
System.out.println("\n parameterCodessize= " + parameterCodes.size());
System.out.println("\n parameterFieldType size= " + parameterFieldType.size());
System.out.println("\n parameterFieldValue size= " + parameterFieldValue.size());
}
eventItem.setParameters(parameters);
return eventItem;
}
private static Parameter createParameter(final String codeValue, final String field, Object value) {
Parameter parameter = new Parameter();
parameter.setCode(codeValue);
if (field.equals("dateValue")) {
parameter.setDateValue((String) value);
} else if (field.equals("fractionalValue")) {
parameter.setFractionalValue((Double) value);
} else if (field.equals("numericValue")) {
parameter.setNumericValue((Double) value);
} else if (field.equals("textValue")) {
parameter.setTextValue((String) value);
} else {
return null;
}
return parameter;
}
public Object run(String methodName, Object... methodArguments) {
return this."$methodName"(*methodArguments)
}
public void run() {
}
}
W tym groovy obiekcie metoda "getProvisionFromJRules" wywołuje reguły w przepływie o nazwie zdefiniowanej w atrybucie flow z parametrami zdefiniowanymi w parametrze event. Natomiast metody "run" pozwalają z poziomu jPALIO wywoływać groovy metodę "getProvisionFromJRules". Przykładem takiego wywołania z inicjacją parametrów może być:
$=(@parameterCodes, $util.emptyList())
$=(@parameterFieldType, $util.emptyList())
$=(@parameterFieldValue, $util.emptyList())
$util.add($@parameterCodes, "code1")
$util.add($@parameterFieldType, "dateValue")
$util.add($@parameterFieldValue, "2010-01-01 00:00:00")
$util.add($@parameterCodes, "code2")
$util.add($@parameterFieldType, "fractionalValue")
$util.add($@parameterFieldValue, 2.2)
$util.add($@parameterCodes, "code3")
$util.add($@parameterFieldType, "numericValue")
$util.add($@parameterFieldValue, 2)
$util.add($@parameterCodes, "code4")
$util.add($@parameterFieldType, "textValue")
$util.add($@parameterFieldValue, "Parameter->text value")
$try({
$=(@commission, $toBigDecimal(
$toString($*application.jrules.SncmWSRunnerClient("getProvisionFromJRules", "multipliedFlow",
$*application.jrules.SncmWSRunnerClient("createEvent", "EntityCode", 100.0,
"2010-01-01", "EventTypeCode", "OrganizationCode", "ProductCode",
$@parameterCodes, $@parameterFieldType, $@parameterFieldValue)
))
))
$@commission
}, {
$error.stackTrace()
})