Welcome to the SwitchYard User Guide. This document provides a detailed explanation of the moving parts in SwitchYard. If you are looking for a way to get up and running quickly, be sure to check out the Getting Started guide quickly.
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.
Camel binding support in SwitchYard allows Camel components to be used as gateway bindings for services and references within an application.
NOTE: The primary focus of Camel integration in 0.1 was the use of the core EIP routing engine within Camel as a service implementation. Testing for Camel bindings was limited to the Camel File component in 0.1, but this will be expanded considerably in 0.2. If you run into an issue with a specific Camel component in SwitchYard, please let us know in the SwitchYard forum.
Composite-level services can be bound to a Camel component using the
<binding.camel>
binding definition. The following configuration options are available for
binding.camel
:
configURI
: contains the Camel endpoint URI used to configure a Camel component instance
operationSelector
: specification of the operation name to use for the message exchange. If the target service only has a single operation, this setting is optional.
Here's an example of what a service binding looks like using a Camel component.
<sca:composite> <sca:service name="SimpleCamelService" promote="SimpleComponent/SimpleCamelService"> <camel:binding.camel configURI="file://target/input?fileName=test.txt&initialDelay=50&delete=true"> <camel:operationSelector operationName="print"/> </camel:binding.camel> </sca:service> <!-- sca:component definition omitted --> </sca:composite>
Binding a reference with Camel is very similar to binding a service. The only significant difference is that specification of the operationSelector is not required on reference bindings.
<sca:composite> <sca:reference name="WarehouseService" promote="OrderComponent/WarehouseService"> <camel:binding.camel configURI="file://target/output"/> </sca:reference> </sca:composite>
The SOAP component in SwitchYard provides SOAP-based web service binding support for services and references in SwitchYard.
Composite-level services can be exposed as a SOAP-based web service using the
<binding.soap>
binding definition. The following configuration options are available for
binding.soap
when binding services:
wsdl
: location of the WSDL used to describe the web service endpoint. A relative path can be used if the WSDL is included in the deployed application. If the WSDL is located outside the application, then a
file:
or
http:
URL can be used.
serverPort
: port number that the HTTP service should bind to for the SOAP endpoint. Defaults to 8080 if unspecified.
port
: port name in the WSDL to use. If unspecified, the first port definition in the WSDL is used for the service endpoint
The default port of the SOAP binding conflicts with the default listener on JBoss AS, so you must specify a unique port in your configuration when deploying to JBoss AS. Tighter integration with JBoss WS is planned to eliminate this annoying constraint.
Here's an example of what a SOAP service binding looks like:
<sca:composite name="orderApp"> <sca:service name="OrderService" promote="OrderService"> <soap:binding.soap> <soap:wsdl>wsdl/OrderService.wsdl</soap:wsdl> <soap:serverPort>9000</soap:serverPort> </soap:binding.soap> </sca:service> </sca:composite>
Binding a reference with SOAP can be used to make SOAP-based web services available to SwitchYard services. The following configuration options are available for
binding.soap
when binding references:
wsdl
: location of the WSDL used to describe the web service endpoint. A relative path can be used if the WSDL is included in the deployed application. If the WSDL is located outside the application, then a
file:
or
http:
URL can be used.
port
: port name in the WSDL to use. If unspecified, the first port definition in the WSDL is used for the service endpoint.
<sca:composite> <sca:reference name="WarehouseService" promote="OrderComponent/WarehouseService"> <camel:binding.camel configURI="file://target/output"/> </sca:reference> </sca:composite>
Transformation represents a change to the format and/or representation of a message's content. The representation of a message is simply the Java contract (e.g. java.lang.String, org.example.MyFancyObject) used to access the underlying content. The format of a message refers to the actual structure of the data itself. Examples of data formats include XML, JSON, CSV, and EDI.
Take the following message content:
<MyBook> <Chapter1> <Chapter2> </MyBook>
The format of this content is XML. One representation of XML in Java is as a String. Of course, the representation could also be a org.w3c.dom.Document, java.io.InputStream, etc.
String content = "<MyBook>...";
Transformation plays an important role in connecting service consumers and providers, since the format and representation of message content can be quite different between the two. For example, a SOAP gateway binding will likely use a different representation and format for messages than a service offered by a Java Bean. In order to route services from the SOAP gateway to the Bean providing the service, the format and representation of the SOAP message will need to change. Implementing the transformation logic directly in the consumer or provider pollutes the service logic and can lead to tight coupling. SwitchYard allows for the transformation logic to declared outside the service logic and injected into the mediation layer at runtime.
Transformation of message content is specified in the descriptor of your SwitchYard application (switchyard.xml). The qualified name of the type being transformed from as well as the type being transformed to are defined along with the transformer implementation. This allows transformation to be a declarative aspect of a SwitchYard application, as the runtime will automatically register and execute transfomers in the course of a message exchange.
<transforms> <transform.java class="org.switchyard.quickstarts.demos.orders.Transformers" from="{urn:switchyard-quickstart-demo:orders:1.0}submitOrder" to="java:org.switchyard.quickstarts.demos.orders.Order"/> </transforms>
There are two methods available for creating a Java-based transformer in SwitchYard:
Implement the
org.switchyard.transform.Transfomer
interface and add a
<transform.java>
definition to your switchyard.xml.
Annotate one or more methods on your Java class with
@Transformer
.
When using the
@Transformer
annotation, the SwitchYard maven plugin will automatically generate the
<transform.java>
definition(s) for you and add them to the switchyard.xml packaged in your application. The following Java class would produce the
<transform.java>
definition provided above:
public class MyTransformer { @Transformer(from = "{urn:switchyard-quickstart-demo:orders:1.0}submitOrder") public Order transform(Element from) { // handle transformation here } }
The optional
from
and
to
elements of the
@Transformer
annotation can be used to specify the qualified type name used during transformer registration. If not supplied, the full class name of the method parameter will be used as the from type and the full class name of the return type will be used as the to type.
There are three distinct transformation models available with Smooks in SwitchYard:
XML to Java : Based on a standard Smooks Java Binding configuration.
Java to XML : Based on a standard Smooks Java Binding configuration.
Smooks : This is a "normal" Smooks transformation in which the developer must define which Smooks filtering Result is to be exported back to the SwitchYard Message as the transformation result.
Smooks transformations are declared by including a
<transform.smooks>
definition in switchyard.xml.
<transform.smooks config="/smooks/OrderAck_XML.xml" from="java:org.switchyard.quickstarts.transform.smooks.OrderAck" to="{urn:switchyard-quickstart:transform-smooks:1.0}submitOrderResponse" type="JAVA2XML"/>
The
config
attribute points to a Smooks resource containing the mapping definition. The type attribute can be one of
SMOOKS
,
XML2JAVA
, or
JAVA2XML
.
The JSON transformer provides a basically mapping facility between POJOs and JSON using the popular Jackson processor. Specification of the transformer requires one Java type and one named type. The following example converts a JSON serialization of an order to the Order object.
<trfm:transform.json from="{urn:switchyard-quickstart:transform-json:1.0}order" to="java:org.switchyard.quickstarts.transform.json.Order"/>
Each SwitchYard application must include a configuration descriptor named
switchyard.xml
in the
/META-INF
directory of it's archive. The basic structure of this descriptor is:
A parent
<switchyard>
element which contains all other configuration.
Exactly one child
<composite>
element, which contains the SCA description of the application.
Zero or one
<transforms>
elements which can contain one or more transform definitions.
Here's an example of what a SwitchYard descriptor looks like:
<switchyard xmlns="urn:switchyard-config:switchyard:1.0" xmlns:sca="http://docs.oasis-open.org/ns/opencsa/sca/200912" xmlns:bean="urn:switchyard-component-bean:config:1.0" xmlns:soap="urn:switchyard-component-soap:config:1.0"> <sca:composite name="orders"> <sca:service name="OrderService" promote="OrderService"> <soap:binding.soap> <soap:serverPort>18001</soap:serverPort> <soap:wsdl>wsdl/OrderService.wsdl</soap:wsdl> </soap:binding.soap> </sca:service> <sca:component name="InventoryService"> <sca:service name="InventoryService"> <sca:interface.java interface="org.switchyard.quickstarts.demos.orders.InventoryService"/> </sca:service> <bean:implementation.bean/> </sca:component> <sca:component name="OrderService"> <sca:service name="OrderService"> <sca:interface.java interface="org.switchyard.quickstarts.demos.orders.OrderService"/> </sca:service> <sca:reference name="InventoryService"> <sca:interface.java interface="org.switchyard.quickstarts.demos.orders.InventoryService"/> </sca:reference> <bean:implementation.bean/> </sca:component> </sca:composite> <transforms xmlns="urn:switchyard-config:transform:1.0"> <transform.java class="org.switchyard.quickstarts.demos.orders.Transformers" from="{urn:switchyard-quickstart-demo:orders:1.0}submitOrder" to="java:org.switchyard.quickstarts.demos.orders.Order"/> <transform.java class="org.switchyard.quickstarts.demos.orders.Transformers" from="java:org.switchyard.quickstarts.demos.orders.OrderAck" to="{urn:switchyard-quickstart-demo:orders:1.0}submitOrderResponse"/> </transforms> </switchyard>
Luckily, SwitchYard can generate the bulk of the above description based off of annotations in your application code, so you won't have to muck with this XML directly. For the portions that can't be generated, Forge tooling fills the gap nicely. While you certainly can play with the XML directly, we try to do what we can to protect you from those pointy angle brackets.
The composition of a SwitchYard application is defined using the Service Component Architecture Assembly Model , an open specification undergoing standardization in OASIS . For the nitty gritty details of the assembly model, please consult the SCA specification. This section provides a brief overview of the important elements:
<composite>
: single, top-level application element which defines a set of services, the relationships and dependencies of those services, and the linkage (if any) to services available outside the application.
<component>
: contains the implementation of a service and the dependencies of that service
<service>
: defines the name and interface for a service. This element is used inside a component definition to declare a service and can also appear inside a composite definition to indicate that a service is visible to outside applications.
<interface.XXX>
: the contract for a service. The type of the interface replaces 'XXX' in the definition. Supported interface types at this point are "java" and "wsdl".
<binding.XXX>
: the binding of a service. The type of the binding replaces 'XXX' in the definition. Example bindings include "binding.soap" and "binding.camel".
<implementation.XXX>
: the implementation of a service. The type of the implementation replaces 'XXX' in the definition. Example implementations include 'implementation.bean" and "implementation.camel".
The
<transforms>
section of SwitchYard configuration is used to define transformers local to your application. Similar to interfaces, bindings, and implementations, each transformer definition includes a type stuff in it's definition (e.g. transform.java, transform.smooks). The
from
and
to
definition on each transformer corresponds to the message type used on a service and/or reference interface used within SwitchYard. See the Transformer section of the User Guide for more information on individual transformer types.
As mentioned earlier, SwitchYard is capable of generating configuration off of annotations in your application code so that you don't have to hand edit XML configuration. The generated configuration is packaged up with your application as part of the Maven build lifecycle and placed in
target/classes/META-INF/switchyard.xml
Your application project can also include a descriptor in
src/main/resources/META-INF/switchyard.xml
This version of the configuration can be edited by the user directly and is also used by Forge tooling to specify configuration in response to SwitchYard forge commands. During the build process, the user-editable switchyard.xml is merged with any generated configuration to produce the final switchyard.xml in the target/ directory.
Testing your applications is dead simple with the comprehensive unit test support provided in SwitchYard. There are two primary elements to test support in SwitchYard:
SwitchYardTestCase
- base unit test class which takes care of bootstrapping an embedded SwitchYard runtime and deploying the project as a SwitchYard application.
TestMixIn
s - composition-based method for adding specific testing tools to your test case. Each MixIn provides customized testing tools for things like service implementations, gateway bindings, and transformers.
Adding test support to your SwitchYard application is simply a matter of adding a dependency to the switchyard-test module in your application's pom.xml.
<dependency> <groupId>org.switchyard</groupId> <artifactId>switchyard-test</artifactId> <version>[release-version]</version> <!-- e.g. "0.1.0" --> <scope>test</scope> </dependency>
To take advantage of the test support in SwitchYard, your unit test should extend the base
SwitchYardTestCase
class.
SwitchYardTestCase
takes care of creating and starting an embedded runtime for each test method. After the embedded runtime is started, the project containing the test is packaged as a SwitchYard application and deployed to it. You can take advantage of various helper methods in the base test class to invoke your service and assert against the result.
@SwitchYardTestCaseConfig(config = "META-INF/switchyard.xml") public class MyServiceTest extends SwitchYardTestCase { @Test public void testOperation() { newInvoker("MyService") .operation("acceptMessage") .sendInOnly("Test message content"); } }
The optional
SwitchYardTestCaseConfig
can be used if you would like to use a different application descriptor than the default META-INF/switchyard.xml to test your application.
The
TestMixIn
feature allows you to selectively enable additional test functionality based on the capabilities of your application. The following MixIn types are available in 0.1:
CDIMixIn
: boostraps a stand-alone CDI environment, automatically discovers CDI beans, registers bean services, and injects references to SwitchYard services.
HTTPMixIn
: client methods for testing HTTP-based services.
SmooksMixIn
: stand-alone testing of any Smoooks transformers in your application.
The 0.1 release of SwitchYard supports the following deployment options:
JBoss Application Server 6.0 Final
JBoss Application Server 7.0 Beta 3
At present, you must use the SwitchYard distribution of AS6 or AS7 with SwitchYard pre-installed. Future releases of SwitchYard will add support for additional runtimes and the option for installing SwitchYard in an existing application server.
Deployment on JBoss AS6 is the same old, same old. Simply copy your SwitchYard application to the the server's deploy directory and the SwitchYard deployer will take care of the rest.
cp myapp.jar $JBOSS_HOME/server/default/deploy/.
Undeploying a SwitchYard application is equally unsurprising. Just remove the app jar from the deploy directory like so:
rm $JBOSS_HOME/server/default/deploy/myapp.jar
Things are a bit different in JBoss AS7. Auto-deploy still exists, but there are some subtle changes to the process. Deploy is still just a matter of copying the archive to the server, but the target directory should be
standalone/deployments
.
cp myapp.jar $JBOSS_HOME/standalone/deployments/.
To undeploy the application, you need to remove the
.deployed
marker file that is generated upon successful deployment of your application:
rm $JBOSS_HOME/standalone/deployments/myapp.jar.deployed
You can find more information on the ins and outs of deployment on JBoss AS7 in the
README.txt
file contained in the standalone/deployments directory of the distribution.
SwitchYard integrates with Seam Forge to provide a set of rapid application development tools for service-oriented applications. Please consult the Getting Started guide for information on how to install Forge and the SwitchYard extensions to Forge.
The first thing you'll want to do with Forge is create a new project. This can be done inside the Forge shell using the new-project command.
$ forge ____ _____ / ___| ___ __ _ _ __ ___ | ___|__ _ __ __ _ ___ \___ \ / _ \/ _` | '_ ` _ \ | |_ / _ \| '__/ _` |/ _ \ \\ ___) | __/ (_| | | | | | | | _| (_) | | | (_| | __/ // |____/ \___|\__,_|_| |_| |_| |_| \___/|_| \__, |\___| |___/ [no project] tmp $ new-project --named syApp --topLevelPackage org.switchyard.examples.forge Use [/private/tmp/syApp] as project directory? [Y/n] Wrote /private/tmp/syApp/src/main/resources/META-INF/forge.xml ***SUCCESS*** Created project [syApp] in new working directory [/private/tmp/syApp]
At this point, you have an empty application with a few Maven facets installed. What's a facet you ask? Read on ....
Facets add capabilities to an application and to the forge environment itself. This allows SwitchYard to add dependencies to your application's pom based on the functionality you will be using, instead of sticking every possible SwitchYard dependency in the application by default. Facets are also used to add commands specific to SwitchYard itself and components which you will be using in your application. The following facets are currently available:
switchyard - core set of commands and dependencies for the SwitchYard runtime
switchyard.bean - commands and dependencies for Bean component services
switchyard.soap - commands and dependencies for SOAP gateway bindings
switchyard.camel - commands and dependencies for Camel services and gateway bindings
Installing a facet can be done directly in the shell using the
install-facet
command.
[syapp] syapp $ project install-facet switchyard.soap ***SUCCESS*** Installed [switchyard.soap] successfully.
The following SwitchYard commands are available in Forge (grouped by facet).
switchyard
switchyard show-confi
g : displays the current state of your application's configuration, including services, references, and bindings.
switchyard promote-service
: promotes an internal application-scoped service to be visible to other applications.
s
witchyard promote-reference
: promotes an internal application-scoped reference so that it can be mapped to services provided in other applications.
switchyard.bean
bean-service create
: creates a new CDI Bean service, consisting of a service interface and implementation class.
switchyard.camel
camel-service create
: creates a new XML or Java DSL Camel route.
camel-binding bind-service
: binds a service using a Camel endpoint URI.
camel-binding bind-reference
: binds a reference using a Camel endpoint URI.
switchyard.soap
soap-binding bind-service
: binds a service to a SOAP endpoint.
s
oap-binding bind-reference
: binds a reference to a SOAP endpoint.