30 Programming Web Services Using XML Over HTTP

This chapter describes how to program Web services using XML over HTTP.

This chapter includes the following sections:

About Programming Web Services Using XML Over HTTP

In addition to standard "SOAP over HTTP" use cases, WebLogic JAX-WS can also be used for some "XML over HTTP" Web services. Use of the XML over HTTP style allows you to build simple RESTful Web services while still leveraging the convenience of the JAX-WS programming model.

Note:

As a best practice, it is recommended that you develop RESTful Web services using the Jersey JAX-RS RI, as described in Developing and Securing RESTful Web Services for Oracle WebLogic Server. The Jersey JAX-RS RI provides an open source, production quality RI for building RESTful Web services and supports all of the HTTP methods.

When using the HTTP protocol to access Web service resources, the resource identifier is the URL of the resource and the standard operation to be performed on that resource is one of the HTTP methods: GET, PUT, DELETE, POST, or HEAD.

Note:

In this JAX-WS implementation, the set of supported HTTP methods is limited to GET and POST. DELETE, PUT, and HEAD are not supported. Any HTTP requests containing these methods will be rejected with a 405 Method Not Allowed error.

If the functionality of PUT and DELETE are required, the desired action can be accomplished by tunneling the actual method to be executed on the POST method. This is a workaround referred to as overloaded POST. (A Web search on "REST overloaded POST" will return a number of ways to accomplish this.

You build RESTful-like endpoints using the invoke() method of the javax.xml.ws.Provider<T> interface (see http://docs.oracle.com/javaee/6/api/javax/xml/ws/Provider.html). The Provider interface provides a dynamic alternative to building an service endpoint interface (SEI).

The procedure in this section describes how to program and compile the JWS file required to implement Web services using XML over HTTP. The procedure shows how to create the JWS file from scratch; if you want to update an existing JWS file, you can also use this procedure as a guide.

It is assumed that you have set up an Ant-based development environment and that you have a working build.xml file to which you can add targets for running the jwsc Ant task and deploying the Web services. For more information, see Chapter 3, "Developing JAX-WS Web Services."

Table 30-1 Steps to Program RESTful Web Services

#
Step Description

1

Create a new JWS file, or update an existing one, that implements the Web service using XML over HTTP.

Use your favorite IDE or text editor. See Programming Guidelines for the Web Service Using XML Over HTTP.

2

Update your build.xml file to include a call to the jwsc Ant task to compile the JWS file into a Web service.

For example:

   <jwsc srcdir="." destdir="output/restEar">
      <jws file="NearbyCity.java" type="JAXWS"/>
    </jwsc>

For more information, see Running the jwsc WebLogic Web Services Ant Task.

3

Run the Ant target to build the Web service.

For example:

prompt> ant build-rest

4

Deploy the Web service as usual.

See Deploying and Undeploying WebLogic Web Services.

5

Access the Web service from your Web service client.

See Accessing the Web Service from a Client.


Programming Guidelines for the Web Service Using XML Over HTTP

The following example shows a simple JWS file that implements a Web service using XML over HTTP; see the explanation after the example for coding guidelines that correspond to the Java code in bold.

package examples.webservices.jaxws.rest;
import javax.xml.ws.WebServiceProvider;
import javax.xml.ws.BindingType;
import javax.xml.ws.Provider; 
import javax.xml.ws.WebServiceContext;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.http.HTTPBinding;
import javax.xml.ws.http.HTTPException;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import javax.annotation.Resource;
import java.io.ByteArrayInputStream;
import java.util.StringTokenizer;

@WebServiceProvider(
   targetNamespace="http://example.org",
   serviceName = "NearbyCityService")
@BindingType(value = HTTPBinding.HTTP_BINDING) 

public class NearbyCity implements Provider<Source> { 
  @Resource(type=Object.class)
  protected WebServiceContext wsContext;

  public Source invoke(Source source)  { 
    try {
        MessageContext messageContext = wsContext.getMessageContext();

        // Obtain the HTTP mehtod of the input request.
        javax.servlet.http.HttpServletRequest servletRequest = 
          (javax.servlet.http.HttpServletRequest)messageContext.get(
           MessageContext.SERVLET_REQUEST);
        String httpMethod = servletRequest.getMethod();
        if (httpMethod.equalsIgnoreCase("GET"));
        {

            String query =
                 (String)messageContext.get(MessageContext.QUERY_STRING); 
            if (query != null && query.contains("lat=") &&
                query.contains("long=")) {
                return createSource(query); 
            } else {
                System.err.println("Query String = "+query);
                throw new HTTPException(404);
            }
            } catch(Exception e) {
              e.printStackTrace();
              throw new HTTPException(500);
            }
        }
        } else {
   // This operation only supports "GET"
       throw new HTTPException405);
   }
    private Source createSource(String str) throws Exception {
        StringTokenizer st = new StringTokenizer(str, "=&/");
        String latLong = st.nextToken();
        double latitude = Double.parseDouble(st.nextToken());
        latLong = st.nextToken();
        double longitude = Double.parseDouble(st.nextToken());
        City nearby = City.findNearBy(latitude, longitude);
        String body = nearby.toXML();
        return new StreamSource(new ByteArrayInputStream(body.getBytes()));
    }

    static class City {
         String city;
         String state;
         double latitude;
         double longitude;
         City(String city, double lati, double longi, String st) {
             this.city = city;
             this.state = st;
             this.latitude = lati;
             this.longitude = longi;
         }

         double distance(double lati, double longi) {
            return Math.sqrt((lati-this.latitude)*(lati-this.latitude) + 
                (longi-this.longitude)*(longi-this.longitude)) ;
         }

         static final City[] cities = {
            new City("San Francisco",37.7749295,-122.4194155,"CA"),
            new City("Columbus",39.9611755,-82.9987942,"OH"),
            new City("Indianapolis",39.7683765,-86.1580423,"IN"),
            new City("Jacksonville",30.3321838,-81.655651,"FL"),
            new City("San Jose",37.3393857,-121.8949555,"CA"),
            new City("Detroit",42.331427,-83.0457538,"MI"),
            new City("Dallas",32.7830556,-96.8066667,"TX"),
            new City("San Diego",32.7153292,-117.1572551,"CA"),
            new City("San Antonio",29.4241219,-98.4936282,"TX"),
            new City("Phoenix",33.4483771,-112.0740373,"AZ"),
            new City("Philadelphia",39.952335,-75.163789,"PA"),
            new City("Houston",29.7632836,-95.3632715,"TX"),
            new City("Chicago",41.850033,-87.6500523,"IL"),
            new City("Los Angeles",34.0522342,-118.2436849,"CA"),
            new City("New York",40.7142691,-74.0059729,"NY")};
        static City findNearBy(double lati, double longi) {
            int n = 0;
            for (int i = 1; i < cities.length; i++)  {
                if (cities[i].distance(lati, longi) <  
                     cities[n].distance(lati, longi)) {
                    n = i;
                }
            }
            return cities[n];
        }

        public String toXML() {
             return "<ns:NearbyCity xmlns:ns=\"http://example.org\"><City>"
                  +this.city+"</City><State>"+ this.state+"</State><Lat>"
                  +this.latitude +
                  "</Lat><Lng>"+this.longitude+"</Lng></ns:NearbyCity>";
        }
    }
}

Follow these guidelines when programming the JWS file that implements the Web service using XML over HTTP. Code snippets of the guidelines are shown in bold in the preceding example.

  • Import the packages required to implement the Provider Web service.

    import javax.xml.ws.WebServiceProvider;
    import javax.xml.ws.BindingType;
    import javax.xml.ws.Provider;
    
  • Annotate the Provider implementation class and set the binding type to HTTP.

    @WebServiceProvider(
       targetNamespace="http://example.org",
       serviceName = "NearbyCityService")
    @BindingType(value = HTTPBinding.HTTP_BINDING)
    
  • Implement the invoke() method of the Provider interface.

    public class NearbyCity implements Provider<Source> {
      @Resource(type=Object.class)
      protected WebServiceContext wsContext;
    
      public Source invoke(Source source)  {
      ...
      }
    
  • Get the request string using the QUERY_STRING field in the javax.xml.ws.handler.MessageContext for processing (see message URL http://docs.oracle.com/javaee/6/api/javax/xml/ws/handler/MessageContext.html). The query string is then passed to the createSource() method that returns the city, state, longitude, and latitude that is closest to the specified values.

    String query =
                 (String)messageContext.get(MessageContext.QUERY_STRING); 
    .
    .
    .
    return createSource(query);
    

Accessing the Web Service from a Client

To access the Web service from a Web service client, use the resource URI. For example:

URL url = new URL (http://localhost:7001/NearbyCity/NearbyCityService?lat=35&long=-120);
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
connection.setRequestMethod("POST");
// Get result
InputStream is = connection.getInputStream();

In this example, you set the latitude (lat) and longitude (long) values, as required, to access the required resource.

Securing Web Services that Use XML Over HTTP

You can secure Web services that use XML over HTTP using the same methods that you use to secure Web applications. For more information, see "Options for Securing Web Application and EJB Resources" inSecuring Resources Using Roles and Policies for Oracle WebLogic Server.