/* * Sun Public License Notice * * The contents of this file are subject to the Sun Public License * Version 1.0 (the "License"). You may not use this file except in * compliance with the License. A copy of the License is available at * http://www.sun.com/ * * The Original Code is NetBeans. The Initial Developer of the Original * Code is Sun Microsystems, Inc. Portions Copyright 1997-2004 Sun * Microsystems, Inc. All Rights Reserved. */ package org.netbeans.installer; import com.installshield.product.SoftwareObject; import com.installshield.product.i18n.ProductResourcesConst; import com.installshield.product.service.product.ProductService; import com.installshield.product.service.registry.RegistryService; import com.installshield.product.wizardbeans.DestinationPanel; import com.installshield.util.LocalizedStringResolver; import com.installshield.util.Log; import com.installshield.wizard.WizardBeanEvent; import com.installshield.wizard.service.ServiceException; import com.installshield.wizard.service.WizardServicesUI; import com.installshield.wizard.service.file.FileService; import java.io.File; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class InstallLocationPanel extends DestinationPanel { private static String BUNDLE = "$L(org.netbeans.installer.Bundle,"; public boolean queryEnter (WizardBeanEvent event) { try { ProductService service = (ProductService) getService(ProductService.NAME); String destination = (String) service.getProductBeanProperty( ProductService.DEFAULT_PRODUCT_SOURCE, null, "installLocation"); if (! System.getProperty("os.name").startsWith("Windows")) { File root = new File("/"); if (! root.canWrite()) { service.setProductBeanProperty( ProductService.DEFAULT_PRODUCT_SOURCE, null, "installLocation", resolveString(BUNDLE + "Product.installLocationForNonRoot)")); } } } catch (ServiceException e) { logEvent(this, Log.ERROR, e); } return super.queryEnter(event); } public boolean queryExit (WizardBeanEvent event) { System.out.println("## InstallLocationPanel.queryExit"); //Default check if selected destination dir is writable, //entered value must be valid path and must not be empty string or string //consisting only of white space chars. boolean ret = super.queryExit(event); if (!ret) { return ret; } //Here we will perform more specific checks. //Check if selected destination directory is empty. //If it is not empty check its content - if it is NB installation //we will offer user to run uninstaller and perform complete clean up. String nbInstallDir = null; Object o = null; Method method = null; try { method = DestinationPanel.class.getDeclaredMethod("getDestination",null); method.setAccessible(true); o = method.invoke(this, null); System.out.println("## o:" + o); } catch (InvocationTargetException ex) { ex.printStackTrace(); } catch (Exception ex) { // If exceptions are thrown, notify them - something is broken. ex.printStackTrace(); } catch (LinkageError ex) { // These too... ex.printStackTrace(); } finally { if (method != null) { method.setAccessible(false); } } if ((o != null) && (o instanceof String)) { nbInstallDir = (String) o; } if (nbInstallDir != null) { } else { //Cannot validate selected nbInstallDir. Something very bad happenned. //Fallback to default error message } return ret; } public void exited (WizardBeanEvent event) { System.out.println("## InstallLocationPanel.exited"); //Call to update product tree super.exited(event); try { //Set install location for storage builder ProductService service = (ProductService)getService(ProductService.NAME); String productDestination = (String) service.getProductBeanProperty( ProductService.DEFAULT_PRODUCT_SOURCE, null, "installLocation"); String sbDestination = productDestination + File.separator + "_uninst" + File.separator + "storagebuilder"; logEvent(this, Log.DBG, "exited productDestination: " + productDestination); logEvent(this, Log.DBG, "exited sbDestination: " + sbDestination); service.setRetainedProductBeanProperty(ProductService.DEFAULT_PRODUCT_SOURCE, Names.STORAGE_BUILDER_ID, "installLocation", sbDestination); } catch (ServiceException e) { logEvent(this, Log.ERROR, e); } } /** * Helper method to validate the data entered for the product destination. * * @boolean true if the specified destination directory exists and writable. false otherwise. */ private boolean validateDestination (String nbInstallDir) { String title = LocalizedStringResolver.resolve (ProductResourcesConst.NAME,"DestinationPanel.destinationDirectory"); logEvent(this, Log.DBG,"validateDestination nbInstallDir: " + nbInstallDir); try { FileService fileService = (FileService) getService(FileService.NAME); //If destination dir already exists check if it is empty. String [] files = fileService.getDirectoryList(nbInstallDir,FileService.FILES_AND_DIRECTORIES); if (files == null) { return true; } else if (files.length > 0) { //Destination directory exists and is not empty. //Check its content: It can be either profiler installation or uknown content. return checkDestinationDirContent(nbInstallDir); } } catch (ServiceException e) { showErrorMsg(title, e.getMessage()); return false; } return true; } /** Check content of selected destination directory if it is not empty. * It can contain: * 1.Uknown content * 2.Older NB installation * 3.The same NB installation * 4.Newer NB installation. * In case 2 and 3 it offers to uninstall previous NB installation first. */ private boolean checkDestinationDirContent (String nbInstallDir) { String currentUID = resolveString(BUNDLE + "Product.UID)"); String title = LocalizedStringResolver.resolve (ProductResourcesConst.NAME,"DestinationPanel.destinationDirectory"); try { // Get the instance of RegistryService RegistryService regserv = (RegistryService) getService(RegistryService.NAME); String [] arr = regserv.getAllSoftwareObjectUIDs(); /*for (int i = 0; i < arr.length; i++) { System.out.println("arr[" + i + "]: " + arr[i]); }*/ //Look for any profiler installation SoftwareObject so = null; for (int i = 0; i < arr.length; i++) { if (arr[i].startsWith(currentUID.substring(0,26))) { so = regserv.getSoftwareObject(arr[i],nbInstallDir); if (so != null) { break; } } } if (so != null) { //Profiler is installed in destination directory //Check version logEvent(this, Log.DBG,"so.UID:" + so.getKey().getUID() + " so.location:" + so.getInstallLocation()); String installedUID = so.getKey().getUID(); //Check main version if (currentUID.substring(0,29).equals(installedUID.substring(0,29))) { //The same main version //We have following possibilities "de" or "00". int orderLength = 0; String s = resolveString(BUNDLE + "Order.length)"); try { orderLength = Integer.parseInt(s); } catch (NumberFormatException exc) { logEvent(this, Log.ERROR,"Incorrect number for Order.length: " + s); } //No order is defined. if (orderLength == 0) { String msg = resolveString(BUNDLE + "NetBeansDirChooser.notEmpty3," + nbInstallDir + ")"); showErrorMsg(title,msg); return false; } String [] orderArray = new String[orderLength]; for (int i = 0; i < orderLength; i++) { orderArray[i] = resolveString(BUNDLE + "Order." + i + ")"); //System.out.println("orderArray[" + i + "]: " + orderArray[i]); } //Find indices for current and installed version int currentIndex = 0; for (int i = 0; i < orderLength; i++) { if (orderArray[i].equals(currentUID.substring(29,32))) { currentIndex = i; } } int installedIndex = 0; for (int i = 0; i < orderLength; i++) { if (orderArray[i].equals(installedUID.substring(29,32))) { installedIndex = i; } } if (currentIndex < installedIndex) { //Newer version is installed ie. currentUID < installedUID String msg = resolveString(BUNDLE + "NetBeansDirChooser.notEmpty4," + nbInstallDir + ")"); showErrorMsg(title,msg); return false; } else if (currentIndex > installedIndex) { //Older version is installed ie. currentUID > installedUID String msg = resolveString(BUNDLE + "NetBeansDirChooser.notEmpty2," + nbInstallDir + ")"); String uninstall = "Uninstall"; String cancel = "Cancel"; Object ret = getWizard().getServices().getUserInput(title, msg, new Object [] {uninstall,cancel},cancel); if (ret == uninstall) { logEvent(this, Log.DBG,"UNINSTALL"); return uninstallPrevious(nbInstallDir); } else { logEvent(this, Log.DBG,"CANCEL"); return false; } } else { //The same version String msg = resolveString(BUNDLE + "NetBeansDirChooser.notEmpty3," + nbInstallDir + ")"); showErrorMsg(title,msg); return false; } } else { if (currentUID.compareTo(installedUID) < 0) { //Newer version is installed ie. currentUID < installedUID String msg = resolveString(BUNDLE + "NetBeansDirChooser.notEmpty4," + nbInstallDir + ")"); showErrorMsg(title,msg); return false; } else if (currentUID.compareTo(installedUID) > 0) { //Older version is installed ie. currentUID > installedUID String msg = resolveString(BUNDLE + "NetBeansDirChooser.notEmpty2," + nbInstallDir + ")"); String uninstall = "Uninstall"; String cancel = "Cancel"; Object ret = getWizard().getServices().getUserInput(title, msg, new Object [] {uninstall,cancel},cancel); if (ret == uninstall) { logEvent(this, Log.DBG,"UNINSTALL"); return uninstallPrevious(nbInstallDir); } else { logEvent(this, Log.DBG,"CANCEL"); return false; } } else { //This should not happen String msg = resolveString(BUNDLE + "NetBeansDirChooser.notEmpty1," + nbInstallDir + ")"); showErrorMsg(title,msg); return false; } } } else { //Uknown content String msg = resolveString(BUNDLE + "NetBeansDirChooser.notEmpty1," + nbInstallDir + ")"); showErrorMsg(title,msg); return false; } } catch (ServiceException exc) { logEvent(this, Log.ERROR, exc); return false; } } private boolean uninstallPrevious (String nbInstallDir) { String currentUID = resolveString(BUNDLE + "Product.UID)"); String title = LocalizedStringResolver.resolve (ProductResourcesConst.NAME,"DestinationPanel.destinationDirectory"); try { FileService fileService = (FileService) getService(FileService.NAME); String uninstallerPath; if (Util.isWindowsOS()) { uninstallerPath = nbInstallDir + File.separator + "_uninst" + File.separator + "uninstaller.exe"; } else { uninstallerPath = nbInstallDir + File.separator + "_uninst" + File.separator + "uninstaller"; } if (!fileService.fileExists(uninstallerPath)) { //Uninstaller not found, cannot uninstall String msg = resolveString(BUNDLE + "NetBeansDirChooser.uninstallerNotFound," + uninstallerPath + ")"); showErrorMsg(title,msg); return false; } //Run uninstaller is separate thread and disable navigation buttons. disableNavigation(); RunUninstaller runUninstaller = new RunUninstaller(uninstallerPath,this); runUninstaller.start(); return false; } catch (ServiceException exc) { Util.logStackTrace(this,exc); String msg = resolveString(BUNDLE + "NetBeansDirChooser.uninstallerError," + exc.getLocalizedMessage() + ")"); showErrorMsg(title,msg); return false; } } private void showErrorMsg(String title, String msg) { try { getWizard().getServices().displayUserMessage(title, msg, WizardServicesUI.ERROR); } catch (Exception e) { throw new Error(); } } private void showLocalizedErrorMsg(String bundle, String titleKey, String msgKey) { try { String title = LocalizedStringResolver.resolve(bundle, titleKey); String msg = LocalizedStringResolver.resolve(bundle, msgKey); getWizard().getServices().displayUserMessage(title, msg, WizardServicesUI.ERROR); } catch (Exception e) { throw new Error(); } } private void showLocalizedErrorMsg(String bundle, String titleKey, String msgKey, String[] params) { try { String title = LocalizedStringResolver.resolve(bundle, titleKey); String msg = LocalizedStringResolver.resolve(bundle, msgKey, params); getWizard().getServices().displayUserMessage(title, msg, WizardServicesUI.ERROR); } catch (Exception e) { throw new Error(); } } private void disableNavigation () { logEvent(this, Log.DBG,"disableNavigation"); getWizard().getUI().setNavigationEnabled(false); getWizard().getUI().setBusy(); } private void enableNavigation () { logEvent(this, Log.DBG,"enableNavigation"); getWizard().getUI().setNavigationEnabled(true); getWizard().getUI().clearBusy(); } /** Used to run uninstaller in separate thread not to block AWT thread in installer * when uninstaller is running. */ private class RunUninstaller extends Thread { private final String uninstallerPath; private final Log log; private Throwable throwable = null; RunUninstaller (String uninstallerPath, Log log) { this.uninstallerPath = uninstallerPath; this.log = log; } public void run() { int returnValue = -1; try { RunCommand runCommand = new RunCommand(); runCommand.execute(uninstallerPath); runCommand.waitFor(); log.logEvent(this, Log.DBG,runCommand.print()); returnValue = runCommand.getReturnStatus(); log.logEvent(this, Log.DBG,"Uninstaller returned: " + returnValue); } catch (Throwable t) { Util.logStackTrace(log,t); } finally { enableNavigation(); if (returnValue != 0) { String title = LocalizedStringResolver.resolve (ProductResourcesConst.NAME,"DestinationPanel.destinationDirectory"); String msg = resolveString(BUNDLE + "NetBeansDirChooser.uninstallerFailed)"); showErrorMsg(title,msg); } } } } }