FileDocCategorySizeDatePackage
BluetoothUrl.javaAPI DocphoneME MR2 API (J2ME)21453Wed May 02 18:00:30 BST 2007com.sun.midp.io

BluetoothUrl

public class BluetoothUrl extends Object
Represents a bluetooth url, i.e. connection string. There are two ways of usage. First one is constructing it giving url string in order to parse it into a set of fields. Second one is constructig it giving fields values in order to get string representation. Whenever incompatible url parts are found IllegalArgumentException is thrown.

Fields Summary
public boolean
isServer
Indicates if it is a sever connection string.
public String
address
Keeps server address for client url, "localhost" for server.
public int
port
PSM for L2CAP or channel id for RFCOMM.
public boolean
master
Master parameter, true by default for server.
public boolean
encrypt
Encrypt parameter.
public boolean
authenticate
Authenticate parameter.
public static final int
L2CAP
Value to indicate L2CAP protocol.
public static final int
RFCOMM
Value to indicate RFCOMM protocol.
public static final int
OBEX
Value to indicate OBEX protocol.
public static final int
UNKNOWN
Value to indicate unknown protocol.
public int
protocol
Indicates protocol type.
private static final int
PROTOCOLS_AMOUNT
Amount of protocols supported.
private static final String[]
protocolName
Keeps protocols indicating strings. Usage: protocolName[L2CAP] to get "l2cap"
public String
uuid
Keeps uuid from server connection string, null for client's one. L2CAP, RFCOMM specific.
public String
name
Name parameter of server url, null for client's one. L2CAP, RFCOMM specific.
private String
url
Url string to parse, lower case.
public String
caseSensitiveUrl
Url string to parse, original case. Required for correct "name" parameter parsing for it is case-sensitive.
public boolean
authorize
Authorize parameter. L2CAP specific.
public int
receiveMTU
RecieveMTU parameter. L2CAP specific.
public int
transmitMTU
TransmitMTU parameter. L2CAP specific.
public static final javax.bluetooth.UUID
UUID_SDP
UUID value to create a transport for Service Discovery Protocol.
private boolean
explicitAuthenticate
Indicates if an explicit "authenticate" parameter found.
private static final String
LOCALHOST
Keeps server host string.
private int
length
Keeps length of url.
private static final String
MASTER
Master parameter name.
private static final String
ENCRYPT
Encrypt parameter name.
private static final String
AUTHENTICATE
Authenticate parameter name.
private static final String
AUTHORIZE
Authorize parameter name.
private static final String
TRANSMITMTU
TransmitMTU parameter name.
private static final String
RECEIVEMTU
ReceiveMTU parameter name.
private static final String
NAME
Name parameter name.
private static final String
TRUE
"true" literal.
private static final String
FALSE
"false" literal.
private Hashtable
parameters
the URL parameters.
private static final Object
on
Stub object for values in parameters hashtable.
private boolean
isSystem
Shows whether this url is generated and validated by SDP routines.
Constructors Summary
public BluetoothUrl(String urlString)
Constructs url object by specified url string. Constructing BluetoothUrl in this manner is a way to parse an url represented by string.

param
urlString url string.


                                   
       
        this(UNKNOWN, urlString, null);
    
public BluetoothUrl(int protocol, String urlString)
Constructs url object by specified protocol and url string without leading protocol name and colon or if protocol is unknown by s string that contains full url.

param
protocol prootocol type, must be one of L2CAP, RFCOMM, OBEX, UNKNOWN.
param
urlString whole url if protocol value is UNKNOWN, a part of url string beyond "protocol:" otherwise.

        this(protocol, urlString, null);
    
public BluetoothUrl(int protocol, String urlString, Object systemToken)
Constructs url object with specified protocol, url and special system token.

see
BluetoothUrl(int, String)
param
protocol prootocol type
param
urlString URL
param
systemToken special object that validates this URL as system if has proper value, usually it is null

        this(protocol);

        isSystem = SDP.checkSystemToken(systemToken);
        caseSensitiveUrl = urlString;
        url = urlString.toLowerCase();
        length = url.length();
        int start;
        int separator = url.indexOf(':");

        if (protocol == UNKNOWN) {
            // url is "PROTOCOL://ADDRESS:...", parsing protocol name
            assertTrue(separator > 0, "Cannot parse protocol name: " + url);
            start = separator + 3; // skip "://"
            String name = urlString.substring(0, start);

            for (int i = 0; i < PROTOCOLS_AMOUNT; i++) {
                if (protocolName[i].equals(name)) {
                    this.protocol = i;
                    separator = url.indexOf(':", start);
                    break;
                }
            }

        } else {
            // url is "//ADDRESS:...", parsing protocol name
            assertTrue(urlString.startsWith("//"),
            "address and protocol name have to be separated by //: " + url);
            // skip "//"
            start = 2;
        }

        assertTrue(separator > start, "Cannot parse address: " + url);

        address = url.substring(start, separator);
        start = separator + 1;


        if (this.protocol == L2CAP) {
            // parsing psm or uuid
            if (address.equals(LOCALHOST)) {
                isServer = true;
                // Now uuid goes till end of string or semicolon.
                separator = getSeparator(start);
                uuid = url.substring(start, separator);

             } else {
                // Now psm goes which is represented by 4 hex digits.
                assertTrue((separator = start + 4) <= length,
                "psm has to be represented by 4 hex digits: " + url);
                port = parseInt(start, separator, 16);
             }

        } else if (this.protocol == RFCOMM ||
                   this.protocol == OBEX) {
            separator = getSeparator(start);
            if (address.equals(LOCALHOST)) {
                isServer = true;
                // Now uuid goes till end of string or semicolon.
                uuid = url.substring(start, separator);
            } else {
                // Now channel id goes which is represented by %d1-30.
                assertTrue(separator <= length,
                "channel id has to go after address: " + url);
                port = parseInt(start, separator, 10);
            }
        } else {
            separator = getSeparator(start);
            port = parseInt(start, separator, 16);
        }

        if (isServer) {
            int length;
            assertTrue(uuid != null && (length = uuid.length()) > 0 &&
                length <= 32, "Invalid UUID");
        } else {
            checkBluetoothAddress();
        }

        // parsing parameters
        parameters = new Hashtable();
        for (start = separator; start < length; start = parseParameter(start));
        parameters = null;

        assertTrue(start == length, "Cannot parse the parameters: " + url);
    
private BluetoothUrl(int protocol)
Universal private constructor.

param
protocol identifies protocol.
exception
IllegalArgument exception if provived parameters are invalid.

        assertTrue(protocol <= UNKNOWN, "Unknown protocol name: " + protocol);
        this.protocol = protocol;
    
Methods Summary
private static voidassertTrue(boolean condition, java.lang.String details)
Asserts that given condition is true.

param
condition condition to check.
param
details condition's description details.
exception
IllegalArgumentException if given condition is flase.

        if (!condition) {
            throw new IllegalArgumentException("unexpected parameter: " +
                                               details);
        }
    
private voidcheckBluetoothAddress()
Checks the string given is a valid Bluetooth address, which means consists of 12 hexadecimal digits.

exception
IllegalArgumentException if string given is not a valid Bluetooth address


        String errorMessage = "Invalid Bluetooth address";
        assertTrue(address != null && address.length() == 12 &&
                address.indexOf('-") == -1, errorMessage);

        try {
            Long.parseLong(address, 16);
        } catch (NumberFormatException e) {
            assertTrue(false, errorMessage);
        }
    
private booleancheckNameFormat(java.lang.String name)
Checks name format. name = 1*( ALPHA / DIGIT / SP / "-" / "_") The core rules from RFC 2234.

param
name the name
return
true if the name format is valid, false otherwise

        char[] a = name.toCharArray();
        boolean ret = a.length > 0;
        for (int i = a.length; --i >= 0 && ret;) {
            ret &= (a[i] >= 'a" && a[i] <= 'z") ||
                (a[i] >= 'A" && a[i] <= 'Z") ||
                (a[i] >= '0" && a[i] <= '9") ||
                (a[i] == '-") ||
                (a[i] == '_") ||
                (a[i] == ' ");
        }
        return ret;
    
public static com.sun.midp.io.BluetoothUrlcreateClientUrl(int protocol, java.lang.String btaddr, int port)
Creates url that represents client connection string.

param
protocol identifies protocol. Should be one of BluetoothUrl.L2CAP, BluetoothUrl.RFCOMM, BluetoothUrl.OBEX
param
btaddr Bluetooth address of server device.
param
port PSM in case of L2CAP or channel id otherwise.
return
BluetoothUrl instance that represents desired connection string.
exception
IllegalArgument exception if provived parameters are invalid.


        assertTrue(protocol != UNKNOWN && btaddr != null,
        "Either unknown protocol name or address");
        BluetoothUrl url = new BluetoothUrl(protocol);

        url.address = btaddr.toLowerCase();
        url.checkBluetoothAddress();
        url.port = port;

        return url;
    
public java.lang.StringgetResourceName()
Creates string representation of the URL without parameters.

return
"PROTOCOL://ADDRESS" string.

        assertTrue(protocol == L2CAP ||
                   protocol == RFCOMM ||
                   protocol == OBEX,
                   "Incorrect protocol bname: " + protocol);
        assertTrue(address != null, "Incorrect address: "+ address);
        return protocolName[protocol] + address;
    
private intgetSeparator(int start)
Retrieves position of semicolon in the rest of url string, returning length of the string if no semicolon found. It also assertd that a non-empty substring starts from start given and ends before semicolon or end of string.

param
start position in url string to start searching at.
return
position of first semicolon or length of url string if there is no semicolon.
exception
IllegalArgumentException if there is no non-empty substring before semicolon or end of url.

        int separator = url.indexOf(';", start);
        if (separator < 0) {
            separator = length;
        }
        assertTrue(start < separator, "Correct separator is not found");

        return separator;
    
public final booleanisSystem()
Tests if this URL is system one. System URL can only by created by SDP server or client and is processed in special way.

return
true if this url is a system one created by SDP routines, false otherwise

        return isSystem;
    
private booleanparseBoolean(int start, int separator)
Parses boolean value from url string.

param
start position to start parsing from.
param
separator position that immediately follows value to parse.
return
true if, comparing case insensitive, specified substring is "TRUE", false if it is "FALSE".
exception
IllegalArgumentException if specified url substring is neither "TRUE" nor "FALSE", case-insensitive.

        String value = url.substring(start, separator);
        if (value.equals(TRUE)) {
            return true;
        }

        assertTrue(value.equals(FALSE), "Incorrect boolean parsing: " + value);
        return false;
    
private intparseInt(int start, int separator, int radix)
Parses integer value from url string.

param
start position to start parsing from.
param
separator position that immediately follows value to parse.
param
radix the radix to use.
return
integer value been parsed.
exception
IllegalArgumentException if given string is not case-insensitive "TRUE" or "FALSE".

        int result = -1;

        try {
            result = Integer.parseInt(
                url.substring(start, separator), radix);
        } catch (NumberFormatException e) {
            assertTrue(false, "Incorrect int parsing: " +
                       url.substring(start, separator));
        }

        return result;
    
private intparseParameter(int start)
Parses parameter in url starting at given position and cheks simple rules or parameters compatibility. Parameter is ";NAME=VALUE". If parsing from given position or a check fails, IllegalArgumentException is thrown.

param
start position to start parsing at, if it does not point to semicolon, parsing fails as well as instance constructing.
return
position number that immediately follows parsed parameter.
exception
IllegalArgumentException if parsing fails or incompatible parameters occured.

        assertTrue(url.charAt(start) == ';",
                   "Cannot parse url parameters: " + url);

        int separator = url.indexOf('=", start) + 1;
        assertTrue(separator > 0, "Cannot parse url parameters: " + url);
        // name is ";NAME="
        String name = url.substring(start, separator);

        start = separator;
        separator = getSeparator(start);

        assertTrue(!parameters.containsKey(name),
        "Duplicate parameter " + name);
        parameters.put(name, on);

        if (name.equals(MASTER)) {
            master = parseBoolean(start, separator);

        } else if (name.equals(ENCRYPT)) {
            encrypt = parseBoolean(start, separator);
            if (encrypt && !explicitAuthenticate) {
                authenticate = true;
            }

        } else if (name.equals(AUTHENTICATE)) {
            authenticate = parseBoolean(start, separator);
            explicitAuthenticate = true;

        } else if (name.equals(NAME)) {
            assertTrue(isServer, "Incorrect parameter for client: " + name);
            // this parameter is case-sensitive
            this.name = caseSensitiveUrl.substring(start, separator);
            assertTrue(checkNameFormat(this.name),
            "Incorrect name format: " + this.name);

        } else if (name.equals(AUTHORIZE)) {
            assertTrue(isServer,  "Incorrect parameter for client: " + name);
            authorize = parseBoolean(start, separator);
            if (authorize && !explicitAuthenticate) {
                authenticate = true;
            }

        } else if (protocol == L2CAP) {
            if (name.equals(RECEIVEMTU)) {
                receiveMTU = parseInt(start, separator, 10);
                assertTrue(receiveMTU > 0,
                           "Incorrect receive MTU: " + receiveMTU);
            } else if (name.equals(TRANSMITMTU)) {
                transmitMTU = parseInt(start, separator, 10);
                assertTrue(transmitMTU > 0,
                           "Incorrect transmit MTU: " + transmitMTU);
            } else {
                assertTrue(false, "Unknown parameter name = " + name);
            }
        } else {
            assertTrue(false, "Unknown parameter name = " + name);
        }
        return separator;
    
public java.lang.StringtoString()
Checks url parts consistency and creates string representation.

return
string representation of the URL.
exception
IllegalArgumentException if URL parts are inconsistent.

        assertTrue(protocol == L2CAP ||
                   protocol == RFCOMM ||
                   protocol == OBEX,
                   "Incorrect protocol bname: " + protocol);

        StringBuffer buffer = new StringBuffer();

        buffer = new StringBuffer(getResourceName());
        buffer.append(':");

        if (isServer) {
            buffer.append(uuid);
            buffer.append(AUTHORIZE).append(authorize ? TRUE : FALSE);
        } else {
            String portStr;

            if (protocol == L2CAP) {
                // in case of l2cap, the psm is 4 hex digits
                portStr = Integer.toHexString(port);
                for (int pad = 4 - portStr.length(); pad > 0; pad--) {
                    buffer.append('0");
                }

            } else if (protocol == RFCOMM ||
                       protocol == OBEX) {
                portStr = Integer.toString(port);
            } else {
                portStr = Integer.toString(port);
            }

            buffer.append(portStr);
        }

        /*
         * note: actually it's not required to add the boolean parameter if it
         * equals to false because if it is not present in the connection
         * string, this is equivalent to 'such parameter'=false.
         * But some TCK tests check the parameter is always present in
         * URL string even its value is false.
         * IMPL_NOTE: revisit this code if TCK changes.
         */
        buffer.append(MASTER).append(master ? TRUE : FALSE);
        buffer.append(ENCRYPT).append(encrypt ? TRUE: FALSE);
        buffer.append(AUTHENTICATE).append(authenticate ? TRUE : FALSE);

        if (receiveMTU != -1) {
            buffer.append(RECEIVEMTU).append(
                Integer.toString(receiveMTU, 10));
        }
        if (transmitMTU != -1) {
            buffer.append(TRANSMITMTU).append(
                Integer.toString(transmitMTU, 10));
        }

        return buffer.toString();