Server Side Comet Publish Application Tutorial

This tutorial demonstrates the simplicity in publishing events from the Server.

To demonstrate the ease of using Comet (AJAX push, reverse AJAX) functionality on the Server within a OfficeFloor web application the following simple chat application will be used for this tutorial.

CometManualApp screenshot.

The application will:

  1. Initially request a user name that is stored in the HTTP session
  2. Send and receive chat messages indicating who sent each message using the respective HTTP session

The application in this tutorial is deliberately simple to allow focus on the Comet functionality.

Download Tutorial Source

Template.html

The below is the content of the Template.html.

<html>
	<body>
		<p>Chat:</p>
		
		<center><big>  <p id="chat"></p>  </big></center>
		
	</body>
</html>

TemplateLogic Class

The template logic object is as follows.

public class TemplateLogic {

	public void login(@Parameter String userName, User user,
			AsyncCallback<Void> callback) {

		user.setName(userName);
		callback.onSuccess(null);
	}

	public void message(@Parameter CometEvent event, User user,
			ConversationSubscription publisher, AsyncCallback<Long> callback) {

		ConversationMessage message = (ConversationMessage) event.getData();
		publisher.message(new ConversationMessage(user.getName(), message
				.getText()));
		callback.onSuccess(Long.valueOf(1));
	}
}

The above provides two methods, that respectively:

  • login the user by storing their user name within the HTTP session
  • handle sending a message which adds the user name and is published by the Server

The following demonstrates the configuration necessary to add the template.

CometApp Add template dialog screenshot.

For manually handling the published event the method name is specified. This allows the Server code to intercept all published events from the clients and manually handle them. In the case of this tutorial, adding the user name to the message before publishing the event. The parameter to this specified method is always a CometEvent. It also follows the GWT RPC handling pattern and therefore must notify that successfully serviced the GWT RPC request via the AsyncCallback.

The typical reason for manually handling the published events is to push them onto a queue for a cluster of web servers. This enables multiple web servers to be notified of the published event and subsequently publish the event to all the Comet clients. This is necessary as the Comet client establishes a connection to only one web server in the cluster.

@CometPublisherInterface

The Comet event is published by the server via the following interface.

@CometPublisherInterface
public interface ConversationSubscription extends CometSubscriber {

	void message(ConversationMessage message);

}

The annotation informs WoOF to dependency inject an implementation of the interface that will allow the server code to publish the CometEvent.

An interface with this annotation must adhere to the same rules of a CometSubscriber (e.g. single method with a single parameter).

OfficeFloor will publish the event with the following details:

  • Listener type: the interface type name
  • Data: the value of the first parameter
  • Filter Key: null

The reason for using the interface is to allow type safe publishing of events.

The following POJO is the event data sent.

public class ConversationMessage implements IsSerializable {

	private String name;

	private String text;

	public ConversationMessage(String name, String text) {
		this.name = name;
		this.text = text;
	}

	public ConversationMessage(String text) {
		this(null, text);
	}
	
	public ConversationMessage() {
	}

	public String getName() {
		return this.name;
	}

	public String getText() {
		return this.text;
	}

}

User Name

The user name is stored in the HTTP session with the following object.

@HttpSessionStateful
public class User implements Serializable {

	private String name;

	public void setName(String name) {
		this.name = name;
	}

	public String getName() {
		return this.name;
	}

}

The following GWT RPC interfaces are used to send the user name to the server.

@RemoteServiceRelativePath("username")
public interface UserNameService extends RemoteService {

	void login(String userName);

}
public interface UserNameServiceAsync {

	void login(String userName, AsyncCallback<Void> callback);

}

Client Side Code

The GWT client side code is included as follows for completeness of this tutorial.

public class CometManualAppEntryPoint implements EntryPoint {

	/**
	 * {@link UserNameService}.
	 */
	private final UserNameServiceAsync userNameService = GWT
			.create(UserNameService.class);

	@Override
	public void onModuleLoad() {

		// Vertically align contents
		RootPanel panel = RootPanel.get("chat");
		VerticalPanel chatPanel = new VerticalPanel();
		panel.add(chatPanel);

		// Provide dialog box for user name
		final DialogBox dialogBox = new DialogBox();
		dialogBox.setModal(true);
		HorizontalPanel userNamePanel = new HorizontalPanel();
		dialogBox.add(userNamePanel);
		userNamePanel.add(new Label("Enter user name: "));
		final TextBox userNameTextBox = new TextBox();
		userNamePanel.add(userNameTextBox);
		Button userNameSubmit = new Button("submit");
		userNamePanel.add(userNameSubmit);
		dialogBox.show();
		dialogBox.center();
		userNameSubmit.addClickHandler(new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				CometManualAppEntryPoint.this.userNameService.login(
						userNameTextBox.getText(), new AsyncCallback<Void>() {
							@Override
							public void onSuccess(Void result) {
								dialogBox.hide();
							}

							@Override
							public void onFailure(Throwable caught) {
								Window.alert("Failed to specify user name");
							}
						});
			}
		});

		// Provide the text area to contain conversation
		final TextArea conversation = new TextArea();
		conversation.setReadOnly(true);
		conversation.setSize("100%", "300px");
		chatPanel.add(conversation);

		// Handle listening for messages
		OfficeFloorComet.subscribe(ConversationSubscription.class,
				new ConversationSubscription() {
					@Override
					public void message(ConversationMessage message) {
						conversation.setText(conversation.getText() + "\n"
								+ message.getName() + ": " + message.getText());
					}
				}, null);

		// Provide means to add message
		HorizontalPanel messagePanel = new HorizontalPanel();
		chatPanel.add(messagePanel);
		final TextBox message = new TextBox();
		message.setWidth("80%");
		messagePanel.add(message);
		Button send = new Button("send");
		messagePanel.add(send);

		// Handle submitting a message
		final ConversationSubscription publisher = OfficeFloorComet
				.createPublisher(ConversationSubscription.class);
		send.addClickHandler(new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				String messageText = message.getText();
				publisher.message(new ConversationMessage(messageText));
			}
		});
	}
}

Next

See the other tutorials for further functionality.