Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-5080151

(cs) 1.4.2_0X: IllegalStateException: recursive invocation on non-english locales

XMLWordPrintable

    • sparc
    • solaris_9



      Name: rv122619 Date: 07/29/2004

      When we replace the System classloader without our own using the approved java.lang.class.loader method the VM fails to start. This is caused by the UnixFileSystem.list method constructing a String. The String construction is failing trying to find the system charset before the SystemClassloader is finished being constructed. This happens on most non-english locales. Specificly JA. This happens on Solaris as well as Linux. I have not been able to try this on Windows.
      Included are 3 source files and a config file. compile and run with the following script:
      echo "compiling"
      javac loader/src/com/jim/*.java
      jar cf loader.jar -C loader/src .

      mv loader.jar loader/dist

      /bigdisk/suwall/jdk1.5.0/bin/javac -source 1.4 test.java
      /bigdisk/suwall/jdk1.5.0/bin/jar cf test.jar *.class
      export LC_ALL=ja
      locale
      echo ""
      for x in /usr/j2re1.4.1_02/bin
      do
      ${x}/java -version
      ${x}/java -debug -cp "loader/dist/loader.jar" -Dsas.app.class.dirs="." -Djava.system.class.loader=com.jim.AppClassLoader test
      =com/jim/AppClassLoader.java========================================
      package com.jim;
      import java.io.IOException;
      import java.io.File;
      import java.net.URL;
      import java.net.MalformedURLException;
      import java.net.URLStreamHandler;
      import java.util.Vector;
      import java.net.URLStreamHandlerFactory;
      import java.util.StringTokenizer;
      import sun.net.www.ParseUtil;

      public class AppClassLoader
      extends java.net.URLClassLoader
      {

      /**
      * The AppClassLoader is the start of the SAS Application level classloaders.
      * This classloader defines the location for the classes used by the application.
      * The system property "sas.app.class.dirs" points to a set of directories that will
      * be scanned for jar files. This acts much like the extensions classloader. The property
      * sas.app.class.path points to a list of classes or jars that actually define the application.
      * This acts much like the classpath and are prepended to the list of jars found using the
      * "sas.app.class.dirs" property.
      */

      public AppClassLoader(ClassLoader parent)
      {
      super(getFileURLs("sas.app.class.dirs", "sas.app.class.path"), new ExtClassLoader(parent)); //$NON-NLS-1$ //$NON-NLS-2$
      }

      /**
      * scans the System property for directories. Each directory is scanned for files.
      * Each file is then returned as an URL. This has the effect of added every jar and
      * zip in each directory to the list. This has the side effect of adding and sub-directory
      * as a directory of classes to the list.
      */

          private static URL[] getFileURLs(String jarProperty, String pathProperty)
      {
      // create an array of path names from the webaf.class.path property
      File[] dirs = getDirs(jarProperty);
      File[] path = getPath(pathProperty);
      // translate these pathnames in URLs
      Vector urls = new Vector();
      int i;
      // first do the path if it exists
      for(i=0;i<path.length;++i)
      {
      if (path[i] != null)
      urls.add(getFileURL(path[i]));
      }

      // next do the jar directories
      for (i = 0; i < dirs.length; i++)
      {
      String[] files = dirs[i].list();
      if (files != null)
      {
      for (int j = 0; j < files.length; j++)
      {
      File f = new File(dirs[i], files[j]);
      urls.add(getFileURL(f));
      }
      }
      }
      URL[] ua = new URL[urls.size()];
      urls.copyInto(ua);
      return ua;
      }

      /**
      * scans the System property for a list of directories.
      */

      private static File[] getDirs(String property)
      {
      String s = System.getProperty(property);
      File[] dirs;
      if (s != null)
      {
      StringTokenizer st =
      new StringTokenizer(s, File.pathSeparator);
      int count = st.countTokens();
      dirs = new File[count];
      for (int i = 0; i < count; i++)
      {
      dirs[i] = new File(st.nextToken());
      }
      }
      else
      {
      dirs = new File[0];
      }
      return dirs;
      }

      /**
      * scans the System property for a list of files.
      */

      private static File[] getPath(String property)
      {
      String s = System.getProperty(property);
      File[] dirs;
      if (s != null)
      {
      StringTokenizer st =
      new StringTokenizer(s, File.pathSeparator);
      int count = st.countTokens();
      dirs = new File[count];
      for (int i = 0; i < count; i++)
      {
      dirs[i] = new File(st.nextToken());
      }
      }
      else
      {
      dirs = new File[0];
      }
      return dirs;
      }

      /**
      * Translated the passed in File into an URL. Handles spaces in file names.
      * @param file The File to be translated into an URL
      * @return URL The file location translated into an URL
      */
          private static URL getFileURL(File file)
      {
      try
      {
        file = file.getCanonicalFile();
      }
      catch (IOException e) {}

              try
      {
                  return ParseUtil.fileToEncodedURL(file);
              }
      catch (MalformedURLException e)
      {
      // Should never happen since we specify the protocol...
      throw new InternalError();
      }
          }


      /**
      * Appends the specified URL to the list of URLs to search for classes and resources.
      *
      * @param url the URL to be added to the search path of URLs
      **/
      public void add(URL u)
      {
      addURL(u);
      }
      }
      =com/jim/ExtClassLoader.java===================================================
      package com.jim;
      import java.io.IOException;
      import java.io.File;
      import java.net.URL;
      import java.net.MalformedURLException;
      import java.net.URLStreamHandler;
      import java.util.Vector;
      import java.net.URLStreamHandlerFactory;
      import java.io.FileInputStream;
      import java.io.BufferedReader;
      import java.io.FileReader;
      import java.io.InputStream;
      import java.io.FileNotFoundException;
      import java.text.MessageFormat;
      import java.util.ResourceBundle;
      import java.util.Locale;


      public class ExtClassLoader
      extends java.net.URLClassLoader
      {

      /*
      * The ExtClassLoader scans the normal extensions classloader
      * for a known set of URLs. These URLs are identified from the contents
      * of a config file. The default config is com.sas.app.JavaEXTs.config.
      * an alternate file will be used if it is speicified in the System property
      * "sas.java.config"
      */
      public ExtClassLoader(ClassLoader parent)
      {
      super(getFilteredURLs(parent), null); // skip the extensions classloader
      }

      /**
      * getFileredURLs scans the extensions classloader for its known URLs and only uses
      * a subset as defined by the contents of JavaEXTs.config. The config file is a list of jar
      * names. Absolute names are not used. Each URL is scanned to determine if it points to
      * a jar named in the config file. Any matches are selected and returned by this method.
      * All jar names must be complete names. Fragments will not match.
      */

      private static URL[] getFilteredURLs(ClassLoader parent)
      {
      ClassLoaderUtil clu = new ClassLoaderUtil();
      Vector v = new Vector();
      int num = 0;
      // read the config file. This handles finding the config via the System Property
      // first then looking near the class.
      String configLocation=null;
      try
      {
      configLocation = System.getProperty("sas.ext.config"); //$NON-NLS-1$
      InputStream in=null;
      if (configLocation != null)
      {
      in=new FileInputStream(configLocation);
      }
      else
      {
      configLocation=clu.getConfigName();
      in = clu.getConfig();

      //if the input stream is null, then throw a FileNotFoundException like the user-specified
      //config strategy will throw and catch below to print out message.
      if (in==null)
      throw new FileNotFoundException();
      }

      BufferedReader br=new BufferedReader(new java.io.InputStreamReader(in, "ISO_8859-1:1987"));

      boolean done = false;
      while(!done)
      {
      String line = br.readLine();
      if (line == null)
      done = true;
      else
      {
      v.addElement(line);
      ++num;
      }
      }
      br.close();
      }
      catch(FileNotFoundException e1)
      {
      //I'm having to do the ResourceBundle work manually since the Launcher jar shouldn't depend on any other jars.
      ResourceBundle resourceBundle=ResourceBundle.getBundle("com.sas.app.Resources", //$NON-NLS-1$
                                                               Locale.getDefault(),
                                                               ExtClassLoader.class.getClassLoader());
      MessageFormat format=new MessageFormat(resourceBundle.getString("ExtClassLoader.ConfigLocationError.txt")); //$NON-NLS-1$
      Object[] messageArgs=new Object[1];
      messageArgs[0]=configLocation;
      System.err.println(format.format(messageArgs));
      }
      catch(IOException e2)
      {
      e2.printStackTrace();
      }

      // grab the urls from the extensions classloader and see which ones match the jars from the
      // list in the config file. We prepend a slash to the jar name so we don't match partials.
      String[] filter = (String[])v.toArray(new String[num]);
      ClassLoader loader = parent.getParent(); // hope this is the extensions classloader
      if (loader instanceof java.net.URLClassLoader)
      {
      URL[] u = ((java.net.URLClassLoader)loader).getURLs();
      v.removeAllElements();
      int i;
      for(i=0;i<u.length;++i)
      {
      int j;
      for(j=0;j<filter.length;++j)
      {
      if (u[i].getFile().endsWith("/"+filter[j])) //$NON-NLS-1$
      v.addElement(u[i]);
      }
      }
      return (URL[])v.toArray(new URL[0]);
      }
      return null;
      }


      }


      /**
       * ClassLoaderUtil is here only to load the config file as a resource. This allows the config to
       * reside inside the jar file.
       */
      class ClassLoaderUtil
      {
      public ClassLoaderUtil()
      {
      }
      public String getConfigName()
      {
      return "JavaEXTs.config"; //$NON-NLS-1$
      }
      public InputStream getConfig()
      {
      return getClass().getResourceAsStream(getConfigName());
      }
      }

      =com/jim/JavaEXTs.config========================================
      dnsns.jar
      ldapsec.jar
      localedata.jar
      sunjce_provider.jar
      =test.java==================================================


      public class test
      {
      public static void main(String[] args)
      {
      System.getProperties().list(System.out);
      System.out.println("test");
      System.exit(0);
      }
      }

      ======================================================================

            iris Iris Clark
            rverabel Raghu Verabelli (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: