Archive.java

00001 /*
00002  * Copyright (c) 2003-2005, KNOPFLERFISH project
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following
00007  * conditions are met:
00008  *
00009  * - Redistributions of source code must retain the above copyright
00010  *   notice, this list of conditions and the following disclaimer.
00011  *
00012  * - Redistributions in binary form must reproduce the above
00013  *   copyright notice, this list of conditions and the following
00014  *   disclaimer in the documentation and/or other materials
00015  *   provided with the distribution.
00016  *
00017  * - Neither the name of the KNOPFLERFISH project nor the names of its
00018  *   contributors may be used to endorse or promote products derived
00019  *   from this software without specific prior written permission.
00020  *
00021  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00022  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00023  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00024  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00025  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00026  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00027  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
00028  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00029  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
00030  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00031  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
00032  * OF THE POSSIBILITY OF SUCH DAMAGE.
00033  */
00034 
00035 package org.knopflerfish.framework.bundlestorage.memory;
00036 
00037 
00038 import org.osgi.framework.Constants;
00039 import java.io.*;
00040 
00041 import java.util.ArrayList;
00042 import java.util.Enumeration;
00043 import java.util.HashMap;
00044 import java.util.Hashtable;
00045 import java.util.Iterator;
00046 import java.util.StringTokenizer;
00047 import java.util.Vector;
00048 import java.util.jar.*;
00049 
00057 class Archive {
00058 
00062   Manifest manifest;
00063 
00068   protected HashMap /* String -> byte[] */ content;
00069   
00070   ArrayList subDirs/*= null*/;
00071   
00079   Archive(InputStream is) throws IOException {
00080     JarInputStream ji = new JarInputStream(is);
00081     manifest = ji.getManifest();
00082     if (manifest == null) {
00083       throw new IOException("Bundle manifest is missing");
00084     }
00085     if (manifest.getMainAttributes().getValue(Constants.BUNDLE_NATIVECODE) != null) {
00086       throw new IOException("Native code not allowed by memory storage");
00087     }
00088     content = loadJarStream(ji);
00089   }
00090 
00091 
00102   Archive(Archive a, String path) throws IOException {
00103     byte [] bs = (byte [])a.content.remove(path);
00104     if (bs != null) {
00105       JarInputStream ji = new JarInputStream(new ByteArrayInputStream(bs));
00106       content = loadJarStream(ji);
00107     } else {
00108       throw new FileNotFoundException("No such file: " + path);
00109     }
00110   }
00111 
00112 
00119   String getAttribute(String key) {
00120     return manifest.getMainAttributes().getValue(key);
00121   }
00122   
00123 
00132   byte[] getClassBytes(String classFile) throws IOException {
00133     byte[] bytes;
00134     if ((bytes = (byte[]) content.remove(classFile)) == null) {
00135       if (subDirs == null) {
00136         return null;
00137       }
00138       Iterator it = subDirs.iterator();
00139       boolean found = false;
00140       while (it.hasNext()) {
00141         String subDir = (String) it.next();
00142         bytes = (byte[]) content.remove(subDir + "/" + classFile);
00143         if (bytes != null) {
00144           found = true;
00145           break;
00146         }
00147       }
00148       if (!found) {
00149         return null;
00150       }
00151     }
00152     return bytes;
00153   }
00154 
00155 
00162   InputStream getInputStream(String component) {
00163     if (component.startsWith("/")) {
00164       component = component.substring(1);
00165     }
00166     byte[] b = (byte[]) content.get(component);
00167     if (b != null) {
00168       return new ByteArrayInputStream(b);
00169     } else {
00170       return null;
00171     }
00172   }
00173   
00174   //Known issues: see FrameworkTestSuite Frame068a and Frame211a. Seems like the manifest 
00175   //gets skipped (I guess in getNextJarEntry in loadJarStream) for some reason
00176   //investigate further later
00177   Enumeration findResourcesPath(String path) {
00178     Vector answer = new Vector();
00179     // "normalize" + erroneous path check: be generous
00180     path.replace('\\', '/');
00181     if (path.startsWith("/")) {
00182       path = path.substring(1);
00183     }
00184     if (!path.endsWith("/") /* in case bad argument */) {
00185       if (path.length() > 1) {
00186         path += "/";
00187       }
00188     }
00189 
00190     Iterator it = content.keySet().iterator();
00191     while (it.hasNext()) {
00192       String entry = (String) it.next();
00193       if (entry.startsWith(path)) {
00194         String terminal = entry.substring(path.length());
00195         StringTokenizer st = new StringTokenizer(terminal, "/");
00196         String entryPath;
00197         if (st.hasMoreTokens()) {
00198           entryPath = path + st.nextToken();
00199         } else {// this should not happen even for "", or?
00200           entryPath = path;
00201         }
00202         if (!answer.contains(entryPath)) {
00203           answer.add(entryPath);
00204         }
00205       }
00206     }
00207 
00208     if (answer.size() == 0) {
00209       return null;
00210     }
00211     return answer.elements();
00212   }
00213 
00214 
00223   Archive getSubArchive(String path) throws IOException {
00224     return new Archive(this, path);
00225   }
00226 
00227 
00228   //
00229   // Private methods
00230   //
00231 
00237   private HashMap loadJarStream(JarInputStream ji) throws IOException {
00238     HashMap files = new HashMap();
00239     JarEntry je;
00240     while ((je = ji.getNextJarEntry()) != null) {
00241       if (!je.isDirectory()) {
00242         int len = (int) je.getSize();
00243         if (len == -1) {
00244           len = 8192;
00245         }
00246         byte[] b = new byte[len];
00247         int pos = 0;
00248         do {
00249           if (pos == len) {
00250             len *= 2;
00251             byte[] oldb = b;
00252             b = new byte[len];
00253             System.arraycopy(oldb, 0, b, 0, oldb.length);
00254           }
00255           int n;
00256           while ((len - pos) > 0 && (n = ji.read(b, pos, len - pos)) > 0) {
00257             pos += n;
00258           }
00259         } while (ji.available() > 0);
00260         if (pos != b.length) {
00261           byte[] oldb = b;
00262           b = new byte[pos];
00263           System.arraycopy(oldb, 0, b, 0, pos);
00264         }
00265         files.put(je.getName(), b);
00266       }
00267     }
00268     return files;
00269   }
00270 
00271 }

Generated on Mon Jan 11 21:19:13 2010 for OpenMobileIS by  doxygen 1.5.4