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