001: /*
002: * $RCSfile: AbstractInstall.java,v $
003: * @modification $Date: 2005/05/12 22:13:02 $
004: * @version $Id: AbstractInstall.java,v 1.18 2005/05/12 22:13:02 deniger Exp $
005: *
006: */
007: /**
008: * This is an abstract base class that defines some methods an
009: * installer/uninstaller need to implement. It has some concrete helper methods.
010: *
011: * Both the Setup and the Uninstall class is a kind of installation.
012: *
013: * This first version have some methods copied from the Setup class that should
014: * not be in this class. The goal is to create a more clean class.
015: *
016: * @see com.memoire.vainstall.Setup
017: * @see com.memoire.vainstall.Uninstall
018: *
019: * @author Henrik Falk
020: * @version $Id: AbstractInstall.java,v 1.18 2005/05/12 22:13:02 deniger Exp $
021: */package com.memoire.vainstall;
022:
023: import java.io.File;
024: import java.io.FileOutputStream;
025: import java.io.FileReader;
026: import java.io.IOException;
027: import java.io.InputStream;
028: import java.io.LineNumberReader;
029: import java.util.Arrays;
030: import java.util.Vector;
031:
032: public abstract class AbstractInstall {
033: public static final int CANCEL = 0x01;
034:
035: public static final int BACK = 0x02;
036:
037: public static final int NEXT = 0x04;
038:
039: public static final int FINISH = 0x08;
040:
041: public static final boolean IS_WIN = System.getProperty("os.name")
042: .startsWith("Win");
043:
044: //MAC_OS X
045: public static final boolean IS_MAC_OS_X = System.getProperty(
046: "os.name").startsWith("Mac OS X");
047:
048: public static final boolean IS_MAC = System.getProperty("os.name")
049: .startsWith("Mac")
050: && !IS_MAC_OS_X;
051:
052: public static final boolean IS_UNIX = !IS_WIN && !IS_MAC
053: || IS_MAC_OS_X;
054:
055: public static final boolean IS_ROOT = (IS_UNIX && "root"
056: .equals(System.getProperty("user.name")))
057: || (IS_WIN && new File("C:\\").canWrite());
058:
059: protected VAStep step_;
060:
061: protected boolean dirty_;
062:
063: /**
064: *
065: */
066: protected VAStepFactory ui_;
067:
068: /**
069: *
070: */
071: protected VAStats stats_;
072:
073: protected static final int LANGUAGE = 0;
074:
075: protected static final int START = 1;
076:
077: protected static final int WELCOME = 2;
078:
079: protected static final int LICENSE = 3;
080:
081: protected static final int README = 4;
082:
083: protected static final int LICENSE_KEY = 5;
084:
085: protected static final int UPGRADE = 6;
086:
087: protected static final int DIRECTORY = 7;
088:
089: protected static final int INSTALL = 8;
090:
091: protected static final int SHORTCUTS = 9;
092:
093: protected static final int END = 10;
094:
095: protected int state_;
096:
097: protected int actionEnabled_;
098:
099: protected File sharedDir_;
100:
101: protected File classloaderTempDir_;
102:
103: protected UpgradeInfo uInfo_;
104:
105: /**
106: * The current language that is choosen
107: */
108: protected String language;
109:
110: public AbstractInstall() {
111: super ();
112: if (IS_WIN) {
113: extractJniDll("/JNIWinShortcut.dll", true);
114: extractJniDll("/ICE_JNIRegistry.dll", false);
115: }
116: actionEnabled_ = 0;
117: stats_ = new VAStats();
118: sharedDir_ = null;
119: uInfo_ = null;
120: dirty_ = false;
121: state_ = START;
122: }
123:
124: /**
125: * This method deletes all files in a directory and updates failures to the
126: * 'stats_' variable This method should moved to a support class and thats
127: * why I made it public.
128: *
129: * @author Henrik Falk
130: * @param dir
131: * File Directory to delete
132: * @return void
133: */
134: public void deleteDirRecursive(File dir) {
135: // verify parameter
136: if (dir == null || dir.exists() == false) {
137: return;
138: }
139: // get list of files in directory if any
140: File[] filelist = dir.listFiles();
141: for (int i = 0; i < filelist.length; i++) {
142: boolean isdir = filelist[i].isDirectory();
143: if (isdir == true) {
144: // delete everything in the directory
145: deleteDirRecursive(filelist[i]);
146: } else {
147: // delete the file
148: if (filelist[i].delete() == false) {
149: stats_.addFile(filelist[i], VAStats.FAILURE);
150: filelist[i].deleteOnExit();
151: VAGlobals.printDebug("F " + filelist[i]
152: + " not deleted");
153: } // endif
154: } // endif
155: } // endfor
156: // delete the directory
157: if (dir.delete() == false) {
158: dir.deleteOnExit();
159: stats_.addDirectory(dir, VAStats.FAILURE);
160: VAGlobals.printDebug("D " + dir + " not deleted");
161: } // endif
162: }
163:
164: public boolean cleanShortcuts(File shortcutLogDir)
165: throws IOException {
166: boolean value;
167: File logFile;
168: Vector directories;
169: logFile = new File(shortcutLogDir, "shortcuts.vai");
170: value = false;
171: if (logFile.exists()) {
172: value = true;
173: directories = deleteFiles(logFile);
174: deleteDirectories(directories);
175: }
176: return value;
177: }
178:
179: protected Vector deleteFiles(File log) throws IOException {
180: Vector dirs = new Vector();
181: LineNumberReader logReader = new LineNumberReader(
182: new FileReader(log));
183: String line = logReader.readLine();
184: while (line != null) {
185: File del = new File(line);
186: if (del.isDirectory()) {
187:
188: dirs.add(del);
189: } else if (del.delete()) {
190: stats_.addFile(del, VAStats.SUCCESS);
191: } else {
192: del.deleteOnExit();
193: stats_.addFile(del, VAStats.FAILURE);
194: VAGlobals.printDebug("F " + del + " not deleted");
195: }
196: line = logReader.readLine();
197: }
198: logReader.close();
199: return dirs;
200: }
201:
202: protected void deleteDirectories(Vector directories)
203: throws IOException {
204: Object[] dirs = directories.toArray();
205: Arrays.sort(dirs);
206: for (int i = dirs.length - 1; i >= 0; i--) {
207: File del = (File) dirs[i];
208: if (del.delete()) {
209: stats_.addDirectory(del, VAStats.SUCCESS);
210: } else {
211: del.deleteOnExit();
212: stats_.addDirectory(del, VAStats.FAILURE);
213: VAGlobals.printDebug("D " + del + " not deleted");
214: }
215: }
216: }
217:
218: private void restoreLastVersion(File sharedDir, UpgradeInfo uInfo) {
219: File destPath = new File(sharedDir, "vai_" + VAGlobals.APP_NAME
220: + "_" + VAGlobals.APP_VERSION);
221: // eliminate new install info
222: if (destPath.exists())
223: deleteDirRecursive(destPath);
224: if ((uInfo == null) || (!uInfo.upgrade))
225: return;
226: File lastVerPath = new File(sharedDir, "vai_"
227: + VAGlobals.APP_NAME + "_" + uInfo.lastVersion());
228: // restore old install info if versions are the same
229: if (destPath.equals(lastVerPath)) {
230: lastVerPath = new File(destPath.getAbsolutePath() + ".bak");
231: lastVerPath.renameTo(destPath);
232: }
233: }
234:
235: public void setActionEnabled(int a) {
236: actionEnabled_ = a;
237: ui_.setActionEnabled(a);
238: }
239:
240: public void cancel() {
241: cleanInstall(sharedDir_, uInfo_);
242: quit();
243: }
244:
245: protected void cleanInstall(File sharedDir, UpgradeInfo uInfo) {
246: if ((!dirty_) || (sharedDir == null) || (!sharedDir.exists())) {
247: VAGlobals.printDebug("No cleaning needed");
248: return;
249: }
250: File uninstDir = new File(sharedDir.getAbsolutePath()
251: + File.separator + "vai_" + VAGlobals.APP_NAME + "_"
252: + VAGlobals.APP_VERSION);
253: if (!uninstDir.exists()) {
254: VAGlobals.printDebug("No cleaning needed");
255: return;
256: }
257: VAGlobals.printDebug("Deleting uninstall files...");
258: if ((uInfo != null) && (uInfo.upgrade)) {
259: restoreLastVersion(sharedDir, uInfo);
260: } else {
261: // delete all in the uninstall directory
262: deleteDirRecursive(uninstDir);
263: }
264: VAGlobals.printDebug("All cleaned OK");
265: }
266:
267: protected void checkUpgrade(File sharedDir, UpgradeInfo uInfo) {
268: VAUpgradeStep step = (VAUpgradeStep) step_;
269: step.status(VAGlobals.i18n("Setup_LookPreviousVersions"));
270: ui_.uiSleep(2000);
271: checkVersions(sharedDir, uInfo);
272: if (uInfo.upgrade) {
273: VAGlobals.printDebug("Previous version found : "
274: + uInfo.lastVersion());
275: step.status(VAGlobals.i18n("Setup_PreviousVersionFound")
276: + " " + uInfo.lastVersion());
277: step.version(uInfo.lastVersion());
278: step.directory(uInfo.lastPath().getAbsolutePath());
279: } else {
280: VAGlobals.printDebug("No previous version found");
281: step.status(VAGlobals.i18n("Setup_NoPreviousVersionFound"));
282: step.version(VAGlobals.i18n("Setup_None"));
283: step.directory(VAGlobals.i18n("Setup_None"));
284: }
285: }
286:
287: private void checkVersions(File sharedDir, UpgradeInfo uInfo) {
288: String[] ls = sharedDir.list(new SetupFileFilter("vai_"
289: + VAGlobals.APP_NAME + "_",
290: SetupFileFilter.STARTS_WITH, SetupFileFilter.FILTER));
291: if ((ls != null) && (ls.length > 0)) {
292: Arrays.sort(ls);
293: uInfo.versions = new String[ls.length];
294: uInfo.paths = new File[ls.length];
295: for (int i = 0; i < ls.length; i++) {
296: uInfo.versions[i] = ls[i].substring(ls[i]
297: .lastIndexOf('_') + 1);
298: try {
299: LineNumberReader log = new LineNumberReader(
300: new FileReader(new File(new File(sharedDir,
301: ls[i]), "uninstall.vai")));
302: String f = log.readLine();
303: if (f != null)
304: uInfo.paths[i] = new File(f);
305: log.close();
306: } catch (IOException ex) {
307: System.err.println(ex.getMessage());
308: uInfo.paths[i] = null;
309: }
310: }
311: }
312: uInfo.upgrade = (uInfo.lastVersion() != null)
313: && (uInfo.lastPath() != null);
314: }
315:
316: /**
317: * @param entryName
318: * the name of the dll file
319: * @param isWinShortcut
320: * true if it's the dll for the JNIWindowsShortcut
321: */
322: private void extractJniDll(String entryName, boolean isWinShortcut) {
323: try {
324: InputStream dll = getClass().getResourceAsStream(entryName);
325: File dllFile = new File(System
326: .getProperty("java.io.tmpdir")
327: + File.separator
328: + entryName
329: .substring(entryName.lastIndexOf('/') + 1));
330: VAGlobals.printDebug("Extracting library " + dllFile);
331: System.out.println(dllFile.getAbsolutePath());
332: FileOutputStream dllout = new FileOutputStream(dllFile);
333: byte[] data = new byte[512];
334: int read = dll.read(data, 0, data.length);
335: while (read > 0) {
336: dllout.write(data, 0, read);
337: read = dll.read(data, 0, data.length);
338: }
339: dll.close();
340: dllout.close();
341: VAGlobals.printDebug(" library extracted");
342: if (isWinShortcut) {
343: JNIWindowsShortcut.LIB_NAME = dllFile.getAbsolutePath();
344: ;
345: } else
346: VAGlobals.JNI_DLL_FILE = dllFile.getAbsolutePath();
347: dllFile.deleteOnExit();
348: } catch (IOException e) {
349: exitOnError(e);
350: }
351: }
352:
353: protected void exitOnError(Throwable e) {
354: if (ui_ != null)
355: ui_.showFatalError(e);
356: else
357: e.printStackTrace();
358: deleteTmpFile();
359: System.exit(1);
360: }
361:
362: private void deleteTmpFile() {
363: if (classloaderTempDir_ != null) {
364: VAGlobals.printDebug("Temporary directory deleted: "
365: + classloaderTempDir_.getAbsolutePath());
366: deleteDirRecursive(classloaderTempDir_);
367: }
368: }
369:
370: protected void quit() {
371: // delete classloader
372: //File classloaderDir = new
373: // File(System.getProperty("user.dir")+File.separator+"com");
374: deleteTmpFile();
375: ui_ = null;
376: VAGlobals.printDebug("Exiting");
377: System.exit(0);
378: }
379:
380: /**
381: * The next step in an install/uninstall
382: *
383: * @return void
384: */
385: public abstract void nextStep();
386:
387: /**
388: * A previous step in an install/uninstall
389: *
390: * @return void
391: */
392: public abstract void previousStep();
393:
394: /**
395: * A redo step in an install/uninstall This is conceptually an 'again' step.
396: * Only 'tui' uses the redo feature at the moment.
397: *
398: * @return void
399: */
400: public abstract void redoStep();
401: }
|