United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
Bug ID: JDK-6515728 JNLP client not following spec for extension uninstaller
JDK-6515728 : JNLP client not following spec for extension uninstaller

Details
Type:
Bug
Submit Date:
2007-01-22
Status:
Closed
Updated Date:
2011-05-18
Project Name:
JDK
Resolved Date:
2011-05-18
Component:
deploy
OS:
windows_xp,windows_2000
Sub-Component:
webstart
CPU:
x86
Priority:
P3
Resolution:
Fixed
Affected Versions:
6
Fixed Versions:

Related Reports
Backport:
Backport:
Duplicate:

Sub Tasks

Description
FULL PRODUCT VERSION :
jre 1.5.0_10-b03, jre 1.6.0-b105

ADDITIONAL OS VERSION INFORMATION :
windows 2000
linux

A DESCRIPTION OF THE PROBLEM :
Per jnlp spec1_5 and spec6_0 section 5.2.3 Launching an Extension installer/uninstaller the jnlp client should "For uninstallation, the JNLP Client must invoke the public static void main(String[]) method in the specified class with the String array {"uninstall"} as an argument."
It does not call the main method at all on uninstall. It should be noted that during install it does call the method with {"install"}. Just never gets called on the uninstall. I have tried calling the uninstall from command line "javaws -uninstall ...",   from the windows add/remove programs, and from java control panel remove application area. I have tried with java 1.5 and java 1.6.  This makes it impossible to fully uninstall a webstart app that has written files onto the user's hard drive.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
follow the steps in the web start tutorial for settup up a web server for use with webstart.
create a small test app(a small swing app is always nice)
create an installer app(simple app that puts a file on the file system when "install" is passed to main and removes the dir when "uninstall" is passed to the main)
(you will want to sign both jars if you are using the all-permissions security)
create 2 jnlp files (one for the app, and one for the extension installer)
deploy using webstart -- note the installer is called during install but NOT during uninstall

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
I would expect the extension uninstaller to be called with "uninstall"
ACTUAL -
The extension is never called on uninstall.

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
jnlp file for test app ----  testOne.jnlp --------
<?xml version="1.0" encoding="utf-8"?>
<jnlp
    spec="1.5+"
    codebase="http://myserver/apps/testInstaller/"
    href="testOne.jnlp">
    <information>
        <title>TestOne Console</title>
        <vendor>Vendor</vendor>
        <homepage href="http://www.mycompany.com"/>
        <description>TestOne Console</description>
        <offline-allowed/>
	<shortcut online="false">
        	<desktop/>
	</shortcut>
    </information>
    <security>
        <all-permissions/>
    </security>
    <resources>
        <j2se version="1.5+"/>
        <jar href="lib/testOne.jar" download="eager"/>
        <extension name="setup"	href="http://myserver/apps/testInstaller/testOneSetup.jnlp"/>
    </resources>
    <application-desc main-class="testone.TOFrame"/>
</jnlp>

jnlp file for extension installer -- testOneSetup.jnlp  -------------------------------------
<?xml version="1.0" encoding="utf-8"?>
<jnlp
    spec="1.5+"
    codebase="http://myserver/apps/testInstaller/"
    href="testOneSetup.jnlp">
    <information>
        <title>TestOne Setup</title>
        <vendor>Vendor</vendor>
        <homepage href="http://www.mycompany.com"/>
	<offline-allowed/>
    </information>
    <security>
        <all-permissions/>
    </security>
    <resources>
        <j2se version="1.5+"/>
        <jar href="lib/testOneSetup.jar" download="eager"/>
    </resources>
    <installer-desc main-class="testone.TOSetup"/>
</jnlp>

source for installer/uninstaller TOSetup ---------------

package testone;

import java.io.File;
import javax.jnlp.ExtensionInstallerService;
import javax.jnlp.ServiceManager;
import javax.swing.JOptionPane;

/**
 * Since this is using the filesystem you would need to sign your jars.
 */
public class TOSetup {
    private static final String APP_TOPLEVEL_LOC = System.getProperty("user.home") +
                                                File.separator + ".myapp";
    /** Creates a new instance of Main */
    public TOSetup() {
    }
    
    /**
     * Webstart client should call this with "install" on first run
     * and "uninstall" on uninstallation of my webstart app.
     * @param args the command line arguments
     *
     */
    public static void main(String[] args) {

        TOSetup tos = new TOSetup();
        if ((args.length > 0) && (args[0].equalsIgnoreCase("install"))) {
            tos.install();
        } else {
            tos.uninstall();
        }
    }
    
    /**
     * Called before my webstart apps first run. Used to put up
     * a storage structure.
     */
    private void install() {
        ExtensionInstallerService installerService = null;
        try {
            installerService = (ExtensionInstallerService) ServiceManager.lookup("javax.jnlp.ExtensionInstallerService");
            installerService.setHeading("Start");
            installerService.setStatus("gathering info...");
            installerService.updateProgress(10);
            final int result = JOptionPane.showConfirmDialog(null,
                    "Would you like to create some stuff?",
                    "Confirm Creation",
                    JOptionPane.YES_NO_OPTION);
            if (JOptionPane.YES_OPTION == result) {
                File myLoc = new File(APP_TOPLEVEL_LOC);
                myLoc.mkdirs();
            }
            installerService.setHeading("Finish");
            installerService.setStatus("All done!");
            installerService.updateProgress(100);
            
            //install successful, don't reboot
            installerService.installSucceeded(false);
        } catch(Exception e) {
            e.printStackTrace();
        }
    }
    
    
    /**
     * Should be called when I uninstall my webstart app.
     * Would remove the test structure created in install.
     */
    private void uninstall() {
        try {
            final int result = JOptionPane.showConfirmDialog(null,
                    "Would you like to remove all settings?",
                    "Confirm Delete",
                    JOptionPane.YES_NO_OPTION);
            if (JOptionPane.YES_OPTION == result) {
                File topLevelLoc = new File(APP_TOPLEVEL_LOC);
                topLevelLoc.delete();
            }
        } catch(Exception e) {
            e.printStackTrace();
        }
    }
}


---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
no known workaround

                                    

Comments
SUGGESTED FIX

In CacheUtil.java, change 129:
        if (lih != null) {
to
        if (lih != null && !ld.isInstaller()) {
                                     
2007-02-20
EVALUATION

The problem is just that the code in CacheUtil.java calls lih.uninstall() before the check: if (lap.isLocallyInstalled() && ld.isInstaller()), and lih.uninstall will clear the isLocallyInstalled field of the lap.
Also,  when re-launching the installer, the isLocallyInstalled field is required to determine whether to call app with "install" or "uninstall" arg.
                                     
2007-02-20



Hardware and Software, Engineered to Work Together