/* * MicroJIAC - A Lightweight Agent Framework * This file is part of MicroJIAC CDC-Launcher. * * Copyright (c) 2007-2012 DAI-Labor, Technische Universität Berlin * * This library includes software developed at DAI-Labor, Technische * Universität Berlin (http://www.dai-labor.de) * * This library is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library. If not, see <http://www.gnu.org/licenses/>. */ /* * $Id$ */ package de.jiac.micro.cl; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.net.URLConnection; import java.net.URLStreamHandler; import java.util.ArrayList; import java.util.List; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; /** * @author Marcel Patzlaff * @version $Revision$ */ final class LocalArchiveEntry extends ClassPathEntry { private final static URLStreamHandler ARCHIVE_URL_STREAM_HANDLER= new URLStreamHandler() { protected URLConnection openConnection(URL u) { String name= u.getFile().substring(1); ArrayList sequences= new ArrayList(); int sequence= 0; for(int index= 0; (index= name.indexOf('!', sequence)) > 0; sequence= index + 1) { sequences.add(name.substring(sequence, index)); } sequences.add(name.substring(sequence)); String[] seqs= new String[sequences.size()]; sequences.toArray(seqs); return new ArchiveURLConnection(u, seqs); } }; private static class ArchiveURLConnection extends URLConnection { private final String[] _sequences; private byte[] _content; private int _contentLength; private long _lastModified; protected ArchiveURLConnection(URL url, String[] sequences) { super(url); _sequences= sequences; } public void connect() throws IOException { if(!connected) { ZipInputStream zipInput= new ZipInputStream(new FileInputStream(_sequences[0])); ByteArrayOutputStream content= new ByteArrayOutputStream(0); long lm= 0; byte[] readBuffer= new byte[128]; try { walkDeeper: for(int s= 1; s < _sequences.length; ++s) { if(zipInput == null) { zipInput= new ZipInputStream(new ByteArrayInputStream(content.toByteArray(), 0, content.size())); } for(ZipEntry ze; (ze= zipInput.getNextEntry()) != null;) { if(ze.getName().equals(_sequences[s])) { lm= ze.getTime(); int estimated= (int) ze.getSize(); if(estimated <= 0) { estimated= 1024; } content.reset(); for(int numBytes= 0; (numBytes= zipInput.read(readBuffer, 0, readBuffer.length)) >= 0;) { content.write(readBuffer, 0, numBytes); } try { zipInput.close(); zipInput= null; } catch (IOException ioe) { // ignore } continue walkDeeper; } } throw new IOException("could not connect to url " + url.toString()); } } finally { if(zipInput != null) { try { zipInput.close(); } catch (IOException ioe) { // ignore } zipInput= null; } } _lastModified= lm; _content= content.toByteArray(); _contentLength= content.size(); connected= true; } } public int getContentLength() { try { connect(); } catch (IOException e) { return 0; } return _contentLength; } public InputStream getInputStream() throws IOException { connect(); return new ByteArrayInputStream(_content); } public long getLastModified() { try { connect(); } catch (IOException e) { return 0; } return _lastModified; } } private final static class InnerArchive { final String name; final byte[] content; InnerArchive(String name, byte[] content) { this.name= name; this.content= content; } } protected static URL createURL(List urlStack, String name) throws IOException { StringBuffer buffer= new StringBuffer(); for(int i= 0; i < urlStack.size(); ++i) { buffer.append('!').append(urlStack.get(i)); } buffer.append('!').append(name); return new URL( "archive", null, -1, buffer.toString(), ARCHIVE_URL_STREAM_HANDLER ); } private static boolean findRecursive(ZipInputStream zipInput, List urlStack, String name, List urls, boolean one) throws IOException { ArrayList innerQueue= null; for(ZipEntry entry= null; (entry= zipInput.getNextEntry()) != null; ) { if(entry.isDirectory()) { continue; } String en= entry.getName(); if(en.equals(name)) { urls.add(createURL(urlStack, name)); if(one) { return true; } } else if(en.indexOf('/') < 0 && isArchive(en)) { // top level inner archive if(innerQueue == null) { innerQueue= new ArrayList(); } // TODO: may fail, getSize is not always correct byte[] buffer= new byte[(int) entry.getSize()]; for(int i= 0, off= 0; i < buffer.length; i+= zipInput.read(buffer, off, buffer.length - i)); innerQueue.add(new InnerArchive(en, buffer)); } } while(innerQueue != null && innerQueue.size() > 0) { InnerArchive innerArchive= (InnerArchive) innerQueue.remove(0); ZipInputStream innerZipInput= new ZipInputStream(new ByteArrayInputStream(innerArchive.content)); urlStack.add(innerArchive.name); try { if(findRecursive(innerZipInput, urlStack, name, urls, one) && one) { return true; } } finally { urlStack.remove(urlStack.size() - 1); close(innerZipInput); } } return false; } private static void close(InputStream in) { try { in.close(); } catch (Exception e) { // ignore; } } protected static boolean isArchive(String name) { // TODO: we should look into the file to determine if it is an archive or not! int p= name.lastIndexOf('.'); if(p > 0) { String suffix= name.substring(p + 1); if(suffix.equalsIgnoreCase("jar") || suffix.equalsIgnoreCase("zip")) { return true; } } return false; } private final File _archiveFile; /*package*/ LocalArchiveEntry(File archiveFile) { _archiveFile= archiveFile; } protected URL findResource(String name) throws IOException { ArrayList urls= new ArrayList(); findRecursive(name, urls, true); return urls.size() <= 0 ? null : (URL) urls.get(0); } protected void findResources(String name, List urls) throws IOException { findRecursive(name, urls, false); } private void findRecursive(String name, List urls, boolean one) throws IOException { ArrayList urlStack= new ArrayList(); ZipInputStream zipInput= new ZipInputStream(new FileInputStream(_archiveFile)); urlStack.add(_archiveFile.getAbsolutePath()); findRecursive(zipInput, urlStack, name, urls, one); close(zipInput); } }