12 Using the HTTP Publish-Subscribe Server

This chapter provides an overview of the HTTP Publish-Subscribe server included in WebLogic Server 10.3.6 and information on how you can use it in your Web application.

This chapter includes the following sections:

Overview of HTTP Publish-Subscribe Servers

An HTTP Publish-Subscribe Server (for simplicity, also called pub-sub server in this document) is a mechanism whereby Web clients subscribe to channels and then publish messages to these channels using asynchronous messages over HTTP.

The simple request/response nature of a standard Web application requires that all communication be initiated by the client; this means that the server can only push updated data to its clients if it receives an explicit request. This mechanism is adequate for traditional applications, such as shopping carts, in which data from the server is required only when a client requests it, but inadequate for dynamic real-time applications such as chat rooms and auction updates in which the server must send data even if a client has not explicitly requested it. The client can use the traditional HTTP pull approach to check and retrieve the latest data at regular intervals, but this approach is lacking in scalability and leads to high network traffic because of redundant checks. The HTTP Publish-Subscribe Server solves this problem by allowing clients to subscribe to a channel (similar to a topic in JMS) and receive messages as they become available.

The pub-sub server is based on the Bayeux protocol, see http://svn.cometd.org/trunk/bayeux/bayeux.html. The Bayeux protocol defines a contract between the client and the server for communicating with asynchronous messages over HTTP. It allows clients to register and subscribe to channels, which are named destinations or sources of events. Registered clients, or the pub-sub server itself, then publishes messages to these channels which in turn any subscribed clients receive.

The pub-sub server can communicate with any client that can understand the Bayeux protocol. The pub-sub server is responsible for identifying clients, negotiating trust, exchanging Bayeux messages, and, most importantly, pushing event messages to subscribed clients.

The following figure describes the basic architecture of the pub-sub server included in WebLogic Server.

Figure 12-1 HTTP Publish-Subscribe Server of WebLogic Server

Surrounding text describes Figure 12-1 .

How the Pub-Sub Server Works

There is a one-to-one relationship between a Web application and a pub-sub server; in other words, each Web application has access to one unique pub-sub server. Each pub-sub server has its own list of channels, which means that there can be channels with the same name used in different Web applications within the same enterprise application. The Web application uses a context object to get a handle to its associated pub-sub server.

The pub-sub server itself is implemented as a Java EE library that its associated Web application references in its weblogic.xml deployment descriptor.

The pub-sub server has its own deployment descriptor, called weblogic-pubsub.xml, that lives in the same directory as other Web application descriptors (WEB-INF). Developers use the descriptor to configure initial channels for the pub-sub server, specify the transport and message handlers, and set up user authentication and authorization.

Web application developers can optionally use server-side pub-sub APIs in their servlets or Java classes to get the pub-sub server context, manage channels, and manage the incoming and outgoing messages to and from the clients. It is not required, however, to use server-side pub-sub APIs. For example, developers can use the pub-sub server to implement a chat feature in their Web application. In a typical chat application, clients perform all the subscribe and publish tasks themselves without any need for additional server-side coding. If, however, developers need the pub-sub server to perform additional steps, such as monitoring, collecting, or interpreting incoming messages from clients, then they must use the server-side pub-sub server APIs to program this functionality.

For Web 2.0 Ajax clients to communicate with the pub-sub server, the clients need a JavaScript library that supports the Bayeux protocol. The pub-sub server provides the Dojo JavaScript library implementation as part of its distribution sample. The Dojo JavaScript library provides four different transports, of which two are supported by the WebLogic pub-sub server: long-polling and callback-polling.

The pub-sub server can run in a clustered environment by using JMS to make the messages shareable between nodes of the cluster. In this case, the pub-sub server essentially delegates message handling to a JMS provider.

You can also specify that messages be persisted to physical storage such as a file system or database. By default messages are not persisted.

The following sections provide additional information about the pub-sub server:

Channels

Channels are named destinations to which clients subscribe and publish messages. Programmers define initial channels, channel mapping, and security by creating the weblogic-pubsub.xml deployment descriptor file and packaging it in the WEB-INF directory of the Web application, alongside the standard web.xml and weblogic.xml files. Programmers can optionally use the pub-sub server APIs in servlets to further find, create, and destroy channels dynamically.

It is up to the programmer to decide whether clients can create and destroy channels. This means that the programmer, if required, will have to constrain the use of the create and destroy methods based on client authorization. Any attempt by an unauthorized client to create or destroy a channel generates an error message.

When the pub-sub server destroys an existing channel, all the clients subscribed to that channel and sub-channels of that channel are automatically unsubscribed. Unsubscribed clients receive a disconnect response message from the pub-sub server when it destroys the channel so that clients can try to reconnect and resubscribe to the other channels.

The channel namespace is hierarchical. This means that a set of channels can be specified for subscriptions by a channel gobbling pattern with wildcards like * and **. The client is automatically registered with any channels that are created after the client subscribed with a wildcard pattern.

Message Delivery and Order of Delivery Guarantee

The order of delivery of messages is not guaranteed between the client and the pub-sub server. This means that if the pub-sub server publishes message1 and then message2, the client may receive the messages in that order, or it may also receive them in reverse order.

On the Web, clients are by definition loosely connected and it is possible that a subscriber is inactive or not connected when the pub-sub server publishes a message. The following rules govern the behavior of message delivery in this case:

  • Messages published by the pub-sub server when a client is unreachable are not delivered to the client.

  • When the clients reconnects back, it will continue to receive newly published messages.

  • In order to recover already-published messages, the pub-sub server must be configured for persistent messages and the channel be configured as a persistent channel.0

Examples of Using the HTTP Publish-Subscribe Server

The information in this topic uses a very simple example to describe the basic functionality and required tasks of using the HTTP pub-sub server. The example is a Web application that consists of only the following components:

  • A web.xml deployment descriptor to configure the pub-sub Java EE library.

  • A weblogic-pubsub.xml deployment descriptor that configures the pub-sub server itself.

  • An HTML file that allows users to subscribe and publish messages; the HTML file uses the DOJO client JavaScript libraries as its programming model.

This example does not use any server-side programming using the pub-sub APIs.

A more complicated example is provided in the WebLogic Server distribution. The example describes a real-world scenario based on stock trading, and makes extensive use of the pub-sub APIs in both the server and client components. The example uses Dojo as its client-side programming framework and provides some of the Dojo JavaScript libraries for your own testing use. The example also shows how to add security to the pub-sub server and client. The example is in the following directory:

WL_HOME/samples/server/examples/src/examples/webapp/pubsub/stock

where WL_HOME refers to the main WebLogic Server installation directory, such as /oraclehome/wlserver_10.3.

Using the HTTP Publish-Subscribe Server: Typical Steps

The following procedure describes the high-level steps to use the HTTP Publish-Subscribe Server.

Note:

In the procedure, it is assumed that you have already created a basic Web application, along with its web.xml and weblogic.xml deployment descriptor files, JSPs, and servlets. For general details about creating Web applications, see Chapter 3, "Creating and Configuring Web Applications".
  1. Update the weblogic.xml deployment descriptor of the Web application, located in the WEB-INF directory, by adding a reference to the shared Java EE library (always called pubsub) in which the pub-sub server is bundled, as shown in bold below:

    <?xml version='1.0' encoding='UTF-8'?>
    <weblogic-web-app
      xmlns="http://xmlns.oracle.com/weblogic/weblogic-web-app"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <library-ref>
        <library-name>pubsub</library-name>
        <specification-version>1.0</specification-version>
      </library-ref>
    </weblogic-web-app>
    

    See "Creating Shared Java EE Libraries and Optional Packages" in Developing Applications for Oracle WebLogic Server for additional child elements of <library-ref> as well as additional general information about shared Java EE libraries.

  2. Create the weblogic-pubsub.xml file to configure initial channels, specify the transport and message handlers, and set up user authentication and authorization. See Creating the weblogic-pubsub.xml File.

  3. Optionally add Java code to a component of your Web application, such as a servlet, if you want the pub-sub server to publish messages to the channels, filter messages from clients, or dynamically create or destroy channels. This step is not necessary. See Programming Using the Server-Side Pub-Sub APIs.

  4. Optionally program and configure a message filter chain if you want to pre-process the messages you receive from a client. See Configuring and Programming Message Filter Chains.

  5. Update the browser client, such as an HTML file or JSP, to allow users to subscribe to channels and send and receive messages. See Updating a Browser Client to Communicate with the Pub-Sub Server.

  6. Reassemble the Web application with new and updated deployment description files and browser clients, and optionally recompile the servlet if you added pub-sub server code.

    Put the new weblogic-pubsub.xml deployment descriptor in the same WEB-INF directory of the Web application that contains the web.xml and weblogic.xml files.

    See Chapter 3, "Creating and Configuring Web Applications" for general information about assembling Web applications.

  7. If you have not already done so, deploy the shared Java EE library WAR file in which the pub-sub server is bundled; you must perform this step before you re-deploy the Web application that uses the pub-sub server, although you only have to perform the step once for the entire WebLogic Server.

    The pub-sub shared Java EE library WAR file is called pubsub-1.0.war and is located in the following directory:

    WL_HOME/common/deployable-libraries
    

    where WL_HOME is the main WebLogic Server installation directory, such as /oraclehome/wlserver_10.3.

    You can use either the Administration Console or the weblogic.Deployer command line tool. See "Install a Java EE Library" for instructions on using the Administration Console or "Deploying Shared Java EE Libraries and Dependent Applications" for details about using weblogic.Deployer.

  8. Redeploy your updated Web application using the Administration Console or the weblogic.Deployer command-line tool.

    See "Install a Web Application" for instructions on using the Administration Console or "Deploying Applications and Modules with weblogic.Deployer" for details about using weblogic.Deployer.

You can now start using the browser client to subscribe to a channel configured in the weblogic-pubsub.xml file and then send or receive messages.

After you have programmed your pub-sub application, you might want to start monitoring it for run-time information; for details, see Getting Run-time Information about the Pub-Sub Server and Channels.

See the following sections for more advanced features of the pub-sub server that you might want to implement:

Creating the weblogic-pubsub.xml File

The weblogic-pubsub.xml deployment descriptor is an XML file that configures the pub-sub server, in particular by specifying the initial channels, configuration properties of the pub-sub server, and security specifications for the clients that subscribe to the channels. Some of this information can be updated at run time by the pub-sub server using the server-side APIs.

The root element of the deployment descriptor is <wlps:weblogic-pubsub>, where the wlps namespace is http://xmlns.oracle.com/weblogic/weblogic-pubsub.

For a full description of the elements of the weblogic-pubsub.xml file, see the Schema. The following list includes some of the more commonly used elements; see the end of this section for a typical example of a weblogic-pubsub.xml file:

  • <wlps:server-config>: Configures the pub-sub server. Child elements of this element include:

    • <wlps:work-manager>: Specifies the name of the work manager that delivers messages to clients.

    • <wlps:publish-without-connect-allowed>: Specifies whether clients can publish messages without having explicitly connected to the pub-sub server.

    • <wlps:supported-transport>: Specifies the supported transports. Currently, the two supported transports are long-polling and callback-polling.

    • <wlps:client-timeout-secs>: Specifies the number of seconds after which the pub-sub server disconnects a client if the client does has not sent back a connect/reconnect message

  • <wlps:channel>: Defines and configures the initial channels. Child elements of this element include:

    • <wlps:channel-pattern>: Specifies the channel pattern, similar to the way servlet URL patterns are specified, such as /foo/bar, /foo/bar/*, /foo/bar/**.

  • <wlps:channel-persistence>: Specifies whether the channel is persistent. For details, sees Advanced Topic: Persisting Messages to Physical Storage.

  • <wlps:channel-constraints>: Configures security for the channel, such which roles are allowed to perform which operations for a given channel. For details, see Enabling Security.

  • <wlps:jms-handler-mapping>: Configures a JMS handler. For details, see Advanced Topic: Using JMS as a Provider to Enable Cluster Support.

The following sample weblogic-pubsub.xml file shows a simple configuration for an application that uses the pub-sub server; see the explanation after the example for details:

<?xml version="1.0" encoding="UTF-8"?>
<wlps:weblogic-pubsub
    xmlns:wlps="http://xmlns.oracle.com/weblogic/weblogic-pubsub">
  <wlps:server-config>
    <wlps:publish-without-connect-allowed>true</wlps:publish-without-connect-allowed>
    <wlps:supported-transport/>
    <wlps:client-timeout-secs>100</wlps:client-timeout-secs>
    <wlps:persistent-client-timeout-secs>400</wlps:persistent-client-timeout-secs>
    <wlps:interval-millisecs>1000</wlps:interval-millisecs>
    <wlps:multi-frame-interval-millisecs>2000</wlps:multi-frame-interval-millisecs>
  </wlps:server-config>
  <wlps:channel>
    <wlps:channel-pattern>/chatrooms/**</wlps:channel-pattern>
  </wlps:channel>
  <wlps:channel-constraint>
    <wlps:channel-resource-collection>
      <wlps:channel-resource-name>all-permissions</wlps:channel-resource-name>
      <wlps:description>Grant all permissions for everything by everyone</wlps:description>
      <wlps:channel-pattern>/chatrooms/*</wlps:channel-pattern>
    </wlps:channel-resource-collection>
  </wlps:channel-constraint>
</wlps:weblogic-pubsub>

In the preceding example:

  • The <wlps:server-config> element configures the pub-sub server itself. In particular, it specifies that clients can publish messages to the pub-sub server without explicitly connecting to it and that the server disconnects the client after 100 seconds if the client has not sent a reconnect message during that time. The <wlps:persistent-client-timeout-secs> element specifies that, in the case of persistent channels, the client has up to 400 seconds to be disconnected to still receive messages published during that time after it reconnects. The <wlps:interval-milliseconds> element specifies that the client can delay up to 1000 milliseconds subsequent requests to the /meta/connect channel. Finally, the <wlps:multi-frame-interval-millisecs> element specifies that the client can delay up to 2000 milliseconds subsequent requests to the /meta/connect channel when multi-frame is detected.

  • The <wlps:channel> element configures a single initial channel to which users can subscribe. This channel is identified with the pattern /chatrooms/**; this pattern is the top of the channel hierarchy.

  • The <wlps:channel-constraints> element provides security constraints about how the /chatrooms/** channel can be used. In this case, all permissions are granted to all users for all channels for all operations.

Programming Using the Server-Side Pub-Sub APIs

The pub-sub server itself might sometimes need to get messages from a channel so as to monitor information or intercept incoming data before it gets published to subscribed clients. The server might also want to publish messages to a channel directly to, for example, make an announcement to all subscribed clients or provide additional services. The pub-sub server might also need to perform maintenance on the channels, such as create new ones or destroy existing ones.

WebLogic Server provides a pub-sub API in the com.bea.httppubsub package to perform all of these tasks. Pub-sub programmers use the API in servlets or POJOs (plain old Java objects) of the Web application that contains the pub-sub application. Programming with the API is optional and needed only if the pub-sub server must perform tasks additional to the standard publish and subscribe on the client side.

Overview of the Main API Classes and Interfaces

The following list describes the main interfaces and classes of the pub-sub server API:

  • com.bea.httppubsub.PubSubServer—This is the most important interface of the pub-sub server API. It represents an instance of the pub-sub server that is associated with the current Web application; you use the context path of the current servlet to get the associated pub-sub server. Using this interface, programmers can manage channels, configure the pub-sub server, and create local clients that are used to publish to and subscribe to channels.

  • com.bea.httppubsub.LocalClient—After a programmer has instanciated an instance of the current pub-sub server using the PubSubServer interface, the programmer must then create a LocalClient, which is the client representative on the server side. This client is always connected to the pub-sub server. Using this client, programmers can publish and subscribe to channels. Remote clients, such as browser-based clients, are represented with the com.bea.httppubsub.Client interface.

  • com.bea.httppubsub.ClientManager—Interface for creating a new LocalClient.

  • com.bea.httppubsub.Channel—Interface that represents a channel and all its subchannels. With this interface, programmers can get the list of clients currently subscribed to a channel and its subchannels, publish messages to a channel, get a list of all subchannels, subscribe or unsubscribe to a channel, and destroy a channel.

  • com.bea.httppubsub.MessageFilter—Interface for creating message filters that intercept the messages that a client publishes to a channel. See Configuring and Programming Message Filter Chains for details.

  • com.bea.httppubsub.DeliveredMessageListener—Interface that programmers use to create an object that listens to a channel and is notified every time a client (remote or local) publishes a message to the channel.

  • com.bea.httppubsub.BayeuxMessage—Interface that represents the messages that are exchanged between the pub-sub server and a Bayeux client.

There are additional supporting classes, interfaces, enums, and exceptions in the com.bea.httppubsub package; see the "HTTP Pub-Sub API Javadoc" for the complete documentation.

The following sections describe how to perform the most common server-side tasks using the pub-sub API, such as publishing messages to and subscribing to a channel. The sample snippets are taken from the Java source files of the pub-sub server sample on the distribution kit: WL_HOME/samples/server/examples/src/examples/webapp/pubsub/stock/src/stockWar, where WL_HOME refers to the main WebLogic Server installation directory, such as /oraclehome/wlserver_10.3.

Getting a Pub-Sub Server Instance and Creating a Local Client

Before you can perform any server-side tasks on the pub-sub server and its channels, you must first instantiate a PubSubServer object which represents the pub-sub server and then create a local client which you use to manipulate the channels on behalf of the pub-sub server.

The following code snippet shows an example:

import com.bea.httppubsub.FactoryFinder;
import com.bea.httppubsub.LocalClient;
import com.bea.httppubsub.PubSubSecurityException;
import com.bea.httppubsub.PubSubServer;
import com.bea.httppubsub.PubSubServerException;
import com.bea.httppubsub.PubSubServerFactory;
import org.json.JSONObject;
public class ApiBasedClient implements Client {
  private PubSubServer pubSubServer;
  private LocalClient localClient;
  public ApiBasedClient(String serverName) throws PubSubServerException {
    PubSubServerFactory pubSubServerFactory =
      (PubSubServerFactory)FactoryFinder.getFactory(FactoryFinder.PUBSUBSERVER_FACTORY);
    pubSubServer = pubSubServerFactory.lookupPubSubServer(serverName);
    localClient = pubSubServer.getClientManager().createLocalClient();
  }
 ...
}

The FactoryFinder class searches for an implementation of the PubSubServerFactory which in turn is used to create PubSubServer instances. The lookupPubSubServer() method of PubSubServerFactory returns a PubSubServer instance based the context path of the servlet from which the method is run. Finally, the createLocalClient() method of the ClientManager of the PubSubServer instance returns a LocalClient object; this is the object that the pub-sub server uses to subscribe and publish to a channel.

Publishing Messages to a Channel

To publish a message to a channel, use the PubSubServer.publishToChannel() method, passing it the LocalClient object, the name of the channel, and the text of the message, as shown in the following code snippet:

public void publish(String channel, JSONObject data) throws IOException {
  try {
    pubSubServer.publishToChannel(localClient, channel, data.toString());
  } catch (PubSubSecurityException e) {
    throw new IOException(e);
  }
}

In the example, the channel variable would contain the name of a channel, such as /my/channel/**.

The publishToChannel() method is asynchronous and returns immediately, or in other words, the method does not wait for the subscribed clients to receive the message.

Subscribing to a Channel

Subscribing to a channel from the server-side is a two step process:

  1. Create a message listener and register it with the LocalClient

  2. Explicitly subscribe to the channel.

The message listener is a class that implements the DeliveredMessageListener interface. This interface defines a single callback method, onPublish(), which is notified whenever the local client receives a message. The callback method is sent a DeliveredMessageEvent instance which represents the message sent to the local client.

To subscribe to a channel, use the PubSubServer.subscribeToChannel() method, passing it the LocalClient object and the name of the channel.

The following code snippet shows an example of both of these steps; see a description of the example directly after the code snippet:

pubSubServer.subscribeToChannel(localClient, "/management/publisher");
localClient.registerMessageListener(new DeliveredMessageListener() {
   private InWebPublisher publisher = new InWebPublisher(contextPath);
   private boolean publishing = false;
   public void onPublish(DeliveredMessageEvent event) {
     Object payLoad = event.getMessage().getPayLoad();
     if (payLoad instanceof String) {
       String command = (String)payLoad;
       if ("start".equals(command) && !publishing) {
         publisher.startup();
         publishing = true;
       } else if ("halt".equals(command) && publishing) {
           publisher.halt();
           publishing = false;
       }
     }
   }
 });

In the preceding example:

  • The pub-sub server subscribes to a channel called /management/publisher.

  • The message listener class is implemented directly in the LocalClient.registerMessageListener() method call.

Configuring and Programming Message Filter Chains

Pub-sub server application developers can program one or more message filters and configure them for a channel so as to intercept the incoming messages from clients and transform or additionally process the messages in some way. A message filter chain refers to more than one filter attached to a channel, where the first configured filter pre-processes the message and then passes it to the second configured filter, and so on. This feature is similar to the filters that were introduced in the servlet 2.3 specification.

Message filters are useful for a variety of reasons. First, they provide the ability to encapsulate recurring tasks in reusable units, which is good programming practice. Second, they provide an easy and consistent way to pre-process an incoming message from a client before the pub-sub server gets it and subsequently sends it out to the subscribers to the channel. Reasons for pre-processing the messages include validating incoming data, gathering monitoring information, tracking the users of the pub-sub application, caching, and so on.

There are two major steps to implementing message filter chains:

Programming the Message Filter Class

Each filter in the chain must have its own user-programmed filter class. The filter class must implement the com.bea.httppubsub.MessageFilter interface. The MessageFilter interface includes a single method, handleMessage(EventMessage); its signature is as follows:

boolean handleMessage(EventMessage message);

The com.bea.httppubsub.EventMessage interface extends BayeaxMessage, which is a JavaScript Object Notation (JSON) (see http://www.json.org/) encoded object. JSON is a lightweight data-interchange format used by the Bayeux protocol. The EventMessage interface defines two methods, getPayload() and setPayload(), that programmers use to access and process the incoming messages.

Because the handleMessage() method returns boolean, a programmer can interrupt all further processing in the message filter chain by returning false in any of the filter classes in the chain. This action not only interrupts the filter processing, but also immediately returns the message back to the client that published it, without sending it on to channel subscribers. This is a great way for programmers to ensure that there is no problem identified in the incoming messages, and, if a problem is found, to prevent the messages to be published to subscribers.

The following example shows a simple implementation of the MessageFilter interface:

package msgfilters;
public static class Filter1 implements MessageFilter {
  public boolean handleMessage(EventMessage message) {
    String msg = (String) message.getPayLoad();
    message.setPayLoad("[" + msg.substring(1, msg.length()-1));
    return true;
  }
}

In the example, the getPayload() method gets the String message from the inputted message parameter; this message either comes directly from the client (if Filter1 is the first configured filter in the chain) or is the result of another filter class if Filter1 is not the first in the chain. The setPayLoad() method resets the message while performing some data manipulation; in the example, the first character of the message is replaced with a [.

Configuring the Message Filter Chain

You configure the message filters in the weblogic-pubsub.xml deployment descriptor of the pub-sub server.

First, you declare the message filters using the <wlps:message-filter> child element of the root <wlps:weblogic-pubsub> element. Then you configure a specific channel by adding a <wlps:message-filter> element for each filter in the chain. The order in which the filters are configured in the <wlps:channel> element is the order in which they execute.

The following example shows how to configure message filters in the weblogic-pubsub.xml deployment descriptor; only relevant information is shown. See the text after the example for an explanation:

<?xml version="1.0" encoding="UTF-8"?>
<wlps:weblogic-pubsub
    xmlns:wlps="http://xmlns.oracle.com/weblogic/weblogic-pubsub">
  <wlps:server-config>
  ...
  </wlps:server-config>
  <wlps:message-filter>
    <wlps:message-filter-name>filter1</wlps:message-filter-name>
    <wlps:message-filter-class>msgfilters.Fiter1</wlps:message-filter-class>
  </wlps:message-filter>
  <wlps:message-filter>
    <wlps:message-filter-name>filter2</wlps:message-filter-name>
    <wlps:message-filter-class>msgfilters.Filter2</wlps:message-filter-class>
  </wlps:message-filter>
  <wlps:channel>
    <wlps:channel-pattern>/firstchannel/*</wlps:channel-pattern>
    <wlps:message-filter>filter1</wlps:message-filter>
  </wlps:channel>
  <wlps:channel>
    <wlps:channel-pattern>/secondchannel/*</wlps:channel-pattern>
    <wlps:message-filter>filter2</wlps:message-filter>
    <wlps:message-filter>filter1</wlps:message-filter>
  </wlps:channel>
</wlps:weblogic-pubsub>

In the example, two filters are declared using the <wlps:message-filter> element: filter1 implemented by the msgfilters.Filter1 class and filter2 implemented by the msgfilters.Filter2 class.

The channel with pattern /firstchannel/* is then configured with filter1. At run time, this means that all messages published to the direct subchannels of /firstchannel are first pre-processed by the msgfilters.Filter1 class.

The channel with pattern /secondchannel/* is configured with two filters: filter2 and filter1. The order in which these two filters are configured is important. At run time, all messages published to the direct subchannels of /secondchannel are first intercepted and processed by the msgfilters.Filter2 class, then the result of this processing is sent to msgfilters.Filter1 which then does its own processing, and then the result is sent to the subscribers of the channel.

Updating a Browser Client to Communicate with the Pub-Sub Server

To update a browser, or any other Web-based client, to communicate with the pub-sub server, you use a JavaScript library that supports the Bayeux protocol. You can use any client-side programming framework of your choosing, provided that it supports the Bayeux protocol. Typically you add the JavaScript to your JSP or HTML file, or whatever implements the Web client.

This section shows an example of using Dojo as the client-side programming framework and updating a JSP. Dojo is a JavaScript-based toolkit that supports the Bayeux protocol as well as AJAX. Although WebLogic Server does not provide the toolkit as an integral feature, it does include a subset of the libraries as part of the installed pub-sub example; see Examples of Using the HTTP Publish-Subscribe Server for details.

There are three main tasks you must perform when programming the Web client to communicate with the pub-sub server:

  • Initialize the Dojo cometd environment.

    The following example shows a typical way to perform this step:

    dojo.io.cometd.init({}, "/context/cometd");
    

    where context refers to the context path of the Web application that hosts the pub-sub application. This initialization step creates a handshake with the pub-sub server so as to determine the transport type for the connection. If the handshake is successful, the client connects to the pub-sub server.

    The cometd part of the initialization string is required, unless you specifically override the default servlet mappings of the pubsub Java EE library that are defined in the web.xml file of the library itself. For details of how to do this, see Overriding the Default Servlet Mapping of the pubsub Java EE Library.

  • Publish a message to a channel.

    The message can be a simple string message or a JSON message. The following example shows how to publish a simple message:

    dojo.io.cometd.publish("/a/channel", "message content");
    

    where /a/channel refers to the name of the channel to which you want to publish the message and the second parameter is the text of the message. The following example shows how to publish a JSON message:

    dojo.io.cometd.publish("/a/channel", {"data": "content"});
    
  • In this example, the second parameter can be any JSON object.

  • Subscribe to a channel.

    Before you can actually subscribe to a channel, you must first implement a callback JavaScript function. This function can have any name; you will later reference the function when you subscribe to a channel. The following example shows how to implement a JavaScript function called onUpdate:

    function onUpdate(message) {
      if (!message.data) {
        alert("bad message format "+message);
      return;
      }
      // fetch the data published by other clients
      var data = message.data;
    }
    

    To actually subscribe to a channel, use the following JavaScript:

    dojo.io.cometd.subscribe("/a/channel", null, "onUpdate");
    

    where /a/channel refers to the channel to which you want to subscribe and onUpdate is the name of the callback JavaScript function you previously defined.

This section covers only the minimal information on using the Dojo toolkit to update a Web based client to communicate with the WebLogic pub-sub server; for additional details, see http://www.dojotoolkit.org/documentation.

Overriding the Default Servlet Mapping of the pubsub Java EE Library

The web.xml of the pubsub Java EE library defines the internal servlet (called PubSubServlet) that implements the pub-sub server as follows:

<web-app>
  <servlet>
    <servlet-name>PubSubServlet</servlet-name>
    <servlet-class>com.bea.httppubsub.servlet.ControllerServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>PubSubServlet</servlet-name>
    <url-pattern>/cometd/*</url-pattern>
  </servlet-mapping>
</web-app>

As shown by the code in bold, the URL pattern for the PubSubServlet is /cometd/*; this is why by default you must use a string such as /mywebapp/cometd when initializing a Web client that communicates with the pub-sub server.

If you need to override this default URL pattern, then update the web.xml file of your Web application with something like the following:

<servlet-mapping>
  <servlet-name>PubSubServlet</servlet-name>
  <url-pattern>/web2/*</url-pattern>
</servlet-mapping>

Now you can specify this new URL pattern, rather than cometd, when using Dojo to initialize a Web client:

dojo.io.cometd.init({}, "/context/web2");

Getting Run-time Information about the Pub-Sub Server and Channels

The pub-sub server exposes all run-time monitoring information using Java Management Extensions (JMX) MBeans. Examples of the type of information you can gather at run time include details about registered clients, channel subscriptions, and message counts.

The pub-sub server uses two kinds of run-time MBeans:

  • weblogic.management.runtime.WebPubSubRuntimeMBean—Encapsulates run-time information about the pub-sub server itself. Examples of information you can get about a pub-sub server using this MBean include the context root of the associated Web application and a handle to a configured channel.

  • weblogic.management.runtime.ChannelRuntimeMBean—Encapsulates information about the channels configured for the pub-sub server. Examples of information you can get about a channel using the MBean include the number of published messages to this channel, the number of current subscribers, and the list of subscribers.

Both MBeans are registered in the WebLogic Server MBean tree and can be reached by navigating through the tree. In particular, WebPubSubRuntimeMBean is registered under WebAppComponentRuntimeMBean of the current Web application and all ChannelRuntimeMBeans are registered under WebPubSubRuntimeMBean.

For complete information on these MBeans, go to the WebLogic Server MBean Reference, open the Runtime MBeans node in the left pane; the run-time MBeans are listed in alphabetical order.

For general information about programming JMX MBeans, see Developing Manageable Applications with JMX.

Enabling Security

The pub-sub server offers the following security features:

The use of these features is described in the sections that follow.

Use Pub-Sub Constraints

The pub-sub server provides the capability to secure a channel via a combination of two mechanisms: a channel constraint and an authorization constraint.

Conceptually, a channel constraint is a container that includes a collection of resources to be protected and, optionally, authorization constraints on the specific resources in the resource collection. The authorization constraints represent WebLogic Server roles and policies, and answer the question "Who can perform a given operation on the resources in the collection?"

You specify the pub-sub constraints in a configuration file, weblogic-pub-sub.xml. The pub-sub server uses the channel constraint and any authorization constraints in the weblogic-pub-sub.xml configuration file to set up roles and policies on the channels.

Consider the example shown in Example 12-1. Significant sections are shown in bold.

Example 12-1 Pub/Sub Constraints

<wlps:channel-constraint>
<wlps:channel-resource-collection>
      <wlps:channel-resource-name>publish</wlps:channel-resource-name>
      <wlps:description>publish channel constraint</wlps:description>
      <wlps:channel-pattern>/stock/* *</wlps:channel-pattern>
      <wlps:channel-pattern>/management/publisher</wlps:channel-pattern>
      <wlps:channel-operation>publish</wlps:channel-operation>
    </wlps:channel-resource-collection>

    <wlps:auth-constraint>
      <wlps:description>publisher</wlps:description>
      <wlps:role-name>publisher</wlps:role-name>
    </wlps:auth-constraint>

  </wlps:channel-constraint>

In this example, the operation publish for the /stock/* * and /management/publisher channels is available only to users with the WebLogic Server role publisher.

Specify Access to Channel Operations

Four types of actions (operations) are allowed on channels:

  • create

  • delete

  • subscribe

  • publish

By default (with no channel constraints defined), subscribe operations are open for all users on all channels.

Similarly, create, delete, and publish operations are restricted for all users on all channels by default. Create, delete, and publish operations are allowed only if explicitly configured in channel constraints.

You use a combination of <wlps:channel-operation> and <wlps:auth-constraint> to specify access to a channel operation for a given role.

For example, in Example 12-2, the publish operation is permitted for authenticated subjects with the publisher role, and denied to all other roles.

Example 12-2 Publisher Role Constraint

<wlps:channel-constraint>

    <wlps:channel-resource-collection>
      <wlps:channel-resource-name>publish</wlps:channel-resource-name>
      <wlps:description>publish channel constraint</wlps:description>
      <wlps:channel-pattern>/stock/* *</wlps:channel-pattern>
      <wlps:channel-pattern>/management/publisher</wlps:channel-pattern>
      <wlps:channel-operation>publish</wlps:channel-operation>
    </wlps:channel-resource-collection>

    <wlps:auth-constraint>
      <wlps:description>publisher</wlps:description>
      <wlps:role-name>publisher</wlps:role-name>
    </wlps:auth-constraint>

  </wlps:channel-constraint>

Restricting Access to All Channel Operations

The presence of an empty authorization constraint (<wlps:auth-constraint> </wlps:auth-constraint>) means that all access is prohibited for the specified channel operations, or all channel operations if <wlps:channel-operation> is not specified.

Therefore, to restrict all channel operations for the channel for all users, set up your weblogic-pub-sub.xml configuration file with an empty <wlps:auth-constraint> element, as follows:

<wlps:channel-constraint>
    <wlps:channel-resource-collection>
      <wlps:description>Restrict All Acesss</wlps:description>
      <wlps:channel-pattern>/**</wlps:channel-pattern>
    </wlps:channel-resource-collection>
        <wlps:auth-constraint> </wlps:auth-constraint>
  </wlps:channel-constraint>

Opening Access to All Channel Operations

The absence of an authorization constraint within a channel constraint means that access is not limited for the specified channel operations, or all channel operations if <wlps:channel-operation> is not specified.

(In contrast, the presence of an empty authorization constraint (<wlps:auth-constraint> </wlps:auth-constraint>) means that all access is prohibited for the specified channel operations, or all channel operations for that channel if <wlps:channel-operation> is not specified.)

Therefore, to open up all channel operations for the channel for all users, set up your weblogic-pub-sub.xml configuration file without <wlps:channel-operation> or <wlps:auth-constraint> elements, as follows:

<wlps:channel-constraint>
    <wlps:channel-resource-collection>
      <wlps:description>All Acesss</wlps:description>
      <wlps:channel-pattern>/**</wlps:channel-pattern>
    </wlps:channel-resource-collection>
    <!-- Not defining an auth-constraint will open up access to everyone -->
  </wlps:channel-constraint>

Updating a Constraint Requires Redeploy of Web Application

Constraints cannot be updated dynamically. You must redeploy the Web application for new settings to take effect.

Map Roles to Principals

Note:

The pub-sub server does not directly perform authentication. Rather, the pub-Sub server runs on top of WebLogic Server (the servlet container) and leverages the WebLogic authentication services. Specifically, the pub-sub server uses the currently-authenticated user (or anonymous) for requests originating from a given client.

The primary pub-sub security mechanism is authorization. As previously described, the pub-sub server uses the a combination of <wlps:channel-operation> and <wlps:auth-constraint> elements to set up roles and policies on the channels. Each bayeux packet corresponds to one bayeux request. One HTTP request can translate to one or more bayeux requests. WebLogic Server (the servlet container) performs authorization checks for the HTTP request, and the pub-sub server performs one authorization check for each bayeux request.

To set up the pub-sub authorization, you must map the role names, which you specify as <wlps:role-name>some-role-name</wlps:role-name> in your weblogic-pub-sub.xml file, to principal names using the security-role-assignment element configured in your weblogic.xml file.

Note:

The absence of such a mapping in the weblogic.xml file will cause the role to be used implicitly; this generates a warning.

As described insecurity-role-assignment, the security-role-assignment element declares a mapping between a security role and one or more principals in the WebLogic Server security realm.

Example 12-3 shows how to use the security-role-assignment element to assign principals to the publisher role.

Example 12-3 security-role-assignment Element

<weblogic-web-app>  
 <security-role-assignment>        
    <role-name>publisher</role-name>
    <principal-name>Tanya</principal-name>
    <principal-name>Fred</principal-name>
    <principal-name>system</principal-name>
 </security-role-assignment>

</weblogic-web-app> 

Configure SSL for Pub-Sub Communication

By default, all pub-sub communication is via HTTP. However, you can configure the pub-sub server to require SSL by modifying the web.xml file. Requiring SSL ensures that all communication between the pub-sub server and the Web 2.0 clients happens over SSL.

WebLogic Server establishes an SSL connection when the user is authenticated using the INTEGRAL or CONFIDENTIAL transport guarantee, as specified in the web.xml file. In Example 12-4, the transport guarantee is set to integral.

Example 12-4 Requiring SSL Via web.xml

<security-constraint> 

<web-resource-collection> 
<web-resource-name>Success</web-resource-name> 
<url-pattern>/cometd/*</url-pattern>

<http-method>GET</http-method> 
<http-method>POST</http-method> 
</web-resource-collection>                

<user-data-constraint>
<transport-guarantee>INTEGRAL</transport-guarantee>
</user-data-constraint>

</security-constraint>  

Additional Security Considerations

This section describes the following additional pub-sub security considerations:

Use AuthCookieEnabled to Access Resources

WebLogic Server allows a user to securely access HTTPS resources in a session that was initiated using HTTP, without loss of session data. To enable this feature, add AuthCookieEnabled="true" to the WebServer element in config.xml:

<WebServer Name="myserver" AuthCookieEnabled="true"/>

Setting AuthCookieEnabled to true, which is the default setting, causes the WebLogic Server instance to send a new secure cookie, _WL_AUTHCOOKIE_JSESSIONID, to the browser when authenticating via an HTTPS connection. Once the secure cookie is set, the session is allowed to access other security-constrained HTTPS resources only if the cookie is sent from the browser.

Note:

This feature will work even when cookies are disabled because WebLogic Server will use URL rewriting over secure connections to rewrite secure URLs in order to encode the authCookieID in the URL along with the JSESSIONID.

Locking Down the Pub-Sub Server

This section describes how to lock down the pub-sub server to prevent unauthorized access. The steps described here offer additional security at the cost of reduced access. It is up to you to decide which level of security is appropriate for your environment.

To lock down the pub-sub server, perform the following steps:

  1. Configure SSL for pub-sub communication, as described in Configure SSL for Pub-Sub Communication.

  2. Require authentication (BASIC, FORM, and so forth.)

    WebLogic Server sets the required authentication method for the Web application in the web.xml file.

    In the following example, HTTP BASIC authentication is required:

    <login-config> 
    <auth-method>BASIC</auth-method> 
    <realm-name>default</realm-name> 
    </login-config> 
    
  3. Ensure auth-cookie is enabled for the Web applications, as described in Use AuthCookieEnabled to Access Resources.

  4. Ensure that all the channels are constrained in the weblogic-pubsub.xml file.

  5. Lock subscribe operations, which are allowed by default.

    <wlps:channel-constraint> 
    <wlps:channel-resource-collection>      
    <wlps:channel-resource-name>publish</wlps:channel-resource-name>      
    <wlps:description>publish channel constraint</wlps:description>      
    <wlps:channel-pattern>/stock/*</wlps:channel-pattern>      
    
    <wlps:channel-pattern>/management/publisher</wlps:channel-pattern>      
    <wlps:channel-operation>publish</wlps:channel-operation>    
    </wlps:channel-resource-collection>
    
    <wlps:auth-constraint>      
    <wlps:description>publisher</wlps:description> 
    <wlps:role-name>publisher</wlps:role-name>
    </wlps:auth-constraint> 
    </wlps:channel-constraint>
    
    <wlps:channel-constraint>
    <wlps:channel-resource-collection>
    <wlps:channel-resource-name>subscribe</wlps:channel-resource-name>      
    <wlps:description>subscribe channel constraint</wlps:description>      
    <wlps:channel-pattern>/stock/*</wlps:channel-pattern>
    <wlps:channel-operation>subscribe</wlps:channel-operation>
    </wlps:channel-resource-collection>
    
    <wlps:auth-constraint>
    <wlps:description>subscriber</wlps:description>
    <wlps:role-name>subscriber</wlps:role-name>
    </wlps:auth-constraint> 
    
    </wlps:channel-constraint>
    

Advanced Topic: Using JMS as a Provider to Enable Cluster Support

Pub-sub server applications can run in a WebLogic Server clustered environment so as to provide scalability and server failover. However, pub-sub applications behave differently depending on the message handler (pub-sub server itself or a JMS provider) that is handling the published messages. In the default non-JMS case, the pub-sub server handles all messages and each instance of the pub-sub server on each node of the cluster is independent and isolated. This means that event messages cannot be shared between different server instances. For example, if a client subscribes to channel /chat on node A of the cluster, it cannot receive messages published to channel /chat on node B of the cluster.

If, for a given channel, you want all messages published to all nodes of a cluster to be shareable by all clients subscribed to the channel, then you must configure the channel for JMS. You do this by updating the appropriate <wlps:channel> element in the weblogic-pubsub.xml deployment descriptor of your application.

When a client publishes a message to a JMS-configured channel, the pub-sub server re-sends the message to a JMS topic. JMS message listeners running on each node of the cluster retrieve the messages from the JMS topics and then deliver them to the subscribed clients on their node.

Configuring JMS as a Handler

You configure the JMS as the message handler for an application in the weblogic-pubsub.xml deployment descriptor of the pub-sub server.

First, you declare the configuration of the JMS handler using the <wlps:jms-handler-mapping> child element of the root <wlps:weblogic-pubsub> element. This is where you specify the URL of the JMS provider, the connection factory JNDI name, and the JMS topic JNDI name. Then you configure a specific channel to be a JMS channel by adding a <wlps:jms-handler-name> child element.

The following example shows how to configure a JMS handler and channel in the weblogic-pubsub.xml deployment descriptor; only relevant information is shown in bold. See the text after the example for an explanation.

Note:

It is assumed in this section that you have already configured your JMS provider and created the connection factory and topic that will be used for the pub-sub JMS channel. See Programming JMS for Oracle WebLogic Server for information about WebLogic JMS or your provider's documentation for details.
<?xml version="1.0" encoding="UTF-8"?>
<wlps:weblogic-pubsub
    xmlns:wlps="http://xmlns.oracle.com/weblogic/weblogic-pubsub">
  <wlps:server-config>
  ...
  </wlps:server-config>
  <wlps:jms-handler-mapping>
    <wlps:jms-handler-name>DefaultJmsHandler</wlps:jms-handler-name>
    <wlps:jms-handler>
       <wlps:jms-provider-url>t3://localhost:7001</wlps:jms-provider-url>
       <wlps:connection-factory-jndi-name>ConnectionFactoryJNDI</wlps:connection-factory-jndi-name>
       <wlps:topic-jndi-name>TopicJNDI</wlps:topic-jndi-name>
    </wlps:jms-handler>
  </wlps:jms-handler-mapping>
  <wlps:channel>
    <wlps:channel-pattern>/chat/**</wlps:channel-pattern>
    <wlps:jms-handler-name>DefaultJmsHandler</wlps:jms-handler-name>
  </wlps:channel>
</wlps:weblogic-pubsub>

In the preceding example:

  • The <wlps:jms-handler-mapping> element defines a JMS handler named DefaultJmsHandler. The <wlps:jms-handler> child element configures specific properties of DefaultJmsHandler that the pub-sub server uses to delegate messages to the JMS topic; in particular, the JMS provider URL that the pub-sub server uses to access the JNDI tree of the JMS provider is t3://localhost:7001, the connection factory JNDI name is ConnectionFactoryJNDI, and the JNDI name of the topic to which the messages will be delegated is TopicJNDI.

  • The <wlps:jms-handler-name> child element of <wlps:channel> specifies that the channel with pattern /chat is actually a JMS channel, with JMS configuration options specified by the DefaultJmsHandler.

For the full list of JMS handler-related XML elements you can include in the weblogic-pubsub.xml deployment descriptor, see the weblogic-pubsub.xsd Schema at http://xmlns.oracle.com/weblogic/weblogic-pubsub/1.0/weblogic-pubsub.xsd.

Configuring Client Session Failover

In addition to server failover, the pub-sub server also supports client session failover in clustered environments. In client failover, whenever the status of the client changes, such as when it subscribes or unsubscribes to a channel, the latest client status is stored into a replicated HTTP session. If one node of the cluster crashes, WebLogic Server attempts to recover the clients on the crashed node by moving them to other available nodes using the replicated HTTP sessions.

To configure client session failover, update the weblogic.xml deployment descriptor file of the Web application that hosts the pub-sub application by adding a <session-descriptor> child element of the root <weblogic-web-app> element and specify that the persistent store type is replicated_if_clustered, as shown below; only relevant sections of the file are shown in bold:

<?xml version='1.0' encoding='UTF-8'?>
<weblogic-web-app
  xmlns="http://xmlns.oracle.com/weblogic/weblogic-web-app"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
 ...
  <session-descriptor>
    <persistent-store-type>replicated_if_clustered</persistent-store-type>
  </session-descriptor>
</weblogic-web-app>

Advanced Topic: Persisting Messages to Physical Storage

If you require that messages published to a particular channel be persisted, then you should configure the channel as a persistent channel. In this case, all messages published to this channel will be persisted to physical storage such as a database or the file system. In particular, this physical storage must be a pre-configured WebLogic persistent store. The WebLogic persistent store provides a built-in, high-performance storage solution for WebLogic Server subsystems and services that require persistence. The persistent store supports persistence to a file-based store or to a JDBC-enabled database. For additional details, see "Using the WebLogic Persistent Store" in Configuring Server Environments for Oracle WebLogic Server.

Oracle recommends that you create your own file or JDBC store to store the persistent messages and configure this store for the persistent channel. If, however, the pub-sub server does not find a store with the configured name, then the server attempts to use the default WebLogic persistent store to store the messages, and logs a warning message to the log file.

The pub-sub server does not allow messages to live in the persistent store indefinitely; rather, it uses a configured maximum duration property to regularly delete old messages from the store after they have been in the store longer than the max duration. By default, this maximum duration is 3600 seconds, but it can be configured differently for each persistent channel.

A client that subscribes to a persistent channel is called a persistent client. The main difference between normal clients and persistent clients is how the pub-sub server handles timeouts. There are two different timeout configuration options when configuring the pub-sub server; the following elements are children of <wlps:server-config> in the weblogic-pubsub.xml file:

  • <wlps:client-timeout-secs>—Specifies the number of seconds after which normal (non-persistent) clients are deleted and persistent clients are deactivated by the pub-sub server, if during that time the client does not send a connect or re-connect message. When deactivating, the server keeps all subscribed persistent channels for the client and unsubscribes the non-persistent channels. The default value is 60 seconds.

  • <wlps:persistent-client-timeout-secs>—Specifies the number of seconds after which persistent clients are disconnected and deleted by the pub-sub server, if during that time the persistent client does not send a connect or re-connect message. This value must be larger than client-timeout-secs. If the persistent client reconnects before the persistent timeout is reached, the client receives all messages that have been published to the persistent channel during that time; if the client reconnects after the timeout, then it does not get the messages. The default value is 600 seconds.

Configuring Persistent Channels

You configure a persistent channel in the weblogic-pubsub.xml deployment descriptor file of the pub-sub server.

First configure the pub-sub by adding a <wlps:persistent-client-timeout-secs> child element of <wlps:server-config> if you want to change the default persistent timeout value of 600 seconds. Then you configure a persistent channel by adding a <wlps:channel-persistence> child element of <wlps:channel> and specify the maximum amount of time that messages for that channel should be persisted and the name of the persistent store to which the messages should be persisted. The following example shows the relevant sections of the weblogic-pubsub.xml file:

<?xml version="1.0" encoding="UTF-8"?>
<wlps:weblogic-pubsub
    xmlns:wlps="http://xmlns.oracle.com/weblogic/weblogic-pubsub">
  <wlps:server-config>
  ...
    <wlps:persistent-client-timeout-secs>400</wlps:persistent-client-timeout-secs>
  </wlps:server-config>
  <wlps:channel>
    <wlps:channel-pattern>/chat/**</wlps:channel-pattern>
    <wlps:channel-persistence>
      <wlps:max-persistent-message-duration-secs>3000</wlps:max-persistent-message-duration-secs>
      <wlps:persistent-store>PubSubFileStore</wlps:persistent-store>
    </wlps:channel-persistence>
  </wlps:channel>
</wlps:weblogic-pubsub>

In the preceding example:

  • The persistent client timeout value is 400 seconds. This value applies to all persistent channels of this pub-sub server.

  • The channel with pattern /chat, and all its subchannels, has been configured as a persistent channel. The messages will be persisted to a WebLogic persistent store called PubSubFileStore and they will live for a maximum of 3000 seconds in the store.

    It is assumed that you have already created and configured the PubSubFileStore using the WebLogic Server Administration Console; for details, see "Using the WebLogic Persistent Store" in Configuring Server Environments for Oracle WebLogic Server.