archive.java

来自「OSGI这是一个中间件,与UPNP齐名,是用于移植到嵌入式平台之上」· Java 代码 · 共 666 行 · 第 1/2 页

JAVA
666
字号
/* * Copyright (c) 2003-2004, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright *   notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above *   copyright notice, this list of conditions and the following *   disclaimer in the documentation and/or other materials *   provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its *   contributors may be used to endorse or promote products derived *   from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */package org.knopflerfish.framework.bundlestorage.file;import org.knopflerfish.framework.*;import org.osgi.framework.Constants;import java.io.*;import java.net.*;import java.security.*;import java.util.StringTokenizer;import java.util.Iterator;import java.util.jar.*;import java.util.zip.*;/** * JAR file handling. * * @author Jan Stein */class Archive {  /**   * Base for filename used to store copy of archive.   */  final private static String ARCHIVE = "jar";  /**   * Directory base name to use for sub-archives.   */  final private static String SUBDIR = "sub";  // Directory where optional bundle files are stored  // these need not be unpacked locally  final private static String OSGI_OPT_DIR = "OSGI-OPT/";  /**   * Controls if we should try to unpack bundles with sub-jars and   * native code.   */  final private static boolean unpack = new Boolean(System.getProperty("org.knopflerfish.framework.bundlestorage.file.unpack", "true")).booleanValue();  /**   * Controls if file: URLs should be referenced only, not copied   * to bundle storage dir   */  boolean bReference = new Boolean(System.getProperty("org.knopflerfish.framework.bundlestorage.file.reference", "false")).booleanValue();  /**   * File handle for file that contains current archive.   */  private File file;  /**   * JAR file handle for file that contains current archive.   */  private ZipFile jar;  /**   * Archives manifest   */  Manifest manifest = null;  /**   * JAR Entry handle for file that contains current archive.   * If not null, it is a sub jar instead.   */  private ZipEntry subJar = null;  /**   * Create an Archive based on contents of an InputStream,   * the archive is saved as local copy in the specified   * directory.   *   * @param dir Directory to save data in.   * @param rev Revision of bundle content (used for updates).   * @param is Jar file data in an InputStream.   * @param url URL to use to CodeSource.   */  Archive(File dir, int rev, InputStream is) throws IOException {    this(dir, rev, is, null);  }  File refFile = null;  Archive(File dir, int rev, InputStream is, URL source) throws IOException {    BufferedInputStream bis = new BufferedInputStream(is, 8192);    JarInputStream ji = null;    boolean doUnpack = false;    // Handle reference: URLs by overriding global flag    if(source != null && "reference".equals(source.getProtocol())) {      bReference = true;    }    if (unpack) {      bis.mark(8192);      ji = new JarInputStream(bis);      manifest = ji.getManifest();      if (manifest != null) {	if (checkManifest()) {	  doUnpack = true;	} else {	  try {	    bis.reset();	  } catch (IOException fail) {	    doUnpack = true;	  }	}      } else {	// The manifest is probably not first in the file. We do not	// unpack to minimize disk footprint. Should we warn?	try {	  bis.reset();	} catch (IOException fail) {	  doUnpack = true;	}      }    }    file = new File(dir, ARCHIVE + rev);    if (doUnpack) {      File f = new File(file, "META-INF");      f.mkdirs();      BufferedOutputStream o = new BufferedOutputStream(new FileOutputStream(new File(f, "MANIFEST.MF")));      try {	manifest.write(o);      } finally {	o.close();      }      ZipEntry ze;      while ((ze = ji.getNextJarEntry()) != null) {	if (!ze.isDirectory()) {	  if(isSkipped(ze.getName())) {	    // Optional files are not copied to disk	  } else {	    StringTokenizer st = new StringTokenizer(ze.getName(), "/");	    f = new File(file, st.nextToken());	    while (st.hasMoreTokens()) {	      f.mkdir();	      f = new File(f, st.nextToken());	    }	    loadFile(f, ji, true);	  }	}      }      jar = null;    } else {      // Only copy to storage when applicable, otherwise      // use reference      if(source != null && bReference && "file".equals(source.getProtocol())) {	refFile = new File(source.getFile());	jar = new ZipFile(refFile);      } else {	loadFile(file, bis, true);	jar = new ZipFile(file);      }      if (manifest == null) {	manifest = getManifest();	checkManifest();      }    }  }  /**   * Return true if the specified path name should be   * skipped when unpacking.   */  boolean isSkipped(String pathName) {    return pathName.startsWith(OSGI_OPT_DIR);  }  /**   * Create an Archive based on contents of a saved   * archive in the specified directory.   * Take lowest versioned archive and remove rest.   *   * @param dir Directory with saved Archive.   * @param url URL to use to CodeSource.   */  Archive(File dir, int rev, String location) throws IOException {    String [] f = dir.list();    file = null;    if (rev != -1) {      file = new File(dir, ARCHIVE + rev);    } else {      rev = Integer.MAX_VALUE;      for (int i = 0; i < f.length; i++) {	if (f[i].startsWith(ARCHIVE)) {	  try {	    int c = Integer.parseInt(f[i].substring(ARCHIVE.length()));	    if (c < rev) {	      rev = c;	      file = new File(dir, f[i]);	    }	  } catch (NumberFormatException ignore) { }	}      }    }    for (int i = 0; i < f.length; i++) {      if (f[i].startsWith(ARCHIVE)) {	try {	  int c = Integer.parseInt(f[i].substring(ARCHIVE.length()));	  if (c != rev) {	    (new File(dir, f[i])).delete();	  }	} catch (NumberFormatException ignore) { }      }      if (f[i].startsWith(SUBDIR)) {	try {	  int c = Integer.parseInt(f[i].substring(SUBDIR.length()));	  if (c != rev) {	    (new FileTree(dir, f[i])).delete();	  }	} catch (NumberFormatException ignore) { }      }    }    if (file == null || !file.exists()) {      if(bReference && (location != null)) {	try {	  URL source = new URL(location);	  if("file".equals(source.getProtocol())) {	    refFile = file = new File(source.getFile());	  }	} catch (Exception e) {	  throw new IOException("Bad file URL stored in referenced jar in: " +				dir.getAbsolutePath() + 				", location=" + location);	}      }      if(file == null || !file.exists()) {	throw new IOException("No saved jar file found in: " + dir.getAbsolutePath() + ", old location=" + location);      }    }        if (file.isDirectory()) {      jar = null;    } else {      jar = new ZipFile(file);    }    manifest = getManifest();  }  /**   * Create a Sub-Archive based on a path to in an already   * existing Archive. The new archive is saved in a subdirectory   * below local copy of the existing Archive.   *   * @param a Parent Archive.   * @param path Path of new Archive inside old Archive.   * @exception FileNotFoundException if no such Jar file in archive.   * @exception IOException if failed to read Jar file.   */  Archive(Archive a, String path) throws IOException {    if (a.jar != null) {      jar = a.jar;      subJar = jar.getEntry(path);      if (subJar == null) {	throw new IOException("No such JAR componenet: " + path);      }      file = a.file;    } else {      file = findFile(a.file, path);      jar = new ZipFile(file);    }  }  /**   * Show file name for archive, if zip show if it is sub archive.   *   * @return A string with result.   */  public String toString() {    if (subJar != null) {      return file.getAbsolutePath() + "(" + subJar.getName() + ")";    } else {      return file.getAbsolutePath();    }  }  /**   * Get revision number this archive.   *   * @return Archive revision number   */  int getRevision() {    try {      return Integer.parseInt(file.getName().substring(ARCHIVE.length()));    } catch (NumberFormatException ignore) {      // assert?      return -1;    }  }  /**

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?