Understanding your JAX-RPC SI Environment, Part 2


by Arun Gupta
Feb 2004

The first part in this series explained the power of the wscompile and wsdeploy tools and the configuration files used by these tools.

This is the second, and the last, part of the series and explains the most common scenarios that you may encounter during the Web Service develop, deploy and invoke cycle and how to achieve them using the wscompile and wsdeploy tools. Figure 1 shows the five common scenarios which are explained in detail below.

 

Scenario # Have Need
Scenario 1 Service endpoint interface and its implementation To deploy the service and expose doc/lit (or rpc/lit or rpc/enc) WSDL; WS-I compliant Web Service
Scenario 2 URL to the WSDL Client to invoke the service using static stubs; Populate header values from the client
Scenario 3 URL to the WSDL Client to invoke the service using Dynamic Proxy
Scenario 4 URL to the WSDL Client to invoke the service using a Dynamic Invocation Interface (DII)
Scenario 5 URL to the WSDL To publish your own service; Expose the same WSDL in your deployed Web Service

Let's examine these use cases and see how the wscompile and wsdeploy tools are used in each case. Each use case may define one or more alternatives that achieves a slightly different purpose.

The files used in the examples are given below:

The source code is available for download

Scenario 1: Service Endpoint Interface - Server

Purpose: Starting with a service endpoint interface and service implementation class, deploy the service and expose a doc/lit (rpc/lit or rpc/enc) WSDL.

  1. Compile the service endpoint interface and service endpoint implementation classes.
  2. Generate a model file using wscompile. Since wscompile expects one of the import, define or gen modes to be specified, use the -define switch as the primary mode and use the -model switch to enable model generation. To ensure that document/literal WSDL is generated, use the -f:documentliteral switch. The command is given below:

    wscompile -define -f:documentliteral -d build/classes -classpath build/classes -model model.xml.gz config.xml

    where config.xml is the tool configuration file starting from a service endpoint interface. Here is what the configuration file will look like:

    <?xml version="1.0" encoding="UTF-8"?>
    <configuration xmlns="
    http://java.sun.com/xml/ns/jax-rpc/ri/config">
        <service name="
    StockQuoteService"
            targetNamespace="
    http://stockquote.org/wsdl"
            typeNamespace="
    http://stockquote.org/types"
            packageName="
    com.example">
            <interface name="
    com.example.StockQuoteProvider"
                servantName="
    com.example.StockQuoteImpl"/>
        </service>
    </configuration>


    Since -define mode is used, this will generate a WSDL with the name identified by the service{name} attribute in config.xml, StockQuoteService.wsdl in this case. This WSDL is a preview of what will be generated at deployment time later by wsdeploy and available as part of the cooked WAR file.

    -d build/classes ensures that .class files are generated in build/classes directory

    -gen mode can be used here instead of -define mode, but using -define mode delays the generation of non-portable artifacts to the deployment stage. Specifying the -model switch captures all the information about the service, including the switches mentioned during the wscompile stage, in the model.
  3. Package service endpoint interface, service endpoint implementation, associated value types, generated model file and deployment descriptor in WAR format, called as raw WAR. Thus StockQuoteProvider, InvalidTickerException and StockQuoteImpl classes in the com.example package, model.xml.gz generated in the previous step and the deployment descriptor are bundled together to make a raw WAR file. The deployment descriptor used in this case is given below:

    <?xml version="1.0" encoding="UTF-8"?>
    <webServices
        xmlns="
    http://java.sun.com/xml/ns/jax-rpc/ri/dd"
        version="
    1.0"
        targetNamespaceBase="
    http://java.sun.com/xml/ns/jax-rpc/wsi/wsdl"
        typeNamespaceBase="
    http://java.sun.com/xml/ns/jax-rpc/wsi/types"
        urlPatternBase="
    /ws">

            <endpoint
                name="
    example"
                displayName="
    Stock Example"
                description="
    Stock Example Web Service endpoint"
                interface="
    com.example.StockQuoteProvider"
                implementation="
    com.example.StockQuoteImpl"
                model="
    /WEB-INF/model.xml.gz"/>

            <endpointMapping
                endpointName="
    example"
                urlPattern="
    /example"/>

    </webServices>


    The location of the model file is specified in the endpointType{model} attribute of the deployment descriptor. All the switches specified during the wscompile stage are stored as part of the model and thus available to the wsdeploy tool for further processing.

    The structure of the raw WAR file is shown below:
     

  4. Generate the cooked WAR file using wsdeploy. The command is:

    wsdeploy -o stock.war stock-raw.war

    where stock-raw.war is the name of the raw WAR file generated in the previous step. wsdeploy processes the model specified in the deployment descriptor, generating one internally if it does not exist, and then generates various implementation-specific artifacts such as ties, serializers, and runtime descriptor from the model, along with the document/literal WSDL. The tool then packages all the artifacts into a cooked WAR file, named stock.war. This cooked WAR file can be deployed in a web container and the endpoint can be accessed at http://<host>:<port>/stock/<url-pattern> where <url-pattern> matches the endpointMappingType{urlPattern} attribute in jaxrpc-ri.xml (http://localhost:8080/stock/example in this case). The structure of the cooked WAR file is shown below:



    wsdeploy processes the deployment descriptor and web.xml bundled with the raw WAR file and generates a new runtime descriptor, jaxrpc-ri-runtime.xml, and web.xml for the cooked WAR file. It also bundles the original jaxrpc-ri.xml and web.xml files (provided with the raw WAR file) in the cooked WAR file as jaxrpc-ri-before.xml and web-before.xml. The new runtime descriptor and web.xml are used by the JAX-RPC runtime for dispatching the request to the appropriate tie/implementation combination.

    StockQuoteProvider_Tie is the generated tie class. InvalidTickerException, StockQuoteImpl, StockQuoteInfo and StockQuoteProvider are copied over from the raw WAR file. All other classes in the cooked WAR file are used for the serialization and deserialization of request and response messages.

    A document/ literal WSDL is generated and can be accessed by appending ?WSDL to the endpoint address. The name of the WSDL is chosen from the <service> element's name specified in config.xml. The default behavior of the wsdeploy tool is to generate a rpc/encoded WSDL. However since -f:documentliteral switch specified during the wscompile stage is passed to wsdeploy through the model, it generates a document/ literal WSDL instead of rpc/encoded. 

Alt-1: To expose an rpc/literal WSDL instead, just change the -f:documentliteral switch to -f:rpcliteral and a rpc/literal WSDL is generated.

Alt-2: To expose a rpc/encoded WSDL instead, do not specify -f:documentliteral switch and a default rpc/encoded WSDL is generated.

Alt-3: To generate a WS-I compliant Web Service, add -f:wsi switch along with -f:documentliteral or -f:rpcliteral.

 

Scenario 2: WSDL - Static Stubs Client

Purpose: Starting with a WSDL, invoke the service using static stubs.

  1. Start with a WSDL-based wscompile configuration file and specify the location of the WSDL file. The configuration file is given below:

    <configuration xmlns="http://java.sun.com/xml/ns/jax-rpc/ri/config">
        <wsdl
            location="./
    StockQuoteService.wsdl"
            packageName="
    com.example"/>
    </configuration>

    where wsdl{location} specifies the location of the WSDL (in this case it is residing in the current working directory). wscompile is instructed to generate the artifacts in the com.example package.
  2. Generate client-side artifacts using the -gen mode of wscompile. The command looks like:

    wscompile -gen:client -d build/classes config.xml

    where config.xml is the tool configuration file starting from a WSDL file. -gen:client enables the generation of client-side artifacts. All the .class files are generated in the build/classes directory. If the wsdl{location} attribute refers to a WSDL located on Internet, then the -httpproxy option may need to be specified if you are behind a firewall. The command in this case is:

    wscompile -gen:client -d classes -httpproxy:<host>:<port> config.xml

    The proxy port is optional and defaults to 8080. StockQuoteService.wsdl is exposed at the URL given above in the configuration file and the list of generated artifacts is shown below:

     

    The StockQuoteService_Impl class is of particular interest as it has an accessor for each of the ports exposed by the WSDL (as defined by section 4.3.11 of the JAX-RPC 1.1 specification). This generated service interface is used for the creation of instances of the generated stub classes in the client code.

    StockQuoteProvider is the generated service endpoint interface mapped from the port in the WSDL. InvalidTickerException and StockQuoteInfo are classes used by the service endpoint interface. StockQuoteProviderPort_Stub is the generated stub class. Other classes are used by JAX-RPC runtime for serialization and de-serialization of SOAP request and response messages.
  3. Use the generated StockQuoteService_Impl class to obtain a reference to the StockQuoteProvider and invoke the Web Service. Here is what the client code looks like:

    package com.example;

    ...

    StockQuoteProvider port = (new StockQuoteService_Impl()).getStockQuoteProviderPort();
    float tradePrice = port.getLastTradePrice("SUNW");


    If the WSDL has the correct endpoint address mentioned for port StockQuoteProviderPort in the WSDL, then wscompile generates pre-configured stubs (i.e. stubs that have their endpoint address correctly set). Otherwise, you need to explicitly set the endpoint address in the generated stubs:

    import javax.xml.rpc.Stub;

    ...

    StockQuoteProvider port = (new StockQuoteService_Impl()).getStockQuoteProviderPort();
    ((Stub)port)._setProperty(Stub.ENDPOINT_ADDRESS_PROPERTY, YOUR_ENDPOINT_ADDRESS);
    float tradePrice = port.getLastTradePrice("SUNW");

    where YOUR_ENDPOINT_ADDRESS is the correct value of the endpoint address.

Alt-1: If the same WSDL is exposed by another endpoint, then you can reuse the generated artifacts and client and set the endpoint address in the client accordingly.

Alt-2: If the Web Service invocation requires header information to be populated from the client-side, then specify -f:explicitcontext feature when generating the client-side artifacts. Each of the headers will then be added as a parameter in the method signature. Values stored in these parameters are passed in SOAP headers. 

 

Scenario 3: WSDL - Dynamic Proxy Client

Purpose: Starting with a WSDL file, invoke the service using dynamic proxy.

This invocation mode should be used when the WSDL contains primitive schema types only. It is recommended to use the static stubs programming model (scenario 2) if schema types other than primitive types are used in the WSDL file.

Dynamic Proxy client supports a service endpoint interface dynamically at runtime without requiring any code generation of a stub class that implements a specific service endpoint interface. The client gets information about the service by looking up its WSDL document. Refer to section 8.2.3 of JAX-RPC 1.1 specification for more details.

Refer to Java Web Services Developer Pack tutorial for an example on how to invoke the service using a dynamic proxy.

 

Scenario 4: WSDL - DII Client

Purpose: Starting with a WSDL file, invoke the service using Dynamic Invocation Interface.

This invocation mode should be used when the WSDL contains primitive schema types only. It is recommended to use the static stubs programming model (scenario 2) if schema types other than primitive types are used in the WSDL file.

DII Client provides support for the dynamic invocation of an operation on the target service endpoint. A client can call a remote procedure even if the signature of the remote procedure or the name of the service are unknown until runtime. Refer to section 8.2.4 of JAX-RPC 1.1 specification for more details.

Refer to Java Web Services Developer Pack tutorial for an example on how to invoke the service using DII.

 

Scenario 5: WSDL - Server

Purpose: Starting with a WSDL file, publish your own service.

  1. Start with a WSDL-based tool configuration file and specify the location of the WSDL file in the configuration file. The configuration file is given below:

    <configuration xmlns="http://java.sun.com/xml/ns/jax-rpc/ri/config">
        <wsdl
            location="http://example.com/stock?WSDL"
            packageName="
    com.example" />
    </configuration>

    where wsdl{location} attribute's value (http://example.com/stock?WSDL in this case) specifies the location of the WSDL. The tool is instructed to generate artifacts in the com.example package. 
  2. Import the WSDL to the generate service endpoint interface and value types. The command is:

    wscompile -import -d build/classes -keep -s build/src -model build/model.xml.gz config.xml

    -keep ensures that all generated .java files are stored.
    -d build/classes ensures that .class files are generated in the build/classes directory.
    -s build/src ensures that generated .java  files are copied to the build/src directory.
    -model switch generates model file in build/model.xml.gz file.

    StockQuoteService.wsdl is exposed at the URL given above in the configuration file and the list of generated artifacts is shown below:



    StockQuoteProvider is the generated service endpoint interface, StockQuoteInfo is the value type used within the interface, and StockQuoteProvider_Impl is a template implementation class which may be used as the base class for the service endpoint implementation class. StockQuoteService.java is the generated service interface used for the creation of instances of generated stub classes. A concrete implementation of this class is generated if -gen:client mode is used instead of -import. GetXXX.java are convenience classes used by the stub for serialization of input and output messages described in the WSDL.
  3. Code the service endpoint implementation using the service endpoint interface, StockQuoteProvider.java, and value types, if any, generated in the previous step. 
  4. Now that both the service endpoint interface and service endpoint implementation are available, follow step 3 in scenario 1 to generate the raw WAR. This is what the deployment descriptor looks like: 

    <?xml version="1.0" encoding="UTF-8"?>
    <webServices
        xmlns="
    http://java.sun.com/xml/ns/jax-rpc/ri/dd"
        version="
    1.0"
        targetNamespaceBase="
    http://java.sun.com/xml/ns/jax-rpc/wsi/wsdl"
        typeNamespaceBase="
    http://java.sun.com/xml/ns/jax-rpc/wsi/types"
        urlPatternBase="
    /ws">

            <endpoint
                name="
    example"
                displayName="
    Stock Example"
                description="
    Stock Example Web Service endpoint"
                interface="
    com.example.StockQuoteProvider"
                implementation="
    com.example.StockQuoteImpl"
                model="
    /WEB-INF/model.xml.gz"
                wsdl="
    /WEB-INF/StockQuoteService.wsdl"/>

            <endpointMapping
                endpointName="
    example"
                urlPattern="
    /example"/>

    </webServices>


    Note, webServices{wsdl} attribute specifies the location of the WSDL and webServices{model} attribute specifies the location of the model file in the raw WAR file. The structure of the raw WAR file is shown below:


  5. Follow step 4 of scenario 1 to generate the cooked WAR. Since the WSDL is pre-bundled with the raw WAR file and the runtime descriptor refers to this WSDL, wsdeploy patches the runtime descriptor, jaxrpc-ri-runtime.xml, with the already existing WSDL file. The structure of the cooked WAR file is shown below:


    Note that the model and WSDL files in the raw WAR file are copied to the cooked WAR file.

    GetLastTradePrice
    , GetLastTradePriceResponse, GetStockQuote, GetStockQuoteResponse, InvalidTickerException, StockQuoteImpl, StockQuoteInfo, StockQuoteProvider, StockQuoteProvider_Impl and StockQuoteService are copied over the from raw WAR file. StockQuoteProvider_Tie is the generated tie class. All other classes are used for the serialization and deserialization of request and response messages.

    wsdeploy processes the deployment descriptor and web.xml files bundled with the raw WAR file and generates a new runtime descriptor, jaxrpc-ri-runtime.xml, and web.xml for the cooked WAR file. It also bundles the original jaxrpc-ri.xml and web.xml (provided with the raw WAR file) in the cooked WAR file as jaxrpc-ri-before.xml and web-before.xml. The new runtime descriptor and web.xml are used by the JAX-RPC runtime for dispatching the request to the appropriate tie/implementation combination.

 

Glossary

Artifact
is a Java class, a WSDL file, a model file, or any other file generated by wscompile or wsdeploy.
cooked WAR
A WAR file, generated by wsdeploy, that can be deployed on a servlet 2.3 container and exposes one or more JAX-RPC based Web Services.
Dynamic Proxy Client
supports a service endpoint interface dynamically at runtime without requiring any code generation of a stub class that implements a specific service endpoint interface. The client gets information about the service by looking up its WSDL document. Refer to section 8.2.3 of JAX-RPC 1.1 specification for more details.
DII Client
provides support for the dynamic invocation of an operation on the target service endpoint. A client can call a remote procedure even if the signature of the remote procedure or the name of the service are unknown until runtime. Refer to section 8.2.4 of JAX-RPC 1.1 specification for more details.
implementation-specific
Specific to a JAX-RPC implementation and not recommended by the specification. Such features bind your application to a specific JAX-RPC implementation only and may make it non-portable. Also known as non-portable artifacts.
Java Web Services Developer Pack
The Java Web Services Developer Pack (Java WSDP) is a free integrated toolkit you can use to build, test and deploy XML applications, Web Services, and Web applications with the latest Web Service technologies and standards implementations.
Model
Model is a JAX-RPC SI specific representation of a Web Service endpoint or client, generated from wscompile, and generally available as a .xml.gz file. It stores all the information in terms of internal data structures that allows easier generation of implementation-specific artifacts. Since wsdeploy supports only a limited set of switches, most of the switches specified during the wscompile stage are stored as part of the model.
Non-portable artifacts
Artifacts with an undefined mapping in JAX-RPC specification such that if multiple implementations of JAX-RPC generate them, they may not look same such as stubs, ties, and serializers. Also known as implementation-specific artifacts.
Portable artifacts
Artifacts with a well-defined mapping in JAX-RPC specification such that if multiple implementations of JAX-RPC generate them, they will look same such as service endpoint interface, value types, and exception classes.
raw WAR
A WAR file containing portable and/or non-portable artifacts generated by wscompile bundled along with a deployment descriptor. Serves as an input to wsdeploy.
wscompile
Tool provided by JAX-RPC SI bundled along with Java Web Services Developer Pack to allow generation of various artifacts required by the JAX-RPC specification and other implementation-specific artifacts required to develop/deploy/invoke a Web Service.
wsdeploy
Tool provided by JAX-RPC SI bundled along with Java Web Services Developer Pack to process a raw WAR into a cooked WAR file.
 

References

  1. Understanding your JAX-RPC SI Environment, Part 1
  2. Java APIs for XML-based RPC
  3. Java Web Services Developer Pack
  4. Java WSDP Tutorial
  5. Building Web Services with JAX-RPC
  6. JAX-RPC Tools 
  7. SOAP Message Handlers Example
  8. Dynamic Proxy Example
  9. DII Example

About the author

Arun Gupta is a Staff Engineer in the Java APIs for XML-based RPC (JAX-RPC) development team at Sun Microsystems. Arun has over seven years of experience in the software industry, working in various  distributed computing technologies, JavaTM platform, C++, and various web-related technologies. In his current role, Arun is part of the JAX-RPC development team and represents Sun in WS-I Sample Application Working Group. He has been with the JAX-RPC group since its inception and has been a significant contributor in evolving the technology.

JAX-RPC team at Sun Microsystems has provided invaluable input to this white paper.

Send feedback to users@jax-rpc.dev.java.net.