JBoss.orgCommunity Documentation
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. Rather than writing our own POJO container to provide this capability, we have implemented the bean component as a Weld extension. No need to learn a new programming model - 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.
Providing a service with the Bean component is as simple as adding 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, defining the service operations that are exposed by SwitchYard.
The only other thing you need is a META-INF/beans.xml file in your deployed application. When the application is deployed, the Weld runtime scans the application for beans and enlists the SwitchYardCDIServiceDiscovery CDI extension in the CDI lifecycle. Our extension will pick up @Service beans and make them available to the application deployer (will depend on the container). At this point, the service can be invoked from other services within SwitchYard or bound to a wire protocol via SwitchYard gateways.
Consuming a SwitchYard service from within a CDI bean is done via @Reference annotations.
@Service(ConsumerService.class) public class ConsumerServiceBean implements ConsumerService { @Reference private SimpleService service; public void consumeSomeService(String consumerName) { service.sayHello("Hello " + consumerName); } } public interface ConsumerService { void consumeSomeService(String consumerName); }
Note that the contract for the service is all that's exposed to the bean consumer. The reference could point to a service that is hosted outside of SwitchYard and exposed over JMS, SOAP, FTP, etc. The SwitchYard runtime handles the resolution of the service reference to a concrete service, allowing your service logic to remain blissfully ignorant. Invocations made through this reference are routed through the SwitchYard exchange mechanism.
The @Reference annotation can accept a service name in cases where the default name resolution (interface Class simple name e.g. "OrderService") are not appropriate.
@Reference("urn:myservices:purchasing:OrderService") private OrderService orders;
This can be useful when the default name resolution is not appropriate. Keep in mind that the name used by the reference is not required to match the target service, but it resolve to a service through some mechanism. For example, the deployed application could contain wiring configuration which maps the service name used by the bean reference to a different service name in the runtime.
Unit testing in SwitchYard is very easy. See the Testing SwitchYard Services documentation.
Easiest way to get started is to create a new application using the SwitchYard Forge Tooling and switchyard.bean facet.
Camel services allow you to leverage the core routing engine inside of Apache Camel to route between services in SwitchYard. The route itself is exposed as a service within SwitchYard, which means it has a well-defined contract and can be injected into any other service in the runtime. The routing logic can be expressed in XML and included directly in the service component configuration, or you can use the Java DSL to define the route in an annotated Java class.
SwitchYard provides an
@Route
annotation which can be used to declare that a class contains a Camel route which should be represented as a service in SwitchYard. The @Route annotation has a single required element which identifies the service interface to be used by the route. Aside from this annotation, the class looks exactly like a route that you would define in Camel alone.
@Route(JavaDSL.class) public class JavaDSLBuilder extends RouteBuilder { public void configure() { from("switchyard://JavaDSL") .log("Message received in Java DSL Route") .log("${body}") .split(body(String.class).tokenize("\n")) .filter(body(String.class).startsWith("sally:")) .to("switchyard://XMLService?operationName=acceptMessage"); } }
When an application containing one or more Java DSL routes is built, the SwitchYard Maven plugin will automatically generate the required service component configuration in
META-INF/switchyard.xml
. The above route would produce the following configuration:
<component name="JavaDSLBuilder"> <service name="JavaDSL"> <interface.java interface="org.switchyard.quickstarts.camel.service.JavaDSL"/> </service> <implementation.camel xmlns="urn:switchyard-component-camel:config:1.0"> <java class="org.switchyard.quickstarts.camel.service.JavaDSLBuilder"/> </implementation.camel> </component>
The "from" endpoint in a Camel service must always equal the service name. This allows SwitchYard to establish service bindings outside the route definition itself.
Configuring a Camel service using XML is done using the <implementation.camel> configuration directly as follows:
<sca:component name="CamelComponent"> <sca:service name="OrderService" > <sca:interface.java interface="org.switchyard.component.camel.deploy.support.OrderService"/> </sca:service> <sca:reference name="WarehouseService"> <sca:interface.java interface="org.switchyard.component.camel.deploy.support.WarehouseService"/> </sca:reference> <implementation.camel> <route xmlns="http://camel.apache.org/schema/spring" id="Camel Test Route"> <log message="ItemId [${body}]"/> <to uri="switchyard://WarehouseService?operationName=hasItem"/> <log message="Title Name [${body}]"/> </route> </implementation.camel> </sca:component>
You'll notice in the above configuration that the route in the <implementation.camel> does not specify a from endpoint on the route definition. For Camel XML routes, Switchyard automatically adds this for the service. The above would be invokable by using the following code (snippet from a SwitchYard test):
String title = newInvoker("OrderService").operation("getTitleForItem").sendInOut("10").getContent(String.class);
Running the above code snippet would generate the following in you console log:
10:57:45,915 INFO [impl.DefaultCamelContext] Apache Camel 2.6.0 (CamelContext: camel-1) started in 0.838 seconds 10:57:46,284 INFO [impl.DefaultCamelContext] Route: Camel Test Route started and consuming from: Endpoint[switchyard://OrderService] 10:57:46,307 INFO [impl.DefaultCamelContext] Apache Camel 2.6.0 (CamelContext: camel-1) is starting 10:57:46,307 INFO [impl.DefaultCamelContext] Total 1 routes, of which 1 is started. 10:57:46,307 INFO [impl.DefaultCamelContext] Apache Camel 2.6.0 (CamelContext: camel-1) started in 0.000 seconds 10:57:46,428 INFO [Camel Test Route] ItemId [10] 10:57:46,434 INFO [Camel Test Route] Title Name [Fletch]
The Camel component contains not only wraps Camel, it defines a Camel component itself which maps to
switchyard://
endpoint URIs. As seen in the above examples, the
switchyard://
endpoint scheme can be used to route between Camel routes and SwitchYard services. Endpoint configuration is very straightforward:
switchyard://[service-name]?operationName=[operation-name]
service-name
: name of the SwitchYard service
operation-name
: name of the service operation to be invoked. This is only used on references and is optional if the target service only has a single operation.