diff options
author | Sven Gothel <[email protected]> | 2020-02-09 14:48:51 +0100 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2020-02-09 14:48:51 +0100 |
commit | 4a656b0ee13332dd635f8f88b8a5c9d564a63f81 (patch) | |
tree | 5ea1c546e6ce2d7d6b30df90c56efd4c4d135f95 | |
parent | b253c12a17b4501dbc44ad0400e7edae619ec895 (diff) |
BluetoothFactory handles API verification via native-API and Manifest attributes; Fix manifest.txt.in ...v2.0.0
Also show Manifest specification + implementation details incl git-commit-sha1
when run in '-Dorg.tinyb.verbose=true' mode.
-rw-r--r-- | java/manifest.txt.in | 16 | ||||
-rw-r--r-- | java/org/tinyb/BluetoothFactory.java | 155 | ||||
-rw-r--r-- | java/tinyb/dbus/DBusManager.java | 28 | ||||
-rw-r--r-- | java/tinyb/dbus/DBusObject.java | 9 |
4 files changed, 175 insertions, 33 deletions
diff --git a/java/manifest.txt.in b/java/manifest.txt.in index 40bd5d85..bac86421 100644 --- a/java/manifest.txt.in +++ b/java/manifest.txt.in @@ -6,8 +6,6 @@ Bundle-SymbolicName: org.tinyb Bundle-Version: @VERSION_SHORT@ Export-Package: org.tinyb Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=1.8))" - -Name: tinyb/ Package-Title: org.tinyb Package-Vendor: ZAFENA AB Package-Version: @VERSION_SHORT@ @@ -19,3 +17,17 @@ Implementation-Vendor: ZAFENA AB Implementation-Version: @VERSION@ Implementation-Commit: @VERSION_SHA1@ Implementation-URL: http://www.zafena.se/ +Extension-Name: org.tinyb +Trusted-Library: true +Permissions: all-permissions +Application-Library-Allowable-Codebase: * + +Name: org/tinyb/ +Sealed: true + +Name: tinyb/dbus/ +Sealed: true + +Name: tinyb/hci/ +Sealed: true + diff --git a/java/org/tinyb/BluetoothFactory.java b/java/org/tinyb/BluetoothFactory.java index b2b90384..8f01db15 100644 --- a/java/org/tinyb/BluetoothFactory.java +++ b/java/org/tinyb/BluetoothFactory.java @@ -24,11 +24,112 @@ */ package org.tinyb; +import java.io.IOException; +import java.io.InputStream; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.net.URL; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.Set; +import java.util.jar.Attributes; +import java.util.jar.Manifest; public class BluetoothFactory { /** + * Name of the native implementation native library basename: {@value} + */ + public static final String ImplNativeLibBasename = "tinyb"; + + /** + * Name of the Jave native library basename: {@value} + */ + public static final String JavaNativeLibBasename = "javatinyb"; + + /** + * Manifest's {@link Attributes.Name#SPECIFICATION_VERSION} or {@code null} if not available. + */ + public static final String APIVersion; + + /** + * Manifest's {@link Attributes.Name#IMPLEMENTATION_VERSION} or {@code null} if not available. + */ + public static final String ImplVersion; + + static final boolean VERBOSE; + + static { + { + final String v = System.getProperty("org.tinyb.verbose", "false"); + VERBOSE = Boolean.valueOf(v); + } + try { + System.loadLibrary(ImplNativeLibBasename); + } catch (final Throwable e) { + System.err.println("Failed to load native library "+ImplNativeLibBasename); + e.printStackTrace(); + throw e; // fwd exception - end here + } + try { + System.loadLibrary(JavaNativeLibBasename); + } catch (final Throwable e) { + System.err.println("Failed to load native library "+JavaNativeLibBasename); + e.printStackTrace(); + throw e; // fwd exception - end here + } + try { + final Manifest manifest = getManifest(BluetoothFactory.class.getClassLoader(), new String[] { "org.tinyb" } ); + final Attributes mfAttributes = null != manifest ? manifest.getMainAttributes() : null; + + // major.minor must match! + final String NAPIVersion = getNativeAPIVersion(); + final String JAPIVersion = null != mfAttributes ? mfAttributes.getValue(Attributes.Name.SPECIFICATION_VERSION) : null; + if ( null != JAPIVersion && JAPIVersion.equals(NAPIVersion) == false) { + final String[] NAPIVersionCode = NAPIVersion.split("\\D"); + final String[] JAPIVersionCode = JAPIVersion.split("\\D"); + if (JAPIVersionCode[0].equals(NAPIVersionCode[0]) == false) { + if (Integer.valueOf(JAPIVersionCode[0]) < Integer.valueOf(NAPIVersionCode[0])) { + throw new RuntimeException("Java library "+JAPIVersion+" < native library "+NAPIVersion+". Please update the Java library."); + } else { + throw new RuntimeException("Native library "+NAPIVersion+" < java library "+JAPIVersion+". Please update the native library."); + } + } else if (JAPIVersionCode[1].equals(NAPIVersionCode[1]) == false) { + if (Integer.valueOf(JAPIVersionCode[1]) < Integer.valueOf(NAPIVersionCode[1])) { + throw new RuntimeException("Java library "+JAPIVersion+" < native library "+NAPIVersion+". Please update the Java library."); + } else { + throw new RuntimeException("Native library "+NAPIVersion+" < java library "+JAPIVersion+". Please update the native library."); + } + } + } + APIVersion = JAPIVersion; + ImplVersion = null != mfAttributes ? mfAttributes.getValue(Attributes.Name.IMPLEMENTATION_VERSION) : null; + if( VERBOSE ) { + System.err.println("tinyb2 java api version "+JAPIVersion); + System.err.println("tinyb2 native api version "+NAPIVersion); + if( null != mfAttributes ) { + final Attributes.Name[] versionAttributeNames = new Attributes.Name[] { + Attributes.Name.SPECIFICATION_TITLE, + Attributes.Name.SPECIFICATION_VENDOR, + Attributes.Name.SPECIFICATION_VERSION, + Attributes.Name.IMPLEMENTATION_TITLE, + Attributes.Name.IMPLEMENTATION_VENDOR, + Attributes.Name.IMPLEMENTATION_VERSION, + new Attributes.Name("Implementation-Commit") }; + for( final Attributes.Name an : versionAttributeNames ) { + System.err.println(" "+an+": "+mfAttributes.getValue(an)); + } + } else { + System.err.println(" No Manifest available;"); + } + } + } catch (final Throwable e) { + System.err.println("Error querying manifest information."); + e.printStackTrace(); + throw e; // fwd exception - end here + } + } + + /** * Fully qualified factory class name for D-Bus implementation: {@value} * <p> * This value is exposed for convenience, user implementations are welcome. @@ -105,5 +206,59 @@ public class BluetoothFactory { return tinyb.dbus.DBusManager.getBluetoothManager(); } + 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<URL> resources = cl.getResources("META-INF/MANIFEST.MF"); + while (resources.hasMoreElements()) { + final URL resURL = resources.nextElement(); + if( debug ) { + System.err.println("resource: "+resURL); + } + final InputStream is = resURL.openStream(); + final Manifest manifest; + try { + manifest = new Manifest(is); + } finally { + try { + is.close(); + } catch (final IOException e) {} + } + final Attributes attributes = manifest.getMainAttributes(); + if(attributes != null) { + final String attributesExtName = attributes.getValue( Attributes.Name.EXTENSION_NAME ); + if( debug ) { + System.err.println("resource: "+resURL+", attributes extName "+attributesExtName+", count "+attributes.size()); + final Set<Object> keys = attributes.keySet(); + for(final Iterator<Object> iter=keys.iterator(); iter.hasNext(); ) { + final Attributes.Name key = (Attributes.Name) iter.next(); + final String val = attributes.getValue(key); + System.err.println(" "+key+": "+val); + } + } + for(int i=0; i < extensions.length && null == extManifests[i]; i++) { + final String extension = extensions[i]; + if( extension.equals( attributesExtName ) ) { + if( 0 == i ) { + return manifest; // 1st one has highest prio - done + } + extManifests[i] = manifest; + } + } + } + } + } catch (final IOException ex) { + throw new RuntimeException("Unable to read manifest.", ex); + } + for(int i=1; i<extManifests.length; i++) { + if( null != extManifests[i] ) { + return extManifests[i]; + } + } + return null; + } + private native static String getNativeAPIVersion(); } diff --git a/java/tinyb/dbus/DBusManager.java b/java/tinyb/dbus/DBusManager.java index e3e86ab6..2b5efe65 100644 --- a/java/tinyb/dbus/DBusManager.java +++ b/java/tinyb/dbus/DBusManager.java @@ -43,15 +43,6 @@ public class DBusManager implements BluetoothManager private long nativeInstance; private static DBusManager inst; - static { - try { - System.loadLibrary("tinyb"); - System.loadLibrary("javatinyb"); - } catch (final UnsatisfiedLinkError e) { - System.err.println("Native code library failed to load.\n" + e); - } - } - private native static String getNativeAPIVersion(); public native BluetoothType getBluetoothType(); @@ -132,25 +123,6 @@ public class DBusManager implements BluetoothManager { if (inst == null) { - final String nativeAPIVersion = getNativeAPIVersion(); - final String APIVersion = DBusManager.class.getPackage().getSpecificationVersion(); - if ( null != APIVersion && APIVersion.equals(nativeAPIVersion) == false) { - final String[] nativeAPIVersionCode = nativeAPIVersion.split("\\D"); - final String[] APIVersionCode = APIVersion.split("\\D"); - if (APIVersionCode[0].equals(nativeAPIVersionCode[0]) == false) { - if (Integer.valueOf(APIVersionCode[0]) < Integer.valueOf(nativeAPIVersionCode[0])) - throw new RuntimeException("Java library is out of date. Please update the Java library."); - else throw new RuntimeException("Native library is out of date. Please update the native library."); - } - else if (APIVersionCode[0].equals("0") == true) { - if (Integer.valueOf(APIVersionCode[1]) < Integer.valueOf(nativeAPIVersionCode[1])) - throw new RuntimeException("Java library is out of date. Please update the Java library."); - else throw new RuntimeException("Native library is out of date. Please update the native library."); - } - else if (Integer.valueOf(APIVersionCode[1]) < Integer.valueOf(nativeAPIVersionCode[1])) - System.err.println("Java library is out of date. Please update the Java library."); - else System.err.println("Native library is out of date. Please update the native library."); - } inst = new DBusManager(); inst.init(); } diff --git a/java/tinyb/dbus/DBusObject.java b/java/tinyb/dbus/DBusObject.java index a9095d1a..66cdde30 100644 --- a/java/tinyb/dbus/DBusObject.java +++ b/java/tinyb/dbus/DBusObject.java @@ -28,6 +28,7 @@ package tinyb.dbus; +import org.tinyb.BluetoothFactory; import org.tinyb.BluetoothObject; import org.tinyb.BluetoothType; @@ -38,9 +39,11 @@ public class DBusObject implements BluetoothObject static { try { - System.loadLibrary("javatinyb"); - } catch (final UnsatisfiedLinkError e) { - System.err.println("Native code library failed to load.\n" + e); + System.loadLibrary(BluetoothFactory.JavaNativeLibBasename); + } catch (final Throwable e) { + System.err.println("Failed to load native library "+BluetoothFactory.JavaNativeLibBasename); + e.printStackTrace(); + throw e; // fwd exception - end here } } |