001: /*
002: * Copyright 1999,2004 The Apache Software Foundation.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.apache.catalina.startup;
018:
019: import java.io.BufferedOutputStream;
020: import java.io.File;
021: import java.io.FileOutputStream;
022: import java.io.InputStream;
023: import java.io.IOException;
024: import java.net.JarURLConnection;
025: import java.net.URL;
026: import java.util.Enumeration;
027: import java.util.jar.JarEntry;
028: import java.util.jar.JarFile;
029:
030: import org.apache.catalina.Host;
031: import org.apache.catalina.Logger;
032: import org.apache.catalina.core.StandardHost;
033: import org.apache.catalina.util.StringManager;
034:
035: /**
036: * Expand out a WAR in a Host's appBase.
037: *
038: * @author Craig R. McClanahan
039: * @author Remy Maucherat
040: * @author Glenn L. Nielsen
041: * @version $Revision: 1.5 $
042: */
043:
044: public class ExpandWar {
045:
046: /**
047: * The string resources for this package.
048: */
049: protected static final StringManager sm = StringManager
050: .getManager(Constants.Package);
051:
052: /**
053: * Expand the WAR file found at the specified URL into an unpacked
054: * directory structure, and return the absolute pathname to the expanded
055: * directory.
056: *
057: * @param host Host war is being installed for
058: * @param war URL of the web application archive to be expanded
059: * (must start with "jar:")
060: *
061: * @exception IllegalArgumentException if this is not a "jar:" URL
062: * @exception IOException if an input/output error was encountered
063: * during expansion
064: */
065: public static String expand(Host host, URL war) throws IOException {
066:
067: int debug = 0;
068: Logger logger = host.getLogger();
069:
070: if (host instanceof StandardHost) {
071: debug = ((StandardHost) host).getDebug();
072: }
073:
074: // Calculate the directory name of the expanded directory
075: if (debug >= 1) {
076: logger.log("expand(" + war.toString() + ")");
077: }
078: String pathname = war.toString().replace('\\', '/');
079: if (pathname.endsWith("!/")) {
080: pathname = pathname.substring(0, pathname.length() - 2);
081: }
082: int period = pathname.lastIndexOf('.');
083: if (period >= pathname.length() - 4)
084: pathname = pathname.substring(0, period);
085: int slash = pathname.lastIndexOf('/');
086: if (slash >= 0) {
087: pathname = pathname.substring(slash + 1);
088: }
089: if (debug >= 1) {
090: logger.log(" Proposed directory name: " + pathname);
091: }
092: return expand(host, war, pathname);
093:
094: }
095:
096: /**
097: * Expand the WAR file found at the specified URL into an unpacked
098: * directory structure, and return the absolute pathname to the expanded
099: * directory.
100: *
101: * @param host Host war is being installed for
102: * @param war URL of the web application archive to be expanded
103: * (must start with "jar:")
104: * @param pathname Context path name for web application
105: *
106: * @exception IllegalArgumentException if this is not a "jar:" URL
107: * @exception IOException if an input/output error was encountered
108: * during expansion
109: */
110: public static String expand(Host host, URL war, String pathname)
111: throws IOException {
112:
113: int debug = 0;
114: Logger logger = host.getLogger();
115:
116: if (host instanceof StandardHost) {
117: debug = ((StandardHost) host).getDebug();
118: }
119:
120: // Make sure that there is no such directory already existing
121: File appBase = new File(host.getAppBase());
122: if (!appBase.isAbsolute()) {
123: appBase = new File(System.getProperty("catalina.base"),
124: host.getAppBase());
125: }
126: if (!appBase.exists() || !appBase.isDirectory()) {
127: throw new IOException(sm.getString("hostConfig.appBase",
128: appBase.getAbsolutePath()));
129: }
130: File docBase = new File(appBase, pathname);
131: if (docBase.exists()) {
132: // War file is already installed
133: return (docBase.getAbsolutePath());
134: }
135:
136: // Create the new document base directory
137: docBase.mkdir();
138: if (debug >= 2) {
139: logger.log(" Have created expansion directory "
140: + docBase.getAbsolutePath());
141: }
142:
143: // Expand the WAR into the new document base directory
144: JarURLConnection juc = (JarURLConnection) war.openConnection();
145: juc.setUseCaches(false);
146: JarFile jarFile = null;
147: InputStream input = null;
148: try {
149: jarFile = juc.getJarFile();
150: if (debug >= 2) {
151: logger.log(" Have opened JAR file successfully");
152: }
153: Enumeration jarEntries = jarFile.entries();
154: if (debug >= 2) {
155: logger.log(" Have retrieved entries enumeration");
156: }
157: while (jarEntries.hasMoreElements()) {
158: JarEntry jarEntry = (JarEntry) jarEntries.nextElement();
159: String name = jarEntry.getName();
160: if (debug >= 2) {
161: logger.log(" Am processing entry " + name);
162: }
163: int last = name.lastIndexOf('/');
164: if (last >= 0) {
165: File parent = new File(docBase, name.substring(0,
166: last));
167: if (debug >= 2) {
168: logger.log(" Creating parent directory "
169: + parent);
170: }
171: parent.mkdirs();
172: }
173: if (name.endsWith("/")) {
174: continue;
175: }
176: if (debug >= 2) {
177: logger.log(" Creating expanded file " + name);
178: }
179: input = jarFile.getInputStream(jarEntry);
180: expand(input, docBase, name);
181: input.close();
182: input = null;
183: }
184: } catch (IOException e) {
185: // If something went wrong, delete expanded dir to keep things
186: // clean
187: deleteDir(docBase);
188: throw e;
189: } finally {
190: if (input != null) {
191: try {
192: input.close();
193: } catch (Throwable t) {
194: ;
195: }
196: input = null;
197: }
198: if (jarFile != null) {
199: try {
200: jarFile.close();
201: } catch (Throwable t) {
202: ;
203: }
204: jarFile = null;
205: }
206: }
207:
208: // Return the absolute path to our new document base directory
209: return (docBase.getAbsolutePath());
210:
211: }
212:
213: /**
214: * Delete the specified directory, including all of its contents and
215: * subdirectories recursively.
216: *
217: * @param dir File object representing the directory to be deleted
218: */
219: public static void deleteDir(File dir) {
220:
221: String files[] = dir.list();
222: if (files == null) {
223: files = new String[0];
224: }
225: for (int i = 0; i < files.length; i++) {
226: File file = new File(dir, files[i]);
227: if (file.isDirectory()) {
228: deleteDir(file);
229: } else {
230: file.delete();
231: }
232: }
233: dir.delete();
234:
235: }
236:
237: /**
238: * Expand the specified input stream into the specified directory, creating
239: * a file named from the specified relative path.
240: *
241: * @param input InputStream to be copied
242: * @param docBase Document base directory into which we are expanding
243: * @param name Relative pathname of the file to be created
244: *
245: * @exception IOException if an input/output error occurs
246: */
247: protected static void expand(InputStream input, File docBase,
248: String name) throws IOException {
249:
250: File file = new File(docBase, name);
251: BufferedOutputStream output = null;
252: try {
253: output = new BufferedOutputStream(
254: new FileOutputStream(file));
255: byte buffer[] = new byte[2048];
256: while (true) {
257: int n = input.read(buffer);
258: if (n <= 0)
259: break;
260: output.write(buffer, 0, n);
261: }
262: } finally {
263: if (output != null) {
264: try {
265: output.close();
266: } catch (IOException e) {
267: // Ignore
268: }
269: }
270: }
271:
272: }
273:
274: }
|