All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.gwtwidgets.client.stream.HtmlStreamReader Maven / Gradle / Ivy

Go to download

*** THIS IS AN OBSOLETE VERSION UPLOADED FOR USE WITH CEDAR-COMMON.*** The Server Library for GWT is a collection of Java server side components for the Google Web Toolkit AJAX framework with the focus on the Spring framework by facilitating publishing of Spring beans as RPC services with support for Hibernate-managed entities.

The newest version!
/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.gwtwidgets.client.stream;

import java.util.Date;

import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.IFrameElement;
import com.google.gwt.dom.client.NodeList;
import com.google.gwt.http.client.URL;
import com.google.gwt.user.client.Timer;

/**
 * Decodes SL stream protocol messages sent via the
 * {@link HtmlSLStreamWriterImpl}. This implementation creates an invisible
 * IFrame which is appended to the current document and polled in intervals.
 * Decoded messages are then removed from the DOM in order to reduce resource
 * consumption.
 * 
 * @author George Georgovassilis, g.georgovassilis[at]gmail.com
 * 
 */

public class HtmlStreamReader {

	protected IFrameElement frame;
	protected long pollingInterval = 1000;
	protected long maxAge = 5 * 60*1000;
	protected Timer timer;
	protected Date dateOfCreation;
	protected int lastMessageId = -1;

	private boolean isObsolete() {
		Date now = new Date();
		long diff = now.getTime() - dateOfCreation.getTime();
		return diff > maxAge;
	}

	//workaround until GWT #2805 is released
	protected native Document getFrameContents(IFrameElement frame)/*-{
			return frame.contentWindow.document; 
		}-*/;

	private Message decodeMessage(Element e) {
		Message message = new Message();
		String content = e.getInnerText();
		String[] parts = content.split(",");
		message.setContent(URL.decodeQueryString(parts[0]));
		for (int i = 1; i < parts.length; i++) {
			String[] keyValuePair = parts[i].split("=");
			message.getAttributes().put(URL.decodeQueryString(keyValuePair[0]), URL.decodeQueryString(keyValuePair[1]));
		}
		message.setSerialNumber(Integer.parseInt(e.getAttribute("id")));
		return message;
	}

	private Message checkForEOF(Document document) {
		NodeList eSpans = document.getElementsByTagName("span");
		if (eSpans.getLength() == 0)
			return null;
		Element eSpan = eSpans.getItem(0);
		if ("EOF".equals(eSpan.getInnerText())) {
			Message message = new Message();
			message.setEOF(true);
			return message;
		}
		return null;
	}

	protected Message readNextMessage() {
		Document document = getFrameContents(frame);
		if (null == document)
			return null;
		NodeList elements = document.getElementsByTagName("div");
		if (elements.getLength() == 0) {
			return checkForEOF(document);
		}
		Element eDiv = elements.getItem(0);
		eDiv.getParentElement().removeChild(eDiv);
		Message message = decodeMessage(eDiv);
		lastMessageId = message.getSerialNumber();
		return message;
	};

	public long getPollingInterval() {
		return pollingInterval;
	}

	/**
	 * Sets a polling interval - messages arriving from the server will be
	 * decoded every such interval. Please note that this parameter is passed to
	 * {@link Timer#schedule(int)} which receives an integer argument; hence
	 * large values for pollingInterval will not yield the
	 * desired behavior.
	 * 
	 * @param pollingInterval
	 *            Polling interval in milliseconds
	 */
	public void setPollingInterval(long pollingInterval) {
		this.pollingInterval = pollingInterval;
	}

	protected Element getFrame() {
		return frame;
	}

	/**
	 * For debugging purposes, can be used to show the IFrame used to receive
	 * server messages.
	 * 
	 * @param status
	 */
	public void setInnerFrameVisibility(boolean status) {
		//		frame.getStyle().setProperty("visibility", status?"visible":"hidden");
	}

	public HtmlStreamReader() {
	}

	/**
	 * Connects to a URL an starts streaming messages from there. Note that
	 * despite this being an asynchronous message, the {@link HtmlStreamReader}
	 * is a stateful object which cannot be used to simultaneously access more
	 * resources.
	 * 
	 * @param url
	 * @param callback
	 */
	public void readAsync(final String url, final StreamCallback callback) {
		GWT.log("Openeing stream to "+url, null);
		final String sUrl = url+(url.contains("&")?"&":"?")+"lastmessageid="+lastMessageId;
		dateOfCreation = new Date();
		frame = Document.get().createIFrameElement();
		setInnerFrameVisibility(false);
		Document.get().getBody().appendChild(frame);
		frame.setSrc(sUrl);
		timer = new Timer() {
			@Override
			public void run() {
				try {
					Message message = null;
					while (null != (message = readNextMessage())) {
						if (message.isEOF()) {
							close();
							callback.onDisconnect();
							return;
						}
						callback.onMessage(message);
					}
					if (isObsolete()) {
						reconnect(url, callback);
						return;
					}
					timer.schedule((int) getPollingInterval());
				} catch (Exception e) {
					close();
					callback.onError(e);
				}
			}
		};
		timer.schedule((int) getPollingInterval());
	}
	
	protected void reconnect(String url, StreamCallback callback){
		GWT.log("Refreshing connection to server with id "+lastMessageId, null);
		close();
		readAsync(url, callback);
	}

	/**
	 * Should be called if the client wants to close the stream communication
	 * with the server.
	 */
	public void close() {
		frame.setSrc("");
		timer.cancel();
		frame.getParentElement().removeChild(frame);
		frame = null;
	}

	/**
	 * Determines the age (in ms) of a connection to a server before closing and refreshing it
	 * @param maxAge
	 */
	public void setMaxAge(long maxAge) {
		this.maxAge = maxAge;
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy