United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
JDK-4788410 : Cannot set preferences factory in web start

Details
Type:
Bug
Submit Date:
2002-12-04
Status:
Closed
Updated Date:
2004-03-16
Project Name:
JDK
Resolved Date:
2003-09-15
Component:
core-libs
OS:
solaris_8,windows_xp,windows_2000
Sub-Component:
java.util
CPU:
x86,sparc
Priority:
P4
Resolution:
Fixed
Affected Versions:
1.2.0,1.4.0,1.4.2,5.0
Fixed Versions:
1.4.2_02 (02)

Related Reports
Backport:
Duplicate:
Duplicate:
Duplicate:
Duplicate:

Sub Tasks

Description
Name: nt126004			Date: 12/04/2002


FULL PRODUCT VERSION :
java version "1.4.0"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.0-b92)
Java HotSpot(TM) Client VM (build 1.4.0-b92, mixed mode)


FULL OPERATING SYSTEM VERSION :
Microsoft Windows 2000 [Version 5.00.2195]


A DESCRIPTION OF THE PROBLEM :
The "java.util.prefs.PreferencesFactory" property isn't
conveyed to the Preferences class to create your own
preferences in web start.  This is especially a problem
considering bug #4772228. This works fine when running with
regular Java.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1.Compile the included source code.
2.run "java -
Djava.util.prefs.PreferencesFactory=XMLPreferencesFactory
Test"
3.You will see a userprefs.xml file in your home directory
that holds some "Experimental Node".
4.jar the classes into a jar file called TestPrefs.jar.
5.Sign the jar.
6.Edit the supplied test.jnlp file to match your web
environment.
7.When you run it, you will notice that the XMLPreferences
doesn't print and preference are saved to you registry.

EXPECTED VERSUS ACTUAL BEHAVIOR :
Under web start it is expected to act as it did under
regular java by saving to the userprefs.xml file.  However
it saves to the registry instead, which is the default
behavior.



ERROR MESSAGES THAT APPEAR :
java.lang.InternalError: Can't instantiate Preferences factory java.lang.ClassNo
tFoundException: XMLPreferencesFactory
        at java.util.prefs.Preferences.<clinit>(Preferences.java:194)
        at sun.awt.im.ExecutableInputMethodManager$2.run(InputMethodManager.java
:785)
        at java.security.AccessController.doPrivileged(Native Method)
        at sun.awt.im.ExecutableInputMethodManager.getUserRoot(InputMethodManage
r.java:783)
        at sun.awt.im.ExecutableInputMethodManager.<init>(InputMethodManager.jav
a:274)
        at sun.awt.im.InputMethodManager.getInstance(InputMethodManager.java:138
)
        at sun.awt.motif.MWindowPeer.init(MWindowPeer.java:92)
        at sun.awt.motif.MFramePeer.<init>(MFramePeer.java:58)
        at sun.awt.motif.MToolkit.createFrame(MToolkit.java:192)
        at java.awt.Frame.addNotify(Frame.java:469)
        at java.awt.Window.pack(Window.java:413)
        at com.sun.javaws.ui.console.Console.show(Console.java:180)
        at com.sun.javaws.Launcher.continueLaunch(Launcher.java:590)
        at com.sun.javaws.Launcher.handleApplicationDesc(Launcher.java:352)
        at com.sun.javaws.Launcher.handleLaunchFile(Launcher.java:177)
        at com.sun.javaws.Launcher.run(Launcher.java:145)
        at java.lang.Thread.run(Thread.java:536)


REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
1) XMLPreferences.java
import java.io.* ;
import java.util.* ;
import java.util.prefs.* ;
import java.util.logging.* ;
/**
* XML file implementation of the preferences API.<p>
* For safety reasons, everything is synchronized across all instances of
* <code>XMLPreferences</code>.  That way nobody can change something in
* the middle of writing to or reading from the file.
*/
public class XMLPreferences
extends AbstractPreferences
{
    /** all methods sync on this */
    private File file ;
    private boolean dirty ;
    private XMLPreferences parent ;
    private String nodeName ;
    private Map entries ;
    private Map children ;

    public XMLPreferences( XMLPreferences parent, String name, File file )
    {
        super( parent, name ) ;
        this.file = file ;
        dirty = false ;
        this.parent = parent ;
        nodeName = name ;
        entries = new HashMap( ) ;
        children = new HashMap( ) ;
    }

    protected void putSpi( String key, String value )
    {
        synchronized( lock )
        {
        System.out.println( "putting in the key/value pair of " + key + "/" +
value + " in preferences node " + nodeName ) ;
        String oldValue = ( String )entries.get(key ) ;
        if ( !value.equals(oldValue ) ) {
            entries.put( key, value ) ;
            setDirty( true ) ;
        }
        }
    }

    protected String getSpi( String key )
    {
        synchronized( lock )
        {
	        return ( String )entries.get(key ) ;
        }
    }

    protected void removeSpi( String key )
    {
        synchronized( lock )
        {
        System.out.println( "removing the key " + key + " from preferences
node " + nodeName ) ;
        if ( entries.get(key ) != null ) {
            entries.remove( key ) ;
            setDirty( true ) ;
        }
        }
    }

    protected void removeNodeSpi( )
    throws BackingStoreException
    {
        synchronized( lock )
        {
        System.out.println( "removing the node " + nodeName ) ;
        if ( parent != null ) {
            parent.children.remove( nodeName ) ;
            parent.setDirty( true ) ;
        }
        }
    }

    protected String[] keysSpi( )
    throws BackingStoreException
    {
        synchronized( lock )
        {
        String[] result = new String[entries.size( )] ;
        return ( String[] )entries.keySet( ).toArray(result ) ;
        }
    }

    protected String[] childrenNamesSpi( )
    throws BackingStoreException
    {
        synchronized( lock )
        {
        String[] result = new String[children.size( )] ;
        return ( String[] )children.keySet( ).toArray(result ) ;
        }
    }

    protected AbstractPreferences childSpi( String name )
    {
        synchronized( lock )
        {
        XMLPreferences child = ( XMLPreferences )children.get(name ) ;
        if ( child == null ) {
            child = new XMLPreferences( this, name, file ) ;
            children.put( name, child ) ;
            setDirty( true ) ;
        }
        return child ;
        }
    }

    public void sync( )
    throws BackingStoreException
    {
        synchronized( lock )
        {
        System.out.println( "syncing the node " + nodeName ) ;
        try {
            if ( isDirty( ) ) {
                XMLPreferences root = this ;
                while ( root.parent != null )
                    root = root.parent ;
                FileOutputStream out = new FileOutputStream( file ) ;
                root.exportSubtree( new BufferedOutputStream(out ) ) ;
                root.dirty = false ;
                out.close( ) ;
            }
        }
        catch ( Exception e ) {
            throw new BackingStoreException( e ) ;
        }
        }
    }

    /** Syncs the whole tree */
    protected void syncSpi( )
    throws BackingStoreException
    {
        synchronized( lock )
        {
        sync( ) ;
        }
    }

    public void flush( )
    throws BackingStoreException
    {
        synchronized( lock )
        {
        System.out.println( "flushing the node " + nodeName ) ;
        sync( ) ;
        }
    }

    /** Syncs/flushes the whole tree */
    protected void flushSpi( )
    throws BackingStoreException
    {
        synchronized( lock )
        {
        flush( ) ;
        }
    }

    protected void setDirty( boolean dirty )
    {
        synchronized( lock )
        {
        XMLPreferences root = this ;
        while ( root.parent != null )
            root = root.parent ;
        root.dirty = dirty ;
        }
    }

    protected boolean isDirty( )
    {
        synchronized( lock )
        {
        XMLPreferences root = this ;
        while ( root.parent != null )
            root = root.parent ;
        return root.dirty ;
        }
    }
}

2) XMLPreferencesFactory.java
import java.io.* ;
import java.util.* ;
import java.util.prefs.* ;

/**
* Don't forget to set System's <code>java.util.prefs.PreferencesFactory</code>.
*/
public class XMLPreferencesFactory
implements PreferencesFactory
{
    private File systemFile ;
    private File userFile ;
    private Preferences systemPref ;
    private Preferences userPref ;
    private boolean systemInit ;
    private boolean userInit ;

    public XMLPreferencesFactory( )
    {
        String homeDir = System.getProperty( "user.home", "." ) ;
        systemFile = new File( homeDir, "syspref.xml" ) ; // make these system
properties
        userFile = new File( homeDir, "userpref.xml" ) ;
        systemPref = new XMLPreferences( null, "", systemFile ) ;
        userPref = new XMLPreferences( null, "", userFile ) ;
        systemInit = false ;
        userInit = false ;
        System.out.println( "loading user preferencs from " + userFile + " and
system preferences from " + systemFile ) ;
    }

    public Preferences systemRoot( )
    {
        if ( !systemInit ) {
            System.out.println( "Loading system preferences" ) ;
            systemInit = true ;
            try {
                InputStream in = new FileInputStream( systemFile ) ;
                Preferences.importPreferences( in ) ;
                in.close( ) ;
            }
            catch ( Exception e ) {
            }
            // register shutdown hook - alway sync at system exit
            Runtime.getRuntime( ).addShutdownHook( new Thread( ) {
                public void run( )
                {
                    System.out.println( "Saving system preferences during
shutdown" ) ;
                    try {
                        systemPref.sync( ) ;
                    } catch( BackingStoreException ex ) {
                        System.err.println( "Couldn't sync the system
preferences at shutdown" ) ;
                    }
                }
            } ) ;
        }
        return systemPref ;
    }

    public Preferences userRoot( )
    {
        if ( !userInit ) {
            userInit = true ;
            System.out.println( "Loading user preferences" ) ;
            try {
                InputStream in = new FileInputStream( userFile ) ;
                Preferences.importPreferences( in ) ;
                in.close( ) ;
            }
            catch ( Exception e ) {
            }
            // register shutdown hook - alway sync at system exit
            Runtime.getRuntime( ).addShutdownHook( new Thread( ) {
                public void run( )
                {
                    System.out.println( "Saving user preferences during
shutdown" ) ;
                    try {
                        userPref.sync( ) ;
                    } catch( BackingStoreException ex ) {
                        System.err.println( "Couldn't sync the user preferences
at shutdown" ) ;
                    }
                }
            } ) ;
        }
        return userPref ;
    }
}

3) Test.java
import java.util.prefs.* ;

public class Test
{
	public static void main( String[] args )
	{
		System.out.println( "Starting the preferences test..." ) ;
		System.err.println( "You should see XMLPreferences stuff being
printed." ) ;
		new Test( ) ;
	}

	public Test( )
	{
		Preferences exNode = Preferences.userRoot( ).node
( "Experimental Node" ) ;
		exNode.put( "key", "value" ) ;
		try {
			exNode.sync( ) ;
		} catch( BackingStoreException ex ) {
			ex.printStackTrace( ) ;
		}
	}
}

4) test.jnlp
<?xml version="1.0" encoding="utf-8"?>

<jnlp spec="1.0+" codebase="http://cartman/~dlipton" href="test.jnlp">
   <information>
      <title>Preferences Test</title>
      <vendor>Random Walk Computing, Inc.</vendor>
      <description>Tests Preferences Bug</description>
   </information>

   <security>
      <all-permissions />
   </security>

   <resources>
      <property name="java.util.prefs.PreferencesFactory"
value="XMLPreferencesFactory"/>
      <j2se href="http://java.sun.com/products/autodl/j2se" version="1.4*" />
      <jar href="TestPrefs.jar" />
   </resources>

   <application-desc main-class="Test" />
</jnlp>
---------- END SOURCE ----------

CUSTOMER WORKAROUND :
THERE IS NO WORKAROUND!!!
(Review ID: 178636) 
======================================================================

                                    

Comments
SUGGESTED FIX

use Thread.currentThread().getContextClassLoader() instead of ClassLoader.getSystemClassLoader() in the static block of java.util.prefs.Preferences.java


###@###.### 2002-12-05
                                     
2002-12-05
EVALUATION

This is due to java.util.prefs.Preferences.java

in the static block, it uses:

 try {
            factory = (PreferencesFactory)
               Class.forName(factoryName, false,
                             ClassLoader.getSystemClassLoader()).newInstance();
        }catch(Exception e) {
            throw new InternalError(
                "Can't instantiate Preferences factory " + e);
        }

getSystemClassLoader will not return JNLPClassLoader, which is required to load the user defined preferences directory class in the jar specified in the jnlp file.

It should probably use Thread.currentThread().getContextClassLoader() instead, which will return the JNLPClassLoader.


###@###.### 2002-12-04

As I understand it, preferences is using the correct method to get the classLoader: the entire VM should be using a single preferences implementation, independent of the calling thread.

My knowledge of web start is weak, but I suspect that this problem will affect many provider frameworks in addition to prefs.

###@###.### 2003-01-14
                                     
2003-01-14
CONVERTED DATA

BugTraq+ Release Management Values

COMMIT TO FIX:
1.4.2_02
tiger-beta
tiger-beta2

FIXED IN:
1.4.2_02
tiger-beta2

INTEGRATED IN:
1.4.2_02
tiger-b43
tiger-beta2

VERIFIED IN:
1.4.2_02


                                     
2004-06-14



Hardware and Software, Engineered to Work Together