我在项目的开发过程中,发现Tomcat解压war 的一点例外。
现象如下:
使用ANT工具把web应用程序打包为war文件。然后把war文件放到tomcat的webapps,让tomcat自己解压。结果出现解压的web应用程序文件丢失。使用rar工具打开war文件。文件都齐全。怎么有这种现象呢??查看tomcat的log文档。发现在解压war文档NullpointException.我升级tomcat到5.0还是出现这种现象。
jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/startup/HostConfig.java
解决方法:
我从tomcat网站下载了catalina 的原代码,进行分析。发现是在解压war文件出现input为null,而 input= jar.getInputStream(entry);然后提高tomcat的debug级别。可以在tomcat的log文档看到tomcat解压war文档的过程。发现如果某些文件名为???.txt,经检查发现原来这个文件的文件名为汉字。
噢!才发现war文件在解压的过程中无法处理汉字的文件名。(因为找不到文件名为???.txt的文件而导致null例外。原来这个文件是个注释文档),所以在使用ant把web应用程序打包为war文件,一定要把文件名为汉字的文件去掉。使用Forte for java的IDE工具把web应用程序打包为war文件会不包含这些文件名为汉字的文件
。
下面是部分war文档解压的部分代码
代码采自jakarta.org
类HostConfig.java
jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/startup/HostConfig.java
解决方法:
我从tomcat网站下载了catalina 的原代码,进行分析。发现是在解压war文件出现input为null,而 input= jar.getInputStream(entry);然后提高tomcat的debug级别。可以在tomcat的log文档看到tomcat解压war文档的过程。发现如果某些文件名为???.txt,经检查发现原来这个文件的文件名为汉字。
噢!才发现war文件在解压的过程中无法处理汉字的文件名。(因为找不到文件名为???.txt的文件而导致null例外。原来这个文件是个注释文档),所以在使用ant把web应用程序打包为war文件,一定要把文件名为汉字的文件去掉。使用Forte for java的IDE工具把web应用程序打包为war文件会不包含这些文件名为汉字的文件
。
下面是部分war文档解压的部分代码
代码采自jakarta.org
类HostConfig.java
jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/startup/HostConfig.java
- protected void deployWARs(File appBase, String[] files) {
- for (int i = 0; i < files.length; i++) {
- if (files[i].equalsIgnoreCase("META-INF"))
- continue;
- if (files[i].equalsIgnoreCase("WEB-INF"))
- continue;
- if (deployed.contains(files[i]))
- continue;
- File dir = new File(appBase, files[i]);
- if (files[i].toLowerCase().endsWith(".war")) {
- deployed.add(files[i]);
- // Calculate the context path and make sure it is unique
- String contextPath = "/" + files[i];
- int period = contextPath.lastIndexOf(".");
- if (period >= 0)
- contextPath = contextPath.substring(0, period);
- if (contextPath.equals("/ROOT"))
- contextPath = "";
- if (host.findChild(contextPath) != null)
- continue;
- // Checking for a nested /META-INF/context.xml
- JarFile jar = null;
- JarEntry entry = null;
- InputStream istream = null;
- BufferedOutputStream ostream = null;
- File xml = new File
- (configBase, files[i].substring
- (0, files[i].lastIndexOf(".")) + ".xml");
- if (!xml.exists()) {
- try {
- jar = new JarFile(dir);
- entry = jar.getJarEntry("META-INF/context.xml");
- if (entry != null) {
- istream = jar.getInputStream(entry);
- ostream =
- new BufferedOutputStream
- (new FileOutputStream(xml), 1024);
- byte buffer[] = new byte[1024];
- while (true) {
- int n = istream.read(buffer);
- if (n < 0) {
- break;
- }
- ostream.write(buffer, 0, n);
- }
- ostream.flush();
- ostream.close();
- ostream = null;
- istream.close();
- istream = null;
- entry = null;
- jar.close();
- jar = null;
- deployDescriptors(configBase(), configBase.list());
- return;
- }
- } catch (Exception e) {
- // Ignore and continue
- if (ostream != null) {
- try {
- ostream.close();
- } catch (Throwable t) {
- ;
- }
- ostream = null;
- }
- if (istream != null) {
- try {
- istream.close();
- } catch (Throwable t) {
- ;
- }
- istream = null;
- }
- entry = null;
- if (jar != null) {
- try {
- jar.close();
- } catch (Throwable t) {
- ;
- }
- jar = null;
- }
- }
- }
- if (isUnpackWARs()) {
- // Expand and deploy this application as a directory
- log.debug(sm.getString("hostConfig.expand", files[i]));
- URL url = null;
- String path = null;
- try {
- url = new URL("jar:file:" +
- dir.getCanonicalPath() + "!/");
- path = ExpandWar.expand(host, url);
- } catch (IOException e) {
- // JAR decompression failure
- log.warn(sm.getString
- ("hostConfig.expand.error", files[i]));
- continue;
- } catch (Throwable t) {
- log.error(sm.getString
- ("hostConfig.expand.error", files[i]), t);
- continue;
- }
- try {
- if (path != null) {
- url = new URL("file:" + path);
- ((Deployer) host).install(contextPath, url);
- }
- } catch (Throwable t) {
- log.error(sm.getString
- ("hostConfig.expand.error", files[i]), t);
- }
- } else {
- // Deploy the application in this WAR file
- log.info(sm.getString("hostConfig.deployJar", files[i]));
- try {
- URL url = new URL("file", null,
- dir.getCanonicalPath());
- url = new URL("jar:" + url.toString() + "!/");
- ((Deployer) host).install(contextPath, url);
- } catch (Throwable t) {
- log.error(sm.getString("hostConfig.deployJar.error",
- files[i]), t);
- }
- }
- }
- }
- }
类 ExpandWar.java
jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/startup/ExpandWar.java
- package org.apache.catalina.startup;
- import java.io.BufferedOutputStream;
- import java.io.File;
- import java.io.FileOutputStream;
- import java.io.InputStream;
- import java.io.IOException;
- import java.net.JarURLConnection;
- import java.net.URL;
- import java.util.Enumeration;
- import java.util.jar.JarEntry;
- import java.util.jar.JarFile;
- import org.apache.catalina.Host;
- import org.apache.catalina.Logger;
- import org.apache.catalina.core.StandardHost;
- import org.apache.catalina.util.StringManager;
- /**
- * Expand out a WAR in a Host‘s appBase.
- *
- * @author Craig R. McClanahan
- * @author Remy Maucherat
- * @author Glenn L. Nielsen
- * @version $Revision: 1.4 $
- */
- public class ExpandWar {
- /**
- * 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 {
- int debug = 0;
- Logger logger = host.getLogger();
- if (host instanceof StandardHost) {
- debug = ((StandardHost) host).getDebug();
- }
- // Calculate the directory name of the expanded directory
- if (debug >= 1) {
- logger.log("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 (debug >= 1) {
- logger.log(" 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 {
- int debug = 0;
- Logger logger = host.getLogger();
- if (host instanceof StandardHost) {
- debug = ((StandardHost) host).getDebug();
- }
- // 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();
- if (debug >= 2) {
- logger.log(" Have created expansion directory " +
- docBase.getAbsolutePath());
- }
- // 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();
- if (debug >= 2) {
- logger.log(" Have opened JAR file successfully");
- }
- Enumeration jarEntries = jarFile.entries();
- if (debug >= 2) {
- logger.log(" Have retrieved entries enumeration");
- }
- while (jarEntries.hasMoreElements()) {
- JarEntry jarEntry = (JarEntry) jarEntries.nextElement();
- String name = jarEntry.getName();
- if (debug >= 2) {
- logger.log(" Am processing entry " + name);
- }
- int last = name.lastIndexOf(‘/‘);
- if (last >= 0) {
- File parent = new File(docBase,
- name.substring(0, last));
- if (debug >= 2) {
- logger.log(" Creating parent directory " + parent);
- }
- parent.mkdirs();
- }
- if (name.endsWith("/")) {
- continue;
- }
- if (debug >= 2) {
- logger.log(" Creating expanded file " + name);
- }
- input = jarFile.getInputStream(jarEntry);
- expand(input, docBase, name);
- 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());
- }
- /**
- * Delete the specified directory, including all of its contents and
- * subdirectories recursively.
- *
- * @param dir File object representing the directory to be deleted
- */
- public static void 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();
- }
- }
- 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
- *
- * @exception IOException if an input/output error occurs
- */
- protected static void 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) {
- [b]int n = input.read(buffer);[/b]
- if (n <= 0)
- break;
- output.write(buffer, 0, n);
- }
- } finally {
- if (output != null) {
- try {
- output.close();
- } catch (IOException e) {
- // Ignore
- }
- }
- }
- }
- }