/**
* Author: Sven Gothel
* Further provides access to certain property settings,
* see {@link #DEBUG}, {@link #VERBOSE}, {@link #DIRECTBT_CHARACTERISTIC_VALUE_CACHE_NOTIFICATION_COMPAT}.
*
* The implementation class must provide the static factory method
*
* public static synchronized BluetoothManager getBluetoothManager() throws BluetoothException { .. }
*
*
* The implementation class must provide the static factory method *
* public static synchronized BluetoothManager getBluetoothManager() throws BluetoothException { .. } ** */ public final String BluetoothManagerClassName; /** Native library basename for the implementation native library */ public final String ImplementationNativeLibraryBasename; /** Native library basename for the Java binding native library */ public final String JavaNativeLibraryBasename; public ImplementationIdentifier(final String BluetoothManagerClassName, final String ImplementationNativeLibraryBasename, final String JavaNativeLibraryBasename) { this.BluetoothManagerClassName = BluetoothManagerClassName; this.ImplementationNativeLibraryBasename = ImplementationNativeLibraryBasename; this.JavaNativeLibraryBasename = JavaNativeLibraryBasename; } /** *
* Implementation compares {@link #BluetoothManagerClassName} only for equality. *
* {@inheritDoc} */ @Override public boolean equals(final Object other) { if( null == other || !(other instanceof ImplementationIdentifier) ) { return false; } final ImplementationIdentifier o = (ImplementationIdentifier)other; return BluetoothManagerClassName.equals( o.BluetoothManagerClassName ); } @Override public String toString() { return "ImplementationIdentifier[class "+BluetoothManagerClassName+ ", implLib "+ImplementationNativeLibraryBasename+ ", javaLib "+JavaNativeLibraryBasename+"]"; } } /** * {@link ImplementationIdentifier} for D-Bus implementation: {@value} ** This value is exposed for convenience, user implementations are welcome. *
*/ public static final ImplementationIdentifier DBusImplementationID = new ImplementationIdentifier("tinyb.dbus.DBusManager", "tinyb", "javatinyb"); /** * {@link ImplementationIdentifier} for direct_bt implementation: {@value} ** This value is exposed for convenience, user implementations are welcome. *
*/ public static final ImplementationIdentifier DirectBTImplementationID = new ImplementationIdentifier("direct_bt.tinyb.DBTManager", "direct_bt", "javadirect_bt"); private static final List* System property {@code org.tinyb.verbose}, boolean, default {@code false}. *
*/ public static final boolean VERBOSE; /** * Debug logging enabled or disabled. ** System property {@code org.tinyb.debug}, boolean, default {@code false}. *
*/ public static final boolean DEBUG; /** * Have direct_bt provide compatibility to TinyB's {@link BluetoothGattCharacteristic} * API: {@link BluetoothGattCharacteristic#getValue() value cache} and * {@link BluetoothGattCharacteristic#enableValueNotifications(BluetoothNotification) value notification}. ** System property {@code direct_bt.tinyb.characteristic.compat}, boolean, default {@code true}. *
*/ public static final boolean DIRECTBT_CHARACTERISTIC_VALUE_CACHE_NOTIFICATION_COMPAT; static { { final String v = System.getProperty("org.tinyb.verbose", "false"); VERBOSE = Boolean.valueOf(v); } { final String v = System.getProperty("org.tinyb.debug", "false"); DEBUG = Boolean.valueOf(v); } { final String v = System.getProperty("direct_bt.tinyb.characteristic.compat", "true"); DIRECTBT_CHARACTERISTIC_VALUE_CACHE_NOTIFICATION_COMPAT = Boolean.valueOf(v); } implIDs.add(DirectBTImplementationID); implIDs.add(DBusImplementationID); } private static ImplementationIdentifier initializedID = null; private static long t0; public static synchronized void checkInitialized() { if( null == initializedID ) { throw new IllegalStateException("BluetoothFactory not initialized."); } } public static synchronized boolean isInitialized() { return null == initializedID; } private static synchronized void initLibrary(final ImplementationIdentifier id) { if( null != initializedID ) { if( id != initializedID ) { throw new IllegalStateException("BluetoothFactory already initialized with "+initializedID+", can't override by "+id); } return; } try { final Throwable[] t = { null }; if( !PlatformToolkit.loadLibrary(id.ImplementationNativeLibraryBasename, BluetoothFactory.class.getClassLoader(), t) ) { throw new RuntimeException("Couldn't load native library with basename <"+id.ImplementationNativeLibraryBasename+">", t[0]); } if( !PlatformToolkit.loadLibrary(id.JavaNativeLibraryBasename, BluetoothFactory.class.getClassLoader(), t) ) { throw new RuntimeException("Couldn't load native library with basename <"+id.JavaNativeLibraryBasename+">", t[0]); } } catch (final Throwable e) { e.printStackTrace(); throw e; // fwd exception - end here } // Map all Java properties '[org.]tinyb.*' and 'direct_bt.*' to native environment. try { if( DEBUG ) { System.err.println("BlootoothFactory: Mapping '[org.]tinyb.*' and 'direct_bt.*' properties to native environment"); } final Properties props = AccessController.doPrivileged(new PrivilegedAction* If found, method returns {@link #getBluetoothManager(ImplementationIdentifier)}, otherwise {@code null}. *
** The chosen implementation can't be changed within a running implementation, an exception is thrown if tried. *
* * @param fqBluetoothManagerImplementationClassName fully qualified class name for the {@link BluetoothManager} implementation * @throws BluetoothException * @throws NoSuchMethodException * @throws SecurityException * @throws IllegalAccessException * @throws IllegalArgumentException * @throws InvocationTargetException * @throws ClassNotFoundException * @see {@link #DBusFactoryImplClassName} * @see {@link #DirectBTFactoryImplClassName} */ public static synchronized BluetoothManager getBluetoothManager(final String fqBluetoothManagerImplementationClassName) throws BluetoothException, NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, ClassNotFoundException { final ImplementationIdentifier id = getImplementationIdentifier(fqBluetoothManagerImplementationClassName); if( null != id ) { return getBluetoothManager(id); } return null; } /** * Returns an initialized BluetoothManager instance using the given {@link ImplementationIdentifier}. ** If the {@link ImplementationIdentifier} has not been {@link #registerImplementationIdentifier(ImplementationIdentifier)}, * it will be added to the list. *
** The chosen implementation can't be changed within a running implementation, an exception is thrown if tried. *
* @param id the specific {@link ImplementationIdentifier} * @throws BluetoothException * @throws NoSuchMethodException * @throws SecurityException * @throws IllegalAccessException * @throws IllegalArgumentException * @throws InvocationTargetException * @throws ClassNotFoundException * @see {@link #DBusFactoryImplClassName} * @see {@link #DirectBTFactoryImplClassName} */ public static synchronized BluetoothManager getBluetoothManager(final ImplementationIdentifier id) throws BluetoothException, NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, ClassNotFoundException { registerImplementationIdentifier(id); initLibrary(id); final Class> factoryImpl = Class.forName(id.BluetoothManagerClassName); return getBluetoothManager(factoryImpl); } /** * Returns an initialized BluetoothManager instance using a D-Bus implementation. ** Issues {@link #getBluetoothManager(ImplementationIdentifier)} using {@link #DBusImplementationID}. *
** The chosen implementation can't be changed within a running implementation, an exception is thrown if tried. *
* @throws BluetoothException * @throws NoSuchMethodException * @throws SecurityException * @throws IllegalAccessException * @throws IllegalArgumentException * @throws InvocationTargetException * @throws ClassNotFoundException */ public static synchronized BluetoothManager getDBusBluetoothManager() throws BluetoothException, NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, ClassNotFoundException { return getBluetoothManager(DBusImplementationID); } /** * Returns an initialized BluetoothManager instance using the DirectBT implementation. ** Issues {@link #getBluetoothManager(ImplementationIdentifier)} using {@link #DirectBTImplementationID}. *
** The chosen implementation can't be changed within a running implementation, an exception is thrown if tried. *
* @throws BluetoothException * @throws NoSuchMethodException * @throws SecurityException * @throws IllegalAccessException * @throws IllegalArgumentException * @throws InvocationTargetException * @throws ClassNotFoundException */ public static synchronized BluetoothManager getDirectBTBluetoothManager() throws BluetoothException, NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, ClassNotFoundException { return getBluetoothManager(DirectBTImplementationID); } private static final boolean debug = false; private static final Manifest getManifest(final ClassLoader cl, final String[] extensions) { final Manifest[] extManifests = new Manifest[extensions.length]; try { final Enumeration