ExchangerCommImpl.java

/*
 * Copyright © 2012 Nokia Corporation. All rights reserved.
 * Nokia and Nokia Connecting People are registered trademarks of Nokia Corporation. 
 * Oracle and Java are trademarks or registered trademarks of Oracle and/or its
 * affiliates. Other product and company names mentioned herein may be trademarks
 * or trade names of their respective owners. 
 * See LICENSE.TXT for license information.
 */ 
package com.nokia.example.bcexchanger.comm;

import java.io.IOException;

import javax.bluetooth.DiscoveryAgent;
import javax.bluetooth.LocalDevice;
import javax.microedition.io.Connection;
import javax.microedition.io.Connector;
import javax.obex.HeaderSet;
import javax.obex.Operation;
import javax.obex.ServerRequestHandler;
import javax.obex.SessionNotifier;

/**
 * 
 * This class is the central class in the OBEX communication module
 * (package bcexchanger.comm).
 * 
 * Class implements interface ExchangerComm and realizes the methods
 * for controlling process of sending and receiving business cards. It
 * also is a parent for states of the BCExchanger communication state
 * machine. It keeps the current state of the state machine and
 * implements interface ExchangerStateParent. Using this interface
 * state classes access to the required functionality of the parent.
 * 
 * This class waits for Bluetooth incoming connection in the separate
 * thread and therefore it implements Runnable interface.
 * 
 * This class also works as a OBEX server. In order to serve OBEX
 * requests it extends the ServerRequestHandler class and overrides
 * some of its methods.
 * 
 * @see bcexchanger.comm.ExchangerStateParent
 *      bcexchanger.comm.ExchangerComm javax.obex.ServerRequestHandler
 *      Design patterns: State
 * 
 */
public class ExchangerCommImpl extends ServerRequestHandler
        implements ExchangerStateParent, ExchangerComm, Runnable {

    // Instance variables
    final private String uuid = "ed495afe28ed11da94d900e08161165f";
    final private String serverURL = "btgoep://localhost:" + uuid;
    private boolean cancelWaitingInvoked = false; // becomes true if
    // cancelWaiting() is
    // called
    private Thread waitingThread;
    private ExchangeListener listener;
    private ExchangerState currentState;
    private SessionNotifier notifier = null;
    private Connection con = null;

    /**
     * Constructor
     * <p>
     * description
     * 
     * @param _listener -
     *          listener of the communication module events
     * @exception
     * @see
     */
    public ExchangerCommImpl(ExchangeListener _listener) {
        listener = _listener;

        startWaiting();
        setState(new IdleState(this));
    }

    public void setState(ExchangerState state) {

        currentState = state;
    }

    public ExchangeListener getListener() {
        return listener;
    }

    public ExchangerState getState() {
        return currentState;
    }

    public void startSending(int oper) throws Exception {
        getState().startSending(oper);
    }

    public void startSending() throws Exception {
        getState().startSending(0);
    }

    public void cancelSending() {
        getState().cancelSending();
    }

    public void startWaiting() {
        cancelWaitingInvoked = false;

        waitingThread = new Thread(this);
        waitingThread.start();
    }

    public void cancelWaiting() {
        cancelWaitingInvoked = true;

        try {
            notifier.close(); // indicate to acceptAndOpen that it is
            // canceled
        } catch (IOException e) {
            // Ignore, we're closing anyways
        }
    }

    public synchronized void run() {
        // initialize stack and make the device discoverable
        try {
            LocalDevice local = LocalDevice.getLocalDevice();
            local.setDiscoverable(DiscoveryAgent.GIAC);
        } catch (Exception e) {
            // catching notifier exception
            listener.onServerError();
            return;
        }
        try {
            notifier = (SessionNotifier) Connector.open(serverURL);
        } catch (IOException e) {
        }
        // the cycle stops only if cancelWaiting() was called
        while (!cancelWaitingInvoked) {
            try {
                con = notifier.acceptAndOpen(this);
                wait(); // wait until the remote peer disconnects
                try {
                    con.close();
                } catch (IOException e) {
                }
            } catch (Exception e) {
                listener.onServerError();
                return;
            }
        }
    }

    /*
     * This method is related to OBEX server functionality. This method
     * is delegating this execution to the current state
     * 
     * @see javax.obex.ServerRequestHandler#onGet()
     */
    public int onGet(Operation op) {
        return getState().onGet(op);
    }

    /*
     * This method is related to OBEX server functionality. This method
     * is delegating this execution to the current state
     * 
     * @see javax.obex.ServerRequestHandler#onPut()
     */
    public int onPut(Operation op) {
        return getState().onPut(op);
    }

    /*
     * This method is related to OBEX server functionality. This method
     * handles OBEX DISCONNECT command from the remote device.
     * 
     * @see javax.obex.ServerRequestHandler#onDisconnect()
     */
    public synchronized void onDisconnect(HeaderSet request,
            HeaderSet reply) {
        super.onDisconnect(request, reply);
        notify();// stops waiting in run()
    }

    public String getUUID() {
        return uuid;
    }
}