#708 Ease eclipse integration; prevent JSTAF UnsatisfiedLinkError

open
Lang::Java (16)
5
2012-02-14
2012-02-14
No

When using JSTAF in eclipse (particularly on Mac OS X) new users get an unsatisfied link error due to Eclipse not picking up the DYLD_LIBRARY_PATH env variable. Can you add a search for the default install paths when this error occurs? It will remove a barrier for adoption for new users...

Thanks,
George C-S

Discussion

  • Sharon Lucas

    Sharon Lucas - 2012-02-14
    • assigned_to: nobody --> slucas
    • summary: Update to ease eclipse integration... --> Ease eclipse integration; prevent JSTAF UnsatisfiedLinkError
     
  • Sharon Lucas

    Sharon Lucas - 2012-02-14

    George was getting the following error when running a Java program that submitted STAF service requests within Eclipse on Mac OS X:

    Exception in thread "main" java.lang.UnsatisfiedLinkError: no JSTAF in java.library.path
    at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1758)
    at java.lang.Runtime.loadLibrary0(Runtime.java:823)
    at java.lang.System.loadLibrary(System.java:1045)
    at com.ibm.staf.STAFHandle.<clinit>(STAFHandle.java:122)
    at com.ibm.automation.core.util.STAFClient.getSTAFHandle(STAFClient.java:23)
    at com.ibm.automation.core.util.STAFClient.submitRequest(STAFClient.java:77)
    at com.ibm.automation.core.util.STAFClient.<clinit>(STAFClient.java:15)

    Even though he had the DYLD_LIBRARY_PATH pointing to the STAF lib directory:

    $ echo $DYLD_LIBRARY_PATH
    /Library/staf/lib:/Library/staf/lib:

    Eclipse did not retain that environment variable. This exception was thrown when the STAFHandle Java class tried to load the JSTAF library (e.g. /usr/local/staf/lib/libJSTAF.dylib) which is needed because it uses JNI to access STAF C++ APIs to register the STAF handle.

    A workaround for this in Eclipse is to open its Properties, go to "Run/Debug Settings", edit its "Launch configuration", and on the "Environment" tab, add environment variable "DYLD_LIBRARY_PATH" and set it to "/Library/staf/lib".

    However, George did not feel this workaround was an easily usable solution to roll out across a team, so he opened this feature request.

     
  • Sharon Lucas

    Sharon Lucas - 2012-03-22

    Tried several things to try to find the STAF libraries when not in the library path, but so far nothing has worked.

    I tried the following two ways to try to prevent this problem, but I'm still getting an error when loading the JSTAF library because it causes the STAF library to be loaded under the covers and it doesn't find it.

    1) Added code to determine the path that contains the JSTAF.jar file and used this to determine the path to the STAF library files (e.g. libSTAF.so, libJSTAF.so, libJSTAFSH.so, etc). Then, added a try/catch around:

    System.loadLibrary(libraryShortName);

    so that if it fails with an UnsatisfiedLinkError on Unix systems to load the specified STAF library (e.g. because java.library.path does not contaoin the STAF/JSTAF libraries), I retried loading the library using its absolute path as follows:

    System.load(libraryFullName);

    But that still didn't resolve the problem. Here's the what I tried:

    // Determine the path that contains the JSTAF.jar as we'll use
    // this to determine the path to the STAF library files (e.g.
    // libSTAF.so, libJSTAF.so, libJSTAFSH.so, etc)
    // Returns the path that contains the JSTAF.jar file (e.g.
    // /usr/local/staf/lib) or null if could not determine the path
    // for the JSTAF.jar file
    private static String getJSTAFJarPath()
    {
    String jarPath = null;
    File jarFile = null;

    try
    {
    jarFile = new File(
    STAFHandle.class.getProtectionDomain().getCodeSource().
    getLocation().toURI().getPath());
    }
    catch (java.net.URISyntaxException e)
    {
    System.out.println("URISyntaxException: " + e);
    return null;
    }

    // When using ANT, this returns the path to the ant.jar file
    // instead of to the JSTAF.jar file location. So, verify
    // that the jar name contains JSTAF.

    if (jarFile.toString().indexOf("JSTAF") == -1)
    {
    System.out.println(
    jarFile.toString() + " does not contain JSTAF");
    return null;
    }

    jarPath = jarFile.getParentFile().getPath();

    System.out.println("JSTAF.jar Path=" + jarPath);

    return jarPath;
    }

    private static void loadLibrary(String libraryShortName, String osName)
    throws UnsatisfiedLinkError
    {
    try
    {
    System.loadLibrary(libraryShortName);
    }
    catch (UnsatisfiedLinkError ule)
    {
    // On Unix systems, in case java.library.path does not contain the
    // STAF/JSTAF libraries, retry using System.load which requires
    // specifying the fully-qualified path to the library file.

    if (osName.indexOf("windows") == 0)
    {
    // Don't need to re-try on Windows as it doesn't set
    // LD_LIBRARY_PATH, LIBPATH, or DYLD_LIBRARY_PATH, so just
    // throw the original UnsatisfiedLinkError
    throw ule;
    }

    // Determine the path that contains the JSTAF.jar as we'll use
    // this to determine the path to the JSTAF library file (e.g.
    // libSTAF.so, libSTAF.dylib, etc)

    if (sLibraryPath == null)
    {
    sLibraryPath = getJSTAFJarPath();

    if (sLibraryPath == null)
    {
    // Throw the original UnsatisfiedLinkError
    throw ule;
    }
    }

    // Library extension for most Unix systems (e.g. Linux, AIX,
    // Solaris, HP-UX IA64, zLinux, FreeBSD, z/OS)
    String libraryExt = "so";

    if (osName.indexOf("mac os x") == 0)
    {
    // Mac OS X systems
    // XXX: .dylib or .jnilib ?
    libraryExt = "dylib";
    }
    else if ((osName.indexOf("hp-ux") == 0) &&
    (System.getProperty("os.arch").equals("IA64")))
    {
    // HP-UX IA64 systems
    libraryExt = "sl";
    }

    String libraryFullName = sLibraryPath + "/lib" +
    libraryShortName + "." + libraryExt;
    System.out.println("Library name=" + libraryFullName);

    File libraryFile = new File(libraryFullName);

    if (!libraryFile.exists())
    {
    System.out.println(libraryFullName + " does not exist");

    // Throw the original UnsatisfiedLinkError
    throw ule;
    }

    // Re-try loading the library using its absolute library
    // file name (in case the LD_LIBRARY_PATH / LIBPATH /
    // DYLD_LIBRARY_PATH environment variable was not set to the
    // STAF lib directory).

    try
    {
    System.out.println("Retry using System.load(" +
    libraryFullName + ")");
    System.load(libraryFullName);
    }
    catch (UnsatisfiedLinkError e)
    {
    //System.out.println("UnsatisfiedLinkError: " + e);
    // Throw the original UnsatisfiedLinkError
    // XXX: throw ule;
    throw e;
    }
    }
    }

    // Static initializer - called first time class is loaded.
    static
    {
    String osName = System.getProperty("os.name").toLowerCase();

    if ((osName.indexOf("aix") == 0) ||
    (osName.indexOf("linux") == 0) ||
    ((osName.indexOf("sunos") == 0) &&
    (System.getProperty("os.arch").equals("sparc"))))
    {
    loadLibrary("STAF", osName);
    System.out.println("Loaded STAF library");
    }

    loadLibrary("JSTAF", osName);
    System.out.println("Loaded JSTAF library");

    initialize();
    }

    2) Determined the path to the STAF libraries and used a trick to add the STAF libraries to the java.library.path (which would only work anyway for certain Java implementations) but that didn't resolve the problem.

    public static void addLibraryPath(String pathToAdd) throws Exception
    {
    Field usrPathsField = ClassLoader.class.getDeclaredField("sys_paths");
    usrPathsField.setAccessible(true);

    // Get array of paths
    String[] pathArray = (String[])usrPathsField.get(null);

    // Check if the path to add is already present
    // XXX: for (String path : pathArray)
    for (int i = 0; i < pathArray.length; i++)
    {
    String path = pathArray[i];

    if (path.equals(pathToAdd))
    {
    return;
    }
    }

    // Add the new path

    String[] newPathArray = new String[pathArray.length + 1];
    System.arraycopy(pathArray, 0, newPathArray, 0, pathArray.length);
    newPathArray[pathArray.length] = pathToAdd;
    usrPathsField.set(null, newPathArray);

    String pathString = "";

    for (int i = 0; i < newPathArray.length; i++)
    {
    pathString += newPathArray[i] + File.pathSeparator;
    }

    System.out.println(pathString);

    // XXX

    System.setProperty("java.library.path", pathString);
    //set sys_paths to null
    final Field sysPathsField = ClassLoader.class.getDeclaredField(
    "sys_paths");
    sysPathsField.setAccessible(true);
    sysPathsField.set(null, null);

    System.out.println("java.library.path=" +
    System.getProperty("java.library.path"));
    }

    // Static initializer - called first time class is loaded.
    static
    {
    // Trick to set "java.library.path" program

    sLibraryPath = getJSTAFJarPath();

    if (sLibraryPath != null)
    {
    try
    {
    addLibraryPath(sLibraryPath);
    }
    catch (java.lang.Exception e)
    {
    // XXX: Ignore as should never happen
    System.out.println("Cannot add to library path: " +
    e.toString());
    }
    }

    // Load STAF and JSTAF libraries as needed and then initialize

    if ((System.getProperty("os.name").toLowerCase().indexOf("aix") == 0) ||
    (System.getProperty("os.name").toLowerCase().indexOf("linux") == 0) ||
    ((System.getProperty("os.name").toLowerCase().indexOf("sunos") == 0)
    && (System.getProperty("os.arch").equals("sparc"))))
    {
    System.out.println("Loading STAF library...");
    System.loadLibrary("STAF");
    }

    System.out.println("Loading JSTAF library...");
    System.loadLibrary("JSTAF");
    initialize();
    }

    Attached a file containing this code.

     
  • Sharon Lucas

    Sharon Lucas - 2012-03-22

    Also, STAFUtil.java loads STAF libraries too so tried making the same changes in it as well, but so far nothing has worked. Attached the updated STAFUtil.java file as well.

     
  • Sharon Lucas

    Sharon Lucas - 2012-03-22

    Also, lang/java/service/STAFServiceHelper.java tries to load STAF libraries so made similar changes, but so far nothing has worked.

     
  • Sharon Lucas

    Sharon Lucas - 2012-03-22

    Note: Attaching the files failed because SourceForge does not allow me to attach files to a Feature Request that I did not open.

     

Get latest updates about Open Source Projects, Conferences and News.

Sign up for the SourceForge newsletter:





No, thanks