/* * Copyright 2010-2013 Institut Pasteur. * * This file is part of Icy. * * Icy is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Icy 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Icy. If not, see <http://www.gnu.org/licenses/>. */ package icy.plugin.classloader; import icy.network.NetworkUtil; import icy.plugin.classloader.exception.JclException; import icy.system.IcyExceptionHandler; import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; import java.net.JarURLConnection; import java.net.URL; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Set; import java.util.jar.JarEntry; import java.util.jar.JarInputStream; import java.util.logging.Level; import java.util.logging.Logger; import java.util.zip.ZipEntry; /** * JarResources reads jar files and loads the class content/bytes in a HashMap * * @author Kamran Zafar * @author Stephane Dallongeville */ public class JarResources { // <resourceName, content> map protected Map<String, byte[]> entryContents; // <resourceName, fileName> map protected Map<String, URL> entryUrls; protected boolean collisionAllowed; // keep trace of loaded resource size protected int loadedSize; private static Logger logger = Logger.getLogger(JarResources.class.getName()); /** * Default constructor */ public JarResources() { entryContents = new HashMap<String, byte[]>(); entryUrls = new HashMap<String, URL>(); collisionAllowed = Configuration.suppressCollisionException(); loadedSize = 0; } public URL getResource(String name) { return entryUrls.get(name); } public byte[] getResourceContent(String name) throws IOException { byte content[] = entryContents.get(name); // we load the content if (content == null) { final URL url = entryUrls.get(name); if (url != null) { // load content and return it loadContent(name, url); content = entryContents.get(name); // try // { // // load content and return it // loadContent(name, url); // content = entryContents.get(name); // } // catch (IOException e) // { // // content cannot be loaded, remove the URL entry // // better to not remove it after all, so we know why it failed next time // // entryUrls.remove(name); // // // and throw exception // throw e; // } } } return content; } protected void loadContent(String name, URL url) throws IOException { // only support JAR resource here final byte[] content = loadJarContent(url); setResourceContent(name, content); } /** * Returns an immutable Set of all resources names */ public Set<String> getResourcesName() { return Collections.unmodifiableSet(entryUrls.keySet()); } /** * Returns an immutable Map of all resources */ public Map<String, URL> getResources() { return Collections.unmodifiableMap(entryUrls); } /** * Returns an immutable Map of all loaded jar resources */ public Map<String, byte[]> getLoadedResources() { return Collections.unmodifiableMap(entryContents); } /** * Reads the jar file from a specified URL * * @throws IOException */ public void loadJar(URL url) throws IOException { if (logger.isLoggable(Level.FINEST)) logger.finest("Loading jar: " + url.toString()); BufferedInputStream bis = null; JarInputStream jis = null; try { final InputStream in = url.openStream(); if (in instanceof BufferedInputStream) bis = (BufferedInputStream) in; else bis = new BufferedInputStream(in); jis = new JarInputStream(bis); JarEntry jarEntry = null; while ((jarEntry = jis.getNextJarEntry()) != null) { if (logger.isLoggable(Level.FINEST)) logger.finest(dump(jarEntry)); if (jarEntry.isDirectory()) continue; if (entryUrls.containsKey(jarEntry.getName())) { if (!collisionAllowed) throw new JclException("Class/Resource " + jarEntry.getName() + " already loaded"); if (logger.isLoggable(Level.FINEST)) logger.finest("Class/Resource " + jarEntry.getName() + " already loaded; ignoring entry..."); continue; } // add to internal resource HashMap entryUrls.put(jarEntry.getName(), new URL("jar:" + url.toString() + "!/" + jarEntry.getName())); } } // catch (NullPointerException e) // { // if (logger.isLoggable(Level.FINEST)) // logger.finest("Done loading."); // } finally { if (jis != null) { try { jis.close(); } catch (IOException e) { // not important System.err.println("JarResources.loadJar(" + url + ") error:"); IcyExceptionHandler.showErrorMessage(e, false, true); } } if (bis != null) { try { bis.close(); } catch (IOException e) { // not important System.err.println("JarResources.loadJar(" + url + ") error:"); IcyExceptionHandler.showErrorMessage(e, false, true); } } } } /** * Load the jar contents from InputStream * * @throws IOException */ protected byte[] loadJarContent(URL url) throws IOException { final JarURLConnection uc = (JarURLConnection) url.openConnection(); final JarEntry jarEntry = uc.getJarEntry(); if (jarEntry != null) { if (logger.isLoggable(Level.FINEST)) logger.finest(dump(jarEntry)); return NetworkUtil.download(uc.getInputStream(), jarEntry.getSize(), null); } throw new IOException("JarResources.loadJarContent(" + url.toString() + ") error:\nEntry not found !"); } protected void setResourceContent(String name, byte content[]) { if (entryContents.containsKey(name)) { if (!collisionAllowed) throw new JclException("Class/Resource " + name + " already loaded"); if (logger.isLoggable(Level.FINEST)) logger.finest("Class/Resource " + name + " already loaded; ignoring entry..."); return; } if (logger.isLoggable(Level.FINEST)) logger.finest("Entry Name: " + name + ", " + "Entry Size: " + content.length); // add to internal resource HashMap entryContents.put(name, content); } /** * For debugging * * @param je * @return String */ private String dump(JarEntry je) { StringBuffer sb = new StringBuffer(); if (je.isDirectory()) sb.append("d "); else sb.append("f "); if (je.getMethod() == ZipEntry.STORED) sb.append("stored "); else sb.append("deflated "); sb.append(je.getName()); sb.append("\t"); sb.append("" + je.getSize()); if (je.getMethod() == ZipEntry.DEFLATED) sb.append("/" + je.getCompressedSize()); return (sb.toString()); } }