Dynamic Service Provider (DSP)

This page describes the Dynamic Service Provider mechanism created as a sub-module of the RiftSaw project.

 

What is DSP

 

The Dynamic Service Provider mechanism provides the ability to dynamically create a service endpoint, based on a supplied interface definition, that can route inbound requests to a service provider implementation.

 

The initial focus of the work is to provide dynamic presentation of web services based on a supplied WSDL interface, although other solutions may be supported in the future. The web service support is being used as part of the RiftSaw BPEL runtime, to route web service requests through to BPEL processes deployed to the BPEL engine.

 

The DSP project is licensed under Apache License, Version 2.0, and is based on work by Heiko Braun as part of the RiftSaw project.

 

 

Infrastructure for DSP

Source Code

 

The source code for the project currently resides in the RiftSaw subversion repository in a top level module called dsp.

 

The project is organised into the following top level modules:

 

  1. api - this module provides the DSP APIs and generic components
  2. jboss - this module provides the JBossAS specific implementation components
  3. samples - includes a 'deployer' example, to show how to use DSP to create and deploy a web service endpoint based on a supplied WSDL

 

Issue Reporting

 

Any issues found with the DSP module should be reported through the RiftSaw JIRA system, setting the component to "Dynamic Service Provider (DSP)".

 

 

Using DSP

 

This section discusses how to use DSP to deploy a Web Service endpoint based on a supplied WSDL definition. This information is based on the samples/deployer example module in the DSP svn repository.

 

There are basically three steps involved in deploying a web service dynamically using DSP.

 

Step 1 - Generate the JAX-WS web service provider for the WSDL definiton

 

/**
 * Deploy the web service, using the artifacts contained within the supplied the root folder
 * and based on the WSDL definition located in the supplied WSDL file.
 * 
 * @param root The root folder containing the artifacts to be included in the web service
 * @param wsdlFile The WSDL definition upon which the web service interface will be based
 * @return The service endpoint reference of the deployed web service
 */
public ServiceEndpointReference deploy(java.io.File root, java.io.File wsdlFile) throws Exception {
        ClassLoader cl=WSDeployer.class.getClassLoader();
        
        javax.wsdl.factory.WSDLFactory factory=javax.wsdl.factory.WSDLFactory.newInstance();
        javax.wsdl.Definition wsdl=factory.newWSDLReader().readWSDL(null, wsdlFile.getAbsolutePath());
        
        WSDLReference wsdlRef=new WSDLReference(wsdl, wsdlFile.toURI());
        

        // Obtain the generator for web service provider
        WebServiceProviderGenerator providerFactory = new WebServiceProviderGenerator();

        javax.wsdl.Service service=(javax.wsdl.Service)wsdl.getServices().values().iterator().next();
        javax.wsdl.Port port=(javax.wsdl.Port)service.getPorts().values().iterator().next();
        

        // Create the metadata for the web service endpoint
        EndpointMetaData metaData=new EndpointMetaData(service.getQName(),
                                port.getName(), new QName("http://www.example.org", "ProcessId"),
                                    UUID.randomUUID().toString());
        

        // Generate the web service provider - the 'ExampleWebServiceFactory' is the
        // factory class that will be used to create an instance of the service
        // provider, which will be used to handle requests from the web service endpoint.
        BaseWebServiceEndpoint providerImpl =
                      providerFactory.createProvider(metaData, wsdlRef, cl,
                              null, ExampleWebServiceFactory.class);


 

The WebServiceProviderGenerator creates a JAX-WS class. When that class is instantiated, it uses an annotation to retrieve the web service factory class details (ExampleWebServiceFactory in this case), and request the service provider from the factory. In this example, the ExampleWebServiceFactory returns an instance of the ExampleWebService class, which simply returns a fault to any request it receives, as well as displaying a message to the console.

 

 

 

Step 2 - Build the Web Service archive, ready for deployment

 

        ServerConfig serverConfig=ServerConfigFactory.getServerConfig();
        
        File warArchive = new DeploymentBuilder(serverConfig)
                    .setEndpoint(metaData.getEndpointId())
                    .setWSDL(wsdlFile, root)
                    .setProvider(providerImpl)
                    .build();

 

The ServerConfig represents information specific to the target platform, such as tmp folder location, host bind address, etc.

 

The DeploymentBuilder is used to incrementally create the WAR file with the artifacts associated with the web service to be deployed. If additional processing of the war is required, then the interface org.jboss.soa.dsp.ws.BuildProcessor can be implemented to modify the war contents as appropriate.

 

For example, when deploying a web service into JBoss, with a jboss-cxf.xml file contained within its set of artifacts being deployed, then an additional build processor can be provided to process the xml file and define the name of the provider class.

 

 

Step 3 - Deploy the Web Service to the target platform

 

 

        URL serviceUrl = new WSDLParser(wsdlRef.getDefinition()).
                         getServiceLocationURL(metaData.getServiceName(),
                                metaData.getPortName());

        ServiceDeployer deployer=new JBossServiceDeployer();
        
        ServiceEndpointReference ref=deployer.deploy(metaData, providerImpl.getClass(),
                                      serviceUrl, cl, warArchive);
        
        return(ref);
}

 

 

NOTE: Currently this code instantiates the JBoss specific service deployer directly. This can be handled through some configuration mechanism, to make the example platform independent.

 

 

The Example

 

Deploying the DSP Example Deployer

 

Check out the source code from the dsp module in the RiftSaw subversion repository. There are now two ways to deploy the example:

 

1) Build with maven and deploy war to server

 

From the root folder, type:

 

     mvn clean install

 

This will build all of the modules, including the samples. Then change directory to samples/deployer/target and copy the dsp-example-deployer.war into the deploy folder of your JBossAS server environment.

 

2) Import example into Eclipse and deploy using WTP framework

 

Start your Eclipse environment, and select "Import->General->Existing Projects into Workspace" and browse for the root directory in the samples folder.

 

Once the dsp-example-deployer example has been added to the Eclipse project explorer, start a JBoss server from the Servers view (this would need to be setup in advance). When the server has started, then select the "Add and Remove ..." menu item associated with the server instance in the Servers view. Then select the dsp-example-deployer entry and press the Finish button.

 

 

 

When the war has been deployed, it will show up in the console as:

 

18:09:27,855 INFO  [TomcatDeployment] deploy, ctxPath=/dsp-deployer-example

 

 

Uploading an Example 'deployment' with wsdl

 

There are two example deployments attached to this article. They are both based on the RiftSaw quickstart hello_world example.

 

The hello_world.zip file is a flat structure, with the wsdl and two other files (bpel and deployment descriptor) that are not actually important - but included to demonstrate how other artifacts are dealt with.

 

The hello_world_sub.zip has the same files, except the two additional files are stored in a sub-folder (called sub).

 

Once the war, created in the previous step, has been deployed to the server, navigate to the main page located at: http://localhost:8080/dsp-example-deployer

 

This should display a simple form requesting a file to be uploaded. This needs to be a zip file that contains a wsdl definition. Initially just use the hello_world.zip attached to this article.

 

 

18:13:21,316 INFO  [STDOUT]         unzipping deploy.xml<br>
18:13:21,318 INFO  [STDOUT]         unzipping HelloWorld.bpel<br>
18:13:21,319 INFO  [STDOUT]         unzipping HelloWorld.wsdl<br>
18:13:21,357 INFO  [STDOUT] Retrieving document at '/home/gbrown/dev/riftsaw/workspace/.metadata/.plugins/org.jboss.ide.eclipse.as.core/JBoss_5.1_Runtime_Server1286274444071/deploy/dsp-deployer-example.war/files/hello_world/HelloWorld.wsdl'.
18:13:21,369 INFO  [STDOUT] SERVICE=Service: name={http://www.jboss.org/bpel/examples/wsdl}HelloService
Port: name=HelloPort
<snip>
locationURI=http://localhost:8080/Quickstart_bpel_hello_worldWS
18:13:21,390 INFO  [STDOUT] PROVIDER=org.jboss.soa.dsp.ws.generated.WebServiceEndpoint_8a387d8b-37ac-4b0e-b0c4-203b9ddbf4ee@fea133
18:13:21,443 INFO  [STDOUT] War Archive=/home/gbrown/NotBackedUp/testing/riftsaw/current/jboss-5.1.0.GA/server/default/tmp/dsp/dsp-8a387d8b-37ac-4b0e-b0c4-203b9ddbf4ee.war
18:13:21,447 INFO  [STDOUT] Service URL=http://localhost:8080/Quickstart_bpel_hello_worldWS
18:13:22,029 WARN  [WSDL11Reader] UsingAddressing extensibility element not supported yet.
18:13:22,117 INFO  [WSDLFilePublisher] WSDL published to: file:/home/gbrown/NotBackedUp/testing/riftsaw/current/jboss-5.1.0.GA/server/default/data/wsdl/dsp-8a387d8b-37ac-4b0e-b0c4-203b9ddbf4ee.war/HelloWorld.wsdl
18:13:22,142 INFO  [DefaultEndpointRegistry] register: jboss.ws:context=Quickstart_bpel_hello_worldWS,endpoint=Endpoint-8a387d8b-37ac-4b0e-b0c4-203b9ddbf4ee
18:13:22,156 INFO  [TomcatDeployment] deploy, ctxPath=/Quickstart_bpel_hello_worldWS
18:13:22,200 WARNING [config] Unable to process deployment descriptor for context '/Quickstart_bpel_hello_worldWS'
18:13:22,200 INFO  [config] Initializing Mojarra (1.2_12-b01-FCS) for context '/Quickstart_bpel_hello_worldWS'
18:13:22,256 INFO  [STDOUT] DEPLOYED endpoint ref=org.jboss.soa.dsp.ServiceEndpointReference@c7bf1752

 

This output includes messages printed to the console at different stages through the deployment steps. So it shows the PROVIDER, the War Archive and the DEPLOYED endpoint information.

 

 

Invoking the Example Sevice Provider via the provided WSDL

 

The final step is to use a Web Service client to invoke the dynamically deployed web service. For example, SOAPUI can be used to send the following message to http://127.0.0.1:8080/Quickstart_bpel_hello_worldWS:

 

 

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsdl="http://www.jboss.org/bpel/examples/wsdl">
   <soapenv:Header/>
   <soapenv:Body>
      <wsdl:hello>
         <TestPart>Hello DSP</TestPart>
      </wsdl:hello>
   </soapenv:Body>
</soapenv:Envelope>

 

This will result in the following response:

 

 

<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
   <env:Header/>
   <env:Body>
      <env:Fault>
         <faultcode xmlns:valueNS="http://www.example.org">valueNS:ExampleFault</faultcode>
      </env:Fault>
   </env:Body>
</env:Envelope>

 

with the following displayed on the JBossAS console:

 

18:21:51,508 INFO  [STDOUT] Retrieving document at 'file:/home/gbrown/dev/riftsaw/workspace/.metadata/.plugins/org.jboss.ide.eclipse.as.core/JBoss_5.1_Runtime_Server1286274444071/deploy/dsp-deployer-example.war/files/hello_world/HelloWorld.wsdl'.
18:21:51,521 INFO  [STDOUT] EXAMPLE SERVICE PROVIDER: invoke org.jboss.soa.dsp.ws.WSInvocationAdapter@163c0d3

 

This fault response is produced by the ExampleServiceProvider:

 

 

public class ExampleServiceProvider implements ServiceProvider {

    public void invoke(InvocationAdapter<?> arg0) throws Exception {
        System.out.println("EXAMPLE SERVICE PROVIDER: invoke "+arg0);
        
        arg0.createFault(null, new QName("http://www.example.org", "ExampleFault"),
                        new MessageAdapter() {

                            public Map<String, Node> getHeaderParts() {
                                return new HashMap<String,Node>();
                            }

                            public Element getMessage() {
                                Element ret=null;
                                
                                try {
                                    ret = javax.xml.parsers.DocumentBuilderFactory.newInstance().
                                        newDocumentBuilder().newDocument().createElement("ExampleFaultDetails");
                                } catch(Exception e) {
                                    e.printStackTrace();
                                }
                                
                                return(ret);
                            }

                            public Element getPart(String arg0) {
                                return null;
                            }

                            public void setHeaderPart(String arg0, Element arg1) {
                            }

                            public void setPart(String arg0, Element arg1) {
                            }
            
        });
    }
}