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 + -
显示快捷键?