Dukascopy
 
 
Wiki JStore Search Login

Attention! Read the forum rules carefully before posting a topic.

    Try to find an answer in Wiki before asking a question.
    Submit programming questions in this forum only.
    Off topics are strictly forbidden.

Any topics which do not satisfy these rules will be deleted.

JNLP Class Loader Fix for long-running Java apps
 Post subject: JNLP Class Loader Fix for long-running Java apps Post rating: 2   New post Posted: Fri 01 Feb, 2013, 01:18 
User avatar

User rating: 98
Joined: Mon 23 Jul, 2012, 02:02
Posts: 656
Location: United States, Durham, NC
I had lots of class loader errors many months ago, and I got this fix from a guy.
Basically, it prevents certain classes from being unloaded which should NOT be unloaded.
Feel free to put this at the very startup of your main in your standalone apps.

The symptoms of the problem are class loader errors after a jnlp-launched Swing app has been
running for many many hours. It has to do with the "guts" of the Java runtime
and make sure that things which should NOT be garbage collected, are not
collected. Way over my head !!! But it works.

There's a reference in the code to the Java BUG which this workaround fixes. Feel free
to look at it, but it's easier just do run this routine on startup of your code.

If you deploy your complex apps using Java Web Start, then this may save you.
Just take it "on faith" -- it works.

HyperScalper

   // this class must NOT be garbage collected
   // and must be retained for lifetime of this app
   static JNLPClassLoaderFix jnlpFix = null;

   public static void main(String[] args) {

         /*
          * FIX to JNLP class loader BUG so that we can use runtimes
          * greater than Java 6 Update 17
          */
         
         try {
            jnlpFix = new JNLPClassLoaderFix();
            jnlpFix.fixIt();
         }
         catch(Exception e) {
            e.printStackTrace();
         }
   // ....... start up your app
        }
      




//package de.bauerkirch.tools.bktimer;
package com.twc.util;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.HashSet;
import java.util.Set;
import com.sun.deploy.cache.CachedJarFile;

// Requires deploy.jar

/**
 * Workaround https://bugs.sun.com/view_bug.do?bug_id=6967414
 * based on squaat's solution
 *
 * @author Henning Pautsch, Bauer+Kirch GmbH
 */
public class JNLPClassLoaderFix {

   private Set<Object> hardlinkedReferences = new HashSet<Object>();

   public boolean fixIt() {
      try {
         Class<?> clazz = Class.forName("com.sun.jnlp.JNLPClassLoader");
         Object jnlpLoader = clazz.getMethod("getInstance").invoke(null);
         if (jnlpLoader == null) {
            System.out.println("Not running in JNLP-Mode. Ignoring Fix");
            return false;
         }
         Object launchDesc = clazz.getMethod("getLaunchDesc").invoke(jnlpLoader);
         Object resources = launchDesc.getClass().getMethod("getResources").invoke(launchDesc);
         Object[] allJars = (Object[]) resources.getClass()
            .getMethod("getEagerOrAllJarDescs", new Class[] { boolean.class }).invoke(resources, true);
         for (Object jarDesc : allJars) {
            URL descLocation = (URL) jarDesc.getClass().getMethod("getLocation").invoke(jarDesc);
            Method getJarMethod;
            CachedJarFile jarFile = null;
            getJarMethod = jnlpLoader.getClass().getMethod("getJarFile", new Class[] { URL.class });
            getJarMethod.setAccessible(true);
            jarFile = (CachedJarFile) getJarMethod.invoke(jnlpLoader, descLocation);

            assert (jarFile != null);

            Object signersResult = invokePrivateMethod(jarFile, "getSigners");
            Object signerMapResult = invokePrivateMethod(jarFile, "getSignerMap");
            Object codeSourceCacheResult = invokePrivateMethod(jarFile, "getCodeSourceCache");
            hardlinkedReferences.add(signersResult);
            hardlinkedReferences.add(signerMapResult);
            hardlinkedReferences.add(codeSourceCacheResult);

            Object signersRef = getPrivateFieldData(jarFile, "signersRef");
            Object signersMapRef = getPrivateFieldData(jarFile, "signerMapRef");
            Object codeSourceCacheRef = getPrivateFieldData(jarFile, "codeSourceCacheRef");
            hardlinkedReferences.add(signersRef);
            hardlinkedReferences.add(signersMapRef);
            hardlinkedReferences.add(codeSourceCacheRef);
         }
      } catch (ClassNotFoundException e) {
         e.printStackTrace();
         return false;
      } catch (IllegalArgumentException e) {
         e.printStackTrace();
         return false;
      } catch (SecurityException e) {
         e.printStackTrace();
         return false;
      } catch (IllegalAccessException e) {
         e.printStackTrace();
         return false;
      } catch (InvocationTargetException e) {
         e.printStackTrace();
         return false;
      } catch (NoSuchMethodException e) {
         e.printStackTrace();
         return false;
      }
      return true;
   }

   private Object invokePrivateMethod(final Object object, final String methodName) {
      Object result = null;
      try {
         Method method = object.getClass().getDeclaredMethod(methodName);
         method.setAccessible(true);
         result = method.invoke(object);
      } catch (SecurityException e) {
         e.printStackTrace();
      } catch (NoSuchMethodException e) {
         e.printStackTrace();
      } catch (IllegalArgumentException e) {
         e.printStackTrace();
      } catch (IllegalAccessException e) {
         e.printStackTrace();
      } catch (InvocationTargetException e) {
         e.printStackTrace();
      }
      return result;
   }

   private Object getPrivateFieldData(final Object object, final String fieldName) {
      Object result = null;
      try {
         Field field = object.getClass().getDeclaredField(fieldName);
         field.setAccessible(true);
         result = field.get(object);
      } catch (SecurityException e) {
         e.printStackTrace();
      } catch (NoSuchFieldException e) {
         e.printStackTrace();
      } catch (IllegalArgumentException e) {
         e.printStackTrace();
      } catch (IllegalAccessException e) {
         e.printStackTrace();
      }
      return result;
   }

}



Attachments:
File comment: Here's the class file with original copyright notice from the author.
JNLPClassLoaderFix.java [3.97 KiB]
Downloaded 411 times
DISCLAIMER: Dukascopy Bank SA's waiver of responsability - Documents, data or information available on this webpage may be posted by third parties without Dukascopy Bank SA being obliged to make any control on their content. Anyone accessing this webpage and downloading or otherwise making use of any document, data or information found on this webpage shall do it on his/her own risks without any recourse against Dukascopy Bank SA in relation thereto or for any consequences arising to him/her or any third party from the use and/or reliance on any document, data or information found on this webpage.
 
 Post subject: Re: JNLP Class Loader Fix for long-running Java apps Post rating: 0   New post Posted: Fri 15 Feb, 2013, 18:31 
User avatar

User rating: 98
Joined: Mon 23 Jul, 2012, 02:02
Posts: 656
Location: United States, Durham, NC
Supporting link for this workaround:

https://forums.oracle.com/forums/thread.jspa?threadID=1303543


//package com.fs;

import java.io.IOException;
import java.lang.ref.SoftReference;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.jar.JarFile;
 
 
/**
 * A utility class for working around the java webstart jar signing/security bug
 *
 *https://forums.oracle.com/forums/thread.jspa?threadID=1303543
 *
 * see https://bugs.sun.com/view_bug.do?bug_id=6967414 and https://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6805618
 * @author Scott Chan
  */
public class JarSignersHardLinker {
   
    private static final String JRE_1_6_0 = "1.6.0_";
   
    /**
     * the 1.6.0 update where this problem first occurred
     */
    private static final int PROBLEM_JRE_UPDATE = 19;
   
    public static final List sm_hardRefs = new ArrayList();
   
    protected static void makeHardSignersRef(JarFile jar) throws java.io.IOException {
       
        System.out.println("Making hard refs for: " + jar );
       
        if(jar != null && jar.getClass().getName().equals("com.sun.deploy.cache.CachedJarFile")) {
 
           //lets attempt to get at the each of the soft links.
           //first neet to call the relevant no-arg method to ensure that the soft ref is populated
           //then we access the private member, resolve the softlink and throw it in a static list.
           
            callNoArgMethod("getSigners", jar);
            makeHardLink("signersRef", jar);
           
            callNoArgMethod("getSignerMap", jar);
            makeHardLink("signerMapRef", jar);
           
//            callNoArgMethod("getCodeSources", jar);
//            makeHardLink("codeSourcesRef", jar);
           
            callNoArgMethod("getCodeSourceCache", jar);
            makeHardLink("codeSourceCacheRef", jar);
        }           
    }
   
   
    /**
     * if the specified field for the given instance is a Softreference
     * That soft reference is resolved and the returned ref is stored in a static list,
     * making it a hard link that should never be garbage collected
     * @param fieldName
     * @param instance
     */
    private static void makeHardLink(String fieldName, Object instance) {
       
        System.out.println("attempting hard ref to " + instance.getClass().getName() + "." + fieldName);
       
        try {
            Field signersRef = instance.getClass().getDeclaredField(fieldName);
           
            signersRef.setAccessible(true);
           
            Object o = signersRef.get(instance);
           
            if(o instanceof SoftReference) {
                SoftReference r = (SoftReference) o;
                Object o2 = r.get();
                sm_hardRefs.add(o2);
            } else {
                System.out.println("noooo!");
            }
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
            return;
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
   
    /**
     * Call the given no-arg method on the given instance
     * @param methodName
     * @param instance
     */
    private static void callNoArgMethod(String methodName, Object instance) {
        System.out.println("calling noarg method hard ref to " + instance.getClass().getName() + "." + methodName + "()");
        try {
            Method m = instance.getClass().getDeclaredMethod(methodName);
            m.setAccessible(true);
           
            m.invoke(instance);
 
        } catch (SecurityException e1) {
            e1.printStackTrace();
        } catch (NoSuchMethodException e1) {
            e1.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }
 
   
    /**
     * is the preloader enabled. ie: will the preloader run in the current environment
     * @return
     */
    public static boolean isHardLinkerEnabled() {
       
       boolean isHardLinkerDisabled = false;  //change this to use whatever mechanism you use to enable or disable the preloader
       
        return !isHardLinkerDisabled && isRunningOnJre1_6_0_19OrHigher() && isRunningOnWebstart();
    }
   
    /**
     * is the application currently running on webstart
     *
     * detect the presence of a JNLPclassloader
     *
     * @return
     */
    public static boolean isRunningOnWebstart() {
        ClassLoader cl = Thread.currentThread().getContextClassLoader();
       
        while(cl != null) {
            if(cl.getClass().getName().equals("com.sun.jnlp.JNLPClassLoader")) {
                return true;
            }
            cl = cl.getParent();
        }
       
        return false;
 
    }
   
    /**
     * Is the JRE 1.6.0_19 or higher?
     * @return
     */
    public static boolean isRunningOnJre1_6_0_19OrHigher() {
        String javaVersion = System.getProperty("java.version");
       
        if(javaVersion.startsWith(JRE_1_6_0)) {
            //then lets figure out what update we are on
            String updateStr = javaVersion.substring(JRE_1_6_0.length());
           
            try {
                return Integer.parseInt(updateStr) >= PROBLEM_JRE_UPDATE;
            } catch (NumberFormatException e) {
                //then unable to determine updatedate level
                return false;
            }
        }
       
        //all other cases
        return false;
       
    }
   
   
   /**
    * get all the JarFile objects for all of the jars in the classpath
    * @return
    */
   public static Set<JarFile> getAllJarsFilesInClassPath() {
   
      Set<JarFile> jars = new LinkedHashSet<JarFile> ();
      
       for (URL url : getAllJarUrls()) {
           try {
               jars.add(getJarFile(url));
           } catch(IOException e) {
              System.out.println("unable to retrieve jar at URL: " + url);
           }
       }
      
       return jars;
   }
   
    /**
     * Returns set of URLS for the jars in the classpath.
     * URLS will have the protocol of jar eg: jar:https://HOST/PATH/JARNAME.jar!/META-INF/MANIFEST.MF
     */
    static Set<URL> getAllJarUrls() {
        try {
            Set<URL> urls = new LinkedHashSet<URL>();
            Enumeration<URL> mfUrls = Thread.currentThread().getContextClassLoader().getResources("META-INF/MANIFEST.MF");
            while(mfUrls.hasMoreElements()) {
                URL jarUrl = mfUrls.nextElement();
//                System.out.println(jarUrl);
                if(!jarUrl.getProtocol().equals("jar")) continue;
                urls.add(jarUrl);
            }
            return urls;
        } catch(IOException e) {
            throw new RuntimeException(e);
        }
    }
   
    /**
     * get the jarFile object for the given url
     * @param jarUrl
     * @return
     * @throws IOException
     */
    public static JarFile getJarFile(URL jarUrl) throws IOException {
        URLConnection urlConnnection = jarUrl.openConnection();
        if(urlConnnection instanceof JarURLConnection) {
            // Using a JarURLConnection will load the JAR from the cache when using Webstart 1.6
            // In Webstart 1.5, the URL will point to the cached JAR on the local filesystem
            JarURLConnection jcon = (JarURLConnection) urlConnnection;
            return jcon.getJarFile();
        } else {
            throw new AssertionError("Expected JarURLConnection");
        }
    }
   
   
    /**
     * Spawn a new thread to run through each jar in the classpath and create a hardlink
     * to the jars softly referenced signers infomation.
     */
    public static void go() {
        if(!isHardLinkerEnabled()) {
           System.out.println("HardLinker is not enabled.");
            return;
        }
       
        System.out.println("Starting Resource Preloader Hardlinker");
       
        Thread t = new Thread(new Runnable() {
 
            public void run() {
               
                try {
                    Set<JarFile> jars = getAllJarsFilesInClassPath();
                   
                    for (JarFile jar : jars) {
                        makeHardSignersRef(jar);
                    }
 
                } catch (Exception e) {
                    System.out.println("Problem preloading resources");
                    e.printStackTrace();
                } catch (Error e) {
                   System.out.println("Error preloading resources");
                   e.printStackTrace();
                }
            }
           
        });
       
        t.start();
       
    }
}



Attachments:
File comment: Another non-conflicting approach if you suspect this issue in your code.
JarSignersHardLinker.java [8.98 KiB]
Downloaded 409 times
DISCLAIMER: Dukascopy Bank SA's waiver of responsability - Documents, data or information available on this webpage may be posted by third parties without Dukascopy Bank SA being obliged to make any control on their content. Anyone accessing this webpage and downloading or otherwise making use of any document, data or information found on this webpage shall do it on his/her own risks without any recourse against Dukascopy Bank SA in relation thereto or for any consequences arising to him/her or any third party from the use and/or reliance on any document, data or information found on this webpage.
 
 Post subject: Re: JNLP Class Loader Fix for long-running Java apps Post rating: 0   New post Posted: Fri 15 Feb, 2013, 19:00 
User avatar

User rating: 98
Joined: Mon 23 Jul, 2012, 02:02
Posts: 656
Location: United States, Durham, NC
This article discusses the possibility that the issue may continue to exist for Java 7.

Again, this is for Java Web Start applications.

https://stackoverflow.com/questions/10905790/java-7u4-webstart-security-exception-class-does-not-match-trust-level


 

Jump to:  

  © 1998-2025 Dukascopy® Bank SA
On-line Currency forex trading with Swiss Forex Broker - ECN Forex Brokerage,
Managed Forex Accounts, introducing forex brokers, Currency Forex Data Feed and News
Currency Forex Trading Platform provided on-line by Dukascopy.com