Building your own service in SwitchYard

Jeff Yu (@jeffyuchang)

Nov 30, 2012

About Me

  • Core developer in JBoss RiftSaw (BPEL), Overlord BAM
  • Committer of Apache ODE, Apache ServiceMix
  • Contributor in various projects: SwitchYard, Apache CXF, JBoss ESB, JBoss jBPM, Picketlink etc
  • Full-time open source developer since 2007
  • @jeffyuchang in both twitter and weibo

Agenda

  • SwitchYard Overview
  • SwitchYard In Action
  • Building a component in SwitchYard

What is SwitchYard?

  • JBoss next generation Enterprise Service Bus (ESB)
  • The successor of the JBoss ESB project
  • Focus on consistent, intuitive user experience
  • Leverage standards and complimentary technologies

Project History

  • First Milestone was released at February 2011
  • 0.1.0.Final was released at June 2011
  • Latest one (0.6.0.Final) was released at 8 Nov, 2012
  • Same people behind the JBoss ESB

Service Oriented Integration

What is in SwitchYard

Configuration Model

  • Every switchyard application needs it, it is named switchyard.xml in the META-INF folder
  • It defines the service implementations, gateways, transformations etc.
  • The elements in switchyard.xml conform to Service Component Architecture (SCA) Assembly Model Specfication

Implementation Component

  • Bean Service: based on Weld Project
  • Camel Service: based on Apache Camel Project
  • BPM Service: based on jBPM5 Project
  • Rules Service: based on Drools Project
  • BPEL Service: based on RiftSaw Project

Gateway Component

  • SOAP Binding
  • RESTEasy Binding
  • Camel Bindings: file,ftp,ftps,amqp,atom,generic,jms,jpa,mail,mock, netty,quartz,seda,sftp,sql,timer,direct
  • HortnetQ Binding
  • JCA Binding
  • HTTP Binding

Transformers

  • Java Transformer
  • Smooks Transformer
  • JSON Transformer
  • XSLT Transformer
  • JAXB Transformer

SwitchYard In Action

							
public interface HelloService {
	String sayHello(String name);
}
							
						
							
@Service(HelloService.class)
public class HelloServiceBean implements HelloService {

	@Override
	public String sayHello(String name) {
		System.out.println("Recieved name is: " + name);
		return "Hello " + name;
	}

}
							
						

SwitchYard in Action (2)


@RunWith(SwitchYardRunner.class)
@SwitchYardTestCaseConfig(mixins = CDIMixIn.class, config = SwitchYardTestCaseConfig.SWITCHYARD_XML)
public class HelloServiceTest {
	@ServiceOperation("HelloService")
	private Invoker service;
	@Test
	public void testSayHello() throws Exception {
		String message = "JUDCon 2012 China";
		String result = service.operation("sayHello").sendInOut(message).getContent(String.class);
		Assert.assertTrue("the result is: " + result, ("Hello " + message).equals(result));
	}
}

SwitchYard In Action(3)


public final class HelloServiceTransformer {
	@Transformer(to = "{urn:com.example.switchyard:judcon-china:0.0.1-SNAPSHOT}sayHelloResponse")
	public Element transformStringToSayHelloResponse(String from) {
		StringBuffer sbuffer = new StringBuffer();
		sbuffer.append("<sayHelloResponse xmlns=\"urn:com.example.switchyard:judcon-china:0.0.1-SNAPSHOT\">")
	        .append("<string>" + from + "</string>").append("</sayHelloResponse>");
		return toElement(sbuffer.toString());
	}
	@Transformer(from = "{urn:com.example.switchyard:judcon-china:0.0.1-SNAPSHOT}sayHello")
	public String transformSayHelloToString(Element from) {
		return new String(getElementValue(from, "urn:string"));
	}						
					

SwitchYard In Action(4)


  <sca:composite name="judcon-china" targetNamespace="urn:com.example.switchyard:judcon-china:0.0.1-SNAPSHOT">
    <sca:component name="HelloServiceBean">
      <bean:implementation.bean class="com.example.switchyard.judcon_china.HelloServiceBean"/>
      <sca:service name="HelloService">
        <sca:interface.java interface="com.example.switchyard.judcon_china.HelloService"/>
      </sca:service>
    </sca:component>
    <sca:service name="HelloServicePortType" promote="HelloServiceBean/HelloService">
      <sca:interface.wsdl interface="HelloService.wsdl#wsdl.porttype(HelloServicePortType)"/>
      <soap:binding.soap>
        <soap:contextMapper/>
        <soap:wsdl>HelloService.wsdl</soap:wsdl>
        <soap:wsdlPort>HelloServicePort</soap:wsdlPort>
        <soap:contextPath>judcon-china</soap:contextPath>
      </soap:binding.soap>
    </sca:service>
  </sca:composite>
					

SwitchYard In Action(5)


@RunWith(SwitchYardRunner.class)
@SwitchYardTestCaseConfig(
        config = SwitchYardTestCaseConfig.SWITCHYARD_XML,
        scanners = {BeanSwitchYardScanner.class, TransformSwitchYardScanner.class},
        mixins = {CDIMixIn.class, HTTPMixIn.class})
public class HelloServiceSoapTest {
	
    private HTTPMixIn httpMixIn;

    @Test
    public void testHelloService() throws Exception {
        httpMixIn.postResourceAndTestXML("http://localhost:8080/judcon-china/HelloService", "/soap-request.xml", "/soap-response.xml");
    }
}
						

SwitchYard In Action(6)

What is next?

  • How can I use BPM service?
  • How can I use the file binding?
  • How can I use the camel service?
  • How can I use the BPEL service with JMS?

Check out the quickstarts, it should give you answers to all of above, and much more!

Building a component in SwitchYard

Project Repository

    using Git, and it is hosted at the Github
  • parents: (manages all dependencies and versions)
  • core
  • components
  • quickstarts
  • release
  • tools
  • console
  • switchyard-openshift

outline of creating a component

  • defining an xsd (configuration) for your component
  • implementing the Component and register it in SwitchYard
  • implementing the Activator for the deployment
  • implementing the serviceHandler (specifically, ExchangeHandler) for the message invocation

Component Registration

  • Implements the org.switchyard.deploy.Component interface (You should extend the BaseComponent)
  • put your component full qualified name in the META-INF/services/org.switchyard.deploy.Component file.

public interface Component {
	Activator createActivator(ServiceDomain domain);
	String getName();
	void init(Configuration config);
	void destroy();
	......
}
						

Creating your Activator

  • Implements the org.switchyard.deploy.Activator interface (you should extend the BaseActivator)
  • implement methods accordingly, like implementing the Bindings or Service component

public interface Activator {
  ServiceHandler activateBinding(QName name, BindingModel config);
  void deactivateBinding(QName name, ServiceHandler handler);

  ServiceHandler activateService(QName name, ComponentModel config);
  void deactivateService(QName name, ServiceHandler handler);
  ......
}
						

Creating your Service Handler


/**
 * The role of a Handler is to handle messages and fault events during the
 * course of a service invocation...
 */
public interface ExchangeHandler {
	void handleMessage(Exchange exchange) throws HandlerException;
	void handleFault(Exchange exchange);
}
						

/**
 * Lifecycle-aware version of ExchangeHandler.  The deployer will invoke
 * start() and stop() in accordance with the deployment's lifecycle.
 */
public interface ServiceHandler extends ExchangeHandler {
    void start();
    void stop();   
}
						

Your Component Model/Configuration


<sca:component name="SayHelloService">
             <bpel:implementation.bpel process="sh:SayHello" />
 ......
 						

<schema targetNamespace="http://docs.oasis-open.org/ns/opencsa/sca/200903"
        xmlns:sca="http://docs.oasis-open.org/ns/opencsa/sca/200912"
		xmlns:xsd="http://www.w3.org/2001/XMLSchema"
		xmlns="http://www.w3.org/2001/XMLSchema"
		elementFormDefault="qualified">

	<!-- SCA-Assembly XML Schema -->
    <import namespace="http://docs.oasis-open.org/ns/opencsa/sca/200912"/>

	
	<element name="implementation.bpel"
		type="sca:BPELImplementation" substitutionGroup="sca:implementation" />

	....
</schema>
					

Your Component Model/Configuration (2)


public interface BPELComponentImplementationModel extends ComponentImplementationModel {
	.....
}
						

public class V1BPELComponentImplementationModel extends V1ComponentImplementationModel implements... {
	......
}
						

Your Component Model/Configuration (3)


public class V1BPELMarshaller extends V1CompositeMarshaller {
    /**
     * Reads in the Configuration, looking for "implementation.bpel".
     * If not found, it falls back to the super class (V1CompositeMarshaller).
     */
    @Override
    public Model read(Configuration config) {
        String name = config.getName();
        if (IMPLEMENTATION_BPEL.equals(name)) {
            return new V1BPELComponentImplementationModel(config, getDescriptor());
        }
        return super.read(config);
    }	
}
						

Your Component Model/Configuration (4)

  • creating the descriptor.properties with content like following in org.switchyard.config.model path

bpel1.namespace=http://docs.oasis-open.org/ns/opencsa/sca/200903
bpel1.schema=bpel-v1.xsd
bpel1.location=/org/switchyard/component/bpel/config/model/v1/
bpel1.marshaller=org.switchyard.component.bpel.config.model.v1.V1BPELMarshaller
					   

project information

Questions?