001/* 002 * $Id: CheckedHelloPanel.java,v 1.4 2005/09/04 02:06:46 jponge Exp $ 003 * IzPack - Copyright 2001-2005 Julien Ponge, All Rights Reserved. 004 * 005 * http://www.izforge.com/izpack/ http://developer.berlios.de/projects/izpack/ 006 * 007 * Copyright 2005 Klaus Bartz 008 * 009 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 010 * in compliance with the License. You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, software distributed under the License 015 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 016 * or implied. See the License for the specific language governing permissions and limitations under 017 * the License. 018 */ 019 020package com.izforge.izpack.panels; 021 022import com.coi.tools.os.win.RegDataContainer; 023import com.coi.tools.os.win.RegistryImpl; 024import com.izforge.izpack.installer.InstallData; 025import com.izforge.izpack.installer.InstallerFrame; 026import com.izforge.izpack.util.AbstractUIHandler; 027import com.izforge.izpack.util.os.RegistryDefaultHandler; 028import com.izforge.izpack.util.os.RegistryHandler; 029 030/** 031 * An extended hello panel class which detects whether the product was already installed or not. 032 * This class should be only used if the RegistryInstallerListener will be also used. Current the 033 * check will be only performed on Windows operating system. This class can be used also as example 034 * how to use the registry stuff to get informations from the current system. 035 * 036 * @author Klaus Bartz 037 */ 038public class CheckedHelloPanel extends HelloPanel 039{ 040 041 /** Flag to break installation or not. */ 042 protected boolean abortInstallation; 043 044 /** 045 * The constructor. 046 * 047 * @param parent The parent. 048 * @param idata The installation data. 049 */ 050 public CheckedHelloPanel(InstallerFrame parent, InstallData idata) 051 { 052 super(parent, idata); 053 abortInstallation = isRegistered(); 054 } 055 056 /** 057 * This method should only be called if this product was allready installed. It resolves the 058 * install path of the first already installed product and asks the user whether to install 059 * twice or not. 060 * 061 * @return whether a multiple Install should be performed or not. 062 * @throws Exception 063 */ 064 protected boolean multipleInstall() throws Exception 065 { 066 // Let us play a little bit with the regstry... 067 // Just for fun we would resolve the path of the already 068 // installed application. 069 // First we need a handler. There is no overhead at a 070 // secound call of getInstance, therefore we do not buffer 071 // the handler in this class. 072 RegistryHandler rh = RegistryDefaultHandler.getInstance(); 073 int oldVal = rh.getRoot(); // Only for security... 074 // We know, that the product is already installed, else we 075 // would not in this method. Now we search for the path... 076 String uninstallName = rh.getUninstallName(); 077 String oldInstallPath = "<not found>"; 078 while (true) // My goto alternative :-) 079 { 080 081 if (uninstallName == null) break; // Should never be... 082 // First we "create" the reg key. 083 String keyName = RegistryHandler.UNINSTALL_ROOT + uninstallName; 084 rh.setRoot(RegistryImpl.HKEY_LOCAL_MACHINE); 085 if (!rh.valueExist(keyName, "UninstallString")) 086 // We assume that the application was installed with 087 // IzPack. Therefore there should be the value "UninstallString" 088 // which contains the uninstaller call. If not we can do nothing. 089 break; 090 // Now we would get the value. A value can have different types. 091 // Therefore we get an container which can handle all possible types. 092 // There are different ways to handle. Use normally only one of the 093 // ways; at this point more are used to demonstrate the different ways. 094 095 // 1. If we are secure about the type, we can extract the value immediately. 096 String valString = rh.getValue(keyName, "UninstallString").getStringData(); 097 098 // 2. If we are not so much interessted at the type, we can get the value 099 // as Object. A DWORD is then a Long Object not a long primitive type. 100 Object valObj = rh.getValue(keyName, "UninstallString").getDataAsObject(); 101 102 // 3. If we are not secure about the type we should differ between possible 103 // types. 104 RegDataContainer val = rh.getValue(keyName, "UninstallString"); 105 int typeOfVal = val.getType(); 106 switch (typeOfVal) 107 { 108 case RegDataContainer.REG_EXPAND_SZ: 109 case RegDataContainer.REG_SZ: 110 valString = val.getStringData(); 111 break; 112 case RegDataContainer.REG_BINARY: 113 case RegDataContainer.REG_DWORD: 114 case RegDataContainer.REG_LINK: 115 case RegDataContainer.REG_MULTI_SZ: 116 throw new Exception("Bad data type of chosen registry value " + keyName); 117 default: 118 throw new Exception("Unknown data type of chosen registry value " + keyName); 119 } 120 // That's all with registry this time... Following preparation of 121 // the received value. 122 // It is [java path] -jar [uninstaller path] 123 int start = valString.lastIndexOf("-jar") + 5; 124 if (start < 5 || start >= valString.length()) 125 // we do not know what todo with it. 126 break; 127 String uPath = valString.substring(start).trim(); 128 if (uPath.startsWith("\"")) uPath = uPath.substring(1).trim(); 129 int end = uPath.indexOf("uninstaller"); 130 if (end < 0) 131 // we do not know what todo with it. 132 break; 133 oldInstallPath = uPath.substring(0, end - 1); 134 // Much work for such a peanuts... 135 break; // That's the problem with the goto alternative. Forget this 136 // break produces an endless loop. 137 } 138 139 rh.setRoot(oldVal); // Only for security... 140 141 // The text will be to long for one line. Therefore we should use 142 // the multi line label. Unfortunately it has no icon. Nothing is 143 // perfect... 144 String noLuck = parent.langpack.getString("CheckedHelloPanel.productAlreadyExist0") 145 + oldInstallPath 146 + parent.langpack.getString("CheckedHelloPanel.productAlreadyExist1"); 147 return (askQuestion(parent.langpack.getString("installer.error"), noLuck, 148 AbstractUIHandler.CHOICES_YES_NO) == AbstractUIHandler.ANSWER_YES); 149 } 150 151 /** 152 * Returns wether the handled application is already registered or not. The validation will be 153 * made only on systems which contains a registry (Windows). 154 * 155 * @return wether the handled application is already registered or not 156 */ 157 protected boolean isRegistered() 158 { 159 boolean retval = false; 160 try 161 { 162 // Get the default registry handler. 163 RegistryHandler rh = RegistryDefaultHandler.getInstance(); 164 if (rh != null) 165 { 166 rh.verify(idata); 167 retval = rh.isProductRegistered(); 168 169 } 170 // else we are on a os which has no registry or the 171 // needed dll was not bound to this installation. In 172 // both cases we forget the "already exist" check. 173 174 } 175 catch (Exception e) 176 { // Will only be happen if registry handler is good, but an 177 // exception at performing was thrown. This is an error... 178 e.printStackTrace(); 179 } 180 return (retval); 181 } 182 183 /** 184 * Indicates wether the panel has been validated or not. 185 * 186 * @return true if the internal abort flag is not set, else false 187 */ 188 public boolean isValidated() 189 { 190 return (!abortInstallation); 191 } 192 193 /* 194 * (non-Javadoc) 195 * 196 * @see com.izforge.izpack.installer.IzPanel#panelActivate() 197 */ 198 public void panelActivate() 199 { 200 if (abortInstallation) 201 { 202 parent.lockNextButton(); 203 try 204 { 205 if (multipleInstall()) 206 { 207 setUniqueUninstallKey(); 208 abortInstallation = false; 209 parent.unlockNextButton(); 210 } 211 } 212 catch (Exception e) 213 { 214 // TODO Auto-generated catch block 215 e.printStackTrace(); 216 } 217 218 } 219 RegistryHandler rh = RegistryDefaultHandler.getInstance(); 220 if( rh != null ) 221 idata.setVariable("UNINSTALL_NAME", rh.getUninstallName()); 222 } 223 224 /** 225 * @throws Exception 226 * 227 */ 228 private void setUniqueUninstallKey() throws Exception 229 { 230 // Let us play a little bit with the regstry again... 231 // Now we search for an unique uninstall key. 232 // First we need a handler. There is no overhead at a 233 // secound call of getInstance, therefore we do not buffer 234 // the handler in this class. 235 RegistryHandler rh = RegistryDefaultHandler.getInstance(); 236 int oldVal = rh.getRoot(); // Only for security... 237 // We know, that the product is already installed, else we 238 // would not in this method. First we get the 239 // "default" uninstall key. 240 String uninstallName = rh.getUninstallName(); 241 int uninstallModifier = 1; 242 while (true) 243 { 244 if (uninstallName == null) break; // Should never be... 245 // Now we define a new uninstall name. 246 String newUninstallName = uninstallName + "(" + Integer.toString(uninstallModifier) 247 + ")"; 248 // Then we "create" the reg key with it. 249 String keyName = RegistryHandler.UNINSTALL_ROOT + newUninstallName; 250 rh.setRoot(RegistryImpl.HKEY_LOCAL_MACHINE); 251 if (!rh.keyExist(keyName)) 252 { // That's the name for which we searched. 253 // Change the uninstall name in the reg helper. 254 rh.setUninstallName(newUninstallName); 255 // Now let us inform the user. 256 emitNotification(parent.langpack 257 .getString("CheckedHelloPanel.infoOverUninstallKey") 258 + newUninstallName); 259 // Now a little hack if the registry spec file contains 260 // the pack "UninstallStuff". 261 break; 262 } 263 uninstallModifier++; 264 } 265 } 266 267}