| /* |
| * Copyright 1999,2004 The Apache Software Foundation. |
| * |
| * 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 org.apache.catalina.startup; |
| |
| import java.io.BufferedOutputStream; |
| import java.io.File; |
| import java.io.FileInputStream; |
| import java.io.FileOutputStream; |
| import java.io.InputStream; |
| import java.io.IOException; |
| import java.net.JarURLConnection; |
| import java.net.URL; |
| import java.nio.channels.FileChannel; |
| import java.util.Enumeration; |
| import java.util.jar.JarEntry; |
| import java.util.jar.JarFile; |
| |
| import org.apache.catalina.Host; |
| import org.apache.catalina.util.StringManager; |
| import org.apache.commons.logging.Log; |
| import org.apache.commons.logging.LogFactory; |
| |
| /** |
| * Expand out a WAR in a Host's appBase. |
| * |
| * @author Craig R. McClanahan |
| * @author Remy Maucherat |
| * @author Glenn L. Nielsen |
| * @version $Revision$ |
| */ |
| |
| public class ExpandWar { |
| |
| private static Log log = LogFactory.getLog(ExpandWar.class); |
| |
| /** |
| * The string resources for this package. |
| */ |
| protected static final StringManager sm = |
| StringManager.getManager(Constants.Package); |
| |
| |
| /** |
| * Expand the WAR file found at the specified URL into an unpacked |
| * directory structure, and return the absolute pathname to the expanded |
| * directory. |
| * |
| * @param host Host war is being installed for |
| * @param war URL of the web application archive to be expanded |
| * (must start with "jar:") |
| * |
| * @exception IllegalArgumentException if this is not a "jar:" URL |
| * @exception IOException if an input/output error was encountered |
| * during expansion |
| */ |
| public static String expand(Host host, URL war) |
| throws IOException { |
| |
| // Calculate the directory name of the expanded directory |
| if (host.getLogger().isDebugEnabled()) { |
| host.getLogger().debug("expand(" + war.toString() + ")"); |
| } |
| String pathname = war.toString().replace('\\', '/'); |
| if (pathname.endsWith("!/")) { |
| pathname = pathname.substring(0, pathname.length() - 2); |
| } |
| int period = pathname.lastIndexOf('.'); |
| if (period >= pathname.length() - 4) |
| pathname = pathname.substring(0, period); |
| int slash = pathname.lastIndexOf('/'); |
| if (slash >= 0) { |
| pathname = pathname.substring(slash + 1); |
| } |
| if (host.getLogger().isDebugEnabled()) { |
| host.getLogger().debug(" Proposed directory name: " + pathname); |
| } |
| return expand(host, war, pathname); |
| |
| } |
| |
| |
| /** |
| * Expand the WAR file found at the specified URL into an unpacked |
| * directory structure, and return the absolute pathname to the expanded |
| * directory. |
| * |
| * @param host Host war is being installed for |
| * @param war URL of the web application archive to be expanded |
| * (must start with "jar:") |
| * @param pathname Context path name for web application |
| * |
| * @exception IllegalArgumentException if this is not a "jar:" URL |
| * @exception IOException if an input/output error was encountered |
| * during expansion |
| */ |
| public static String expand(Host host, URL war, String pathname) |
| throws IOException { |
| |
| // Make sure that there is no such directory already existing |
| File appBase = new File(host.getAppBase()); |
| if (!appBase.isAbsolute()) { |
| appBase = new File(System.getProperty("catalina.base"), |
| host.getAppBase()); |
| } |
| if (!appBase.exists() || !appBase.isDirectory()) { |
| throw new IOException |
| (sm.getString("hostConfig.appBase", |
| appBase.getAbsolutePath())); |
| } |
| File docBase = new File(appBase, pathname); |
| if (docBase.exists()) { |
| // War file is already installed |
| return (docBase.getAbsolutePath()); |
| } |
| |
| // Create the new document base directory |
| docBase.mkdir(); |
| |
| // Expand the WAR into the new document base directory |
| JarURLConnection juc = (JarURLConnection) war.openConnection(); |
| juc.setUseCaches(false); |
| JarFile jarFile = null; |
| InputStream input = null; |
| try { |
| jarFile = juc.getJarFile(); |
| Enumeration jarEntries = jarFile.entries(); |
| while (jarEntries.hasMoreElements()) { |
| JarEntry jarEntry = (JarEntry) jarEntries.nextElement(); |
| String name = jarEntry.getName(); |
| int last = name.lastIndexOf('/'); |
| if (last >= 0) { |
| File parent = new File(docBase, |
| name.substring(0, last)); |
| parent.mkdirs(); |
| } |
| if (name.endsWith("/")) { |
| continue; |
| } |
| input = jarFile.getInputStream(jarEntry); |
| |
| // Bugzilla 33636 |
| File expandedFile = expand(input, docBase, name); |
| long lastModified = jarEntry.getTime(); |
| if ((lastModified != -1) && (lastModified != 0) && (expandedFile != null)) { |
| expandedFile.setLastModified(lastModified); |
| } |
| |
| input.close(); |
| input = null; |
| } |
| } catch (IOException e) { |
| // If something went wrong, delete expanded dir to keep things |
| // clean |
| deleteDir(docBase); |
| throw e; |
| } finally { |
| if (input != null) { |
| try { |
| input.close(); |
| } catch (Throwable t) { |
| ; |
| } |
| input = null; |
| } |
| if (jarFile != null) { |
| try { |
| jarFile.close(); |
| } catch (Throwable t) { |
| ; |
| } |
| jarFile = null; |
| } |
| } |
| |
| // Return the absolute path to our new document base directory |
| return (docBase.getAbsolutePath()); |
| |
| } |
| |
| |
| /** |
| * Copy the specified file or directory to the destination. |
| * |
| * @param src File object representing the source |
| * @param dest File object representing the destination |
| */ |
| public static boolean copy(File src, File dest) { |
| |
| boolean result = true; |
| |
| String files[] = null; |
| if (src.isDirectory()) { |
| files = src.list(); |
| result = dest.mkdir(); |
| } else { |
| files = new String[1]; |
| files[0] = ""; |
| } |
| if (files == null) { |
| files = new String[0]; |
| } |
| for (int i = 0; (i < files.length) && result; i++) { |
| File fileSrc = new File(src, files[i]); |
| File fileDest = new File(dest, files[i]); |
| if (fileSrc.isDirectory()) { |
| result = copy(fileSrc, fileDest); |
| } else { |
| FileChannel ic = null; |
| FileChannel oc = null; |
| try { |
| ic = (new FileInputStream(fileSrc)).getChannel(); |
| oc = (new FileOutputStream(fileDest)).getChannel(); |
| ic.transferTo(0, ic.size(), oc); |
| } catch (IOException e) { |
| log.error(sm.getString |
| ("expandWar.copy", fileSrc, fileDest), e); |
| result = false; |
| } finally { |
| if (ic != null) { |
| try { |
| ic.close(); |
| } catch (IOException e) { |
| } |
| } |
| if (oc != null) { |
| try { |
| oc.close(); |
| } catch (IOException e) { |
| } |
| } |
| } |
| } |
| } |
| return result; |
| |
| } |
| |
| |
| /** |
| * Delete the specified directory, including all of its contents and |
| * subdirectories recursively. |
| * |
| * @param dir File object representing the directory to be deleted |
| */ |
| public static boolean delete(File dir) { |
| if (dir.isDirectory()) { |
| return deleteDir(dir); |
| } else { |
| return dir.delete(); |
| } |
| } |
| |
| |
| /** |
| * Delete the specified directory, including all of its contents and |
| * subdirectories recursively. |
| * |
| * @param dir File object representing the directory to be deleted |
| */ |
| public static boolean deleteDir(File dir) { |
| |
| String files[] = dir.list(); |
| if (files == null) { |
| files = new String[0]; |
| } |
| for (int i = 0; i < files.length; i++) { |
| File file = new File(dir, files[i]); |
| if (file.isDirectory()) { |
| deleteDir(file); |
| } else { |
| file.delete(); |
| } |
| } |
| return dir.delete(); |
| |
| } |
| |
| |
| /** |
| * Expand the specified input stream into the specified directory, creating |
| * a file named from the specified relative path. |
| * |
| * @param input InputStream to be copied |
| * @param docBase Document base directory into which we are expanding |
| * @param name Relative pathname of the file to be created |
| * @return A handle to the expanded File |
| * |
| * @exception IOException if an input/output error occurs |
| */ |
| protected static File expand(InputStream input, File docBase, String name) |
| throws IOException { |
| |
| File file = new File(docBase, name); |
| BufferedOutputStream output = null; |
| try { |
| output = |
| new BufferedOutputStream(new FileOutputStream(file)); |
| byte buffer[] = new byte[2048]; |
| while (true) { |
| int n = input.read(buffer); |
| if (n <= 0) |
| break; |
| output.write(buffer, 0, n); |
| } |
| } finally { |
| if (output != null) { |
| try { |
| output.close(); |
| } catch (IOException e) { |
| // Ignore |
| } |
| } |
| } |
| |
| return file; |
| } |
| |
| |
| } |