com.intel.bluetooth.BlueCoveImpl Maven / Gradle / Ivy
/**
* BlueCove - Java library for Bluetooth
* Copyright (C) 2004 Intel Corporation
* Copyright (C) 2006-2008 Vlad Skarzhevskyy
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* @version $Id: BlueCoveImpl.java 2389 2008-08-11 23:47:04Z skarzhevskyy $
*/
package com.intel.bluetooth;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;
import javax.bluetooth.BluetoothStateException;
import com.intel.bluetooth.BluetoothStack.LibraryInformation;
/**
*
* Singleton class used as holder for BluetoothStack.
*
* Under security manager all you need to do is initialize BlueCoveImpl inside
* Privileged context.
*
* If automatic Bluetooth Stack detection is not enough Java System property
* "bluecove.stack" can be used to force desired Stack Initialization. Values
* "widcomm", "bluesoleil" or "winsock". By default winsock is selected if
* available.
*
* Another property "bluecove.stack.first" is used optimize stack detection. If
* -Dbluecove.stack.first=widcomm then widcomm (bluecove.dll) stack is loaded
* first and if not available then BlueCove will switch to winsock. By default
* intelbth.dll is loaded first.
*
* If multiple stacks are detected they are selected in following order:
* "winsock", "widcomm", "bluesoleil". Since BlueCove v2.0.1
* "bluecove.stack.first" will alter the order of stack selection.
*
* To use jsr-82 emulator set "bluecove.stack" value to "emulator".
*
* If System property is not an option (e.g. when running in Webstart) create
* text file "bluecove.stack" or "bluecove.stack.first" containing stack name
* and add this file to BlueCove or Application jar. (Since v2.0.1)
*
* Use `LocalDevice.getProperty("bluecove.stack")` to find out which stack is
* used.
*
* @author vlads
*
*/
public class BlueCoveImpl {
public static final int versionMajor1 = 2;
public static final int versionMajor2 = 0;
public static final int versionMinor = 3;
public static final int versionBuild = 99;
public static final String versionSufix = ""; // SNAPSHOT
public static final String version = String.valueOf(versionMajor1) + "." + String.valueOf(versionMajor2) + "."
+ String.valueOf(versionMinor) + versionSufix;
public static final int nativeLibraryVersionExpected = versionMajor1 * 1000000 + versionMajor2 * 10000
+ versionMinor * 100 + versionBuild;
public static final String STACK_WINSOCK = "winsock";
public static final String STACK_WIDCOMM = "widcomm";
public static final String STACK_BLUESOLEIL = "bluesoleil";
public static final String STACK_TOSHIBA = "toshiba";
public static final String STACK_BLUEZ = "bluez";
public static final String STACK_OSX = "mac";
public static final String STACK_EMULATOR = "emulator";
// We can't use the same DLL on windows for all implementations.
// Since WIDCOMM need to be compile /MD using VC6 and winsock /MT using
// VC2005
// This variable can be used to simplify development/test builds
private static final boolean oneDLLbuild = false;
public static final String NATIVE_LIB_MS = "intelbth";
public static final String NATIVE_LIB_WIDCOMM = oneDLLbuild ? NATIVE_LIB_MS : "bluecove";
public static final String NATIVE_LIB_TOSHIBA = "bluecove";
public static final String NATIVE_LIB_BLUEZ = "bluecove";
public static final String NATIVE_LIB_OSX = "bluecove";
/**
* To work on BlueSoleil version 2.3 we need to compile C++ code /MT the
* same as winsock.
*/
public static final String NATIVE_LIB_BLUESOLEIL = NATIVE_LIB_MS;
static final int BLUECOVE_STACK_DETECT_MICROSOFT = 1;
static final int BLUECOVE_STACK_DETECT_WIDCOMM = 1 << 1;
static final int BLUECOVE_STACK_DETECT_BLUESOLEIL = 1 << 2;
static final int BLUECOVE_STACK_DETECT_TOSHIBA = 1 << 3;
static final int BLUECOVE_STACK_DETECT_OSX = 1 << 4;
public static final int BLUECOVE_STACK_DETECT_BLUEZ = 1 << 5;
public static final int BLUECOVE_STACK_DETECT_EMULATOR = 1 << 6;
static final String TRUE = "true";
static final String FALSE = "false";
private static final String FQCN = BlueCoveImpl.class.getName();
private static final Vector fqcnSet = new Vector();
/* The context to be used when loading native DLL */
private Object accessControlContext;
private static ShutdownHookThread shutdownHookRegistered;
private static BlueCoveImpl instance;
private static BluetoothStackHolder singleStack;
private static ThreadLocalWrapper threadStack;
private static BluetoothStackHolder threadStackIDDefault;
private static Hashtable resourceConfigProperties = new Hashtable();
private static Hashtable/* */stacks = new Hashtable();
private static Vector initializationProperties = new Vector();
static {
fqcnSet.addElement(FQCN);
for (int i = 0; i < BlueCoveConfigProperties.INITIALIZATION_PROPERTIES.length; i++) {
initializationProperties.addElement(BlueCoveConfigProperties.INITIALIZATION_PROPERTIES[i]);
}
}
/**
* Enables the use of Multiple Adapters and Bluetooth Stacks in parallel.
*/
private static class BluetoothStackHolder {
private BluetoothStack bluetoothStack;
Hashtable configProperties = new Hashtable();
private static BluetoothStack getBluetoothStack() throws BluetoothStateException {
return instance().getBluetoothStack();
}
public String toString() {
if (bluetoothStack == null) {
return "not initialized";
}
return bluetoothStack.toString();
}
}
/**
* bluetoothStack.destroy(); May stuck forever. Exit JVM anyway after
* timeout.
*/
private class AsynchronousShutdownThread extends Thread {
final Object monitor = new Object();
int shutdownStart = 0;
AsynchronousShutdownThread() {
super("BluecoveAsynchronousShutdownThread");
}
public void run() {
synchronized (monitor) {
while (shutdownStart == 0) {
try {
monitor.wait();
} catch (InterruptedException e) {
return;
}
}
}
if (shutdownStart == -1) {
return;
}
if (!stacks.isEmpty()) {
for (Enumeration en = stacks.elements(); en.hasMoreElements();) {
BluetoothStackHolder s = (BluetoothStackHolder) en.nextElement();
if (s.bluetoothStack != null) {
try {
s.bluetoothStack.destroy();
} finally {
s.bluetoothStack = null;
}
}
}
stacks.clear();
System.out.println("BlueCove stack shutdown completed");
}
synchronized (monitor) {
monitor.notifyAll();
}
}
void deRegister() {
shutdownStart = -1;
synchronized (monitor) {
monitor.notifyAll();
}
}
}
private class ShutdownHookThread extends Thread {
AsynchronousShutdownThread shutdownHookThread;
ShutdownHookThread(AsynchronousShutdownThread shutdownHookThread) {
super("BluecoveShutdownHookThread");
this.shutdownHookThread = shutdownHookThread;
}
public void run() {
final Object monitor = shutdownHookThread.monitor;
synchronized (monitor) {
shutdownHookThread.shutdownStart = 1;
monitor.notifyAll();
if (!stacks.isEmpty()) {
try {
monitor.wait(7000);
} catch (InterruptedException e) {
}
}
}
}
void deRegister() {
shutdownHookRegistered = null;
UtilsJavaSE.runtimeRemoveShutdownHook(this);
shutdownHookThread.deRegister();
}
}
/**
* Applications should not used this function. Allow default initialization.
* In Secure environment instance() should be called initially from secure
* context.
*
* @return Instance of the class, getBluetoothStack() can be called.
*/
public static synchronized BlueCoveImpl instance() {
if (instance == null) {
instance = new BlueCoveImpl();
}
return instance;
}
private BlueCoveImpl() {
try {
accessControlContext = AccessController.getContext();
} catch (Throwable javaME) {
}
// Initialization in WebStart.
DebugLog.isDebugEnabled();
copySystemProperties(null);
}
static int getNativeLibraryVersion() {
return nativeLibraryVersionExpected;
}
private synchronized void createShutdownHook() {
if (shutdownHookRegistered != null) {
return;
}
AsynchronousShutdownThread shutdownHookThread = new AsynchronousShutdownThread();
if (UtilsJavaSE.runtimeAddShutdownHook(shutdownHookRegistered = new ShutdownHookThread(shutdownHookThread))) {
UtilsJavaSE.threadSetDaemon(shutdownHookThread);
shutdownHookThread.start();
}
}
private int getStackId(String stack) {
if (STACK_WIDCOMM.equalsIgnoreCase(stack)) {
return BLUECOVE_STACK_DETECT_WIDCOMM;
} else if (STACK_BLUESOLEIL.equalsIgnoreCase(stack)) {
return BLUECOVE_STACK_DETECT_BLUESOLEIL;
} else if (STACK_TOSHIBA.equalsIgnoreCase(stack)) {
return BLUECOVE_STACK_DETECT_TOSHIBA;
} else if (STACK_WINSOCK.equalsIgnoreCase(stack)) {
return BLUECOVE_STACK_DETECT_MICROSOFT;
} else if (STACK_BLUEZ.equalsIgnoreCase(stack)) {
return BLUECOVE_STACK_DETECT_BLUEZ;
} else if (STACK_WINSOCK.equalsIgnoreCase(stack)) {
return BLUECOVE_STACK_DETECT_OSX;
} else if (STACK_EMULATOR.equalsIgnoreCase(stack)) {
return BLUECOVE_STACK_DETECT_EMULATOR;
} else {
return 0;
}
}
private Class loadStackClass(String classPropertyName, String classNameDefault) throws BluetoothStateException {
String className = getConfigProperty(classPropertyName);
if (className == null) {
className = classNameDefault;
}
try {
return Class.forName(className);
} catch (ClassNotFoundException e) {
DebugLog.error(className, e);
}
throw new BluetoothStateException("BlueCove " + className + " not available");
}
private BluetoothStack newStackInstance(Class ctackClass) throws BluetoothStateException {
String className = ctackClass.getName();
try {
return (BluetoothStack) ctackClass.newInstance();
} catch (InstantiationException e) {
DebugLog.error(className, e);
} catch (IllegalAccessException e) {
DebugLog.error(className, e);
}
throw new BluetoothStateException("BlueCove " + className + " can't instantiate");
}
private BluetoothStack loadStack(String classPropertyName, String classNameDefault) throws BluetoothStateException {
return newStackInstance(loadStackClass(classPropertyName, classNameDefault));
}
static void loadNativeLibraries(BluetoothStack stack) throws BluetoothStateException {
// Check is libraries already loaded
try {
if ((UtilsJavaSE.canCallNotLoadedNativeMethod) && (stack.isNativeCodeLoaded())) {
return;
}
} catch (Error e) {
// We caught UnsatisfiedLinkError
}
LibraryInformation[] libs = stack.requireNativeLibraries();
if ((libs == null) || (libs.length == 0)) {
// No native libs for this stack
return;
}
for (int i = 0; i < libs.length; i++) {
Class c = libs[i].stackClass;
if (c == null) {
c = stack.getClass();
}
if (!NativeLibLoader.isAvailable(libs[i].libraryName, c)) {
throw new BluetoothStateException("BlueCove library " + libs[i].libraryName + " not available");
}
}
}
private static boolean isNativeLibrariesAvailable(BluetoothStack stack) {
try {
if (UtilsJavaSE.canCallNotLoadedNativeMethod) {
return stack.isNativeCodeLoaded();
}
} catch (Error e) {
// We caught UnsatisfiedLinkError
}
LibraryInformation[] libs = stack.requireNativeLibraries();
if ((libs == null) || (libs.length == 0)) {
// No native libs for this stack
return true;
}
for (int i = 0; i < libs.length; i++) {
Class c = libs[i].stackClass;
if (c == null) {
c = stack.getClass();
}
if (!NativeLibLoader.isAvailable(libs[i].libraryName, c)) {
return false;
}
}
return true;
}
private BluetoothStack detectStack() throws BluetoothStateException {
BluetoothStack detectorStack = null;
String stackFirstDetector = getConfigProperty(BlueCoveConfigProperties.PROPERTY_STACK_FIRST);
String stackSelected = getConfigProperty(BlueCoveConfigProperties.PROPERTY_STACK);
if (stackFirstDetector == null) {
stackFirstDetector = stackSelected;
}
if (STACK_EMULATOR.equals(stackSelected)) {
detectorStack = loadStack("bluecove.emulator.class", "com.intel.bluetooth.BluetoothEmulator");
} else {
switch (NativeLibLoader.getOS()) {
case NativeLibLoader.OS_LINUX:
Class stackClass = loadStackClass("bluecove.bluez.class", "com.intel.bluetooth.BluetoothStackBlueZ");
detectorStack = newStackInstance(stackClass);
loadNativeLibraries(detectorStack);
stackSelected = detectorStack.getStackID();
break;
case NativeLibLoader.OS_MAC_OS_X:
detectorStack = new BluetoothStackOSX();
loadNativeLibraries(detectorStack);
stackSelected = detectorStack.getStackID();
break;
case NativeLibLoader.OS_WINDOWS:
case NativeLibLoader.OS_WINDOWS_CE:
detectorStack = createDetectorOnWindows(stackFirstDetector);
if (DebugLog.isDebugEnabled()) {
detectorStack.enableNativeDebug(DebugLog.class, true);
}
break;
default:
throw new BluetoothStateException("BlueCove not available");
}
}
int libraryVersion = detectorStack.getLibraryVersion();
if (nativeLibraryVersionExpected != libraryVersion) {
DebugLog.fatal("BlueCove native library version mismatch " + libraryVersion + " expected "
+ nativeLibraryVersionExpected);
throw new BluetoothStateException("BlueCove native library version mismatch");
}
if (stackSelected == null) {
// auto detect
int aval = detectorStack.detectBluetoothStack();
DebugLog.debug("BluetoothStack detected", aval);
int detectorID = getStackId(detectorStack.getStackID());
if ((aval & detectorID) != 0) {
stackSelected = detectorStack.getStackID();
} else if ((aval & BLUECOVE_STACK_DETECT_MICROSOFT) != 0) {
stackSelected = STACK_WINSOCK;
} else if ((aval & BLUECOVE_STACK_DETECT_WIDCOMM) != 0) {
stackSelected = STACK_WIDCOMM;
} else if ((aval & BLUECOVE_STACK_DETECT_BLUESOLEIL) != 0) {
stackSelected = STACK_BLUESOLEIL;
} else if ((aval & BLUECOVE_STACK_DETECT_TOSHIBA) != 0) {
stackSelected = STACK_TOSHIBA;
} else if ((aval & BLUECOVE_STACK_DETECT_OSX) != 0) {
stackSelected = STACK_OSX;
} else {
DebugLog.fatal("BluetoothStack not detected");
throw new BluetoothStateException("BluetoothStack not detected");
}
} else {
DebugLog.debug("BluetoothStack selected", stackSelected);
}
BluetoothStack stack = setBluetoothStack(stackSelected, detectorStack);
stackSelected = stack.getStackID();
copySystemProperties(stack);
if (!stackSelected.equals(STACK_EMULATOR)) {
System.out.println("BlueCove version " + version + " on " + stackSelected);
}
return stack;
}
/**
* List the local adapters that can be initialized using configuration
* property "bluecove.deviceID". (Linux BlueZ and Emulator)
*
* The first stack/adapter would be initialized if not initialized already,
* you can exclude it from the list.
*
* The function return empty list on non bluez environment.
*
* @return List of Strings
* @throws BluetoothStateException
* if stack interface can't be initialized
* @see com.intel.bluetooth.BlueCoveConfigProperties#PROPERTY_LOCAL_DEVICE_ID
* @see com.intel.bluetooth.BlueCoveLocalDeviceProperties#LOCAL_DEVICE_PROPERTY_DEVICE_ID
*/
public static Vector getLocalDevicesID() throws BluetoothStateException {
Vector v = new Vector();
String ids = BluetoothStackHolder.getBluetoothStack().getLocalDeviceProperty(
BlueCoveLocalDeviceProperties.LOCAL_DEVICE_DEVICES_LIST);
if (ids != null) {
UtilsStringTokenizer tok = new UtilsStringTokenizer(ids, ",");
while (tok.hasMoreTokens()) {
v.addElement(tok.nextToken());
}
}
return v;
}
/**
* API that enables the use of Multiple Adapters and Bluetooth Stacks in
* parallel in the same JVM. Each thread should call
* setThreadBluetoothStackID() before using JSR-82 API.
*
* Affects the following JSR-82 API methods:
*
*
* LocalDevice.getLocalDevice();
* LocalDevice.getProperty(String);
* Connector.open(...);
* methods of RemoteDevice instance created by user.
*
*
* Example
*
*
*
* BlueCoveImpl.useThreadLocalBluetoothStack();
* // On Windows
* BlueCoveImpl.setConfigProperty("bluecove.stack", "widcomm");
* // On Linux or in Emulator
* // BlueCoveImpl.setConfigProperty("bluecove.deviceID", "0");
*
* final Object id1 = BlueCoveImpl.getThreadBluetoothStackID();
* ... do some work with stack 1
*
* // Illustrates attaching thread to already initialized stack interface
* Thread t1 = new Thread() {
* public void run() {
* BlueCoveImpl.setThreadBluetoothStackID(id1);
* agent = LocalDevice.getLocalDevice().getDiscoveryAgent();
* agent.startInquiry(...);
* .....
* }
* };
* t1.start();
*
* // Illustrates initialization of new/different stack interface in new thread
* // Start another thread that is using different stack
* Thread t2 = new Thread() {
* public void run() {
* // On Windows
* BlueCoveImpl.setConfigProperty("bluecove.stack", "winsock");
* // On Linux or in Emulator
* // BlueCoveImpl.setConfigProperty("bluecove.deviceID", "1");
* agent = LocalDevice.getLocalDevice().getDiscoveryAgent();
* agent.startInquiry(...);
* .....
* }
* }
* t2.start();
*
* Thread t3 = new Thread() {
* public void run() {
* // Wrong, will produce error: Thread StackID not configured
* Connector.open("btspp://12345678:1");
* .....
* }
* };
* t3.start();
*
*
*
* @see #setConfigProperty
*/
public static synchronized void useThreadLocalBluetoothStack() {
if (threadStack == null) {
threadStack = new ThreadLocalWrapper();
}
BluetoothStackHolder s = ((BluetoothStackHolder) threadStack.get());
if (s == null) {
// Move initialized single stack to this thread
if (singleStack != null) {
s = singleStack;
singleStack = null;
} else {
s = new BluetoothStackHolder();
}
threadStack.set(s);
}
}
/**
* Initialize BluetoothStack if not already done and returns the ID to be
* used in other threads accessing the same stack.
*
* @return an object that represents Adapter/BluetoothStack, stackID to be
* used in call to setThreadBluetoothStackID
* @throws BluetoothStateException
* if the Bluetooth system could not be initialized
*/
public static synchronized Object getThreadBluetoothStackID() throws BluetoothStateException {
useThreadLocalBluetoothStack();
BluetoothStackHolder.getBluetoothStack();
return threadStack.get();
}
/**
* Returns the ID to be used in other threads accessing the same stack.
*
* @return an object that represents Adapter/BluetoothStack, stackID to be
* used in call to setThreadBluetoothStackID
or
* null if ThreadLocalBluetoothStack not used.
*/
public static synchronized Object getCurrentThreadBluetoothStackID() {
if (threadStack == null) {
return null;
}
return threadStack.get();
}
/**
* Updates the current Thread BluetoothStack. Updating is possible only if
* stackID
was obtained using the
* getThreadBluetoothStackID()
method. Should be called before
* connection is made or LocalDevice received from
* LocalDevice.getLocalDevice().
*
* @param stackID
* stackID to use or null
to detach the current
* Thread
*/
public static synchronized void setThreadBluetoothStackID(Object stackID) {
if ((stackID != null) && (!(stackID instanceof BluetoothStackHolder))) {
throw new IllegalArgumentException("stackID is not valid");
}
if (threadStack == null) {
throw new IllegalArgumentException("ThreadLocal configuration is not initialized");
}
threadStack.set(stackID);
}
/**
* Detach BluetoothStack from ThreadLocal. Used for removing itself from
* container threads. Also can be use to initialize different stack in the
* same thread.
*/
public static synchronized void releaseThreadBluetoothStack() {
if (threadStack == null) {
throw new IllegalArgumentException("ThreadLocal configuration is not initialized");
}
threadStack.set(null);
}
/**
* Set default Thread BluetoothStack for Threads that do not call
* setThreadBluetoothStackID(stackID)
. Updating is possible
* only if stackID
was obtained using the
* getThreadBluetoothStackID()
method.
*
* @param stackID
* stackID to use or null
to remove default
*/
public static synchronized void setDefaultThreadBluetoothStackID(Object stackID) {
if ((stackID != null) && (!(stackID instanceof BluetoothStackHolder))) {
throw new IllegalArgumentException("stackID is not valid");
}
if (threadStack == null) {
throw new IllegalArgumentException("ThreadLocal configuration is not initialized");
}
threadStackIDDefault = (BluetoothStackHolder) stackID;
}
static synchronized void setThreadBluetoothStack(BluetoothStack bluetoothStack) {
if (threadStack == null) {
return;
}
BluetoothStackHolder s = ((BluetoothStackHolder) threadStack.get());
if ((s != null) && (s.bluetoothStack == bluetoothStack)) {
return;
}
BluetoothStackHolder sh = (BluetoothStackHolder) stacks.get(bluetoothStack);
if (sh == null) {
throw new RuntimeException("ThreadLocal not found for BluetoothStack");
}
threadStack.set(sh);
}
/**
* Shutdown BluetoothStack assigned for current Thread and clear
* configuration properties for this thread
*/
public static synchronized void shutdownThreadBluetoothStack() {
// ThreadLocal configuration is not initialized
if (threadStack == null) {
return;
}
BluetoothStackHolder s = ((BluetoothStackHolder) threadStack.get());
if (s == null) {
return;
}
if (threadStackIDDefault == s) {
threadStackIDDefault = null;
}
s.configProperties.clear();
if (s.bluetoothStack != null) {
BluetoothConnectionNotifierBase.shutdownConnections(s.bluetoothStack);
RemoteDeviceHelper.shutdownConnections(s.bluetoothStack);
s.bluetoothStack.destroy();
stacks.remove(s.bluetoothStack);
s.bluetoothStack = null;
}
}
/**
* Shutdown all BluetoothStacks interfaces initialized by BlueCove
*/
public static synchronized void shutdown() {
for (Enumeration en = stacks.elements(); en.hasMoreElements();) {
BluetoothStackHolder s = (BluetoothStackHolder) en.nextElement();
s.configProperties.clear();
if (s.bluetoothStack != null) {
BluetoothConnectionNotifierBase.shutdownConnections(s.bluetoothStack);
RemoteDeviceHelper.shutdownConnections(s.bluetoothStack);
try {
s.bluetoothStack.destroy();
} finally {
s.bluetoothStack = null;
}
}
}
stacks.clear();
singleStack = null;
threadStackIDDefault = null;
if (shutdownHookRegistered != null) {
shutdownHookRegistered.deRegister();
}
clearSystemProperties();
}
/**
* API that can be used to configure BlueCove properties instead of System
* properties. Initialization properties should be changed before stack
* initialized. If null
is passed as the value
* then the property will be removed.
*
* @param name
* property name
* @param value
* property value
*
* @see com.intel.bluetooth.BlueCoveConfigProperties
*
* @exception IllegalArgumentException
* if the stack already initialized and property can't be
* changed.
*/
public static void setConfigProperty(String name, String value) {
if (name == null) {
throw new NullPointerException("key is null");
}
BluetoothStackHolder sh = currentStackHolder(true);
if ((sh.bluetoothStack != null) && (initializationProperties.contains(name))) {
throw new IllegalArgumentException("BlueCove Stack already initialized");
}
if (value == null) {
sh.configProperties.remove(name);
} else {
sh.configProperties.put(name, value);
}
}
static String getConfigProperty(String key) {
if (key == null) {
throw new NullPointerException("key is null");
}
String value = null;
BluetoothStackHolder sh = currentStackHolder(false);
if (sh != null) {
value = (String) sh.configProperties.get(key);
}
if (value == null) {
try {
value = System.getProperty(key);
} catch (SecurityException webstart) {
}
}
if (value == null) {
synchronized (resourceConfigProperties) {
Object casheValue = resourceConfigProperties.get(key);
if (casheValue != null) {
if (casheValue instanceof String) {
value = (String) casheValue;
}
} else {
value = Utils.getResourceProperty(BlueCoveImpl.class, key);
if (value == null) {
resourceConfigProperties.put(key, new Object());
} else {
resourceConfigProperties.put(key, value);
}
}
}
}
return value;
}
static boolean getConfigProperty(String key, boolean defaultValue) {
String value = getConfigProperty(key);
if (value != null) {
return TRUE.equals(value) || "1".equals(value);
} else {
return defaultValue;
}
}
static String[] getSystemPropertiesList() {
String[] p = { "bluetooth.master.switch", "bluetooth.sd.attr.retrievable.max",
"bluetooth.connected.devices.max", "bluetooth.l2cap.receiveMTU.max", "bluetooth.sd.trans.max",
"bluetooth.connected.inquiry.scan", "bluetooth.connected.page.scan", "bluetooth.connected.inquiry",
"bluetooth.connected.page" };
return p;
}
static void clearSystemProperties() {
UtilsJavaSE.setSystemProperty("bluetooth.api.version", null);
UtilsJavaSE.setSystemProperty("obex.api.version", null);
String[] property = getSystemPropertiesList();
for (int i = 0; i < property.length; i++) {
UtilsJavaSE.setSystemProperty(property[i], null);
}
}
void copySystemProperties(BluetoothStack bluetoothStack) {
UtilsJavaSE.setSystemProperty("bluetooth.api.version", "1.1");
UtilsJavaSE.setSystemProperty("obex.api.version", "1.1");
if (bluetoothStack != null) {
String[] property = getSystemPropertiesList();
for (int i = 0; i < property.length; i++) {
UtilsJavaSE.setSystemProperty(property[i], bluetoothStack.getLocalDeviceProperty(property[i]));
}
}
}
public String getLocalDeviceFeature(int featureID) throws BluetoothStateException {
return ((BluetoothStackHolder.getBluetoothStack().getFeatureSet() & featureID) != 0) ? TRUE : FALSE;
}
private BluetoothStack createDetectorOnWindows(String stackFirst) throws BluetoothStateException {
if (stackFirst != null) {
DebugLog.debug("detector stack", stackFirst);
BluetoothStack detectorStack;
if (STACK_WIDCOMM.equalsIgnoreCase(stackFirst)) {
detectorStack = new BluetoothStackWIDCOMM();
if (isNativeLibrariesAvailable(detectorStack)) {
return detectorStack;
}
} else if (STACK_BLUESOLEIL.equalsIgnoreCase(stackFirst)) {
detectorStack = new BluetoothStackBlueSoleil();
if (isNativeLibrariesAvailable(detectorStack)) {
return detectorStack;
}
} else if (STACK_WINSOCK.equalsIgnoreCase(stackFirst)) {
detectorStack = new BluetoothStackMicrosoft();
if (isNativeLibrariesAvailable(detectorStack)) {
return detectorStack;
}
} else if (STACK_TOSHIBA.equalsIgnoreCase(stackFirst)) {
detectorStack = new BluetoothStackToshiba();
if (isNativeLibrariesAvailable(detectorStack)) {
return detectorStack;
}
} else {
throw new IllegalArgumentException("Invalid BlueCove detector stack [" + stackFirst + "]");
}
}
BluetoothStack stack = new BluetoothStackMicrosoft();
if (isNativeLibrariesAvailable(stack)) {
return stack;
}
stack = new BluetoothStackWIDCOMM();
if (isNativeLibrariesAvailable(stack)) {
return stack;
}
throw new BluetoothStateException("BlueCove libraries not available");
}
/**
* @deprecated use setConfigProperty("bluecove.stack", ...);
*
* @param stack
* @return stack ID
* @throws BluetoothStateException
*/
public String setBluetoothStack(String stack) throws BluetoothStateException {
return setBluetoothStack(stack, null).getStackID();
}
private synchronized BluetoothStack setBluetoothStack(String stack, BluetoothStack detectorStack)
throws BluetoothStateException {
if (singleStack != null) {
if (singleStack.bluetoothStack != null) {
singleStack.bluetoothStack.destroy();
stacks.remove(singleStack.bluetoothStack);
singleStack.bluetoothStack = null;
}
} else if (threadStack != null) {
BluetoothStackHolder s = ((BluetoothStackHolder) threadStack.get());
if ((s != null) && (s.bluetoothStack != null)) {
s.bluetoothStack.destroy();
stacks.remove(s.bluetoothStack);
s.bluetoothStack = null;
}
}
BluetoothStack newStack;
if ((detectorStack != null) && (detectorStack.getStackID()).equalsIgnoreCase(stack)) {
newStack = detectorStack;
} else if (STACK_WIDCOMM.equalsIgnoreCase(stack)) {
newStack = new BluetoothStackWIDCOMM();
} else if (STACK_BLUESOLEIL.equalsIgnoreCase(stack)) {
newStack = new BluetoothStackBlueSoleil();
} else if (STACK_TOSHIBA.equalsIgnoreCase(stack)) {
newStack = new BluetoothStackToshiba();
} else {
newStack = new BluetoothStackMicrosoft();
}
loadNativeLibraries(newStack);
int libraryVersion = newStack.getLibraryVersion();
if (nativeLibraryVersionExpected != libraryVersion) {
DebugLog.fatal("BlueCove native library version mismatch " + libraryVersion + " expected "
+ nativeLibraryVersionExpected);
throw new BluetoothStateException("BlueCove native library version mismatch");
}
if (DebugLog.isDebugEnabled()) {
newStack.enableNativeDebug(DebugLog.class, true);
}
newStack.initialize();
createShutdownHook();
// Store stack in Thread or static variables
BluetoothStackHolder sh = currentStackHolder(true);
sh.bluetoothStack = newStack;
stacks.put(newStack, sh);
if (threadStack != null) {
threadStack.set(sh);
}
return newStack;
}
public void enableNativeDebug(boolean on) {
BluetoothStackHolder s = currentStackHolder(false);
if ((s != null) && (s.bluetoothStack != null)) {
s.bluetoothStack.enableNativeDebug(DebugLog.class, on);
}
}
private static BluetoothStackHolder currentStackHolder(boolean create) {
if (threadStack != null) {
BluetoothStackHolder s = ((BluetoothStackHolder) threadStack.get());
if ((s == null) && (threadStackIDDefault != null)) {
return threadStackIDDefault;
}
if ((s == null) && create) {
s = new BluetoothStackHolder();
threadStack.set(s);
}
return s;
} else {
if ((singleStack == null) && create) {
singleStack = new BluetoothStackHolder();
}
return singleStack;
}
}
/**
* Applications should not used this function.
*
* @return current BluetoothStack implementation
* @throws BluetoothStateException
* when BluetoothStack not detected. If one connected the
* hardware later, BlueCove would be able to recover and start
* correctly
* @exception Error
* if called from outside of BlueCove internal code.
*/
public synchronized BluetoothStack getBluetoothStack() throws BluetoothStateException {
Utils.isLegalAPICall(fqcnSet);
BluetoothStackHolder sh = currentStackHolder(false);
if ((sh != null) && (sh.bluetoothStack != null)) {
return sh.bluetoothStack;
} else if ((sh == null) && (threadStack != null)) {
throw new BluetoothStateException("No BluetoothStack or Adapter for current thread");
}
BluetoothStack stack;
if (accessControlContext == null) {
stack = detectStack();
} else {
stack = detectStackPrivileged();
}
return stack;
}
private BluetoothStack detectStackPrivileged() throws BluetoothStateException {
try {
return (BluetoothStack) AccessController.doPrivileged(new PrivilegedExceptionAction() {
public Object run() throws BluetoothStateException {
return detectStack();
}
}, (AccessControlContext) accessControlContext);
} catch (PrivilegedActionException e) {
Throwable cause = UtilsJavaSE.getCause(e);
if (cause instanceof BluetoothStateException) {
throw (BluetoothStateException) cause;
}
throw (BluetoothStateException) UtilsJavaSE.initCause(new BluetoothStateException(e.getMessage()), cause);
}
}
}