Chapter 8. Service Implementations

8.1. Bean

8.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.
Note
In a SwitchYard Beans service implementation java:comp/BeanManager lookup via JNDI is not supported. You can use @InjectBeanManager, which is supported.

8.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.

8.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 8.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.

    Figure 8.1. Creating a New Bean Service

    New bean service class
    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
       }
    }
    
    

8.1.4. Providing a Service

Procedure 8.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.

8.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.

8.1.6. Consuming a Service

Procedure 8.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;

8.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.

8.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);
}


8.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.

8.1.10. Accessing Invocation Properties

Procedure 8.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.

8.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.

8.1.12. Implementation Properties

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

8.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 8.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.

8.1.14. @Property

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