Chapter 9. Service Implementations

9.1. Bean

9.1.1. Bean Service Component

The Bean Component is a pluggable container in SwitchYard which allows Java classes (or beans) to provide and consume services. This means that you can implement a service by simply annotating a Java class. It also means you can consume a service by injecting a reference to that service directly into your Java class.

9.1.2. Bean Services

Bean Services are standard CDI beans with a few extra annotations. This also opens up the possibilities of how SwitchYard is used; you can now expose existing CDI-based beans in your application as services to the outside world or consume services within your bean.

9.1.3. Create a Bean Service

Prerequisites

  • Name: the name of the Java class for your bean service.
  • Service Name: the name of the service your bean provides.
  • Interface: the contract for the service being provided. Java is the only valid interface type for bean services.

Procedure 9.1. Task

  1. Create a new Bean Service Class in the SwitchYard Editor JBoss Developer Studio plug-in.

    Note

    If you provide the interface value first, it automatically generates default names for Name and Service Name.
    New bean service class

    Figure 9.1. Creating a New Bean Service

    The example above shows ExampleBean as the name of the class and com.example.switchyard.docs.Example as the interface.
  2. Click Finish.
    Your new class looks like this:
    package com.example.switchyard.docs;
     
    import org.switchyard.component.bean.Service;
     
    @Service(Example.class)
    public class ExampleBean implements Example {
    }
    The @Service annotation allows the SwitchYard CDI Extension to discover your bean at runtime and register it as a service. The value of the annotation (Example.class in the above example) represents the service contract for the service. Every bean service must have an @Service annotation with a value identifying the service interface for the service.
  3. After creating a bean service, complete the service definition by adding one or more operations to the service interface and a corresponding implementation in your bean:
    package com.example.switchyard.docs;
     
    import org.switchyard.component.bean.Service;
     
    @Service(Example.class)
    public class ExampleBean implements Example {
     
       public void greet(Person person) {
           // implement service logic here for greet operation
       }
    }
    

9.1.4. Providing a Service

Procedure 9.2. Task

  • In order to provide a service with the Bean component, add an @Service annotation to your bean:
     @Service(SimpleService.class)
    public class SimpleServiceBean implements SimpleService {
       public String sayHello(String message) {
          System.out.println("*** Hello message received: " + message);
          return "Hi there!!";
       }  
    }
     
    public interface SimpleService {
       String sayHello(String message);
    }
    
    The SimpleService interface represents the Service Interface that defines the service operations exposed by SwitchYard.

9.1.5. @Service

The @Service annotation allows the SwitchYard CDI Extension to discover your bean at runtime and register it as a service. The value of the annotation (SimpleService.class in the above example) represents the service contract for the service. Every bean service must have an @Service annotation with a value identifying the service interface for the service.
The META-INF/beans.xml file in your deployed application tells the JBoss application server to look for beans in this application and to activate the CDI. The SwitchYardCDIServiceDiscovery CDI extension picks up the @Service beans and makes them available to the application deployer. The service can now be invoked from other services within SwitchYard or bound to a wire protocol through SwitchYard gateways.

9.1.6. Consuming a Service

Procedure 9.3. Task

  • In order to consume a SwitchYard service from within a CDI bean, add a @Reference annotation to your bean:
    @Service(ConsumerService.class)
    public class ConsumerServiceBean implements ConsumerService {
     
      @Inject
      @Reference
       private SimpleService service;
     
       public void consumeSomeService() {
          service.sayHello("Hello");
       }  
    }
     
    public interface ConsumerService {
     
       void consumeSomeService();
    }
    
    By default, SwitchYard expects a service reference to be declared with a name which matches the Java type used for the reference. In the above example, the SimpleService type expects a service reference called "SimpleService" in your SwitchYard configuration. However, the @Reference annotation also accepts a service name if the service reference name does not match the Java type name of the contract. For example:
    @Reference("urn:myservices:purchasing:OrderService")
    private OrderService orders;

9.1.7. @Reference

The @Reference annotation enables CDI beans to consume other services. The reference can point to services provided in the same application by other implementations, or to a service that is hosted outside of SwitchYard and exposed over JMS, SOAP, or FTP. The JBoss application server routes the invocations made through this reference through the SwitchYard exchange mechanism.

9.1.8. ReferenceInvoker

Although the @Reference annotation injects a reference using the Java interface of the reference contract, it does not allow you to use SwitchYard API constructs like the Message and Context interfaces.
When invoking a reference from a Bean service, the ReferenceInvoker enables you to access an attachment or a context property.
To use a ReferenceInvoker, replace the service contract interface type with a ReferenceInvoker type. It allows SwitchYard to inject the correct instance automatically.

Note

Red Hat recommends you create a new instance of ReferenceInvocation each time you want to invoke a service using ReferenceInvoker.
For example, here is an instance which uses a ReferenceInvoker to invoke SimpleService.
@Inject 
@Reference("SimpleService")
private ReferenceInvoker service;
 
public void consumeSomeService(String consumerName) {
   service.newInvocation("sayHello")
      .setProperty("myHeader", "myValue")
      .invoke(consumerName);
}

9.1.9. Invocation Properties

While it is a best practice to write your service logic to the data that is defined in the contract (the input and output message types), there can be situations where you need to access contextual information like message headers such as received file name in your implementation. To facilitate this, the Bean component allows you to access the SwitchYard Exchange Context instance associated with a given Bean Service Operation invocation.
Invocation properties represent the contextual information (like message headers) in your bean implementation.

9.1.10. Accessing Invocation Properties

Procedure 9.4. Task

  • To enable access to the invocation properties, add a Context property to your bean and annotate it with the CDI @Inject annotation:
    package com.example.switchyard.docs;
    
    import javax.inject.Inject;
    
    import org.switchyard.Context;
    import org.switchyard.component.bean.Service;
    @Service(SimpleService.class)
    public class SimpleServiceBean implements SimpleService {
     
    @Inject
    private Context context;
     
    public String sayHello(String message) {
            System.out.println("*** Funky Context Property Value: " + context.getPropertyValue("funkyContextProperty"));
            return "Hi there!!";
        }
    }
    
    Here, the Context interface allows your bean logic to get and set properties in the context.

    Note

    You can invoke the Context instance only within the scope of one of the Service Operation methods. If you invoke it outside this scope, it results in an UnsupportedOperationException error.

9.1.11. @Inject

The @Inject annotation lets you define an injection point that is injected during bean instantiation. Once your beans are registered as Services, they can be injected as CDI beans using @Inject annotation.

9.1.12. Implementation Properties

Implementation properties represent environmental properties that are defined in the SwitchYard application descriptor (switchyard.xml) for your bean implementation.

9.1.13. Accessing Implementation Properties

Implementation properties represent environmental properties that you have defined in the SwitchYard application descriptor (switchyard.xml) for your bean implementation. Implementation properties in SwitchYard are the properties that you can configure on a specific service implementation. That is, you can make the property value available to service logic executing inside an implementation container. Here is an example:
<sca:component name="SimpleServiceBean">
      <bean:implementation.bean class="com.example.switchyard.switchyard_example.SimpleServiceBean"/>
      <sca:service name="SimpleService">
        <sca:interface.java interface="com.example.switchyard.switchyard_example.SimpleService">
        	<properties>
        		<property name="userName" value="${user.name}"/>
        	</properties>
        </sca:interface.java>
      </sca:service>
    </sca:component>

Procedure 9.5. Task

  • To access the Implementation Properties, add an @Property annotation to your bean class identifying the property you want to inject:
    package com.example.switchyard.docs;
    
    import org.switchyard.component.bean.Property;
    import org.switchyard.component.bean.Service;
    
    @Service(SimpleService.class)
    public class SimpleServiceBean implements SimpleService {
    
    	@Property(name="userName")
    	private String name;
    	
    	@Override
    	public String sayHello(String message) {
            return "Hello " + name + ", I got a message: " + message;
        }
    
    }
    
    Here, the @Property annotation is used for injecting the user.name property.

9.1.14. @Property

The @Property annotation enables you to identify the implementation property that you want to inject in a bean.

9.2. BPM

9.2.1. BPM Component

SwitchYard implements the Business Process Management (BPM) functionality through the BPM Component. The BPM Component is a pluggable container in SwitchYard that allows you to expose a business process as a service. Using the BPM component, you can start a process, signal a process event, or abort a process.

9.2.2. Create a BPM Service

Prerequisites

  • File Name: The file name of the new BPMN 2 Process definition.
  • Interface Type: The contract for the service provided by your bean. BPM supports Java and WSDL contract types.
  • Service Name: The name of the service provided by your bean.

Procedure 9.6. Task

  1. Create a new BPMN file in the SwitchYard Editor JBoss Developer Studio plug-in.
  2. Input the values into the SwitchYard Editor's New SwitchYard BPMN File Screen.
    New SwitchYard BPMN File Screen

    Figure 9.2. New SwitchYard BPMN File Screen

  3. Click Finish.
    This creates a new service component definition for your process service and an empty BPMN process definition.
  4. After creating a new BPM Service, create the BPMN 2 process definition and configure the BPM service component to interact with that process definition.

9.2.3. Process Interaction

You define interaction with a process by the actions you add to a BPM service component. Study this sample code which is for a service contract:
package org.switchyard.userguide;
public interface MyService {
    public void start(String data);
    public void signal(String data);
    public void stop(String data);
}
By using actions, you can map an operation in the service contract to one of the following interactions with a business process:
START_PROCESS
Operations configured with the START_PROCESS action type start new process instances.
When you start your process (actually, any interaction with a service whose implementation is bpm), the processInstanceId is put into the SwitchYard context at Scope.EXCHANGE and is fed back to your client in a binding-specific way. For SOAP, it is in the form of a SOAP header in the SOAP response envelope:
<soap:Header>
    <bpm:processInstanceId xmlns:bpm="urn:switchyard-component-bpm:bpm:1.0">1</bpm:processInstanceId>
</soap:Header>
			
In future process interactions, you need to send back that same processInstanceId, so that the correlation is done properly. For SOAP, that means including the same SOAP header that was returned in the response to be sent back with subsequent requests.

Important

If you are using persistence, the sessionId is also available in the Context, and must be fed back as well. It looks the same as the processInstanceId in the SOAP header.
SIGNAL_EVENT
Operations configured with the SIGNAL_EVENT action type have to signal the associated process instance. The processInstanceId must be available in the Context so the correct process instance is correlated.
There are two other pieces of information that are needed when signaling an event:
  • The "id". In BPMN2 lexicon, this is known as the "signal id", but in jBPM can also be known as the "event type". This is set as the id of the annotation.

    Note

    In BPMN2, a signal looks like this:
    <signal id="foo" value="bar"/> 
    			 
    In jBPM, it is the signal id that is respected, not the name. This might require you to tweak a tooling-generated id if you want to customize its name.
  • The "event object". This is the data representing the event itself. There are two ways to pass in the event object:
    1. The first way is through a Context object. The way in which this is passed is similar to the processInstanceId, and it is known as "signalEvent". If you use this, you are limited to a String type.
    2. The second way is through the Message content object itself (that is, your payload). If the signalEvent Context property is absent, the content of the Message is used as the event object.
ABORT_PROCESS_INSTANCE
If an operation is configured with the ABORT_PROCESS_INSTANCE action type, associated process instances are aborted. Note that the processInstanceId must be available in the Context so the correct process instance is correlated.

9.2.4. Use Process Variables

Prerequisites

  • JBoss Developer Studio jBPM Plug-In

Procedure 9.7. Use Process Variables

  1. Click on the white space around a process or on any of your process nodes.
  2. Access the Properties view.
  3. Declare the variablenames at the process level and in the Parameter Mapping (and possibly Result Mapping).

9.2.5. Mappings

Mappings are the way to move data in or out of the action for that operation. You can specify as many mappings as you like for an action, and they get grouped as globals, inputs or outputs:
Mapping variables from your SwitchYard Exchange, Context or Message into jBPM process variables can be done with expressions. Each action for a process service has a distinct set of variable mappings.
  • Global mappings are used to provide data that is applicable to the entire action, and is often used in classic in/out param (or data-holder/provider) fashion. An example of a global mapping is a global variable specified within a Drools Rule Language (DRL) file.
  • Input mappings are used to provide data that represents parameters being fed into an action. An example of an input mapping for BPM is a process variable used while starting a business process. For Rules, it could be a fact to insert into a rules engine session.
  • Output mappings are used to return data from an action. An example of an output mapping is a BPM process variable that you want to set as the outgoing (response) message’s content.

Note

The onlyexpressionType supported currently is MVEL, so you do not have to specify it. The expression itself can be any MVEL expression

9.2.6. expressionType Properties

These variables are available by default:
exchange
The current org.switchyard.Exchange.
context
The current org.switchyard.Context.
message
The current org.switchyard.Message.
Whatever the resultant value of the expression is constitutes the data that is made available to the action.
expression="message.content"
This is the same as message.getContent().
expression="context[‘foo’]" scope="IN"
This is the same as context.getProperty("foo", Scope.IN).getValue() in a null-safe manner.

Note

Specifying the scope attribute only matters if you use the context variable inside your expression. If you don’t specify a scope, the default Context access (which is done like a Map, if you picked up on that), is done with Scope.EXCHANGE for global mappings, Scope.IN for input mappings, and Scope.OUT for output mappings.
Specifying the variable attribute is often optional, but this depends on the usage. For example, if you are specifying a global variable for a rule, or a process variable to put into (or get out of) a BPM process, then it is required. However, if the result of the expression is to be used as facts for rule session insertion, then specifying a variable name is not applicable.
Here is some XML sample code:
	<mapping expression="theExpression" expressionType="MVEL" scope="IN" variable="theVariable"/>
	

9.2.7. Consuming a Service

There are two ways of consuming Services with the SwitchYard BPM component:
  1. By invoking the BPM implementation through a gateway binding. Since the BPM component exposes a Java interface fronting the business process, you can use any of the bindings provided by SwitchYard. (You could, for example, use either a SOAP Binding or a Camel Binding.)
  2. By invoking other SwitchYard Services from inside a BPM process itself. To do this, you can use the SwitchYardServiceWorkItemHandler, which is provided out-of-the-box. (To make authoring BPMN2 processes easier, SwitchYard provides a widget for the Eclipse BPMN2 Modeler visual editor palette.)

9.2.8. SwitchYard Service Task Properties

You can use the following properties to configure the SwitchYard Service task.
Service Naming Properties:
ServiceName
This is the name of the SwitchYard service to invoke. It is a mandatory property
ServiceOperationName
This is the name of the operation within the SwitchYard service to invoke. It is an optional property. (The default behavior is to use the single method name in the service interface, if there is just one.)
Content I/O Properties:
ContentInputName
This is the process variable into which the message content is placed. It is an optional property. The default value is contentInput.
ContentOutputName
The process variable from which the message content is obtained. It is an optional property. The default value is contentOutput.
Fault-Handling Properties:
FaultResultName
This is the name of the output parameter (in other words, the result variable) under which the exception is stored. It is optional.
FaultSignalId
This is the bpmn signal id (or event type) that is used to signal an event in the same process instance. The event object is the exception. This is an optional property.
FaultWorkItemAction
This property determines what happens after a fault occurs. If it is set to null, nothing is done. If set to complete, the current work item (that is, the SwitchYard service task) is completed. If it is set to abort, the current work item is aborted. (The default setting is null.) This property is optional.

9.2.9. SwitchYard Service Fault Handling

The SwitchYardServiceWorkItemHandler class is used for fault handling in the Switchyard Service tasks during process execution. It executes service references according to the SwitchYard's fault-handling properties that you have configured. The SwitchYard's fault-handling properties define the behavior of the SwitchYardServiceWorkItemHandler class when a fault is encountered during the execution of the service reference.
You can use the SwitchYardServiceWorkItemHandler class for fault handling in the following scenarios:
  • If you want to have a split gateway in your process flow, to inspect a process variable for any occurrence of a fault. To achieve this, you need to set the following fault-handling properties in your SwitchYard Service task:
    • FaultResultName: Specifying the FaultResultName property enables the SwitchYardServiceWorkItemHandler class to make the fault available as an output parameter of the task. You can then associate it with a process variable, and inspect for existence in your split gateway.
    • FaultWorkItemAction: Specifying the FaultWorkItemAction property to complete enables the process to continue on to your split gateway.
  • If you want to have a single shared path of fault-handling in your process flow. To achieve this, you need to set the following fault-handling properties in your SwitchYard Service task:
    • FaultSignalId: Specifying the FaultSignalId property same as the Signal ID you specified in your bpmn2 process definition, enables you to add an event node in your process that is triggered with this signal id. The flow starting from this event node is your fault handling path. The SwitchYardServiceWorkItemHandler class then signals the proper event with the configured ID.

9.2.10. Using The Standard BPMN2 Service Task

You can invoke SwitchYard Services using the standard BPMN2 Service Task. You can use the Service Task icon from the BPMN2 Editor palette and configure its properties. To configure the Service Task, keep in mind the following points:
  • The <serviceTask> attribute invokes SwitchYard when it has an implementation="##SwitchYard" attribute.
  • The ServiceName is derived from the BPMN2 interfaceImplementationRef.
  • The ServiceOperationName is derived from the BPMN2 operationImplementationRef.
  • The ContentInputName is always called Parameter.
  • The ContentOutputName is always called Result.

9.2.11. Resources

A resource represents an artifact that your BPM process uses at runtime. A resource can be a properties file or a Drools Rule Language file. You can configure the list of resources available to your process in the BPM service component.

9.2.12. WorkItemHandler Interface

A work item handler is responsible for executing work items of a specific type. They represent the glue code between an abstract, high-level work item that is used inside the process and the implementation of this work item. You can add your own code into the business process using the WorkItemHandler. To do so, implement the org.kie.runtime.process.WorkItemHandler interface and add a handler definition to your BPM service component.

9.3. BPEL

9.3.1. BPEL Component

The BPEL Component is a pluggable container in SwitchYard that allows you to expose a WS-BPEL business process as a service through an interface defined using WSDL.

9.3.2. Providing a Service with the BPEL Component

Procedure 9.8. 

  1. Define your process using WS-BPEL within JBoss Developer Studio (with JBoss Integration and SOA Development tooling installed).
  2. Define a WSDL interface for the BPEL service.
  3. Define a Deployment Descriptor using the ODE Deployment Descriptor editor bundled with JBoss Tools.
  4. Add the component containing the implementation and service interface to the SwitchYard configuration.

9.3.3. Example of BPEL Component Configuration

Here is an example of the component section of the SwitchYard configuration:
 <sca:component name="SayHelloService">
   	 <bpel:implementation.bpel process="sh:SayHello"/>
   	 <sca:service name="SayHelloService">
   	   <sca:interface.wsdl interface="SayHelloArtifacts.wsdl#wsdl.porttype(SayHello)"/>
   	 </sca:service>
  </sca:component>
The BPEL component contains a single implementation.bpel element that identifies the fully qualified name of the BPEL process. This component may also contain one or more service elements defining the WSDL port types through which the BPEL process can be accessed.
In the packaged Switchyard application, ensure that the BPEL process associated with this fully qualified name must be present within the root folder of the distribution, along with the deployment descriptor (deploy.xml). Here is an example of the deployment descriptor for the BPEL process referenced above:
	<deploy xmlns="http://www.apache.org/ode/schemas/dd/2007/03"
	 xmlns:examples="http://www.jboss.org/bpel/examples">

	<process name="examples:SayHello">
	 <active>true</active>
 	 <retired>false</retired>
	  <process-events generate="all"/>
  	  <provide partnerLink="client">
	  	<service name="examples:SayHelloService" port="SayHelloPort"/>
	  </provide>
	</process>
	</deploy>

9.3.4. Consuming a Service from a BPEL Process

To enable a BPEL process to invoke other services, you need to define the WSDL interface representing the service to be consumed, using an invoke element within the deployment descriptor. For example, in the deploy.xml file:
  <process name="ls:loanApprovalProcess">
  	<active>true</active>
  	<process-events generate="all"/>
  	<provide partnerLink="customer">
  	  <service name="ls:loanService" port="loanService_Port"/> 
  	</provide> 
  	<invoke partnerLink="assessor" usePeer2Peer="false"> 
  	  <service name="ra:riskAssessor" port="riskAssessor_Port"/> 
  	</invoke> 
  </process>
Here, the usePeer2Peer property informs the BPEL engine not to use internal communications for sending messages between BPEL processes that may be executing within the same engine, and instead pass messages through the SwitchYard infrastructure.
For each consumed service, you can then create a reference element within the SwitchYard configuration to locate the WSDL file and identify the port type associated with the required WSDL service or port, as shown in the switchyard.xml file below:
  <sca:component name="loanService">
  	<bpel:implementation.bpel process="ls:loanApprovalProcess" />
  	<sca:service name="loanService">
  	  <sca:interface.wsdl interface="loanServicePT.wsdl#wsdl.porttype(loanServicePT)"/> 
  	</sca:service> 
  	<sca:reference name="riskAssessor"> 
  	  <sca:interface.wsdl interface="riskAssessmentPT.wsdl#wsdl.porttype(riskAssessmentPT)"/> 
  	</sca:reference> 
  </sca:component>

9.3.5. Property Injection into a BPEL Process

You can inject properties into your BPEL process definition by using the SwitchYardPropertyFunction.resolveProperty() XPath custom function. The bpel:copy section copies Greeting property value into the ReplySayHelloVar variable in example shown below:
  <bpel:copy>	
    <bpel:from xmlns:property="java:org.switchyard.component.bpel.riftsaw.SwitchYardPropertyFunction"
      expressionLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath2.0">
       <![CDATA[concat(property:resolveProperty('Greeting'), $ReceiveSayHelloVar.parameters/tns:input)]]>
    </bpel:from>
    <bpel:to part="parameters" variable="ReplySayHelloVar">
      <bpel:query queryLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0"><![CDATA[tns:result]]></bpel:query>
    </bpel:to>
  </bpel:copy>  

9.3.6. Maintaining Multiple Versions of a BPEL Process

You can use the BPEL processes to implement long lasting stateful business processes. However the BPEL process may need to change, over the course of its lifetime, to accommodate new requirements. This introduces the problem of how to deal with the existing active instances of the BPEL process that may not complete for weeks, months or even years. To deal with multiple version of a BPEL process and to enable new requirements to be introduced (while still preserving the original process definitions associated with existing active process instances), you can associate a version number with the BPEL process by adding it as a suffix to the BPEL file name.
For example, if your BPEL process is located in the HelloWorld.bpel file, then you can simply add a hyphen followed by the version number, such as HelloWorld-32.bpel. This indicates that this is the thirty second version of this BPEL process. Whenever you define a new version of the BPEL process, package it in the SwitchYard application along side the previous versions of the BPEL process. It is important that the older version of the BPEL process remain in the SwitchYard application until there are no longer any active process instances associated with that version. You need to then re-deploy the SwitchYard application, without undeploying the previous version. If you undeploy the previous version of the SwitchYard application, the BPEL engine deletes all outstanding active instances associated with the deleted process definitions.
You can version the BPEL process but not the WSDL interfaces. So you must ensure that any changes made to the WSDL interfaces are backward compatible, so that both the new and older versions of the BPEL (that still have active process instances) are not affected by the changes.

9.3.7. Structure of a SwitchYard BPEL Application

For SwitchYard BPEL applications, the artifacts within the src/main/resources folder are structured differently. The switchyard.xml configuration file is located in the META-INF folder. However, the BPEL deployment descriptor (deploy.xml), and the BPEL process definition are located in the root folder. You can locate the WSDL interface definitions, and any accompanying XSD schemas in the sub-folders. You must ensure that the BPEL process and SwitchYard BPEL component configuration define the correct relative path for the artifacts.
Here is an example that shows the structure of the say_hello SwitchYard BPEL quickstart:
say_hello
	src/main/java
	src/main/resources
  	   META-INF
	      switchyard.xml
	   deploy.xml
	   SayHello.bpel
	   SayHelloArtifacts.wsdl
	JRE System Library [JavaSE-1.6]
	src
	pom.xml

9.4. Camel

9.4.1. Camel Services

Camel services allow you to leverage the core routing engine of Apache Camel to route between services in SwitchYard. Camel endpoints function as protocol adapters, exposing services hosted in SwitchYard to the outside world and allowing external services to be invoked from within SwitchYard. You can define the Camel routes using Java DSL or XML and deploy them within SwitchYard to handle pipeline orchestration between SwitchYard services.

9.4.2. Create a Camel Service

Prerequisites

  • Name: the name of the Java class or XML file for your bean service.
  • Service Name: the name of the service your bean provides.
  • Interface: the contract for the service being provided. Camel supports Java and WSDL contract types.

Procedure 9.9. Create a Camel Service

  1. Create a new Camel Route file resource in the SwitchYard Editor JBoss Developer Studio plug-in.
  2. Decide whether to use DSL or XML dialect for the route. (Functionally, they are more or less equivalent, the choice is determined by how you want to express your routing logic.)
  3. If you want create a Java DSL route, select the "Camel (Java)" implementation type. For XML, use the "Camel (XML)" type.
  4. Input the values into the SwitchYard Editor's New Route File Screen.
  5. Click Finish.

9.4.3. Guidelines of Camel Route

These are some general guidelines to keep in mind when creating either type of route:
  • There is only one route per service.
  • The consumer or "from" endpoint in a route is always a "switchyard" endpoint and the endpoint name must equal the service name. This is default behavior in the tooling.
  • To consume other services from within your route, only use "switchyard" consumer (in other words "to") endpoints. This keeps your routing logic independent of the binding details for consumed services.

9.4.4. Java DSL Route

You can define Camel routes using the Java Domain Specific Language (DSL). To implement the Java DSL, extend the RouteBuilder class. As there can be only one route per service, you can have only one RouteBuilder class for each Camel routing service in your application. You can then add logic to your routing service in the configure() method as shown below:
package com.example.switchyard.docs;
 
import org.apache.camel.builder.RouteBuilder;
 
public class CamelServiceRoute extends RouteBuilder {
    /**
     * The Camel route is configured through this method.  The from:
     * endpoint is required to be a SwitchYard service.
     */
    public void configure() {
        // TODO Auto-generated method stub
        from("switchyard://Example").log(
                "Received message for 'Example' : ${body}");
    }
}

9.4.5. XML Route

You can define Camel routes using XML. To define Camel routes in XML files, use the <route> tag with the namespace "http://camel.apache.org/schema/spring" as shown below:
  <?xml version="1.0" encoding="ASCII"?>
  <route xmlns="http://camel.apache.org/schema/spring">
   <from uri="switchyard://Example"/>
   <log message="Example - message received: ${body}"/>
  </route>
You can have only one file containing a route definition for each XML routing service in your application.

9.4.6. Consuming Services From Camel Routes

You can invoke another service from your Camel route by using the SwitchYard producer endpoint (switchyard://) within your route as shown below:
switchyard://[service-name]?operationName=[operation-name]
Here,
  • service-name: Name of the SwitchYard service. This value should match the name of a service reference defined on the service component for the route.
  • operation-name: Name of the service operation you want to invoke. This is only used on references and is optional if the target service only has a single operation.
The example below illustrates the default XML route modified to invoke a SwitchYard service:
  <?xml version="1.0" encoding="ASCII"?>
    <route xmlns="http://camel.apache.org/schema/spring">
  	 <from uri="switchyard://Example"/>
  	 <log message="Example - message received: ${body}"/>
  	      <!-- Invoke hasItem operation on WarehouseService -->
  	 <to uri="switchyard://WarehouseService?operationName=hasItem"/>
    </route>

9.4.7. Using Scripting Languages

Camel supports dynamic scripting languages inside the XML and Java DSL route logic. You can use the scripting languages in the following ways:
  1. You can use them to create a predicate in a message filter as shown below:
    public class ScriptingBuilder extends RouteBuilder
    {
    public void configure()
    {
    from("switchyard://Inbound").filter().javaScript("request.getHeader('myHeader') != null").to("switchyard://Outbound");
    }
    }
  2. You can use them to implement your service using transform element as shown below:
    
    public class ScriptingImplementationBuilder extends RouteBuilder {
    public void configure()
    {
    from("switchyard://Inbound").transform().groovy("classpath:script.groovy"); 
    // classpath resource
    from("switchyard://InboundBsh").transform().language("beanshell", "file:script.bsh");
    // file system resource
    }
    }
    
Additionally, you can generate responses by using predefined variables like request, response, or exchange inside your script.

9.4.8. Supported Scripting Languages

SwitchYard supports the following scripting languages inside the XML and Java DSL route logic:
  • BeanShell
  • JavaScript
  • Groovy
  • Ruby
  • Python

9.4.9. Using CDI Beans in Camel Routes

The Camel component provides a convenient and powerful mechanism for routing between SwitchYard services using Java DSL or XML routing definitions. When creating these routes, you may need to add logic to the service pipeline that is specific to the Camel route. Instead of implementing your logic as a service, you can add a CDI bean to your application and call that as a bean from within your Camel route. SwitchYard integrates the CDI Bean Manager with the Camel Bean Registry to allow you to reference CDI Beans in your Camel routes. For example, you can use the following CDI bean inside your SwitchYard Camel Routes:
@Named("StringSupport")
@ApplicationScoped
public class StringUtil 
 {
     public String trim(String string)
     {
      return string.trim();
     }
 }
The SwitchYard Camel Route logic implemented with this CDI bean looks like this:
 public class ExampleBuilder extends RouteBuilder
 {
     public void configure()
     {
        from("switchyard://ExampleBuilder")
            .split(body(String.class).tokenize("\n"))
            .filter(body(String.class).startsWith("sally:"))
            .to("bean:StringSupport");
     }
 }
Any Java class annotated with @Named annotation in your application is available through Camel's Bean registry.

9.4.10. Injecting Implementation Properties in Camel Routes

SwitchYard integrates with the Properties Component in Camel to make system and application properties available inside your route definitions. You can inject properties into your camel route using {{propertyName}} expression, where propertyName is the name of the property.
For example, the following camel route expects the user.name property to be injected in the last <Log> statement:
  <route xmlns="http://camel.apache.org/schema/spring" id="CamelTestRoute">
    <log message="ItemId [${body}]"/>
    <to uri="switchyard://WarehouseService?operationName=hasItem"/>
    <log message="Title Name [${body}]"/>
    <log message="Properties [{{user.name}}]"/>
  </route>

9.5. Rules

9.5.1. Rules Component

The Rules component is a pluggable container in SwitchYard which allows you to expose business rules as a service. You can add a custom interface to your rules and annotate its methods to define which methods should execute the rules. The Rules component supports Drools as the rule engine.

9.5.2. Create a Rules Service

Prerequisites

  • File Name: the name of the file that is used to create a new template rules definition.
  • Service Name: the name of the service that your rules provide.
  • Interface Type: the contract for the service being provided. Rules services support Java and WSDL contract types.
  • Package Name: package name used for the new Rules file.

Procedure 9.10. Create a Rules Service

  1. Create a new SwitchYard Rules file in the SwitchYard Editor JBoss Developer Studio plug-in.
  2. The MyService interface can be as simple as this, with no SwitchYard-specific imports:
    package com.example.switchyard.docs;
    public interface Example {
        public void process(MyData data);
      }
    
  3. The generated rule template looks like this:
    package com.example.switchyard.docs
    import org.switchyard.Message
    global Message message
     
    rule "RulesExample"
        when
            // insert conditional here
        then
            // insert consequence here
            System.out.println("service: ExampleService, payload: " + message.getContent());
    end
    
  4. Input the values into the SwitchYard Editor's SwitchYard Rules File screen.
  5. Click Finish.

9.5.3. Stateless and Stateful Rules Executions

Introduction

By default, service method invocation creates a new Drools knowledge session, execute it given the passed-in domain data and then be disposed cleanly.

However, it is possible to configure SwitchYard so that a stateful knowledge session is used. To do this, you use the FIRE_ALL_RULES action type instead of EXECUTE.
There is also a capability which allows you to insert facts into a stateful knowledge session without firing the rules. In this case, use the INSERT action type.

9.5.4. Stateless Knowledge Session

Stateless session that does not utilize inference is the simplest use case for JBoss Rules. A stateless session can be called like a function. It can be passed some data and then receive some results back.
Here are some common use cases for stateless sessions:
Validation
Is this person eligible for a mortgage?
Calculation
Compute a mortgage premium.
Routing and Filtering
Filter incoming messages, such as emails, into folders.
Send incoming messages to a destination.

9.5.5. Stateful Knowledge Session

A stateful knowledge session is one which persists in memory, allowing it to span multiple invocations. They can change iteratively over time. In contrast to a Stateless Session, the dispose() method must be called afterwards to ensure there are no memory leaks, as the Knowledge Base contains references to Stateful Knowledge Sessions when they are created. StatefulKnowledgeSession also supports the BatchExecutor interface, like StatelessKnowledgeSession, the only difference being that the FireAllRules command is not automatically called at the end for a Stateful Session.
Here are some common use cases for Stateful Sessions:
Monitoring
Stock market monitoring and analysis for semi-automatic buying.
Diagnostics
Fault finding and medical diagnostics
Logistics
Parcel tracking and delivery provisioning
Compliance
Validation of legality for market trades.

9.5.6. Mapping Global Variables

You can map variables from your SwitchYard Exchange, Context or Message into JBoss Rules globals with MVEL expressions.
  1. To map the variables, hover the mouse over the Rules component in switchyard.xml and click Properties icon.
    Properties dialog for Rules Component

    Figure 9.3. Properties dialog for Rules Component

  2. In the Properties dialog, click Implementation. From the right hand side panel, click Operations tab to view Operation Mapping tooling window.
    Operations Mapping

    Figure 9.4. Operations Mapping

9.5.7. Map Global Variables

  1. Configure the rules implementation.

    Note

    Your expression can use the variables exchange (org.switchyard.Exchange), context (org.switchyard.Context) or message (org.switchyard.Message).
    Context can be accessed in the expression as a java.util.Map. When accessing it as such, the default properties Scope is IN. This can be overridden using the contextScope attribute by changing it to OUT or EXCHANGE
  2. Use these global variables in your JBoss Rules Drools Rule Language file:
    package example
     
    global java.lang.String service
    global java.lang.String messageId
    global com.example.Payload payload
     
    rule "Example"
        when
            ...
        then
            ...
            System.out.println("service: " + service + ", messageId: " + messageId + ", payload: " + payload);
    end
    

    Note

    In a more realistic scenario, the payload would be accessed in rule firing because it was inserted into the session directly by the RulesExchangeHandler, and thus evaluated (rather than being accessed as a global).

9.5.8. Mapping Facts

The object which is inserted into the rules engine as a fact by default is the SwitchYard message's content. However, you can override this by specifying your own fact mappings.

9.5.9. Notes About Mapping Facts

  • If you specify your own fact mappings, the SwitchYard message's content is not inserted as a fact. You can add a fact mapping with an expression of "message.content" if you want to still include it.
  • There is no point in specifying the "variable" attribute of the mappings (as done for global mappings), as the result of each expression is inserted as a nameless fact.
    For stateless execution, the full list of facts is passed to the StatelessKnowledgeSessions' execute(Iterable) method.
    For stateful execution, each fact is individually inserted into the StatefulKnowledgeSession.
  • If the result of the mapping expression implements Iterable (for example, a Collection), then the result is iterated over, and each iteration is inserted as a separate fact, rather than the parent Iterable itself being inserted. This is not recursive behavior (because it is only done once).

9.5.10. Auditing a Service

SwitchYard supports basic audit mechanism to audit the Drools rules execution. For auditing a service, SwitchYard requires a CDI environment to run. You can write custom auditors for your service and use listeners to monitor them. For example, you can use listeners to audit a BPM process and save the audit details into a database while the process progresses. The listener then reports the audit details at a later time.

9.5.11. Consuming a Service from the Rules Component

Consuming a SwitchYard Service from within the Rules Component leverages the Channels capability. You can configure channels within your process that executes business rules.

9.6. Knowledge Services

9.6.1. Knowledge Services

Knowledge Services are SwitchYard services that leverage Knowledge, Innovation and Enterprise (KIE) and provide knowledge based content as outputs. The Knowledge Services leverage Drools and jBPM. Drools and jBPM are tightly integrated under KIE, and hence both SwitchYard's BPM component and Rules component share most of their runtime configuration.

9.6.2. Actions

When you invoke a SwitchYard operation, it results in the execution of the corresponding Action. Actions are how Knowledge Services know how to map service operation invocations to their appropriate runtime counterparts. For example, when you invoke a method myOperation, it may result in execution of actions like execute some business rules or start a business process. Here is an example of Actions attribute illustrating myOperation method and an action of type ACTION_TYPE:
<actions>
 <action id="myId" operation="myOperation" type="ACTION_TYPE">
  <globals>
   <mapping/>
  </globals>
  <inputs>
   <mapping/>
  </inputs>
  <outputs>
   <mapping/>
  </outputs>
 </action>
</actions>
Here, the placeholder ACTION_TYPE can hold values for the actual ActionTypes specific to the BPM or Rules components.

9.6.3. Mappings

You can use Mappings to move data in or out of the action for an operation. You can specify as many mappings as you like for an action. The mappings are categorized as global, input, and output mappings:
  • Global Mappings: Use the global mappings to provide data that is applicable to the entire action. You can use them in an in/out parameter or a data-holder/provider structure. An example of a global mapping is a global variable specified within a Drools Rule Language (DRL) file.
  • Input Mappings: Use the input mappings to provide data that represents parameters provided to an action. An example of an input mapping for BPM is a process variable used while starting a business process. An example of an input mapping for Rules is a fact to insert into a rules engine session.
  • Output Mappings: Use the output mappings to return data out of an action. An example of an output mapping is a BPM process variable that you want to set as the outgoing (response) message’s content.

9.6.4. MVEL expressionType

The mappings support a default expressionType called MVEL. You can use following variables with MVEL:
  • exchange: The current org.switchyard.Exchange.
  • context: The current org.switchyard.Context.
  • message: The current org.switchyard.Message.
Here are some examples of the expressions using default variables:
expression="message.content" - This is the same as message.getContent().
expression="context[‘foo’]" scope="IN" - This is the same as context.getProperty("foo", Scope.IN).getValue(), in a null-safe manner.

Note

Specify the scope attribute only if you use the context variable inside your expression. If you do not specify a scope, the default Context access is done with Scope.EXCHANGE for global mappings, Scope.IN for input mappings, and Scope.OUT for output mappings.
It is important to specify a global variable for a rule, or a process variable to put into (or get out of) a BPM process. However, if you need to use the result of an expression as facts for rule session insertion, then you need not specify a variable name. Here is an XML example of how you can specify variable name:
 <mapping expression="theExpression" expressionType="MVEL" scope="IN" variable="theVariable"/>

9.6.5. Channels

Drools support the use of Channels that are the exit points in your Drools Rule Language (DRL) file. Channels must implement org.kie.runtime.Channel. Here is an example illustrating the use of channels in a method:

package com.example
rule "example rule"
    when
        $f : Foo ( bar > 10 )
    then
        channels["Bar"].send( $f.getBar() );
end
The following example illustrates use of channels in XML:

<channels>
    <channel class="com.example.BarChannel" name="Bar"/>
</channels>

9.6.6. SwitchYard Service Channel

SwitchYard provides an out-of-the-box channel called SwitchYard Service channel, which allows you to invoke (one-way) other SwitchYard services directly and easily from your DRL. Here is an example:

<channel name="HelloWorld" reference="HelloWorld" operation="greet"/>
Here,
  • class: The channel implementation class. Default value is SwitchYardServiceChannel.
  • name: The channel name.
  • reference: The service reference qualified name.
  • operation: The service reference operation name.
  • input: The service reference operation input name.

9.6.7. Listeners

You can use Listeners to monitor specific types of events that occur during Knowledge execution. For example, you can use listeners to audit a BPM process and save the audit details into a database while the process progresses. The listener then reports the audit details at a later time. Drools and jBPM provide many out-of-the-box listeners. If you write your own listener, ensure that it implements java.util.EventListener.
To register your listener, you must implement one of the KIE/Drools/jBPM Listener interfaces. For example:
  • org.drools.event.WorkingMemoryEventListener
  • org.drools.event.AgendaEventListener
  • org.kie.event.process.ProcessEventListener
Here is an example of listener implementation:

<listeners><listener class="org.drools.event.DebugProcessEventListener"/>
<listener class="org.kie.event.rule.DebugWorkingMemoryEventListener"/>
<listener class="com.example.MyListener"/>
</listeners>

9.6.8. Loggers

Loggers are special types of listeners, which you can use to output the events that occur during Knowledge execution. Support for loggers use a dedicated configuration element. You can log events to the console or a file. If events log are directed to a file, you can open those logs with the JBoss Developer Studio or JBoss Developer Studio Integration Stack. Here is an example of a logger implementation:
<loggers>
    <logger interval="2000" log="myLog" type="THREADED_FILE"/>
    <logger type="CONSOLE/>
</loggers>

9.7. Manifest

9.7.1. Manifest

The Manifest is where you specify from where the "intelligence" of the component is to come. For the BPM component, you need to specify, at the minimum, the location of the BPMN 2 process definition file. For the Rules component, you can specify the location of DRL, DSL, DSLR or XLS files.

9.7.2. Ways of Configuring the Manifest

Note

The following code examples assume there is a DRL file located on the classpath at com/example/MyRules.drl.
There are two ways to to configure the Manifest:
  • with a KIE Container. (This relies upon the existence of a META-INF/kmodule.xml configuration file.)
    Here is the sample META-INF/kmodule.xml file:
    <kmodule xmlns="http://jboss.org/kie/6.0.0/kmodule">
        <kbase name="com.example">
            <ksession name="my-session"/>
        </kbase>
    </kmodule>
    			
    Here is the sample XML file:
    <manifest>
        <container sessionName="my-session"/>
    </manifest>
    			
    In addition to the sessionName attribute, you can also specify baseName and releaseId, if you desire.
    To enable it to scan for updates, simply set scan="true" and, optionally,
     scanInterval=<# of milliseconds> 
  • with a manually defined list of resources.
    Here is the sample XML file:
    <manifest>
        <resources>
            <resource location="com/example/MyProcess.bpmn" type="BPMN2"/>
            <resource location="com/example/MyRules.drl" type="DRL"/>
        </resources>
    </manifest>
    			

Important

These two options are mutually exclusive: You have to choose one or the other.

9.8. Properties

9.8.1. Properties

Properties allow you to provide "hints" to the underlying KIE/Drools/jBPM runtime on how certain options are configured. Use them to avoid having to expose every single KIE/Drools/jBPM option as a configurable element or attribute within SwitchYard.

9.8.2. Add a Property

Procedure 9.11. Add a Property

  1. Launch the JBoss Developer Studio's SwitchYard Editor.
  2. Open a Type Hierarchy that has a root of org.kie.conf.Option.
  3. Here you can see the full list. Here is one example:
    <properties>
        <property name="drools.clockType" value="pseudo"/>
        <property name="drools.eventProcessingMode" value="stream"/>
    </properties>