FileDocCategorySizeDatePackage
ServiceSearcher.javaAPI DocphoneME MR2 API (J2ME)15079Wed May 02 18:00:32 BST 2007com.sun.kvem.jsr082.bluetooth

ServiceSearcher

public class ServiceSearcher extends ServiceSearcherBase
This class saves information about responses to SDP_ServiceSearchRequest and SDP_ServiceAttributeRequest requests and provides functionality of DiscoveryAgent.serviceSearch using multiple requests via SDPClient (Service Discovery Protocol)

Fields Summary
private static final boolean
DEBUG
Set to false in RR version - then the javac skip the code.
private static final String
cn
this class name for debug.
private short
transactionID
ID of transaction this listener works in.
private javax.bluetooth.DiscoveryListener
discListener
Listens for service discovery and is informed as a service is discovered.
private SDPClient
sdp
SDP client to send requests.
private int[]
handles
Service records handles retrieved from a server response.
private int
processedHandle
Number of service records handles processed.
private boolean
inactive
Indicates if this listener is inactive.
private boolean
canceled
Indicates if service search has been canceled.
private boolean
notified
Indicates if listener notification has been called.
private static int
requestCounter
Current quantity of service discovering requests.
private static Hashtable
searchers
Keeps the references of current service search requests.
Constructors Summary
ServiceSearcher(int[] attrSet, javax.bluetooth.UUID[] uuidSet, javax.bluetooth.RemoteDevice btDev, javax.bluetooth.DiscoveryListener discListener)
Creates ServiceSearcher and save all required info in it.

param
attrSet list of attributes whose values are requested.
param
uuidSet list of UUIDs that indicate services relevant to request.
param
btDev remote Bluetooth device to listen response from.
param
discListener discovery listener.
see
SDPClient#serviceSearchRequest
see
SDPClient#serviceAttributeRequest


                                                       
         
              
        super(attrSet, uuidSet, btDev);

        if (discListener == null) {
            throw new NullPointerException("DiscoveryListener is null");
        }
        this.discListener = discListener;
    
Methods Summary
static booleancancel(int transactionID)
Cancels transaction with given ID.

param
transactionID ID of transaction to be cancelled.
return
false if there is no open transaction with ID given, true otherwise.

        ServiceSearcher carrier = (ServiceSearcher)
                searchers.get(new Integer(transactionID));

        if (carrier == null) {
            return false;
        } else {
            return carrier.cancel();
        }
    
booleancancel()
Cancels current transaction.

return
false if there is no current transaction, cancels it and returns true otherwise.

        synchronized (this) {
            if (inactive) {
                return false;
            }
            inactive = true;

            if (sdp == null) {
                return false;
            }

            if (canceled) {
                return false;
            }
            canceled = true;
        }

        // cancel running effective transaction if any.
        // if sdp.cancelServiceSearch returns false (there is no running
        // transactions) then call the notification directly.
        if (!sdp.cancelServiceSearch(transactionID)) {
            new NotifyListenerRunner(
                DiscoveryListener.SERVICE_SEARCH_TERMINATED);
        }

        return true;
    
public voiderrorResponse(int errorCode, java.lang.String info, int transactionID)
Receives SDP_ErrorResponse and completes the search request activity by error reason.

param
errorCode error code form SDP_ErrorResponse.
param
info error details firm SDP_ErrorResponse.
param
transactionID ID of transaction response got within.

        if (DEBUG) {
            System.out.println(cn + ".errorResponse: called");
        }

        stop();

        if ((errorCode == SDP_INVALID_VERSION)
                || (errorCode == SDP_INVALID_SYNTAX)
                || (errorCode == SDP_INVALID_PDU_SIZE)
                || (errorCode == SDP_INVALID_CONTINUATION_STATE)
                || (errorCode == SDP_INSUFFICIENT_RESOURCES)) {
            notifyListener(DiscoveryListener.SERVICE_SEARCH_ERROR);
            System.err.println(info);
        } else if (errorCode == SDP_INVALID_SR_HANDLE) {
            notifyListener(DiscoveryListener.SERVICE_SEARCH_NO_RECORDS);
            System.err.println(info);
        } else if (errorCode == IO_ERROR) {
            notifyListener(
                    DiscoveryListener.SERVICE_SEARCH_DEVICE_NOT_REACHABLE);
        } else if (errorCode == TERMINATED) {
            new NotifyListenerRunner(
                    DiscoveryListener.SERVICE_SEARCH_TERMINATED);
        }
    
private booleanisCanceled()
Determines whether the service search has been canceled by the application and did not complete.

return
true indicates the service search has been canceled; false the application has not called cancel operation

        return canceled;
    
private voidnotifyListener(int respCode)
Notifies the listener that service search has been completed with specified response code.

param
respCode response code.

         // guard against multiple notification calls
        synchronized (this) {
            if (!notified) {
                notified = true;
            } else {
                return;
            }
        }

        if (DEBUG) {
            String codeStr = "Undefined";

            switch (respCode) {
            case DiscoveryListener.SERVICE_SEARCH_COMPLETED:
                codeStr = "SERVICE_SEARCH_COMPLETED";
                break;

            case DiscoveryListener.SERVICE_SEARCH_DEVICE_NOT_REACHABLE:
                codeStr = "SERVICE_SEARCH_DEVICE_NOT_REACHABLE";
                break;

            case DiscoveryListener.SERVICE_SEARCH_ERROR:
                codeStr = "SERVICE_SEARCH_ERROR";
                break;

            case DiscoveryListener.SERVICE_SEARCH_NO_RECORDS:
                codeStr = "SERVICE_SEARCH_NO_RECORDS";
                break;

            case DiscoveryListener.SERVICE_SEARCH_TERMINATED:
                codeStr = "SERVICE_SEARCH_TERMINATED";
                break;
            default:
            }
            System.out.println("serviceSearchCompleted:");
            System.out.println("\ttransID=" + transactionID);
            System.out.println("\trespCode=" + codeStr);
            System.out.println("\tinactive=" + inactive);
        }

        try {
            discListener.serviceSearchCompleted(transactionID, respCode);
        } catch (Throwable e) {
            e.printStackTrace();
        }
    
public voidserviceAttributeResponse(int[] attrIDs, javax.bluetooth.DataElement[] attributeValues, int transactionID)
Receives arrays of service record attributes and their values retrieved from server response.

        if (DEBUG) {
            System.out.println(cn + ".serviceAttributeResponse: called");
        }

        // there is no reason to process service attributes if service
        // search is canceled
        if (isCanceled()) {
            return;
        }

        synchronized (this) {
            processedHandle++;
        }

        if (attributeValues != null) {
            ServiceRecordImpl[] serviceRecordSet =
                    new ServiceRecordImpl[1];
            serviceRecordSet[0] =
                    new ServiceRecordImpl(btDev, attrIDs, attributeValues);
            try {
                // The spec for DiscoveryAgent.cancelServiceSearch() says:
                // "After receiving SERVICE_SEARCH_TERMINATED event,
                // no further servicesDiscovered() events will occur
                // as a result of this search."
                if (isCanceled()) {
                    return;
                }
                discListener.servicesDiscovered(this.transactionID,
                        serviceRecordSet);
            } catch (Throwable e) {
                e.printStackTrace();
            }
        }

        if (processedHandle == handles.length) {
            stop();
            notifyListener(DiscoveryListener.SERVICE_SEARCH_COMPLETED);
            return;
        }

        try {
            // there is no reason to continue attributes discovery if search
            //  is canceled
            if (isCanceled()) {
                return;
            }
            sdp.serviceAttributeRequest(handles[processedHandle],
                    attrSet, transactionID, this);
        } catch (IOException ioe) {
            if (DEBUG) {
                ioe.printStackTrace();
            }
            stop();
            notifyListener(
                    DiscoveryListener.SERVICE_SEARCH_DEVICE_NOT_REACHABLE);
        }
    
public voidserviceSearchAttributeResponse(int[] attrIDs, javax.bluetooth.DataElement[] attributeValues, int transactionID)
Base class method not relevant to this subclass, must never be called.

        if (DEBUG) {
            System.out.println(cn + ".serviceSearchAttributeResponse: called");
        }
        throw new RuntimeException("Unexpected call");
    
public voidserviceSearchResponse(int[] handleList, int transactionID)
Receives array of handles retrieved form SDP_serviceSearchResponse.

param
handleList service record handles retrieved from SDP_srviceSearchResponse.
param
transactionID ID of transaction response has been received in.

        if (DEBUG) {
            System.out.println(cn + ".serviceSearchResponse: called");
        }

        // there is no reason to perform response processing if search
        //  is canceled
        if (isCanceled()) {
            return;
        }

        if (handleList == null || handleList.length == 0) {
            stop();
            notifyListener(DiscoveryListener.SERVICE_SEARCH_NO_RECORDS);
            return;
        }

        synchronized (this) {
            handles = handleList;
            processedHandle = 0;
        }

        try {
            // there is no reason to request service attributes if service
            // search is canceled
            if (isCanceled()) {
                return;
            }
            sdp.serviceAttributeRequest(handles[processedHandle],
                    attrSet, transactionID, this);
        } catch (IOException ioe) {
            if (DEBUG) {
                ioe.printStackTrace();
            }
            stop();
            notifyListener(
                    DiscoveryListener.SERVICE_SEARCH_DEVICE_NOT_REACHABLE);
        }
    
intstart()
Starts SDP_ServiceSearchRequest.

see
SDPClient#serviceSearchRequest
return
ID of transaction that has been initiated by the request.

        synchronized (ServiceSearcher.class) {
            if (requestCounter == ServiceRecordImpl.TRANS_MAX) {
                throw new BluetoothStateException(
                        "Too much concurrent requests");
            }
            requestCounter++;
        }
        transactionID = SDPClient.newTransactionID();
        searchers.put(new Integer(transactionID), this);

        try {
            sdp = new SDPClient(btDev.getBluetoothAddress());
            sdp.serviceSearchRequest(uuidSet, transactionID, this);
        } catch (IOException ioe) {
            if (DEBUG) {
                ioe.printStackTrace();
            }

            synchronized (this) {
                stop();
                new NotifyListenerRunner(
                        DiscoveryListener.SERVICE_SEARCH_DEVICE_NOT_REACHABLE);
            }
        }

        return transactionID;
    
voidstop()
Finishes the service searcher activity.

        SDPClient sdp;
        SDPClient.freeTransactionID(transactionID);
        searchers.remove(new Integer(transactionID));

        synchronized (this) {
            if (this.sdp == null) {
                return;
            }
            inactive = true;
            sdp = this.sdp;
            this.sdp = null;
        }

        synchronized (ServiceSearcher.class) {
            requestCounter --;
        }

        try {
            sdp.close();
        } catch (IOException ioe) {
            if (DEBUG) {
                ioe.printStackTrace();
            }
            // ignore
        }