Package blackberry.common.push

Source Code of blackberry.common.push.PushDaemon$CommandListener

/*
* Copyright 2010-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.
*/
package blackberry.common.push;

import java.io.IOException;
import java.util.Vector;

import javax.microedition.io.StreamConnection;

import net.rim.blackberry.api.push.PushApplication;
import net.rim.blackberry.api.push.PushApplicationStatus;
import net.rim.device.api.io.http.PushInputStream;
import net.rim.device.api.system.Application;
import net.rim.device.api.system.ApplicationDescriptor;
import net.rim.device.api.system.ApplicationManager;
import net.rim.device.api.system.ApplicationManagerException;
import net.rim.device.api.system.CodeSigningKey;
import net.rim.device.api.system.ControlledAccess;
import net.rim.device.api.system.EventLogger;
import net.rim.device.api.system.RuntimeStore;
import net.rim.device.api.util.DataBuffer;
import blackberry.common.util.ID;
import blackberry.core.ApplicationRegistry;
import blackberry.core.WidgetProperties;

/**
* The push daemon is responsible for receiving push messages, store them in a message queue and notify the UI application. It
* launches the UI application if it is not running.
*
*
*/
public class PushDaemon extends Application implements PushApplication {
   
    // Registration status
    public static final int SUCCESS = 0;
    public static final int NETWORK_ERROR = 1;
    public static final int REJECTED_BY_SERVER = 2;
    public static final int INVALID_PARAMETERS = 3;
    public static final int GENERAL_ERROR = -1;
    private static final int CHUNK_SIZE = 256;

    private int _maxQueueCap;
    private String _entryPage;
    private DaemonStore _daemonStore;
    private CommandListener _commandListener;
    private ApplicationDescriptor _uiAppDesc;

    /**
     * Data object used between the daemon and widget to communicate
     */
    final public static class DaemonStore {
        private static final long DAEMON_STORE_ID;
       
        private Vector _commandQueue;
        private Vector _messageQueue;

        static {
            DAEMON_STORE_ID = ID.getUniqueID( "DAEMON_STORE_ID" );
        }

        public static DaemonStore loadFromStore() {
            DaemonStore store = null;

            Object storeObject = RuntimeStore.getRuntimeStore().get( DAEMON_STORE_ID );
            if( storeObject != null ) {
                store = (DaemonStore) storeObject;
            } else {
                store = new DaemonStore();
                CodeSigningKey codeSigningKey = CodeSigningKey.get( store );
                RuntimeStore.getRuntimeStore().put( DAEMON_STORE_ID, new ControlledAccess( store, codeSigningKey ) );
            }

            return store;
        }

        private DaemonStore() {
            _commandQueue = new Vector();
            _messageQueue = new Vector();
        }

        /**
         * Get vector holding command messages to the daemon
         *
         * @return command queue vector
         */
        public Vector getCommandQueue() {
            return _commandQueue;
        }

        /**
         * Get vector holding push messages
         *
         * @return message queue object
         */
        public Vector getMessageQueue() {
            return _messageQueue;
        }

    }

    /**
     * Constructor.
     *
     * @param entryPage
     *            The page of the UI application to be shown if it is not running
     * @param maxQueueCap
     *            The maximum number of message to store in the message queue
     */
    public PushDaemon( String entryPage, int maxQueueCap ) {
        _entryPage = entryPage;
        _maxQueueCap = maxQueueCap;

        _daemonStore = DaemonStore.loadFromStore();
        _daemonStore.getCommandQueue().removeAllElements(); // clear all commands

        _commandListener = new CommandListener();
        _commandListener.start();
       
        _uiAppDesc = new ApplicationDescriptor( ApplicationDescriptor.currentApplicationDescriptor(), PushPersistentStore.getAppDescArgs() );
       
        EventLogger.logEvent( WidgetProperties.getInstance().getGuid(), "PushDaemon is started.".getBytes() );
    }

    /**
     * onMessage handle inbound push notifications
     *
     * @param stream
     *            inbound PushInputStream
     *
     * @param conn
     *            inbound StreamConnection
     *
     * @see PushApplication#.onMessage(PushInputStream, StreamConnection)
     */
    public void onMessage( PushInputStream inputStream, StreamConnection conn ) {
        handleMessage( inputStream, conn );
    }

    /**
     * onStatusChange Called when Push Status changes
     *
     * @param status
     *            changed push state.
     *
     * @see PushApplication#onStatusChange(PushApplicationStatus)
     */
    public void onStatusChange( PushApplicationStatus status ) {
        handleStatusChange( status );
    }

    private void launchUI() {
        // launch UI if it is not running
        EventLogger.logEvent( WidgetProperties.getInstance().getGuid(), ( "Check if application is running" ).getBytes(),
                EventLogger.DEBUG_INFO );
        if( !ApplicationRegistry.isAppRunning() ) {
            EventLogger.logEvent( WidgetProperties.getInstance().getGuid(), ( "Launch application" ).getBytes(),
                    EventLogger.DEBUG_INFO );
            ApplicationDescriptor newAppDesc = new ApplicationDescriptor( _uiAppDesc, new String[] { _entryPage } );
            try {
                ApplicationManager.getApplicationManager().runApplication( newAppDesc, false );
            } catch( ApplicationManagerException e ) {
                EventLogger.logEvent( WidgetProperties.getInstance().getGuid(), ( "Error launching UI" ).getBytes(),
                        EventLogger.ERROR );
            }
        }
    }

    private void handleMessage( PushInputStream inputStream, StreamConnection conn ) {

        EventLogger.logEvent( WidgetProperties.getInstance().getGuid(), ( "handleMessage is called." ).getBytes(), EventLogger.DEBUG_INFO );
       
        DataBuffer db = null;
        try {
            /**
             * Does this need to be synch'd? This should be a single threaded instance that runs autonomously on a port.
             *
             * Might want to call this in the the PushService class to catch IOPortAlreadyBoundException so we can properly throw
             * this back up via JavaScript so the developer realizes that the port they tried to open is unavailable.
             */

            Vector messageQueue = _daemonStore.getMessageQueue();

            // extract the data from the input stream
            db = new DataBuffer();
            byte[] data = new byte[ CHUNK_SIZE ];
            int chunk = 0;
            while( -1 != ( chunk = inputStream.read( data ) ) ) {
                db.write( data, 0, chunk );
            }

            // trim the array - the buffer in DataBuffer grows
            // past the size and fills with empty chars
            db.trim();

            // synchronize this block to avoid race conditions with the queue
            synchronized( messageQueue ) {
                // Create push object, add to queue for callback thread
                PushData pd = new PushData( conn, inputStream, db.getArray() );
                if( _maxQueueCap > 0 ) {
                    if( messageQueue.size() >= _maxQueueCap ) {
                        messageQueue.removeElementAt( 0 );
                    }
                }

                messageQueue.addElement( pd );
                messageQueue.notify();
            }
        } catch( IOException e1 ) {
            // a problem occurred with the input stream
            // however, the original StreamConnectionNotifier is still valid
            if( inputStream != null ) {
                try {
                    inputStream.close();
                } catch( IOException e2 ) {
                }
            }
            if( conn != null ) {
                try {
                    conn.close();
                } catch( IOException e2 ) {
                }
            }
        }

        launchUI();
    }

    private void handleStatusChange( PushApplicationStatus applicationStatus ) {
        int result = GENERAL_ERROR;
        boolean simChange = false;
        int status = applicationStatus.getStatus();

        EventLogger.logEvent( WidgetProperties.getInstance().getGuid(), ( "handleStatusChange is called, status:" + status ).getBytes(), EventLogger.DEBUG_INFO );

        if( status == PushApplicationStatus.STATUS_ACTIVE ) {
            result = SUCCESS;
        } else if( status == PushApplicationStatus.STATUS_FAILED ) {
            if( applicationStatus.getReason() == PushApplicationStatus.REASON_NETWORK_ERROR ) {
                result = NETWORK_ERROR;
            } else if( applicationStatus.getReason() == PushApplicationStatus.REASON_REJECTED_BY_SERVER ) {
                result = REJECTED_BY_SERVER;
            } else if( applicationStatus.getReason() == PushApplicationStatus.REASON_INVALID_PARAMETERS ) {
                result = INVALID_PARAMETERS;
            } else if( applicationStatus.getReason() == PushApplicationStatus.REASON_SIM_CHANGE ) {
                simChange = true;
            }
        } else if( status == PushApplicationStatus.STATUS_NOT_REGISTERED ) {
            if( applicationStatus.getReason() == PushApplicationStatus.REASON_NETWORK_ERROR ) {
                result = NETWORK_ERROR;
            } else if( applicationStatus.getReason() == PushApplicationStatus.REASON_REJECTED_BY_SERVER ) {
                result = REJECTED_BY_SERVER;
            } else if( applicationStatus.getReason() == PushApplicationStatus.REASON_INVALID_PARAMETERS ) {
                result = INVALID_PARAMETERS;
            } else if( applicationStatus.getReason() == PushApplicationStatus.REASON_SIM_CHANGE ) {
                simChange = true;
            }
        }

        Vector messageQueue = _daemonStore.getMessageQueue();

        synchronized( messageQueue ) {
            Object data;
            if( simChange ) {
                data = new SimChangeData();
            } else {
                data = new StatusChangeData( result );
            }
            messageQueue.addElement( data );
            messageQueue.notify();
        }

        launchUI();
    }

    public static class StatusChangeData {
        private int _status;

        public StatusChangeData( int status ) {
            _status = status;
        }

        public int getStatus() {
            return _status;
        }
    }

    public static class SimChangeData {
    }

    public class CommandListener extends Thread {

        private boolean _stop;

        public CommandListener() {
            _stop = false;
        }

        /**
         * @see java.lang.Thread
         */
        public void run() {
            while( !_stop ) {

                Vector commandQueue = _daemonStore.getCommandQueue();

                synchronized( commandQueue ) {
                    if( commandQueue.size() == 0 ) {
                        try {
                            commandQueue.wait();
                        } catch( Exception e ) {
                            // ignore - check loop
                        }
                    }
                    if( commandQueue.size() > 0 ) {
                        _stop = true;
                    }
                }
            }
            EventLogger.logEvent( WidgetProperties.getInstance().getGuid(), "PushDaemon exits".getBytes() );
            System.exit( 0 );
        }
    }
}
TOP

Related Classes of blackberry.common.push.PushDaemon$CommandListener

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.