blob: 34b8acb6512819ed89a737cdcc6c516eafb44cbe [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.mesos;
public class MesosNativeLibrary {
/**
* Represent a 'libmesos' version with Major, Minor, and Patch versions. We
* use a class here to make it easier to do version compatibility checking.
* For example:
* <pre>
* {@code
* static Version BugFixVersion = new Version(0, 22, 1);
* public static void myFunction() {
* if (version().compareTo(BugFixVersion) >= 0) {
* // New behavior with bug fix.
* } else {
* // Old behavior for backwards compatibility.
* }
* }
* }
* </pre>
*/
public static class Version implements Comparable<Version> {
public Version(long major, long minor, long patch) {
if (major < 0) {
throw new IllegalArgumentException(
"Major version must not be negative");
}
if (minor < 0) {
throw new IllegalArgumentException(
"Minor version must not be negative");
}
if (patch < 0) {
throw new IllegalArgumentException(
"Patch version must not be negative");
}
this.major = major;
this.minor = minor;
this.patch = patch;
}
public Version(long major, long minor) {
this(major, minor, 0);
}
public Version(long major) {
this(major, 0, 0);
}
public boolean equals(Version other) {
return other != null &&
major == other.major &&
minor == other.minor &&
patch == other.patch;
}
/**
* Compare this version to an 'other' one. The comparison is done
* lexicographically. This returns -1 if this version is 'lesser' than the
* other, 0 if they are equivalent, and 1 if this version is 'greater'.
*/
@Override
public int compareTo(Version other) {
if (other == null) {
throw new IllegalArgumentException("other Version must not be null");
}
if (major < other.major) {
return -1;
} else if (major > other.major) {
return 1;
}
if (minor < other.minor) {
return -1;
} else if (minor > other.minor) {
return 1;
}
if (patch < other.patch) {
return -1;
} else if (patch > other.patch) {
return 1;
}
return 0;
}
/**
* A helper that is easier to use than 'compareTo', this returns
* true if 'this' version is strictly 'less than', not 'less than
* or equal to' the 'other' version.
*/
public boolean before(Version other) {
return this.compareTo(other) < 0;
}
/**
* A helper that is easier to use than 'compareTo', this returns
* true if 'this' version is strictly 'greater than', not 'greater
* than or equal to' the 'other' version.
*/
public boolean after(Version other) {
return this.compareTo(other) > 0;
}
public final long major;
public final long minor;
public final long patch;
}
/**
* Attempts to load the native library (if it was not previously loaded)
* from the given path. If the path is null 'java.library.path' is used to
* load the library.
*/
public static synchronized void load(String path) {
// Our JNI library will actually set 'loaded' to true once it is
// loaded, that way the library can get loaded by a user via
// 'System.load' in the event that they want to specify an
// absolute path and we won't try and reload the library ourselves
// (which would probably fail because 'java.library.path' might
// not be set).
if (loaded) {
return;
}
// In some circumstances, such as when sandboxed class loaders are used,
// the current thread's context class loader will not be able to see
// MesosNativeLibrary (even when executing this code!).
// We therefore, temporarily swap the thread's context class loader with
// the class loader that loaded this class, for the duration of the native
// library load.
ClassLoader contextClassLoader =
Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(
MesosNativeLibrary.class.getClassLoader());
try {
if (path != null) {
System.load(path);
} else {
// TODO(tillt): Change the default fallback to JNI specific library
// once libmesos has been split.
System.loadLibrary("mesos");
}
} catch (UnsatisfiedLinkError error) {
System.err.println("Failed to load native Mesos library from " +
(path != null ? path : System.getProperty("java.library.path")));
throw error;
} finally {
Thread.currentThread().setContextClassLoader(contextClassLoader);
}
}
public static void load() {
// Try to get the JNI specific library path from the environment.
String path = System.getenv("MESOS_NATIVE_JAVA_LIBRARY");
// As a fallback, use deprecated environment variable to extract that path.
if (path == null) {
path = System.getenv("MESOS_NATIVE_LIBRARY");
if (path != null) {
System.out.println("Warning: MESOS_NATIVE_LIBRARY is deprecated, " +
"use MESOS_NATIVE_JAVA_LIBRARY instead. Future releases will " +
"not support JNI bindings via MESOS_NATIVE_LIBRARY.");
}
}
load(path);
}
/**
* Returns the version of the native loaded library, or throws a
* runtime exception if the library is not loaded. This was
* introduced in MESOS 0.22.1. Any version prior to that will be
* 0.0.0. This means you should not make version specific decision
* before the 0.22.1 version boundary. For example, if you found a
* bug that was fixed in 0.19.0, you will *not* be able to perform
* the following check correctly:
*
* if (version().before(new Version(0, 19, 0))) {
* ...
* }
*
* This predicate will return true for all versions up until 0.22.1.
*/
public static synchronized Version version() {
// Since we allow 'load' to be called with a parameter, we can not load on
// behalf of the user here. Instead, we throw an exception if the library
// has not been loaded.
if (!loaded) {
throw new RuntimeException("'libmesos' not loaded");
}
if (version == null) {
// Try to load the libmesos version identifier. If we get an
// 'UnsatisfiedLinkError' then this means we are loading a 'libmesos' with
// a version prior to 0.22.1, which is when the 'MAJOR', 'MINOR', and
// 'PATCH' version identifiers were introduced.
try {
version = _version();
} catch (UnsatisfiedLinkError error) {
System.err.println(
"WARNING: using an old version of 'libmesos'" +
" without proper version information: " + error.getMessage());
// If we're using a version of 'libmesos' less than 0.22.1, then we set
// the version to 0.0.0.
version = new Version(0, 0, 0);
}
}
return version;
}
public static final String VERSION = "@PACKAGE_VERSION@";
private static Version version = null;
private static boolean loaded = false;
/**
* Native implementation of 'libmesos' version identifier function.
*/
private static native Version _version();
}