12 Using Callbacks to Notify Clients of Events

This chapter describes how to callbacks with WebLogic Java API for XML-based RPC (JAX-RPC) web services to notify clients of events.

This chapter includes the following sections:

Overview of Callbacks

Callbacks notify a client of your web service that some event has occurred. For example, you can notify a client when the results of that client's request are ready, or when the client's request cannot be fulfilled.

When you expose a method as a standard public operation in your JWS file (by using the @WebMethod annotation), the client sends a SOAP message to the web service to invoke the operation. When you add a callback to a web service, however, you define a message that the web service sends back to the client web service, notifying the client of an event that has occurred. So exposing a method as a public operation and defining a callback are completely symmetrical processes, with opposite recipients.

WebLogic Server automatically routes the SOAP message from client invoke to the target web service. In order to receive callbacks, however, the client must be operating in an environment that provides the same services. This typically means the client is a web service running on a Web server. If the client does not meet these requirements, it is likely not capable of receiving callbacks from your web service.

The protocol and message format used for callbacks is always the same as the protocol and message format used by the conversation start method that initiated the current conversation. If you attempt to override the protocol or message format of a callback, an error is thrown.

Callback Implementation Overview and Terminology

To implement callbacks, you must create or update the following three Java files:

  • Callback interface: Java interface file that defines the callback methods. You do not explicitly implement this file yourself; rather, the jwsc Ant task automatically generates an implementation of the interface. The implementation simply passes a message from the target web service back to the client web service. The generated web service is deployed to the same WebLogic Server that hosts the client web service.

    In the example in this section, the callback interface is called CallbackInterface. The interface defines a single callback method called callbackOperation().

  • JWS file that implements the target web service: The target web service includes one or more standard operations that invoke a method defined in the callback interface; this method in turn sends a message back to the client web service that originally invoked the operation of the target web service.

    In the example, this web service is called TargetService and it defines a single standard method called targetOperation().

  • JWS file that implements the client web service: The client web service invokes an operation of the target web service. This web service includes one or more methods that specify what the client should do when it receives a callback message back from the target web service via a callback method.

    In the example, this web service is called CallbackClient and the method that is automatically invoked when it receives a callback is called callbackHandler(). The method that invokes TargetService in the standard way is called clientOperation().

The following graphic shows the flow of messages:

Description of message_flow.gif follows
Description of the illustration ''message_flow.gif''

  1. The clientOperation() method of the CallbackClient web service, running in one WebLogic Server instance, explicitly invokes the targetOperation() operation of the TargetService. The TargetService service might be running in a separate WebLogic Server instance.

  2. The implementation of the TargetService.targetOperation() method explicitly invokes the callbackOperation() operation of the CallbackInterface, which implements the callback service. The callback service is deployed to the WebLogic Server which hosts the client web service.

  3. The jwsc-generated implementation of the CallbackInterface.callbackOperation() method simply sends a message back to the CallbackClient web service. The client web service includes a method callbackHandler() that handles this message.

Programming Callbacks: Main Steps

The procedure in this section describes how to program and compile the three JWS files that are required to implement callbacks: the target web service, the client web service, and the callback interface. The procedure shows how to create the JWS files from scratch; if you want to update existing JWS files, 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.

Table 12-1 Steps to Program Callbacks

#
Step Description

1

Create a new JWS file, or update an existing one, that implements the target web service.

Use your favorite IDE or text editor. See Programming Guidelines for Target Web Service.

Note: The JWS file that implements the target web service invokes one or more callback methods of the callback interface. However, the step that describes how to program the callback interface comes later in this procedure. For this reason, programmers typically program the three JWS files at the same time, rather than linearly as implied by this procedure. The steps are listed in this order for clarity only.

2

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

See "Running the jwsc WebLogic Web Services Ant Task".

3

Run the Ant target to build the target web service.

For example:

prompt> ant build-mainService

4

Deploy the target web service as usual.

See "Deploying and Undeploying WebLogic Web Services".

5

Create a new JWS file, or update an existing one, that implements the client web service.

It is assumed that the client web service is deployed to a different WebLogic Server instance from the one that hosts the target web service. See Programming Guidelines for the Callback Client Web Service.

6

Create the callback JWS interface that implements the callback web service.

See Programming Guidelines for the Callback Interface.

7

Update the build.xml file that builds the client web service.

The jwsc Ant task that builds the client web service also implicitly generates the callback web service from the callback interface file. See Updating the build.xml File for the Client Web Service.

8

Run the Ant target to build the client and callback web services.

For example:

prompt> ant build-clientService

9

Deploy the client web service as usual.

See "Deploying and Undeploying WebLogic Web Services".


Programming Guidelines for Target Web Service

The following example shows a simple JWS file that implements the target web service; see the explanation after the example for coding guidelines that correspond to the Java code in bold.

package examples.webservices.callback;

import weblogic.jws.WLHttpTransport;
import weblogic.jws.Callback; 

import javax.jws.WebService;
import javax.jws.WebMethod;

@WebService(name="CallbackPortType",
            serviceName="TargetService",
            targetNamespace="http://examples.org/")

@WLHttpTransport(contextPath="callback",
                 serviceUri="TargetService",
                 portName="TargetServicePort")

/**
 * callback service
 */

public class TargetServiceImpl {

  @Callback 
  CallbackInterface callback; 

  @WebMethod
  public void targetOperation (String message) {

        callback.callbackOperation (message); 
  }

}

Follow these guidelines when programming the JWS file that implements the target web service. Code snippets of the guidelines are shown in bold in the preceding example.

  • Import the required JWS annotations:

    import weblogic.jws.Callback;
    
  • Use the @weblogic.jws.Callback JWS annotation to specify that a variable is a callback, which means that you can use the annotated variable to send callback events back to a client web service that invokes an operation of the TargetService web service. The data type of the variable is the callback interface, which in this case is called CallbackInterface.

    @Callback
    CallbackInterface callback;
    
  • In a method that implements an operation of the TargetService, use the annotated variable to invoke one of the callback methods of the callback interface, which in this case is called callbackOperation():

    callback.callbackOperation (message);
    

See "JWS Annotation Reference" in WebLogic Web Services Reference for Oracle WebLogic Server for additional information about the WebLogic-specific JWS annotations discussed in this section.

Programming Guidelines for the Callback Client Web Service

The following example shows a simple JWS file for a client web service that invokes the target web service described in Programming Guidelines for Target Web Service; see the explanation after the example for coding guidelines that correspond to the Java code in bold.

package examples.webservices.callback;

import weblogic.jws.WLHttpTransport;
import weblogic.jws.ServiceClient; 
import weblogic.jws.CallbackMethod; 
import weblogic.jws.security.CallbackRolesAllowed; 
import weblogic.jws.security.SecurityRole; 

import javax.jws.WebService;
import javax.jws.WebMethod;

import examples.webservices.callback.CallbackPortType; 

import java.rmi.RemoteException;

@WebService(name="CallbackClientPortType",
            serviceName="CallbackClientService",
            targetNamespace="http://examples.org/")

@WLHttpTransport(contextPath="callbackClient",
                 serviceUri="CallbackClient",
                 portName="CallbackClientPort")

public class CallbackClientImpl {

  @ServiceClient( 
     wsdlLocation="http://localhost:7001/callback/TargetService?WSDL", 
     serviceName="TargetService", 
     portName="TargetServicePort") 
  @CallbackRolesAllowed(@SecurityRole(role="mgr", mapToPrincipals="joe")) 
  private CallbackPortType port; 

  @WebMethod
  public void clientOperation (String message) {

    try {

        port.targetOperation(message); 
    }
    catch (RemoteException e) {
      e.printStackTrace();
    }

  }
  @CallbackMethod(target="port", operation="callbackOperation") 
  @CallbackRolesAllowed(@SecurityRole(role="engineer",  mapToPrincipals="shackell")) 
  public void callbackHandler(String msg) { 

        System.out.println (msg); 
  } 

}

Follow these guidelines when programming the JWS file that invokes the target web service; code snippets of the guidelines are shown in bold in the preceding example:

  • Import the required JWS annotations:

    import weblogic.jws.ServiceClient;
    import weblogic.jws.CallbackMethod;
    
  • Optionally import the security-related annotations if you want to specify the roles that are allowed to invoke the callback methods:

    import weblogic.jws.security.CallbackRolesAllowed;
    import weblogic.jws.security.SecurityRole;
    
  • Import the JAX-RPC stub of the port type of the target web service you want to invoke. The actual stub itself will be created later by the jwsc Ant task. The stub package is specified by the packageName attribute of the <clientgen> child element of <jws>, and the name of the stub is determined by the WSDL of the invoked web service.

    import examples.webservices.callback.CallbackPortType;
    
  • In the body of the JWS file, use the @ServiceClient JWS annotation to specify the WSDL, name, and port of the target web service you want to invoke. You specify this annotation at the field-level on a private variable, whose data type is the JAX-RPC port type of the web service you are invoking.

    @ServiceClient(
       wsdlLocation="http://localhost:7001/callback/TargetService?WSDL",
       serviceName="TargetService",
       portName="TargetServicePort")
    @CallbackRolesAllowed(@SecurityRole(role="mgr", mapToPrincipals="joe"))
    private CallbackPortType port;
    

    The preceding code also shows how to use the optional @CallbackRolesAllowed annotation to specify the list of @SecurityRoles that are allowed to invoke the callback methods.

  • Using the variable you annotated with the @ServiceClient annotation, invoke an operation of the target web service. This operation in turn will invoke a callback method of the callback interface:

    port.targetOperation(message);
    
  • Create a method that will handle the callback message received from the callback service. You can name this method anything you want. However, its signature should exactly match the signature of the corresponding method in the callback interface.

    Annotate the method with the @CallbackMethod annotation to specify that this method handles callback messages. Use the target attribute to specify the name of the JAX-RPC port for which you want to receive callbacks (in other words, the variable you previously annotated with @ServiceClient). Use the operation attribute to specify the name of the callback method in the callback interface from which this method will handle callback messages.

      @CallbackMethod(target="port", operation="callbackOperation")
      @CallbackRolesAllowed(@SecurityRole(role="engineer",  mapToPrincipals="shackell"))
      public void callbackHandler(String msg) {
            System.out.println (msg);
      }
    

    The preceding code also shows how to use the optional @CallbackRolesAllowed annotation to further restrict the security roles that are allowed to invoke this particular callback method.

See "JWS Annotation Reference" in WebLogic Web Services Reference for Oracle WebLogic Server for additional information about the WebLogic-specific JWS annotations discussed in this section.

Programming Guidelines for the Callback Interface

The callback interface is also a JWS file that implements a web service, except for one big difference: instead of using the standard @javax.jws.WebService annotation to specify that it is a standard web service, you use the WebLogic-specific @weblogic.jws.CallbackService to specify that it is a callback service. The attributes of @CallbackService are a restricted subset of the attributes of @WebService.

Follow these restrictions on the allowed data types and JWS annotations when programming the JWS file that implements a callback service:

  • You cannot use any WebLogic-specific JWS annotations other than @weblogic.jws.CallbackService.

  • You can use all standard JWS annotations except for the following:

    • javax.jws.HandlerChain

    • javax.jws.soap.SOAPMessageHandler

    • javax.jws.soap.SOAPMessageHandlers

  • You can use all supported data types as parameters or return values except Holder classes (user-defined data types that implement the javax.xml.rpc.holders.Holder interface).

The following example shows a simple callback interface file that implements a callback web service. The target web service, described in Programming Guidelines for Target Web Service, explicitly invokes a method in this interface. The jwsc-generated implementation of the callback interface then automatically sends a message back to the client web service that originally invoked the target web service; the client service is described in Programming Guidelines for the Callback Client Web Service. See the explanation after the example for coding guidelines that correspond to the Java code in bold.

package examples.webservices.callback;

import weblogic.jws.CallbackService; 

import javax.jws.Oneway;
import javax.jws.WebMethod;

@CallbackService 
public interface CallbackInterface { 

  @WebMethod
  @Oneway 
  public void callbackOperation (String msg); 

}

Follow these guidelines when programming the JWS interface file that implements the callback web service. Code snippets of the guidelines are shown in bold in the preceding example.

  • Import the required JWS annotation:

    import weblogic.jws.CallbackService;
    
  • Annotate the interface declaration with the @CallbackService annotation to specify that the JWS file implements a callback service:

    @CallbackService
    public interface CallbackInterface {
    
  • Create a method that the target web service explicitly invokes; this is the method that automatically sends a message back to the client service that originally invoked the target web service. Because this is a Java interface file, you do not provide an implementation of this method. Rather, the WebLogic web services runtime generates an implementation of the method via the jwsc Ant task.

    public void callbackOperation (String msg);
    

    Note:

    Although the example shows the callback method returning void and annotated with the @Oneway annotation, this is not a requirement.

See "JWS Annotation Reference" in WebLogic Web Services Reference for Oracle WebLogic Server for additional information about the WebLogic-specific JWS annotations discussed in this section.

Updating the build.xml File for the Client Web Service

When you run the jwsc Ant task against the JWS file that implements the client web service, the task implicitly also generates the callback web service, as described in this section.

You update a build.xml file to generate a client web service that invokes the target web service by adding taskdefs and a build-clientService target that looks something like the following example. See the description after the example for details.

<taskdef name="jwsc"
  classname="weblogic.wsee.tools.anttasks.JwscTask" />

<target name="build-clientService">

  <jwsc
      srcdir="src"
      destdir="${clientService-ear-dir}" >

      <jws file="examples/webservices/callback/CallbackClientImpl.java" >

        <clientgen
          wsdl="http://${wls.hostname}:${wls.port}/callback/TargetService?WSDL"
          packageName="examples.webservices.callback"
          serviceName="TargetService" />

      </jws>

  </jwsc>

</target>

Use the taskdef Ant task to define the full classname of the jwsc Ant tasks.

Update the jwsc Ant task that compiles the client web service to include a <clientgen> child element of the <jws> element so as to generate and compile the JAX-RPC stubs for the deployed TargetService web service. The jwsc Ant task automatically packages them in the generated WAR file so that the client web service can immediately access the stubs. You do this because the CallbackClientImpl JWS file imports and uses one of the generated classes.

Because the WSDL of the target web service includes an additional <service> element that describes the callback web service (which the target web service invokes), the <clientgen> child element of the jwsc Ant task also generates and compiles the callback web service and packages it in the same EAR file as the client web service.