FileDocCategorySizeDatePackage
ClientHandler.javaAPI DocphoneME MR2 API (J2ME)8344Wed May 02 18:00:30 BST 2007com.sun.midp.jsr82emul

ClientHandler.java

/*
 *   
 *
 * Copyright  1990-2007 Sun Microsystems, Inc. All Rights Reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License version
 * 2 only, as published by the Free Software Foundation.
 * 
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * General Public License version 2 for more details (a copy is
 * included at /legal/license.txt).
 * 
 * You should have received a copy of the GNU General Public License
 * version 2 along with this work; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 * 
 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
 * Clara, CA 95054 or visit www.sun.com if you need additional
 * information or have any questions.
 */
package com.sun.midp.jsr82emul;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import javax.microedition.io.SocketConnection;
import com.sun.midp.io.BluetoothUrl;
import java.util.Hashtable;
import java.util.Enumeration;

/**
 * Handles communication with a client.
 */
class ClientHandler implements Runnable {
    /** Handle that identifies corresponding data on server. */
    int handle;
    /** Common handlers counter. */
    private static int nextHandle = 0;
    
    /** Bluetooth address of device or device emulation client belongs to. */
    byte[] bluetoothAddress = null;
    
    /** If not <code>null</code>, IP address of computer client works at. */
    byte[] ipAddress = null;
    
    /**
     * Keeps device state if this handler handles device, 
     * <code>null</code> otherwise. 
     */
    DeviceState deviceState = null;
        
    /**
     * if this handler handles device, then keeps services available at it,
     * else <code>null</code>. 
     */
    Hashtable deviceServices = null;
        
    /**
     * Keeps messenger that provides utilities for communicating with client.
     */
    private Messenger messenger = new Messenger();
    
    /** Keeps socket connection to the server. */
    private SocketConnection connection; 
    /** Keeps input stream from server. */
    private InputStream fromClient;                                   
    /** Keeps output stream to server. */
    private OutputStream toClient;
    
    /** 
     * Retrieves handle value for a new handler. 
     * @return new free handle value
     */
    private static synchronized int getNextHandle() {
        return ++nextHandle;
    }
    
    /**
     * Constructs client handle to communicate with a client thru
     * given connection.
     * @param connection an open connection with a client on the other side
     * @exception IOException if connection fails
     */
    ClientHandler(SocketConnection connection) throws Exception {
        this.connection = connection;
        fromClient = connection.openDataInputStream();
        toClient = connection.openDataOutputStream();
        handle = getNextHandle();
        
        Thread t = new Thread(this);
        t.start();
    }

    /** 
     * Implements <code>Runnable</code>, processes client's rquests.
     */
    public void run() {
        Exception exception = null;
    
        try {
            loop:
            while (true) {
                messenger.receive(fromClient);
            
                switch (messenger.getCode()) {
                    case Messenger.REGISTER_DEVICE:
                        ipAddress = messenger.getBytes();
                        
                        deviceServices = new Hashtable();
                        // IMPL_NOTE: how it works against Push TCK tests?
                        // default device state: not discoverable
                        deviceState = new DeviceState();
                        
                        bluetoothAddress = EmulationServer.getInstance().
                            registerDevice(deviceState);
                        
                        messenger.sendBytes(toClient, Messenger.REGISTERED,
                            bluetoothAddress);
                            
                        break;
                        
                    case Messenger.UPDATE_DEVICE_STATE:
                        deviceState.update(messenger.getInt());
                        break;
                        
                    case Messenger.REGISTER_SERVICE:
                        ServiceConnectionData serv = new ServiceConnectionData(
                            messenger.getBytes(),
                            ServiceConnectionData.SERVER_DATA);
                        serv.address = ipAddress;
                        
                        ServiceKey key = EmulationServer.getInstance().
                            registerService(serv, bluetoothAddress);
        
                        if (!deviceServices.containsKey(key)) {
                            deviceServices.put(
                                new Integer(serv.socketPort), key);
                        }
                        break;

                    case Messenger.UNREGISTER_SERVICE:
                        key = (ServiceKey)deviceServices.
                            remove(new Integer(messenger.getInt()));
                        
                        if (key != null) {
                            EmulationServer.getInstance().
                                    unregisterService(key);
                            key = null;
                        }
                        break;
                                                
                    case Messenger.CONNECT_TO_SERVICE:
                        serv = EmulationServer.getInstance().connectToService(
                                new ServiceConnectionData(
                                    messenger.getBytes(),
                                    ServiceConnectionData.CONN_REQUEST_DATA));
                        
                        messenger.sendBytes(toClient, Messenger.SERVICE_AT,
                            serv.toByteArray(
                            ServiceConnectionData.CONNECTION_DATA));
                        
                        break;
                        
                    case Messenger.START_INQUIRY:
                        InquiryResults results = EmulationServer.getInstance().
                            runInquiry(messenger.getInt(), bluetoothAddress);
                        messenger.sendBytes(toClient, 
                            Messenger.INQUIRY_COMPLETED, results.toByteArray());
                        break;
                        
                    case Messenger.DONE:
                        break loop;
                
                    default: throw new EmulationException("Unknown client request");
                }
            } // end of loop:
        
        } catch (EmulationException ee) {
            exception = ee;
        } catch (IOException e) {
            exception = e;
        } finally {
            if (exception != null) {
                try {
                    messenger.send(toClient, Messenger.ERROR, exception.getMessage());
                } catch (IOException e) {
                    // ignoring - stop handling anyway
                }
            }
            
            if (deviceState != null) {
                EmulationServer.getInstance().
                    unregisterDevice(bluetoothAddress);
            
                Enumeration records = deviceServices.elements();
                while (records.hasMoreElements()) {
                    EmulationServer.getInstance().unregisterService(
                        (ServiceKey)records.nextElement());
                }
            }
            disconnect();
        }
    }
    
    /**
     * Closes current socket connection.
     */
    private void disconnect() {
        try { 
            connection.close();
            toClient.close();
            fromClient.close();
        } catch (IOException e) {
            // ignoring
        }
        
        connection = null;
        fromClient = null;
        toClient = null;
    }
}