Udostępnienie interfejsu JRules dla jPALIO

Aby udostępnić JRules dla JPalio przez webservices należy:

  1. zainstalować Eclipse IDE wraz pluginem Rule Studio
  2. stworzyć projekt typu XOM. Projekt ten będzie zawierał dane wymieniane poprzez webservices pomiędzy JPalio a JRules. Te same dane będą także podstawą werbalizacji w kolejnym projekcie typu "Rule project". Przykładowymi mapowaniami danych w tym projekcie mogą być:
    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;
    	}
    
    }
    oraz
    package 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;
       }
    
    }
  3. stworzyć projekt typu "rules" z zależnością do poprzednio zdefiniowanego projektu XOM. Projekt ten będzie zawierał projektowane reguły i przepływy. W tym projekcie należy zdefiniować werbalizację oraz parametry wejściowe / wyjściowe dla przyszłego interfejsu webservices. Przykładem tego może być:
  4. zwrócić uwagę na zdefiniowanie parametru flow typu string z kierunikem "IN". Parametr ten będzie wykorzystany do zarządzania, wyboru przepływu w środowisku jPALIO.
  5. przed rozpoczęciem definiowania nowych reguł i przepływów warto zapoznać się z dokumentacją oraz krótkimi filmami instruktażowymi np.:
    ILOG JRules : My First Business Rule
    ,
    Create a Business Object Model in IBM ILOG JRules,
    Create a Rule Project in IBM ILOG JRules,
    Write an Action Rule in IBM ILOG JRules,
    Create a Rule Flow in IBM ILOG JRules,
    Write a Scoring Rule With a Decision Table in IBM ILOG JRules.
  6. zdefiniować podstawowe reguły i przepływy lub ich szablony
  7. stworzyć projekt typu "RuleApp" z wcześniej zdefiniowanych reguł i przepływów. Projekt ten zawiera wykonywalne reguły które muszą być umieszczone na serwerze wykonawczym RES. Dlatego też projekt ten musi być połączony z projektem konfiguracją serwera. Projekt konfiguracji serwera RES tworzy się przez "File-> New -> Other -> Rule Studio -> Rule Execution Server Configuration Project". Po konfiguracji tych dwóch projektów możliwe jest umieszczenie na serwerze RES zaprojektowanych reguł za pomocą kliknięcia prawym przyciskiem myszy na projekcie typu "RuleApp" a następnie wybraniu opcji "RuleApp -> Deploy". Wynikowym widokiem w projekcie typu "Rules" powinnien być projekt podobny do:
  8. poprawne umieszczenie reguł na serwerze wykonawczym powinno być widoczne na stronie http://adres:8080/res w sposób podobny do:
  9. wystawić usługę webservices. W tym celu generuje jednocześnie się dwa projekty klienta oraz serwera za pomocą "File -> New -> Other -> Rule Stydio -> Client Project for RuleApps". W kolejnych oknach wybieramy "Rule Execution Server -> Web Service", nazwę projektu, projekt typu "RuleApp" oraz zaznaczamy opcję "Specify an alternative ruleflow task to start the execution of a ruleset(s)". Dzięki tej opcji będziemy mogli przekazanym parametrem "flow" wybierać przepływ dla przekazanych parametrów w wywołaniu JRules. W nowo wygenerowanym projekcie działającym po stronie serwera należy dopisać w klasie z nazwą o suffixie "RunnerImpl" linię:
    request.setTaskName(rulesetrequest.getFlow());

    cała metoda powinna być podobna do: 
    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ę.

    Kolejny krok integracji z jPALIO dotyczy klienta webservices. I jest on opisany w dalszym rozdziale.