/** * BrowserRimPushDemo.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.server.browserpushdemo.rimpush; import java.io.*; import java.net.*; import java.util.*; public class BrowserRimPushDemo { public static final String CHANNEL = "Browser-Channel"; public static final String CHANNEL_DELETE = "Browser-Channel-Delete"; private static final String PROPERTIES_FILE = "com/rim/samples/server/browserpushdemo/rimpush/rim_browserpush.properties"; /** * Main method to read in properties file and invoke the push method. * * @param args Command-line arguments (not used). */ public static void main( String[] args ) { // load the properties file Properties prop = new Properties(); try { prop.load( new FileInputStream( PROPERTIES_FILE ) ); } catch ( FileNotFoundException fnfe ) { throw new RuntimeException( "Properties file not found: " + fnfe.getMessage() ); } catch ( IOException ioe ) { throw new RuntimeException( "Error reading properties file: " + ioe.getMessage() ); } // The host name and port of Mobile Data Service to perform the push. String mdsHostName = prop.getProperty( "mdsHostName" ); int mdsPort = Integer.parseInt( prop.getProperty( "mdsPort" ) ); // Handheld email to which to push the page. String email = prop.getProperty( "email" ); // The channel ID. String channelID = prop.getProperty( "channelID" ); // The type of push. String pushType = prop.getProperty( "pushType" ); // The title of the page to push. String pushTitle = prop.getProperty( "pushTitle" ); // The actual page (and icons) to push. String contentUrlString = prop.getProperty( "contentUrlString" ); String unreadIconUrl = prop.getProperty( "unreadIconUrl" ); String readIconUrl = prop.getProperty( "readIconUrl" ); // The reliability settings. String pushReliability = prop.getProperty( "pushReliability" ); String notifyUrl = prop.getProperty( "notifyUrl" ); // The push ID. String pushID = prop.getProperty( "pushID" ); // Push the page to the handheld. pushPage( mdsHostName, mdsPort, email, channelID, contentUrlString, pushType, pushTitle, unreadIconUrl, readIconUrl, pushReliability, notifyUrl, pushID ); } /** * Pushes a webpage to a BlackBerry handheld. */ public static void pushPage( String mdsHostName, int mdsPort, String email, String channelID, String contentUrlString, String pushType, String pushTitle, String unreadIconUrl, String readIconUrl, String pushReliability, String notifyUrl, String pushID ) { // Start the notification thread to receive push notifications from the MDS. new NotificationThread().start(); // Two HttpURLConnections are used. One connects to the content server to // retrieve the information to be pushed to the handheld. The other connects // to the Mobile Data Service to deliver that information for pushing down // to the handheld. try { URL mdsUrl = new URL( "http", mdsHostName, mdsPort, "/push?DESTINATION=" + email + "&PORT=7874&REQUESTURI=/" ); HttpURLConnection mdsConn = (HttpURLConnection) mdsUrl.openConnection(); // Set additional header properties for the push. mdsConn.setRequestProperty( "Content-Location", contentUrlString ); mdsConn.setRequestProperty( "X-Rim-Push-Title", pushTitle ); mdsConn.setRequestProperty( "X-Rim-Push-Type", pushType ); mdsConn.setRequestProperty( "X-Rim-Push-ID", pushID ); if ( pushType.equals( CHANNEL ) || pushType.equals( CHANNEL_DELETE ) ) { mdsConn.setRequestProperty( "X-Rim-Push-Channel-ID", contentUrlString ); if ( pushType.equals( CHANNEL ) ) { mdsConn.setRequestProperty( "X-Rim-Push-Unread-Icon-URL", unreadIconUrl ); mdsConn.setRequestProperty( "X-Rim-Push-Read-Icon-URL", readIconUrl ); } } mdsConn.setRequestProperty( "X-Rim-Push-Reliability", pushReliability ); mdsConn.setRequestProperty( "X-Rim-Push-NotifyURL", notifyUrl ); try { mdsConn.setRequestMethod( "POST" ); } catch ( ProtocolException e ) { throw new RuntimeException( "Error setting request method: " + e.getMessage() ); } mdsConn.setAllowUserInteraction( false ); mdsConn.setDoInput( true ); if ( pushType.equals( CHANNEL_DELETE ) ) { mdsConn.setDoOutput( false ); } else { mdsConn.setDoOutput( true ); // Channel is not being deleted, so get content from the content server. URL contentUrl; try { contentUrl = new URL( contentUrlString ); } catch ( MalformedURLException e ) { throw new RuntimeException( "Invalid content URL: " + e.getMessage() ); } HttpURLConnection contentConn = (HttpURLConnection) contentUrl.openConnection(); contentConn.setAllowUserInteraction( false ); contentConn.setDoInput( true ); contentConn.setDoOutput( false ); contentConn.setRequestMethod( "GET" ); contentConn.connect(); // Read the header properties from the push connection and // write them to Mobile Data Service connection. String name; String value; for ( int i = 0; true; ++i ) { name = contentConn.getHeaderFieldKey( i ); value = contentConn.getHeaderField( i ); if ( name == null && value == null ) break; if ( name == null || value == null ) continue; if ( name.equals( "X-Rim-Push-Type" ) ) continue; if ( name.equals( "Transfer-Encoding" ) ) continue; System.out.println( "Setting header property: " + name + " = " + value ); mdsConn.setRequestProperty( name, value ); } // Read content from the push connection and write it to the // MDS connection. // // NOTE: This step can be skipped (except for Browser-Content type) // and then the browser will fetch the page itself. // NOTE: If the code is modified to push the same page to multiple // devices, the content should be copied to a temporary file // first to avoid multiple requests to the content URL. copyStreams( contentConn.getInputStream(), mdsConn.getOutputStream() ); } System.out.println( "Connecting to " + mdsHostName + ':' + mdsPort ); mdsConn.connect(); int rescode = mdsConn.getResponseCode(); if ( rescode != HttpURLConnection.HTTP_OK ) { throw new RuntimeException( "Cannot push data; received bad response code from Mobile Data Service: " + rescode + ", " + mdsConn.getResponseMessage() ); } System.out.println( "Pushed page to the handheld." ); // Display the values read from the properties file. displayProperties( mdsHostName, mdsPort, email, channelID, pushType, pushTitle, contentUrlString, unreadIconUrl, readIconUrl, pushReliability, notifyUrl, pushID ); } catch ( IOException e ) { throw new RuntimeException( "Cannot push page: " + e.toString() ); } } /** * Displays the values read from the properties file. */ private static void displayProperties( String mdsHostName, int mdsPort, String email, String channelID, String pushType, String pushTitle, String contentUrlString, String unreadIconUrl, String readIconUrl, String pushReliability, String notifyUrl, String pushID ) { System.out.println( "\n------------------------------------" ); System.out.println( "\nProperties:\n" ); System.out.println( "mdsHostName = " + mdsHostName ); System.out.println( "mdsPort = " + mdsPort ); System.out.println( "email = " + email ); System.out.println( "channelID = " + channelID ); System.out.println( "pushType = " + pushType ); System.out.println( "pushTitle = " + pushTitle ); System.out.println( "contentUrlString = " + contentUrlString ); System.out.println( "unreadIconUrl = " + unreadIconUrl ); System.out.println( "readIconUrl = " + readIconUrl ); System.out.println( "pushReliability = " + pushReliability ); System.out.println( "notifyUrl = " + notifyUrl ); System.out.println( "pushID = " + pushID ); } /** * Method to read data from the input stream and copy it to the output stream. * * @param ins The input stream to copy from. * @param outs The output stream to copy to. */ private static void copyStreams( InputStream ins, OutputStream outs ) throws IOException { int maxRead = 1024; byte [] buffer = new byte[1024]; int bytesRead; for ( ; ; ) { bytesRead = ins.read( buffer ); if ( bytesRead <= 0 ) break; outs.write( buffer, 0, bytesRead ); } } /** * Thread that receives push notifications from the MDS. */ private static class NotificationThread extends Thread { private static final int NOTIFY_PORT = 7778; /** * Receives push notification data from the MDS and displays it on screen. */ public void run() { try { System.out.println( "Waiting for notification on port " + NOTIFY_PORT + "..." ); while ( true ) { ServerSocket serverSocket = new ServerSocket( NOTIFY_PORT ); serverSocket.setSoTimeout( 120000 ); try { Socket clientSocket = serverSocket.accept(); InputStream input = clientSocket.getInputStream(); StringBuffer buffer = new StringBuffer(); int byteRead = input.read(); while ( byteRead != -1 && input.available() > 0 ) { buffer.append( (char) byteRead ); byteRead = input.read(); } clientSocket.close(); // Display the push notification received from the MDS. System.out.println( "\n------------------------------------" ); System.out.println( "\nPush notification received from MDS:" ); System.out.println ( '\n' + buffer.toString() ); break; // received notification...thread's work is done } catch ( SocketTimeoutException ste ) { System.out.println( "Notification connection timeout. Restarting..." ); } serverSocket.close(); } } catch ( Exception exception ) { exception.printStackTrace(); } } } }