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

ServiceRecordImpl

public final class ServiceRecordImpl extends Object implements javax.bluetooth.ServiceRecord
Service record implementation.

Fields Summary
static final int
RETRIEVABLE_MAX
Maxumum quantity of attributes in one request
static final int
TRANS_MAX
Maximum number of concurrent service searches that can exist at any one time.
private javax.bluetooth.RemoteDevice
remoteDevice
Remote device service provided by.
private BluetoothNotifier
notifier
Service notifier.
private Hashtable
attributesTable
Attribues of the record.
private int
serviceClasses
Bit scale that keeps service classes.
private static final int
MASK_OVERFLOW
Mask to identify attribute IDs out of range.
private static final int
MASK_INCORRECT_CLASS
Mask of incorrect class bits.
public static final int
SERVICE_RECORD_HANDLE
ServiceRecordHandle attribute ID.
public static final int
PROTOCOL_DESCRIPTOR_LIST
ProtocolDescriptorList attribute ID.
public static final int
SERVICE_CLASS_ATTR_ID
Service class attribute id.
public static final int
NAME_ATTR_ID
Name attribute id.
private int
protocol
Protocol type.
private String
btaddr
Bluetooth address of device service record came from.
private int
port
PSM or channel id.
Constructors Summary
protected ServiceRecordImpl(javax.bluetooth.RemoteDevice device, int[] attrIDs, javax.bluetooth.DataElement[] attrValues)
Creates service records on client device.

param
device server device
param
attrIDs attributes IDs
param
attrValues attributes values


     
        int retrievableMax = 5; // default value
        try {
            retrievableMax = Integer.parseInt(LocalDevice.getProperty(
                "bluetooth.sd.attr.retrievable.max"));
        } catch (NumberFormatException e) {
            System.err.println("Internal error: ServiceRecordImpl: "
                    + "improper retrievable.max value");
        }
        RETRIEVABLE_MAX = retrievableMax;

        int transMax = 10;  // default value
        try {
            transMax = Integer.parseInt(LocalDevice.getProperty(
                "bluetooth.sd.trans.max"));
        } catch (NumberFormatException e) {
            System.err.println("Internal error: ServiceRecordImpl: "
                    + "improper trans.max value");
        }
        TRANS_MAX = transMax;
    
        init(attrIDs, attrValues);
        remoteDevice = device;
    
public ServiceRecordImpl(BluetoothNotifier notifier, int[] attrIDs, javax.bluetooth.DataElement[] attrValues)
Creates service records for the given notifier.

param
notifier notifier to be associated with this service record
param
attrIDs attributes IDs
param
attrValues attributes values

        init(attrIDs, attrValues);
        this.notifier = notifier;
    
Methods Summary
private voidattrsInit(int[] attrIDs, javax.bluetooth.DataElement[] attrValues)
Fills up attributes table by values given.

param
attrIDs attributes IDs
param
attrValues attributes values

        for (int i = 0; i < attrIDs.length; i++) {
            attributesTable.put(new Integer(attrIDs[i]),
                    dataElementCopy(attrValues[i]));
        }
        DataElement handle = getAttributeValue(SERVICE_RECORD_HANDLE);
        if (handle == null) {
            attributesTable.put(new Integer(SERVICE_RECORD_HANDLE),
                    new DataElement(DataElement.U_INT_4, 0));
        }
    
public synchronized com.sun.kvem.jsr082.bluetooth.ServiceRecordImplcopy()
Creates a copy of this record. The copy recieves new instances of attributes values which are of types DataElement.DATSEQ or DataElement.DATALT (the only data element types that can be modified after creation).

return
new instance, a copy of this one.

        int count = attributesTable.size();
        int[] attrIDs = new int[count];
        DataElement[] attrValues = new DataElement[count];

        Enumeration ids = attributesTable.keys();
        Enumeration values = attributesTable.elements();

        for (int i = 0; i < count; i++) {
            attrIDs[i] = ((Integer)ids.nextElement()).intValue();
            // no nedd to copy elements here; service record constructor
            // performs the copying
            attrValues[i] = (DataElement)values.nextElement();
        }

        ServiceRecordImpl servRec = new ServiceRecordImpl(notifier,
                      attrIDs, attrValues);
        servRec.serviceClasses = serviceClasses;
        return servRec;
    
private javax.bluetooth.DataElementdataElementCopy(javax.bluetooth.DataElement original)
Creates a copy of DataElement if it's necessary.

param
original data element to be copied if its type allows value modification
return
copy of data element

        if ((original.getDataType() == DataElement.DATSEQ)
                || (original.getDataType() == DataElement.DATALT)) {
            DataElement copy = new DataElement(original.getDataType());
            Enumeration elements = (Enumeration) original.getValue();

            while (elements.hasMoreElements()) {
                copy.addElement(dataElementCopy((DataElement)
                        elements.nextElement()));
            }
            return copy;
        } else {
            return original;
        }
    
public synchronized int[]getAttributeIDs()

        int[] attrIDs = new int[attributesTable.size()];
        Enumeration e = attributesTable.keys();

        for (int i = 0; i < attrIDs.length; i++) {
            attrIDs[i] = ((Integer) e.nextElement()).intValue();
        }
        return attrIDs;
    
public javax.bluetooth.DataElementgetAttributeValue(int attrID)

        if ((attrID & MASK_OVERFLOW) != 0) {
            throw new IllegalArgumentException(
                    "attrID isn't a 16-bit unsigned integer");
        }
        DataElement attrValue = (DataElement) attributesTable.get(new
                Integer(attrID));

        if (attrValue == null) {
            return null;
        } else {
            return dataElementCopy(attrValue);
        }
    
public synchronized java.lang.StringgetConnectionURL(int requiredSecurity, boolean mustBeMaster)

        // protocol, btaddr, port
        retrieveUrlCommonParams();
        BluetoothUrl url = BluetoothUrl.createClientUrl(
                protocol, btaddr, port);

        if (mustBeMaster) {
            url.master = true;
        } else {
            url.master = false;
        }

        switch (requiredSecurity) {
        case NOAUTHENTICATE_NOENCRYPT:
            break;
        case AUTHENTICATE_ENCRYPT:
            url.encrypt = true;
        case AUTHENTICATE_NOENCRYPT:
            url.authenticate = true;
            break;
        default:
            throw new IllegalArgumentException("unsupported security type: "
                    + requiredSecurity);
        }

        return url.toString();
    
public intgetDeviceServiceClasses()
Retrieve service classes bits provided by corresponing service at local device.

return
an integer that keeps the service classes bits

        if (remoteDevice != null) {
            throw new RuntimeException(
                "This ServiceRecord was created by a call to "
                + "DiscoveryAgent.searchServices()");
        }

        // it's necessary to improve these code
        return serviceClasses;
    
public intgetHandle()
Returns service record handle.

return
service record handle, or 0 if the record is not in SDDB.

        DataElement handle = getAttributeValue(SERVICE_RECORD_HANDLE);
        return handle != null ? (int)handle.getLong() : 0;
    
public javax.bluetooth.RemoteDevicegetHostDevice()

        return remoteDevice;
    
public BluetoothNotifiergetNotifier()
Returns notifier that has created this record.

return
corresponding notifier.

        return notifier;
    
private voidinit(int[] attrIDs, javax.bluetooth.DataElement[] attrValues)
Creates attributes table and fills it up by values given.

param
attrIDs attributes IDs
param
attrValues attributes values

        attributesTable = new Hashtable(attrIDs.length + 1);
        attrsInit(attrIDs, attrValues);
    
public synchronized booleanpopulateRecord(int[] attrIDs)

        Hashtable dupChecker = new Hashtable();
        Object checkObj = new Object();

        if (remoteDevice == null) {
            throw new RuntimeException("local ServiceRecord");
        }

        if (attrIDs.length == 0) {
            throw new IllegalArgumentException("attrIDs size is zero");
        }

        if (attrIDs.length > RETRIEVABLE_MAX) {
            throw new IllegalArgumentException(
                    "attrIDs size exceeds retrievable.max");
        }

        for (int i = 0; i < attrIDs.length; i++) {
            if ((attrIDs[i] & MASK_OVERFLOW) != 0) {
                throw new IllegalArgumentException("attrID does not represent "
                    + "a 16-bit unsigned integer");
            }

            // check attribute ID duplication
            if (dupChecker.put(new Integer(attrIDs[i]), checkObj) != null) {
                throw new IllegalArgumentException(
                        "duplicated attribute ID");
            }
        }

        // obtains transaction ID for request
        short transactionID = SDPClient.newTransactionID();

        // SDP connection and listener. They are initialized in try blok.
        SDPClient sdp = null;
        SRSDPListener listener = null;

        try {
            // prepare data for request
            DataElement handleEl = (DataElement) attributesTable.get(
                    new Integer(SERVICE_RECORD_HANDLE));
            int handle = (int) handleEl.getLong();

            // create and prepare SDP listner
            listener = new SRSDPListener();

            // create SDP connection and ..
            sdp = new SDPClient(remoteDevice.getBluetoothAddress());

            // ... and make request
            sdp.serviceAttributeRequest(handle, attrIDs, transactionID,
                    listener);

            synchronized (listener) {
                if ((listener.ioExcpt == null)
                        && (listener.attrValues == null)) {
                    try {
                        listener.wait();
                    } catch (InterruptedException ie) {
                        // ignore (breake waiting)
                    }
                }
            }
        } finally {

            // Closes SDP connection and frees transaction ID in any case
            SDPClient.freeTransactionID(transactionID);

            // if connection was created try to close it
            if (sdp != null) {
                try {
                    sdp.close();
                } catch (IOException ioe) {
                    // ignore
                }
            }
        }

        if (listener.ioExcpt != null) {
            throw listener.ioExcpt;
        } else if (listener.attrValues == null) {
            return false;
        } else if (listener.attrValues.length == 0) {
            return false;
        } else {
            attrsInit(listener.attrIDs, listener.attrValues);
            return true;
        }
    
private voidretrieveUrlCommonParams()
Retrieves service protocol, device address and port (PSM or channel) from service record attributes. Results are set to protocol, btaddr and port variables correspondingly.

        if (protocol != BluetoothUrl.UNKNOWN) {
            // already retrieved
            return;
        }

        if (remoteDevice != null) {
            btaddr = remoteDevice.getBluetoothAddress();
        } else {
            try {
                btaddr = LocalDevice.getLocalDevice().getBluetoothAddress();
            } catch (BluetoothStateException bse) {
                throw new IllegalArgumentException("cannot generate url");
            }
        }

        /*
         * There are three protocols supported -
         * they are obex or rfcomm or l2cap. So, if obex is
         * found in ProtocolDescriptorList, the protocol is btgoep,
         * if RFCOMM is found (and no obex) - the btspp, otherwise
         * the protocol is btl2cap.
         */
        DataElement protocolList = getAttributeValue(PROTOCOL_DESCRIPTOR_LIST);
        Enumeration val = (Enumeration) protocolList.getValue();
        int type = -1; // 0 = l2cap, 1 = spp, 2 = obex
        final UUID L2CAP_UUID = new UUID(0x0100);
        final UUID RFCOMM_UUID = new UUID(0x0003);
        final UUID OBEX_UUID = new UUID(0x0008);

        // go through all of the protocols in the protocols list
        while (val.hasMoreElements()) {
            DataElement protoDE = (DataElement) val.nextElement();

            // application adds a garbage in protocolList - ignore
            if (protoDE.getDataType() != DataElement.DATSEQ) {
                continue;
            }
            Enumeration protoEnum = (Enumeration) protoDE.getValue();
            int tmpPort = -1;
            int tmpType = -1;

            // look on protocol details
            while (protoEnum.hasMoreElements()) {
                DataElement de = (DataElement) protoEnum.nextElement();

                // may be PSM or channel id
                if (de.getDataType() == DataElement.U_INT_1 ||
                        de.getDataType() == DataElement.U_INT_2)  {
                    tmpPort = (int) de.getLong();
                } else if (de.getDataType() == DataElement.UUID) {
                    UUID protoUUID = (UUID) de.getValue();

                    if (protoUUID.equals(L2CAP_UUID)) {
                        tmpType = 0;
                    } else if (protoUUID.equals(RFCOMM_UUID)) {
                        tmpType = 1;
                    } else if (protoUUID.equals(OBEX_UUID)) {
                        tmpType = 2;
                    }
                }
            }

            /*
             * ok, new protocol has been parsed - let's check if it
             * is over the previous one or not.
             *
             * Note, that OBEX protocol may appear before the RFCOMM
             * one - in this case the port (channel id) is not set -
             * need to check this case separately.
             */
            if (tmpType > type) {
                type = tmpType;

                // no "port" for obex type (obex = 2)
                if (tmpType != 2) {
                    port = tmpPort;
                }
            } else if (tmpType == 1) {
                port = tmpPort;
            }
        }

        switch (type) {
        case 0:
            protocol = BluetoothUrl.L2CAP;
            break;
        case 1:
            protocol = BluetoothUrl.RFCOMM;
            break;
        case 2:
            protocol = BluetoothUrl.OBEX;
            break;
        default:
            throw new IllegalArgumentException("wrong protocol list");
        }
    
public synchronized booleansetAttributeValue(int attrID, javax.bluetooth.DataElement attrValue)


        if ((attrID & MASK_OVERFLOW) != 0) {
            throw new IllegalArgumentException(
                    "attrID does not represent a 16-bit unsigned integer");
        }

        if (attrID == SERVICE_RECORD_HANDLE) {
            throw new IllegalArgumentException(
                    "attrID is the value of ServiceRecordHandle (0x0000)");
        }

        if (remoteDevice != null) {
            throw new RuntimeException(
                    "can't update ServiceRecord of the RemoteDevice");
        }
        Object key = new Integer(attrID);

        if (attrValue == null) {
            return attributesTable.remove(key) != null;
        } else {
            attributesTable.put(key, dataElementCopy(attrValue));
            return true;
        }
    
public synchronized voidsetDeviceServiceClasses(int classes)

        // checks that it's service record from remote device
        if (remoteDevice != null) {
            throw new RuntimeException("This ServiceRecord was created"
                    + " by a call to DiscoveryAgent.searchServices()");
        }

        // checks correction of set classbits
        if ((classes & MASK_INCORRECT_CLASS) != 0) {
            throw new IllegalArgumentException("attempt to set incorrect bits");
        }
        serviceClasses = classes;
    
public voidsetHandle(int handle)
Sets service record handle.

param
handle new service record handle value

        Integer attrID = new Integer(SERVICE_RECORD_HANDLE);
        attributesTable.remove(attrID);
        attributesTable.put(attrID, new DataElement(
                DataElement.U_INT_4, handle));