All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.izforge.izpack.util.LibraryRemover Maven / Gradle / Ivy

There is a newer version: 5.2.3
Show newest version
/*
 * IzPack - Copyright 2001-2013 Julien Ponge, All Rights Reserved.
 *
 * http://izpack.org/
 * http://izpack.codehaus.org/
 *
 * Copyright 2006 Klaus Bartz
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.izforge.izpack.util;

import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.TreeSet;

/**
 * This class tries to remove a given list of files which are locked by this process. For this the
 * paths of the files are stored in a temporary file and a new process will be created. The class
 * files which are needed by the new process will be unpacked from the jar file under users temp dir
 * in a "sandbox". The new process receive the path of the temporary file and some other
 * information. After a wait intervall it reads the path file and removes all files which there are
 * listed. Next the created "sandbox" and the path file will be removed. This class uses the
 * characteristik of the system loader that jar files will be keeped open, simple class files will
 * be closed after loading a class. Therefore jar files are locked and cannot be deleted, class
 * files are not locked and deletable.
* The idea for this stuff is copied from Chadwick McHenry's SelfModifier in the uninstaller stuff * of IzPack. * * @author Klaus Bartz */ public class LibraryRemover { /** * All class files which are needed for the second process. All have to be in this installers * jar file. No slash in front should be used; no dot else slashes should be used; * extension (.class) will be required. */ private static final String[] SANDBOX_CONTENT = {"com/izforge/izpack/util/LibraryRemover.class"}; /** * System property name of base for log and sandbox of secondary processes. */ private static final String BASE_KEY = "lib.rem.base"; /** * System property name of phase (1, 2, or 3) indicator. */ private static final String PHASE_KEY = "self.mod.phase"; /** * Prefix of sandbox, path and log file. */ private static final String PREFIX = "InstallRemover"; /** * Phase of this process. */ private int phase = 0; /** * Log for phase 2, because we can't capture the stdio from them. */ private File logFile = null; /** * Directory which we extract too, invoke from, and finally delete. */ private File sandbox = null; /** * The file which contains the paths of the files to delete. */ private File specFile = null; /** * For logging time. */ private SimpleDateFormat isoPoint = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS"); /** * Also for logging time. */ private Date date = new Date(); /** * Constructor for both phases. Depending on the phase different initializing will be performed. * * @param phase for which an object should be created. * @throws IOException */ private LibraryRemover(int phase) throws IOException { this.phase = phase; if (phase == 1) { ProcessHelper.tryExecJava(); } else { logFile = new File(System.getProperty(BASE_KEY) + ".log"); specFile = new File(System.getProperty(BASE_KEY) + ".spec"); sandbox = new File(System.getProperty(BASE_KEY) + ".d"); } } /** * Entry point for phase 1. This class tries to remove all files given in the Vector. * * @param temporaryFileNames * @throws IOException */ public static void invoke(List temporaryFileNames) throws IOException { LibraryRemover self = new LibraryRemover(1); self.invoke1(temporaryFileNames); } /** * Internal invoke method for phase 1. * * @param temporaryFileNames list of paths of the files which should be removed * @throws IOException */ private void invoke1(List temporaryFileNames) throws IOException { // Initialize sandbox and log file to be unique, but similarly named while (true) { logFile = File.createTempFile(PREFIX, ".log"); String canonicalPath = logFile.getCanonicalPath(); specFile = new File(canonicalPath.substring(0, canonicalPath.length() - 4) + ".spec"); sandbox = new File(canonicalPath.substring(0, canonicalPath.length() - 4) + ".d"); // check if the similarly named directory is free if (!sandbox.exists()) { break; } logFile.delete(); } if (!sandbox.mkdir()) { throw new RuntimeException("Failed to create temp dir: " + sandbox); } sandbox = sandbox.getCanonicalFile(); logFile = logFile.getCanonicalFile(); OutputStream out = null; InputStream in = null; byte[] buf = new byte[5120]; int extracted = 0; // Write out the class files from the current installer jar into the sandbox. // This allows later to delete the classes because class files are deleteable // also the using process is running, jar files are not deletable in that // situation., for (String aSANDBOX_CONTENT : SANDBOX_CONTENT) { in = getClass().getResourceAsStream("/" + aSANDBOX_CONTENT); File outFile = new File(sandbox, aSANDBOX_CONTENT); File parent = outFile.getParentFile(); if (parent != null && !parent.exists()) { parent.mkdirs(); } out = new BufferedOutputStream(new FileOutputStream(outFile)); int n; while ((n = in.read(buf, 0, buf.length)) > 0) { out.write(buf, 0, n); } out.close(); extracted++; } // We write a file which contains the paths to remove. out = new BufferedOutputStream(new FileOutputStream(specFile)); BufferedWriter specWriter = new BufferedWriter(new OutputStreamWriter(out)); Iterator iter = temporaryFileNames.iterator(); while (iter.hasNext()) { specWriter.write(iter.next()); if (iter.hasNext()) { specWriter.newLine(); } } specWriter.flush(); out.close(); spawn(2); // finally, if all went well, the invoking process must exit log("library cleanup done"); // // IZPACK-276: // Do never call System.exit during a cleanup otherwise the correct exit value is lost! // System.exit(0); } /** * Returns an ArrayList of the files to delete. * * @return The files list. * @throws Exception Description of the Exception */ private ArrayList getFilesList() throws Exception { // Initialisations TreeSet files = new TreeSet(Collections.reverseOrder()); InputStream in = new FileInputStream(specFile); InputStreamReader inReader = new InputStreamReader(in); BufferedReader reader = new BufferedReader(inReader); // We read it String read = reader.readLine(); while (read != null) { files.add(new File(read)); read = reader.readLine(); } in.close(); // We return it return new ArrayList(files); } /** * Invoke methode for phase 2. */ private void invoke2() { try { // Give main program time to exit. try { Thread.sleep(1000); } catch (Exception x) { } ArrayList files = getFilesList(); // We destroy the files log("deleteing temporary dlls/shls"); for (File file : files) { file.delete(); if (file.exists()) { log(" deleting of " + file.getCanonicalPath() + " failed!!!"); } else { log(" " + file.getCanonicalPath()); } } // clean up and go log("deleteing sandbox"); deleteTree(sandbox); specFile.delete(); } catch (Exception e) { log(e); } } /** * Copied from com.izforge.izpack.uninstaller.SelfModifier. Little addaption for this class. * * @param nextPhase phase of the spawn * @return created process object * @throws IOException */ private Process spawn(int nextPhase) throws IOException { String base = logFile.getAbsolutePath(); base = base.substring(0, base.length() - 4); // invoke from tmpdir, passing target method arguments as args, and // SelfModifier parameters as sustem properties String[] javaCmd = new String[]{ProcessHelper.getJavaCommand(), "-classpath", sandbox.getAbsolutePath(), "-D" + BASE_KEY + "=" + base, "-D" + PHASE_KEY + "=" + nextPhase, getClass().getName()}; StringBuilder sb = new StringBuilder("Spawning phase "); sb.append(nextPhase).append(": "); for (String aJavaCmd : javaCmd) { sb.append("\n\t").append(aJavaCmd); } log(sb.toString()); // Just invoke it and let it go, the exception will be caught above return ProcessHelper.exec(javaCmd); } /** * Recursively delete a file structure. Copied from com.izforge.izpack.uninstaller.SelfModifier. * Little addaption to this class. * * @return command for spawning */ public static boolean deleteTree(File file) { if (file.isDirectory()) { File[] files = file.listFiles(); if (files != null) { for (File file1 : files) { deleteTree(file1); } } } return file.delete(); } public static void main(String[] args) { // Phase 2 removes given path list, sandbox and spec file. // Phase 3 as used in SelfModifier will be not needed here because // this class do not use a GUI which can call exit like the // one in SelfModifier. try { // all it's attributes are retrieved from system properties LibraryRemover librianRemover = new LibraryRemover(2); librianRemover.invoke2(); } catch (IOException ioe) { System.err.println("Error invoking a secondary phase"); System.err.println("Note that this program is only intended as a secondary process"); ioe.printStackTrace(); } } /** * ******************************************************************************************** * --------------------------------------------------------------------- Logging * --------------------------------------------------------------------- Copied from * com.izforge.izpack.uninstaller.SelfModifier. */ PrintStream log = null; private PrintStream checkLog() { try { if (log == null) { log = new PrintStream(new FileOutputStream(logFile.toString(), true)); } } catch (IOException x) { System.err.println("Phase " + phase + " log err: " + x.getMessage()); x.printStackTrace(); } date.setTime(System.currentTimeMillis()); return log; } private void log(Throwable t) { if (checkLog() != null) { log.println(isoPoint.format(date) + " Phase " + phase + ": " + t.getMessage()); t.printStackTrace(log); } } private void log(String msg) { if (checkLog() != null) { log.println(isoPoint.format(date) + " Phase " + phase + ": " + msg); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy