Bug 432589 - [enterprise] possibility to configure the delete-check when redeploying webapps
diff --git a/org.eclipse.virgo.web.war.deployer/src/main/java/org/eclipse/virgo/web/war/deployer/IOUtils.java b/org.eclipse.virgo.web.war.deployer/src/main/java/org/eclipse/virgo/web/war/deployer/IOUtils.java
new file mode 100755
index 0000000..4472932
--- /dev/null
+++ b/org.eclipse.virgo.web.war.deployer/src/main/java/org/eclipse/virgo/web/war/deployer/IOUtils.java
@@ -0,0 +1,157 @@
+/*******************************************************************************
+ * Copyright (c) 2012 SAP AG
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *   SAP AG - initial contribution
+ *******************************************************************************/
+package org.eclipse.virgo.web.war.deployer;
+
+import java.io.BufferedInputStream;
+import java.io.EOFException;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Enumeration;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+
+public class IOUtils {
+	private static final char SEPARATOR1 = '/';
+	private static final char SEPARATOR2 = '\\';
+
+	public static boolean recursiveDelete(File root) {
+		if (root == null) {
+			return true;
+		}
+
+		if (root.isDirectory()) {
+			File[] files = root.listFiles();
+			if (files != null) {
+				for (int i = 0; i < files.length; i++) {
+					File file = files[i];
+					if (file.isDirectory()) {
+						recursiveDelete(file);
+					} else {
+						file.delete();
+					}
+				}
+			}
+		}
+
+		return root.delete();
+	}// end of recursiveDelete(File root)
+
+	public static void extractJar(File srcFile, File destDir) throws IOException {
+		if (srcFile == null)
+			throw new IllegalArgumentException("Source file is null.");
+
+		if (destDir == null)
+			throw new IllegalArgumentException("Destination directory is null.");
+
+		if (!srcFile.isFile() || !srcFile.canRead())
+			throw new IllegalArgumentException("Source file must be a readable file [" + srcFile + "].");
+
+		if (destDir.exists())
+			recursiveDelete(destDir);
+
+		destDir.mkdirs();
+		if (!destDir.exists())
+			throw new IOException("Could not create destination directory [" + destDir + "].");
+
+		JarFile zip = new JarFile(srcFile);
+		try {
+			Enumeration<JarEntry> enumZipEntries = zip.entries();
+			String entryName = null;
+			JarEntry theEntry = null;
+
+			while (enumZipEntries.hasMoreElements()) {
+				theEntry = (JarEntry) enumZipEntries.nextElement();
+				entryName = theEntry.getName();
+				if (entryName != null) {
+					extractFile(zip, entryName, destDir);
+				}
+			}
+		} finally {
+			if (zip != null) {
+				try {
+					zip.close();
+				} catch (Exception e) {
+				}
+			}
+		}
+	}// end of extractJar(File srcFile, File destDir)
+
+	private static void extractFile(JarFile zipf, String entryName, File dir) throws IOException {
+		if (zipf == null)
+			throw new IllegalArgumentException("Cannot extract zip file, that is null.");
+
+		if (entryName == null)
+			throw new IllegalArgumentException("Cannot extract zip entry, that is null.");
+
+		if (dir == null)
+			throw new IllegalArgumentException("Cannot extract zip file to directory, that is null.");
+
+		String fName = entryName;
+		fName = fName.replace(SEPARATOR1, File.separatorChar);
+		fName = fName.replace(SEPARATOR2, File.separatorChar);
+		File f = new File(dir, fName);
+
+		if (f.isDirectory()) {
+			return;
+		}
+
+		File parent = f.getParentFile();
+		parent.mkdirs();
+		JarEntry entry = (JarEntry) zipf.getEntry(entryName);
+
+		if (entry == null) {
+			entry = (JarEntry) zipf.getEntry(entryName.replace(SEPARATOR2, SEPARATOR1));
+		}
+
+		if (entry == null) {
+			entry = (JarEntry) zipf.getEntry(entryName.replace(SEPARATOR1, SEPARATOR2));
+		}
+
+		JarEntry tempent = new JarEntry(entry);
+
+		if (tempent == null || tempent.isDirectory()) {
+			return;
+		}
+
+		InputStream in = new BufferedInputStream(zipf.getInputStream(tempent));
+		FileOutputStream fos = new FileOutputStream(f);
+		int count = 1024;
+		byte[] buff = new byte[count];
+		try {
+			while (count == 1024) {
+				count = in.read(buff);
+
+				if (count > 0) {
+					fos.write(buff, 0, count);
+				}
+			}
+		} catch (EOFException ex) {
+			buff = new byte[(int) tempent.getSize()];
+			in.read(buff);
+		} finally {
+			if (in != null) {
+				try {
+					in.close();
+				} catch (Exception e) {
+				}
+			}
+			if (fos != null) {
+				try {
+					fos.close();
+				} catch (Exception e) {
+				}
+			}
+		}
+	}// end of extractFile(JarFile zipf, String entryName, File dir)
+
+}// end of class
diff --git a/org.eclipse.virgo.web.war.deployer/src/main/java/org/eclipse/virgo/web/war/deployer/WARDeployer.java b/org.eclipse.virgo.web.war.deployer/src/main/java/org/eclipse/virgo/web/war/deployer/WARDeployer.java
index 4740097..0ac08bd 100644
--- a/org.eclipse.virgo.web.war.deployer/src/main/java/org/eclipse/virgo/web/war/deployer/WARDeployer.java
+++ b/org.eclipse.virgo.web.war.deployer/src/main/java/org/eclipse/virgo/web/war/deployer/WARDeployer.java
@@ -50,6 +50,7 @@
 import org.eclipse.virgo.util.io.IOUtils;
 import org.eclipse.virgo.util.io.JarUtils;
 import org.eclipse.virgo.util.io.PathReference;
+import org.eclipse.virgo.util.io.FatalIOException;
 import org.eclipse.virgo.util.osgi.manifest.BundleManifest;
 import org.eclipse.virgo.util.osgi.manifest.BundleManifestFactory;
 import org.osgi.framework.Bundle;
@@ -126,6 +127,9 @@
 	
 	private static final long CHECK_INTERVAL = 1000;
 
+    private static final boolean UNPACK_TO_DESTRUCTIVE = 
+        Boolean.parseBoolean(System.getProperty("org.eclipse.virgo.web.war.deployer.unpackToDestructive", "true"));
+
     private EventLogger eventLogger;
 
     private BundleInfosUpdater bundleInfosUpdaterUtil;
@@ -188,7 +192,16 @@
         final Bundle installed;
         try {
             // Extract the war file to the webapps directory. Use always JarUtils.unpackToDestructive.
-            JarUtils.unpackToDestructive(new PathReference(deployedFile), new PathReference(warDir));
+            try {
+                JarUtils.unpackToDestructive(new PathReference(deployedFile), new PathReference(warDir));
+            } catch (FatalIOException e) {
+                if (UNPACK_TO_DESTRUCTIVE) {
+                    throw e;
+                } else {
+                    this.logger.warn("Cannot delete directory '" + warDir + "'.", e);
+                    org.eclipse.virgo.web.war.deployer.IOUtils.extractJar(deployedFile, warDir);
+                }
+            }
             // make the manifest transformation in the unpacked location
             transformUnpackedManifest(warDir, warName);
 
@@ -388,7 +401,16 @@
             		loader.close();
             	}
                 // Extract the war file to the webapps directory. Use always JarUtils.unpackToDestructive.
-                JarUtils.unpackToDestructive(new PathReference(updatedFile), new PathReference(warDir));
+                try {
+                    JarUtils.unpackToDestructive(new PathReference(updatedFile), new PathReference(warDir));
+                } catch (FatalIOException e) {
+                    if (UNPACK_TO_DESTRUCTIVE) {
+                        throw e;
+                    } else {
+                        this.logger.warn("Cannot delete directory '" + warDir + "'.", e);
+                        org.eclipse.virgo.web.war.deployer.IOUtils.extractJar(updatedFile, warDir);
+                    }
+                }
                 // make the manifest transformation in the unpacked location
                 transformUnpackedManifest(warDir, warName);
                 this.eventLogger.log(WARDeployerLogEvents.NANO_UPDATING, bundle.getSymbolicName(), bundle.getVersion());
@@ -718,7 +740,16 @@
         final Bundle installed;
         try {
             // Extract the war file to the webapps directory. Use always JarUtils.unpackToDestructive.
-            JarUtils.unpackToDestructive(new PathReference(deployedFile), new PathReference(warDir));
+            try {
+                JarUtils.unpackToDestructive(new PathReference(deployedFile), new PathReference(warDir));
+            } catch (FatalIOException e) {
+                if (UNPACK_TO_DESTRUCTIVE) {
+                    throw e;
+                } else {
+                    this.logger.warn("Cannot delete directory '" + warDir + "'.", e);
+                    org.eclipse.virgo.web.war.deployer.IOUtils.extractJar(deployedFile, warDir);
+                }
+            }
             // make the manifest transformation in the unpacked location
             transformUnpackedManifest(warDir, warName);
             // install the bundle