/*
*
*
* Portions Copyright 2000-2009 Sun Microsystems, Inc. All Rights
* Reserved. Use is subject to license terms.
* 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.
*/
/*
* (c) Copyright 2001, 2002 Motorola, Inc. ALL RIGHTS RESERVED.
*/
package javax.bluetooth;
import java.util.Vector;
/*
* This class is defined by the JSR-82 specification
* <em>Java™ APIs for Bluetooth™ Wireless Technology,
* Version 1.1.</em>
*/
// JAVADOC COMMENT ELIDED
public class DataElement {
// JAVADOC COMMENT ELIDED
public static final int NULL = 0x0000;
// JAVADOC COMMENT ELIDED
public static final int U_INT_1 = 0x0008;
// JAVADOC COMMENT ELIDED
public static final int U_INT_2 = 0x0009;
// JAVADOC COMMENT ELIDED
public static final int U_INT_4 = 0x000A;
// JAVADOC COMMENT ELIDED
public static final int U_INT_8 = 0x000B;
// JAVADOC COMMENT ELIDED
public static final int U_INT_16 = 0x000C;
// JAVADOC COMMENT ELIDED
public static final int INT_1 = 0x0010;
// JAVADOC COMMENT ELIDED
public static final int INT_2 = 0x0011;
// JAVADOC COMMENT ELIDED
public static final int INT_4 = 0x0012;
// JAVADOC COMMENT ELIDED
public static final int INT_8 = 0x0013;
// JAVADOC COMMENT ELIDED
public static final int INT_16 = 0x0014;
// JAVADOC COMMENT ELIDED
public static final int URL = 0x0040;
// JAVADOC COMMENT ELIDED
public static final int UUID = 0x0018;
// JAVADOC COMMENT ELIDED
public static final int BOOL = 0x0028;
// JAVADOC COMMENT ELIDED
public static final int STRING = 0x0020;
// JAVADOC COMMENT ELIDED
public static final int DATSEQ = 0x0030;
// JAVADOC COMMENT ELIDED
public static final int DATALT = 0x0038;
/* Keeps the specified or derived type of the element. */
private int valueType;
/* Keeps the boolean value for the type BOOL. */
private boolean booleanValue;
/* Keeps the long value for the types *INT*. */
private long longValue;
/*
* Keeps the misc type value for the rest of types.
*
* This field also keeps the value for the type DATALT and DATSEQ.
* In this case it's a Vector. The access to the Vector elements
* is synchronized in cldc (according the source code). But,
* this is not documented, so we make a synchronize access
* to this field to fit any cldc implementation.
*/
private Object miscValue;
// JAVADOC COMMENT ELIDED
public DataElement(int valueType) {
switch (valueType) {
case NULL: /* miscValue = null in this case. */
break;
case DATALT: /* falls through */
case DATSEQ:
this.miscValue = new Vector();
break;
default:
throw new IllegalArgumentException(
"Invalid valueType for this constructor: " + valueType);
}
this.valueType = valueType;
}
// JAVADOC COMMENT ELIDED
public DataElement(boolean bool) {
valueType = BOOL;
booleanValue = bool;
}
// JAVADOC COMMENT ELIDED
public DataElement(int valueType, long value) {
long min = 0;
long max = 0;
switch (valueType) {
case U_INT_1:
max = 0xffL;
break;
case U_INT_2:
max = 0xffffL;
break;
case U_INT_4:
max = 0xffffffffL;
break;
case INT_1:
min = Byte.MIN_VALUE;
max = Byte.MAX_VALUE;
break;
case INT_2:
min = -0x8000L;
max = 0x7fffL;
break;
case INT_4:
min = Integer.MIN_VALUE;
max = Integer.MAX_VALUE;
break;
case INT_8:
min = Long.MIN_VALUE;
max = Long.MAX_VALUE;
break;
default:
throw new IllegalArgumentException(
"Invalid 'valueType' for this constructor: " + valueType);
}
// check if value in the valid rangle for this type
if (value < min || value > max) {
throw new IllegalArgumentException(
"Invalid 'value' for specified type: " + value);
}
this.valueType = valueType;
this.longValue = value;
}
// JAVADOC COMMENT ELIDED
public DataElement(int valueType, Object value) {
boolean isCorrectValue = true;
switch (valueType) {
case URL: /* falls through */
case STRING:
isCorrectValue = value instanceof String;
break;
case UUID:
isCorrectValue = value instanceof UUID;
break;
case INT_16: /* falls through */
case U_INT_16:
isCorrectValue = value instanceof byte[]
&& ((byte[]) value).length == 16;
break;
case U_INT_8:
isCorrectValue = value instanceof byte[]
&& ((byte[]) value).length == 8;
break;
default:
throw new IllegalArgumentException(
"Invalid 'valueType' for this constructor: " + valueType);
}
// check if value in the valid rangle for this type
if (!isCorrectValue) {
throw new IllegalArgumentException(
"Invalid 'value' for specified type: " + value);
}
this.valueType = valueType;
this.miscValue = value;
}
// JAVADOC COMMENT ELIDED
public synchronized void addElement(DataElement elem) {
/*
* We can't optimize this by invoking the
* this.insertElementAt(elem, getSize()), because
* the ClassCastException may be thrown from getSize()
* which gives us improper stack trace.
*/
if (valueType != DATSEQ && valueType != DATALT) {
throw new ClassCastException(
"Invalid element type for this method: " + valueType);
}
if (elem == null) {
throw new NullPointerException("Specified element is null");
}
((Vector) miscValue).addElement(elem);
}
// JAVADOC COMMENT ELIDED
public synchronized void insertElementAt(DataElement elem, int index) {
if (valueType != DATSEQ && valueType != DATALT) {
throw new ClassCastException(
"Invalid element type for this method: " + valueType);
}
if (elem == null) {
throw new NullPointerException("Specified element is null");
}
/*
* We can't use the Vector.insertElementAt check for out of
* bounds, because Vector throws ArrayIndexOutOfBoundsException
* in this case.
*/
if (index < 0 || index > ((Vector) miscValue).size()) {
throw new IndexOutOfBoundsException(
"Specified index is out of range");
}
((Vector) miscValue).insertElementAt(elem, index);
}
// JAVADOC COMMENT ELIDED
public synchronized int getSize() {
if (valueType != DATSEQ && valueType != DATALT) {
throw new ClassCastException(
"Invalid element type for this method: " + valueType);
}
return ((Vector) miscValue).size();
}
// JAVADOC COMMENT ELIDED
public boolean removeElement(DataElement elem) {
if (valueType != DATSEQ && valueType != DATALT) {
throw new ClassCastException(
"Invalid element type for this method: " + valueType);
}
if (elem == null) {
throw new NullPointerException("Specified element is null");
}
/*
* The Bluetooth spec says the two DataElement equals if their
* references are equal. According to cldc1.1 ref impl sources,
* the Vector uses 'equals' call, and the Object.equls uses
* a references compare, so we may not care about doing this here.
*/
return ((Vector) miscValue).removeElement(elem);
}
// JAVADOC COMMENT ELIDED
public int getDataType() {
return valueType;
}
// JAVADOC COMMENT ELIDED
public long getLong() {
switch (valueType) {
case U_INT_1: /* falls through */
case U_INT_2: /* falls through */
case U_INT_4: /* falls through */
case INT_1: /* falls through */
case INT_2: /* falls through */
case INT_4: /* falls through */
case INT_8:
break;
default:
throw new ClassCastException(
"Invalid element type for this method: " + valueType);
}
return longValue;
}
// JAVADOC COMMENT ELIDED
public boolean getBoolean() {
if (valueType != BOOL) {
throw new ClassCastException(
"Invalid element type for this method: " + valueType);
}
return booleanValue;
}
// JAVADOC COMMENT ELIDED
public synchronized Object getValue() {
Object retValue = miscValue;
/*
* According to cldc & bluetooth specifications, the String and UUID
* are immutable, so we may not return a clone object to safe
* the stored one.
*
* The Vector.elements() returns an Enumeration, which does not allow
* to break the Vector either.
*
* The array may be modified by reference, so we have to return
* a clone.
*/
switch (valueType) {
case URL: /* falls through */
case STRING: /* falls through */
case UUID:
break;
case DATALT: /* falls through */
case DATSEQ:
retValue = ((Vector) miscValue).elements();
break;
case U_INT_8: /* falls through */
case U_INT_16: /* falls through */
case INT_16:
int length = ((byte[]) miscValue).length;
retValue = new byte[length];
System.arraycopy(miscValue, 0, retValue, 0, length);
break;
default:
throw new ClassCastException(
"Invalid element type for this method: " + valueType);
}
return retValue;
}
} // end of class 'DataElement' definition