/** * HTTPPushDemo.java * * Copyright � 1998-2011 Research In Motion Limited * * 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. * * Note: For the sake of simplicity, this sample application may not leverage * resource bundles and resource strings. However, it is STRONGLY recommended * that application developers make use of the localization features available * within the BlackBerry development platform to ensure a seamless application * experience across a variety of languages and geographies. For more information * on localizing your application, please refer to the BlackBerry Java Development * Environment Development Guide associated with this release. */ package com.rim.samples.device.httppushdemo; import java.io.IOException; import java.io.InputStream; import javax.microedition.io.Connector; import javax.microedition.io.StreamConnection; import javax.microedition.io.StreamConnectionNotifier; import net.rim.device.api.io.http.HttpServerConnection; import net.rim.device.api.io.http.MDSPushInputStream; import net.rim.device.api.system.Application; import net.rim.device.api.system.DeviceInfo; import net.rim.device.api.ui.Field; import net.rim.device.api.ui.UiApplication; import net.rim.device.api.ui.component.Dialog; import net.rim.device.api.ui.component.LabelField; import net.rim.device.api.ui.component.RichTextField; import net.rim.device.api.ui.component.SeparatorField; import net.rim.device.api.ui.container.MainScreen; import net.rim.device.api.util.DataBuffer; /** * The client side of a simple HTTP Push system. This application will listen * for data on the specified port and render the data when it arrives. */ public class HTTPPushDemo extends UiApplication { // Constants // ---------------------------------------------------------------- private static final String URL = "http://:100"; // PORT 100. private static final int CHUNK_SIZE = 256; // Members // ------------------------------------------------------------------ private ListeningThread _listeningThread; private HTTPPushDemoScreen _mainScreen; private RichTextField _infoField; private RichTextField _imageField; /** * Entry point for application. * * @param args * Command line arguments. */ public static void main(final String[] args) { // Create a new instance of the application and make the currently // running thread the application's event dispatch thread. final HTTPPushDemo theApp = new HTTPPushDemo(); theApp.enterEventDispatcher(); } /** * Creates a new HTTPPushDemo object */ public HTTPPushDemo() { // Make sure that the device is a simulator. // If it isn't display a dialog and exit the application. if (!DeviceInfo.isSimulator()) { UiApplication.getUiApplication().invokeLater(new Runnable() { public void run() { Dialog.alert("This application must be run on a simulator. Exiting application..."); System.exit(0); } }); } else { _mainScreen = new HTTPPushDemoScreen(); _mainScreen.setTitle(new LabelField("HTTP Push Demo", Field.USE_ALL_WIDTH)); _infoField = new RichTextField(); _mainScreen.add(_infoField); _mainScreen.add(new SeparatorField()); _imageField = new RichTextField(); _mainScreen.add(_imageField); // Start the listening thread _listeningThread = new ListeningThread(); _listeningThread.start(); _infoField.setText("HTTP Listen object started"); pushScreen(_mainScreen); } } // Inner Classes // ------------------------------------------------------------ /** * This class implements a Thread object which trys to connect to a HTTP url * and retrieve the url's contents to render to the screen. */ private class ListeningThread extends Thread { private boolean _stop = false; private StreamConnectionNotifier _notify; /** * Stops the thread from listening */ private synchronized void stop() { _stop = true; if (_notify != null) { try { _notify.close(); } catch (final Exception e) { } } } /** * Listen for data from the HTTP url. After the data has been read, * render the data onto the screen. * * @see java.lang.Runnable#run() */ public void run() { // Wait for the app's event thread to start while (!HTTPPushDemo.this.hasEventThread()) { Thread.yield(); } StreamConnection stream = null; InputStream input = null; MDSPushInputStream pushInputStream = null; try { _notify = (StreamConnectionNotifier) Connector.open(URL + ";deviceside=false"); while (!_stop) { // NOTE: the following will block until data is received stream = _notify.acceptAndOpen(); try { input = stream.openInputStream(); pushInputStream = new MDSPushInputStream( (HttpServerConnection) stream, input); // Extract the data from the input stream final DataBuffer db = new DataBuffer(); byte[] data = new byte[CHUNK_SIZE]; int chunk = 0; while (-1 != (chunk = input.read(data))) { db.write(data, 0, chunk); } updateMessage(data); // If the push server has application level reliabilty // enabled, this method call will acknowledge receipt // of the push. pushInputStream.accept(); data = db.getArray(); } catch (final IOException ioe) { // A problem occurred with the input stream , however, // the original // StreamConnectionNotifier is still valid. errorDialog(ioe.toString()); } finally { if (input != null) { try { input.close(); } catch (final IOException ioe) { } } if (stream != null) { try { stream.close(); } catch (final IOException ioe) { } } } } } catch (final IOException ioe) { errorDialog(ioe.toString()); } finally { if (_notify != null) { try { _notify.close(); _notify = null; } catch (final IOException e) { } } } UiApplication.getUiApplication().invokeLater(new Runnable() { public void run() { _mainScreen.close(); } }); } } /** * Updates the message currently displayed with new data. * * @param data * The data to display */ private void updateMessage(final byte[] data) { Application.getApplication().invokeLater(new Runnable() { public void run() { // Query the user to load the received message final String[] choices = { "Ok", "Cancel" }; if (0 != Dialog.ask( "New message received. Do you want to render it?", choices, 0)) { return; } _infoField.setText("Text received - size: " + data.length); try { _imageField.setText(new String(data)); } catch (final Exception e) { errorDialog("RichTextField#setText(String) threw " + e.toString()); } } }); } /** * Presents a dialog to the user with a given message * * @param message * The text to display */ public static void errorDialog(final String message) { UiApplication.getUiApplication().invokeAndWait(new Runnable() { public void run() { Dialog.alert(message); } }); } /** * This class acts as the MainScreen and calls the HTTPPushDemo.onExit() * when closing. */ private class HTTPPushDemoScreen extends MainScreen { /** * @see net.rim.device.api.ui.Screen#close() */ public void close() { _listeningThread.stop(); super.close(); } } }