Pages

Tuesday, November 3, 2009

Working with Apache Tuscany, The Java SCA based platform part 1

In this blogpost and future blogposts I will try to give you a jumpstart with Apache Tuscany Java SCA. If you follow my blog you may already know that I also work and make blogsposts over an other Service Component Architecture (SCA)-based SOA platform ( Oracle Soa Suite 11g). Soa Suite 11g has a different SCA approach and has much better designer support. But it is nice to take a look at Tuscany and see how this java SCA implementation works.

I will explain how you can make some composite applications. In this blogpost we start easy with building a composite application with
  • Simple java Component
  • Jax-ws component
  • Component with references to other components ( wires )
  • Service on a component
  • Using a second composite


Here a overview of my test project.


First we need to download Apache Tuscany Java SCA

We start with a simple java component with its interface.

package nl.whitehorses.tuscany.step1;

public interface JavaService {
public String getData();
}

package nl.whitehorses.tuscany.step1;

public class JavaServiceImpl implements JavaService {

public String getData() {
return "Hello from java component";
}
}

We can add this component in the step1 composite file and provide the java implementation class.

<?xml version="1.0" encoding="UTF-8"?>
<composite xmlns="http://www.osoa.org/xmlns/sca/1.0"
targetNamespace="http://whitehorses"
name="step1">

<component name="JavaCp">
<implementation.java class="nl.whitehorses.tuscany.step1.JavaServiceImpl" />
</component>

</composite>

Last part of step 1 is to run this composite application, now we have to load and test the composite application.

package nl.whitehorses.tuscany.step1;

import org.apache.tuscany.sca.host.embedded.SCADomain;

public class ClientStep1 {

public final static void main(String[] args) throws Exception {

SCADomain scaDomain = SCADomain.newInstance("step1.composite");
JavaService javaService = scaDomain.getService(JavaService.class, "JavaCp");

System.out.println("java: " + javaService.getData());

scaDomain.close();
}
}


In step 2 we will call a jax-ws webservice. In this step we also need to add a reference to the component.

To make this work I created first a jax-ws service and deploy this to an application server.

package nl.whitehorses.soa.ws;

import javax.jws.WebService;

@WebService
public class Helloworld {

public String getResponse( String message){
return message;

}
}

In the tuscany client project we need to generate a webservice proxy client for this webservice.
Create an implemention class for this ws proxy client. In this class we need to add a reference with the name jaxws and a setter. We will use this in the composite xml

package nl.whitehorses.tuscany.step2;

import nl.whitehorses.soa.ws.proxy.Helloworld;
import org.osoa.sca.annotations.Reference;

public class HelloworldServiceImpl implements Helloworld{

private Helloworld jaxws;

@Reference
public void setJaxws(Helloworld jaxws) {
this.jaxws = jaxws;
}

public String getResponse( String message){
return jaxws.getResponse(message);

}
}

create a new composite file where we will add this component and its reference. In the reference we need to provide the web service binding

<?xml version="1.0" encoding="UTF-8"?>
<composite xmlns="http://www.osoa.org/xmlns/sca/1.0"
targetNamespace="http://whitehorses"
name="step2">

<component name="HelloworldCp">
<implementation.java class="nl.whitehorses.tuscany.step2.HelloworldServiceImpl" />
<reference name="jaxws">
<binding.ws wsdlElement="http://ws.soa.whitehorses.nl/#wsdl.port(HelloworldService/HelloworldPort)"
uri="http://localhost:7101/jaxws/HelloworldPort?wsdl#wsdl.interface(HelloworldService)"/>
</reference>
</component>

</composite>

And at last the test client

package nl.whitehorses.tuscany.step2;


import org.apache.tuscany.sca.host.embedded.SCADomain;
import nl.whitehorses.soa.ws.proxy.Helloworld;

public class ClientStep2 {

public final static void main(String[] args) throws Exception {

SCADomain scaDomain = SCADomain.newInstance("step2.composite");
Helloworld helloworld = scaDomain.getService(Helloworld.class, "HelloworldCp");

System.out.println("ws: " + helloworld.getResponse("hello"));

scaDomain.close();
}
}

In step 3 we will expose an component as a service. First step is to make an interface with the methods which we want to expose in this web service. We have to add Remotable annotation.

package nl.whitehorses.tuscany.step3;

import org.osoa.sca.annotations.Remotable;

@Remotable
public interface TuscanyService {

public String getJaxwsResponse( String message);

public String getJavaData();

public String getJavaData2();

}

The implementatation of this component with the Service annotation and off course the references to the other components.

package nl.whitehorses.tuscany.step3;

import nl.whitehorses.soa.ws.proxy.Helloworld;

import org.osoa.sca.annotations.Reference;
import org.osoa.sca.annotations.Service;
import nl.whitehorses.tuscany.step1.JavaService;

@Service(TuscanyService.class)
public class TuscanyServiceImpl implements TuscanyService {

private Helloworld helloworldComponent;
private JavaService javaComponent;
private JavaService javaComponent2;

@Reference
public void setHelloworldComponent(Helloworld helloworldComponent) {
this.helloworldComponent = helloworldComponent;
}

@Reference
public void setJavaComponent(JavaService javaComponent) {
this.javaComponent = javaComponent;
}

@Reference
public void setJavaComponent2(JavaService javaComponent2) {
this.javaComponent2 = javaComponent2;
}


public String getJaxwsResponse(String message) {
return helloworldComponent.getResponse(message) ;
}

public String getJavaData() {
return javaComponent.getData();
}

public String getJavaData2() {
return javaComponent2.getData();
}
}


The step3 composite file has a TuscanyServiceComponent with 3 references to the step 1 and 2 components and this component has also a service. In this service we have to provide the ws url.

<?xml version="1.0" encoding="UTF-8"?>
<composite xmlns="http://www.osoa.org/xmlns/sca/1.0"
targetNamespace="http://whitehorses"
name="step3">

<component name="TuscanyServiceComponent">
<implementation.java class="nl.whitehorses.tuscany.step3.TuscanyServiceImpl" />
<reference name="helloworldComponent" target="HelloworldCp" />
<reference name="javaComponent" target="JavaCp" />
<reference name="javaComponent2" target="JavaCp2" />
<service name="TuscanyService">
<binding.ws uri="http://localhost:8085/TuscanyService"/>
</service>
</component>

<component name="JavaCp">
<implementation.java class="nl.whitehorses.tuscany.step1.JavaServiceImpl" />
</component>

<component name="JavaCp2">
<implementation.java class="nl.whitehorses.tuscany.step1.JavaServiceImpl" />
</component>

<component name="HelloworldCp">
<implementation.java class="nl.whitehorses.tuscany.step2.HelloworldServiceImpl" />
<reference name="jaxws">
<binding.ws wsdlElement="http://ws.soa.whitehorses.nl/#wsdl.port(HelloworldService/HelloworldPort)"
uri="http://localhost:7101/jaxws/HelloworldPort?wsdl#wsdl.interface(HelloworldService)"/>
</reference>
</component>

</composite>

The client code which tests the main component and start the service on this component

package nl.whitehorses.tuscany.step3;

import java.io.IOException;
import org.apache.tuscany.sca.host.embedded.SCADomain;

public class ClientStep3 {

public final static void main(String[] args) throws Exception {

SCADomain scaDomain = SCADomain.newInstance("step3.composite");
TuscanyService tuscanyService = scaDomain.getService(TuscanyService.class, "TuscanyServiceComponent");

System.out.println("ws: "+tuscanyService.getJaxwsResponse("hello"));
System.out.println("java: "+tuscanyService.getJavaData());
System.out.println("java2: "+tuscanyService.getJavaData2());

try {
System.out.println("ws service started (press enter to shutdown)");
System.in.read();
} catch (IOException e) {
e.printStackTrace();
}

scaDomain.close();
}
}

Now we can use soapui to test this web service.


In the last step in this blog I will use a second composite which will be called by the first composite.
First we create a new composite xml. We will copy a java component from the step3 composite to this composite. Give this composite a new name and target namespace. We will use these values to import this composite. This component needs a service else we can not call it from the main composite.

<?xml version="1.0" encoding="UTF-8"?>
<composite xmlns="http://www.osoa.org/xmlns/sca/1.0"
targetNamespace="http://whitehorses2"
name="step4_2">

<service name="JavaCpService" promote="JavaCp">
<interface.java interface="nl.whitehorses.tuscany.step1.JavaService"/>
</service>

<component name="JavaCp">
<implementation.java class="nl.whitehorses.tuscany.step1.JavaServiceImpl" />
</component>

</composite>

The main composite called step4_1 need the namespace of the second composite. The JavaCp2 component import the second composite by using the target namespace of the second composite and with its name. In the javaComponent2 reference of the TuscanyServiceComponent will call JavaCp2 component followed by the service name of the second composite.

<?xml version="1.0" encoding="UTF-8"?>
<composite xmlns="http://www.osoa.org/xmlns/sca/1.0"
targetNamespace="http://whitehorses"
xmlns:whitehorses2="http://whitehorses2"
name="step4_1">

<component name="TuscanyServiceComponent">
<implementation.java class="nl.whitehorses.tuscany.step3.TuscanyServiceImpl" />
<reference name="helloworldComponent" target="HelloworldCp" />
<reference name="javaComponent" target="JavaCp" />
<reference name="javaComponent2" target="JavaCp2/JavaCpService" />
<service name="TuscanyService">
<binding.ws uri="http://localhost:8085/TuscanyService"/>
</service>
</component>

<component name="JavaCp">
<implementation.java class="nl.whitehorses.tuscany.step1.JavaServiceImpl" />
</component>

<component name="HelloworldCp">
<implementation.java class="nl.whitehorses.tuscany.step2.HelloworldServiceImpl" />
<reference name="jaxws">
<binding.ws wsdlElement="http://ws.soa.whitehorses.nl/#wsdl.port(HelloworldService/HelloworldPort)"
uri="http://localhost:7101/jaxws/HelloworldPort?wsdl#wsdl.interface(HelloworldService)"/>
</reference>
</component>

<component name="JavaCp2">
<implementation.composite name="whitehorses2:step4_2"/>
</component>
</composite>



and at last the step 4 test client.

package nl.whitehorses.tuscany.step4;

import nl.whitehorses.tuscany.step3.TuscanyService;
import java.io.IOException;
import org.apache.tuscany.sca.host.embedded.SCADomain;

public class ClientStep4 {

public final static void main(String[] args) throws Exception {

SCADomain scaDomain = SCADomain.newInstance("step4_1.composite");
TuscanyService tuscanyService = scaDomain.getService(TuscanyService.class, "TuscanyServiceComponent");

System.out.println("ws: "+tuscanyService.getJaxwsResponse("hello"));
System.out.println("java: "+tuscanyService.getJavaData());
System.out.println("java2: "+tuscanyService.getJavaData2());

try {
System.out.println("ws service started (press enter to shutdown)");
System.in.read();
} catch (IOException e) {
e.printStackTrace();
}

scaDomain.close();
}
}

Here you can download my jdeveloper 11G test project.

5 comments:

  1. Have you taken a look at Fabric3, another open-source SCA framework? The authors of "Understanding SCA" (recommend that book) are involved in Fabric3.

    ReplyDelete
  2. For Eclipse you can use the
    SCA Tools.
    http://www.eclipse.org/stp/sca/

    ReplyDelete
  3. I've done this exact example with a subtle modification. I changed the TuscanyServiceComponent binding for:



    and it throws a

    java.lang.NullPointerException at org.apache.tuscany.sca.core.databinding.wire.PassByValueInterceptor.invoke(PassByValueInterceptor.java:62)

    In particular Tuscany seems to complain about exposing the result of the JAXWS through the service if this doesn't have a binding.ws as well.

    public String getJaxwsResponse(String message) {
    return helloworldComponent.getResponse(message) ;
    }

    What is that exception telling me exactly? Can anyone throw some light on all of this?
    Thanks.

    ReplyDelete
    Replies
    1. Hi,

      can you escape the code so I can see it .

      thanks

      Delete
  4. Hi Edwin,

    thanks for the reply. It's been solved already. I don't remember what the problem was exactly. It had something to do with a call to the wrong domain instance in the main method of my launcher class. The composites and all of the implementation was ok really.

    ReplyDelete