001: /*
002: * IzPack - Copyright 2001-2008 Julien Ponge, All Rights Reserved.
003: *
004: * http://izpack.org/
005: * http://izpack.codehaus.org/
006: *
007: * Licensed under the Apache License, Version 2.0 (the "License");
008: * you may not use this file except in compliance with the License.
009: * You may obtain a copy of the License at
010: *
011: * http://www.apache.org/licenses/LICENSE-2.0
012: *
013: * Unless required by applicable law or agreed to in writing, software
014: * distributed under the License is distributed on an "AS IS" BASIS,
015: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016: * See the License for the specific language governing permissions and
017: * limitations under the License.
018: */
019:
020: package com.izforge.izpack.uninstaller;
021:
022: import java.io.BufferedReader;
023: import java.io.File;
024: import java.io.InputStream;
025: import java.io.InputStreamReader;
026: import java.io.ObjectInputStream;
027: import java.io.PrintWriter;
028: import java.io.StringWriter;
029: import java.util.ArrayList;
030: import java.util.Collections;
031: import java.util.Iterator;
032: import java.util.List;
033: import java.util.TreeSet;
034:
035: import com.izforge.izpack.ExecutableFile;
036: import com.izforge.izpack.event.UninstallerListener;
037: import com.izforge.izpack.installer.UninstallData;
038: import com.izforge.izpack.util.AbstractUIProgressHandler;
039: import com.izforge.izpack.util.Debug;
040: import com.izforge.izpack.util.FileExecutor;
041: import com.izforge.izpack.util.OsVersion;
042: import com.izforge.izpack.util.os.unix.ShellScript;
043:
044: /**
045: * The files destroyer class.
046: *
047: * @author Julien Ponge
048: */
049: public class Destroyer extends Thread {
050:
051: /** True if the destroyer must force the recursive deletion. */
052: private boolean forceDestroy;
053:
054: /** The installation path. */
055: private String installPath;
056:
057: /** the destroyer listener. */
058: private AbstractUIProgressHandler handler;
059:
060: /**
061: * The constructor.
062: *
063: * @param installPath The installation path.
064: * @param forceDestroy Shall we force the recursive deletion.
065: * @param handler The destroyer listener.
066: */
067: public Destroyer(String installPath, boolean forceDestroy,
068: AbstractUIProgressHandler handler) {
069: super ("IzPack - Destroyer");
070:
071: this .installPath = installPath;
072: this .forceDestroy = forceDestroy;
073: this .handler = handler;
074: }
075:
076: /** The run method. */
077: public void run() {
078: try {
079: // We get the list of uninstaller listeners
080: List[] listeners = getListenerLists();
081: // We get the list of the files to delete
082: ArrayList<ExecutableFile> executables = getExecutablesList();
083:
084: FileExecutor executor = new FileExecutor(executables);
085: executor.executeFiles(ExecutableFile.UNINSTALL,
086: this .handler);
087:
088: ArrayList<File> files = getFilesList();
089: int size = files.size();
090:
091: // Custem action listener stuff --- beforeDeletion ----
092: informListeners(listeners[0],
093: UninstallerListener.BEFORE_DELETION, files, handler);
094:
095: handler.startAction("destroy", size);
096:
097: // We destroy the files
098: for (int i = 0; i < size; i++) {
099: File file = files.get(i);
100: // Custem action listener stuff --- beforeDelete ----
101: informListeners(listeners[1],
102: UninstallerListener.BEFORE_DELETE, file,
103: handler);
104:
105: file.delete();
106:
107: // Custem action listener stuff --- afterDelete ----
108: informListeners(listeners[1],
109: UninstallerListener.AFTER_DELETE, file, handler);
110:
111: handler.progress(i, file.getAbsolutePath());
112: }
113:
114: // Custem action listener stuff --- afterDeletion ----
115: informListeners(listeners[0],
116: UninstallerListener.AFTER_DELETION, files, handler);
117:
118: if (OsVersion.IS_UNIX) {
119: execRootScript(getRootScript());
120: }
121: // We make a complementary cleanup
122: handler.progress(size, "[ cleanups ]");
123: cleanup(new File(installPath));
124:
125: handler.stopAction();
126: } catch (Exception err) {
127: handler.stopAction();
128: err.printStackTrace();
129:
130: StackTraceElement str[] = err.getStackTrace();
131: for (StackTraceElement aStr : str) {
132:
133: }
134:
135: StringWriter trace = new StringWriter();
136: //err.printStackTrace(new PrintStream);
137: err.printStackTrace(new PrintWriter(trace));
138:
139: handler.emitError("exception caught", err.toString() + "\n"
140: + trace.toString());
141: }
142: }
143:
144: /**
145: * Asks the JVM for the uninstaller deletion.
146: *
147: * @exception Exception Description of the Exception
148: */
149: // private void askUninstallerRemoval() throws Exception
150: // {
151: // // Initialisations
152: // InputStream in = Destroyer.class.getResourceAsStream("/jarlocation.log");
153: // InputStreamReader inReader = new InputStreamReader(in);
154: // BufferedReader reader = new BufferedReader(inReader);
155: //
156: // // We delete
157: // File jar = new File(reader.readLine());
158: // File path = new File(reader.readLine());
159: // File inst = new File(installPath);
160: // jar.deleteOnExit();
161: // path.deleteOnExit();
162: // inst.deleteOnExit();
163: // }
164: /**
165: * Returns an ArrayList of the files to delete.
166: *
167: * @return The files list.
168: * @exception Exception Description of the Exception
169: */
170: private ArrayList<File> getFilesList() throws Exception {
171: // Initialisations
172: TreeSet<File> files = new TreeSet<File>(Collections
173: .reverseOrder());
174: InputStream in = Destroyer.class
175: .getResourceAsStream("/install.log");
176: InputStreamReader inReader = new InputStreamReader(in);
177: BufferedReader reader = new BufferedReader(inReader);
178:
179: // We skip the first line (the installation path)
180: reader.readLine();
181:
182: // We read it
183: String read = reader.readLine();
184: while (read != null) {
185: files.add(new File(read));
186: read = reader.readLine();
187: }
188:
189: // We return it
190: return new ArrayList<File>(files);
191: }
192:
193: /**
194: * Gets the List of all Executables
195: * @return The ArrayList of the Executables
196: * @throws Exception
197: */
198: private ArrayList<ExecutableFile> getExecutablesList()
199: throws Exception {
200: ArrayList<ExecutableFile> executables = new ArrayList<ExecutableFile>();
201: ObjectInputStream in = new ObjectInputStream(Destroyer.class
202: .getResourceAsStream("/executables"));
203: int num = in.readInt();
204: for (int i = 0; i < num; i++) {
205: ExecutableFile file = (ExecutableFile) in.readObject();
206: executables.add(file);
207: }
208: return executables;
209: }
210:
211: /**
212: * Gets the root files.
213: *
214: * @return The files which should remove by root for another user
215: * @throws Exception
216: */
217: private String getRootScript() throws Exception {
218: String result = "";
219: ObjectInputStream in = new ObjectInputStream(Destroyer.class
220: .getResourceAsStream("/" + UninstallData.ROOTSCRIPT));
221:
222: result = in.readUTF();
223:
224: return result;
225: }
226:
227: /**
228: * Removes the given files as root for the given Users
229: *
230: * @param aRootScript The Script to exec as uninstall time by root.
231: */
232: private void execRootScript(String aRootScript) {
233: if (!"".equals(aRootScript)) {
234: Debug.log("Will Execute: " + aRootScript);
235:
236: try {
237: String result = ShellScript.execAndDelete(
238: new StringBuffer(aRootScript), File
239: .createTempFile(
240: this .getClass().getName(),
241: Long.toString(System
242: .currentTimeMillis())
243: + ".sh").toString());
244: Debug.log("Result: " + result);
245: } catch (Exception ex) {
246: Debug.log("Exeption during su remove: "
247: + ex.getMessage());
248: }
249: }
250: }
251:
252: /**
253: * Makes some reccursive cleanups.
254: *
255: * @param file The file to wipe.
256: * @exception Exception Description of the Exception
257: */
258: private void cleanup(File file) throws Exception {
259: if (file.isDirectory()) {
260: File[] files = file.listFiles();
261: int size = files.length;
262: for (int i = 0; i < size; i++)
263: cleanup(files[i]);
264: file.delete();
265: } else if (forceDestroy)
266: file.delete();
267:
268: }
269:
270: // CUSTOM ACTION STUFF -------------- start -----------------
271:
272: /**
273: * Load the defined uninstall listener objects.
274: *
275: * @return a list with the defined uninstall listeners
276: * @throws Exception
277: */
278: private List[] getListenerLists() throws Exception {
279: ArrayList[] uninstaller = new ArrayList[] { new ArrayList(),
280: new ArrayList() };
281: // Load listeners if exist
282: InputStream in;
283: ObjectInputStream objIn;
284: in = Destroyer.class
285: .getResourceAsStream("/uninstallerListeners");
286: if (in != null) {
287: objIn = new ObjectInputStream(in);
288: List listeners = (List) objIn.readObject();
289: objIn.close();
290: Iterator iter = listeners.iterator();
291: while (iter != null && iter.hasNext()) {
292: Class<UninstallerListener> clazz = (Class<UninstallerListener>) Class
293: .forName(((String) iter.next()));
294: UninstallerListener ul = clazz.newInstance();
295: if (ul.isFileListener())
296: uninstaller[1].add(ul);
297: uninstaller[0].add(ul);
298: }
299: }
300: return uninstaller;
301: }
302:
303: /**
304: * Informs all listeners.
305: *
306: * @param listeners list with the listener objects
307: * @param action identifier which callback should be called
308: * @param param parameter for the call
309: * @param handler the current progress handler
310: */
311:
312: private void informListeners(List listeners, int action,
313: Object param, AbstractUIProgressHandler handler) {
314: // Iterate the action list.
315: Iterator iter = listeners.iterator();
316: UninstallerListener il = null;
317: while (iter.hasNext()) {
318: try {
319: il = (UninstallerListener) iter.next();
320: switch (action) {
321: case UninstallerListener.BEFORE_DELETION:
322: il.beforeDeletion((List) param, handler);
323: break;
324: case UninstallerListener.AFTER_DELETION:
325: il.afterDeletion((List) param, handler);
326: break;
327: case UninstallerListener.BEFORE_DELETE:
328: il.beforeDelete((File) param, handler);
329: break;
330: case UninstallerListener.AFTER_DELETE:
331: il.afterDelete((File) param, handler);
332: break;
333: }
334: } catch (Throwable e) { // Catch it to prevent for a block of uninstallation.
335: handler
336: .emitError(
337: "Skipping custom action because exception caught during "
338: + il.getClass().getName(), e
339: .toString());
340: }
341: }
342: }
343:
344: // CUSTOM ACTION STUFF -------------- end -----------------
345:
346: }
|