/** * * Copyright 2015 Kamran Zafar * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.xeustechnologies.jcl; import java.io.BufferedInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.jar.JarEntry; import java.util.jar.JarFile; import java.util.jar.JarInputStream; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.xeustechnologies.jcl.exception.JclException; /** * JarResources reads jar files and loads the class content/bytes in a HashMap * * @author Kamran Zafar * */ public class JarResources { protected Map<String, JclJarEntry> jarEntryContents; protected boolean collisionAllowed; private final transient Logger logger = LoggerFactory.getLogger( JarResources.class ); /** * Default constructor */ public JarResources() { jarEntryContents = new HashMap<String, JclJarEntry>(); collisionAllowed = Configuration.suppressCollisionException(); } /** * @param name * @return URL */ public URL getResourceURL(String name) { JclJarEntry entry = jarEntryContents.get(name); if (entry != null) { if (entry.getBaseUrl() == null) { throw new JclException( "non-URL accessible resource" ); } try { return new URL( entry.getBaseUrl().toString() + name ); } catch (MalformedURLException e) { throw new JclException( e ); } } return null; } /** * @param name * @return byte[] */ public byte[] getResource(String name) { JclJarEntry entry = jarEntryContents.get(name); if (entry != null) { return entry.getResourceBytes(); } else { return null; } } /** * Returns an immutable Map of all jar resources * * @return Map */ public Map<String, byte[]> getResources() { Map<String, byte[]> resourcesAsBytes = new HashMap<String, byte[]>(jarEntryContents.size()); for (Map.Entry<String, JclJarEntry> entry : jarEntryContents.entrySet()) { resourcesAsBytes.put(entry.getKey(), entry.getValue().getResourceBytes()); } return resourcesAsBytes; } /** * Reads the specified jar file * * @param jarFile */ public void loadJar(String jarFile) { logger.debug( "Loading jar: {}", jarFile ); FileInputStream fis = null; try { File file = new File( jarFile ); String baseUrl = "jar:" + file.toURI().toString() + "!/"; fis = new FileInputStream( file ); loadJar(baseUrl, fis); } catch (IOException e) { throw new JclException( e ); } finally { if (fis != null) try { fis.close(); } catch (IOException e) { throw new JclException( e ); } } } /** * Reads the jar file from a specified URL * * @param url */ public void loadJar(URL url) { logger.debug( "Loading jar: {}", url.toString() ); InputStream in = null; try { String baseUrl = "jar:" + url.toString() + "!/"; in = url.openStream(); loadJar( baseUrl, in ); } catch (IOException e) { throw new JclException( e ); } finally { if (in != null) try { in.close(); } catch (IOException e) { throw new JclException( e ); } } } public void loadJar(String argBaseUrl, InputStream jarStream) { loadJar(argBaseUrl, jarStream, true); } /** * Load the jar contents from InputStream * @param argBaseUrl * */ public void loadJar(String argBaseUrl, InputStream jarStream, boolean closeStream) { BufferedInputStream bis = null; JarInputStream jis = null; try { bis = new BufferedInputStream( jarStream ); jis = new JarInputStream( bis ); JarEntry jarEntry = null; while (( jarEntry = jis.getNextJarEntry() ) != null) { logger.debug( dump( jarEntry ) ); if (jarEntry.isDirectory()) { continue; } if (jarEntryContents.containsKey( jarEntry.getName() )) { if (!collisionAllowed) throw new JclException( "Class/Resource " + jarEntry.getName() + " already loaded" ); else { logger.debug( "Class/Resource {} already loaded; ignoring entry...", jarEntry.getName() ); continue; } } logger.debug( "Entry Name: {}, Entry Size: {}", jarEntry.getName(), jarEntry.getSize() ); byte[] b = new byte[2048]; ByteArrayOutputStream out = new ByteArrayOutputStream(); int len = 0; while (( len = jis.read( b ) ) > 0) { out.write( b, 0, len ); } // add to internal resource HashMap JclJarEntry entry = new JclJarEntry(); entry.setBaseUrl(argBaseUrl); entry.setResourceBytes(out.toByteArray()); jarEntryContents.put( jarEntry.getName(), entry ); logger.debug("{}: size={}, csize={}", jarEntry.getName(), out.size(), jarEntry.getCompressedSize()); out.close(); } } catch (IOException e) { throw new JclException( e ); } catch (NullPointerException e) { logger.debug( "Done loading." ); } finally { if(closeStream) { if (jis != null) try { jis.close(); } catch (IOException e) { throw new JclException(e); } if (bis != null) try { bis.close(); } catch (IOException e) { throw new JclException(e); } } } } /** * 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() == JarEntry.STORED) { sb.append( "stored " ); } else { sb.append( "defalted " ); } sb.append( je.getName() ); sb.append( "\t" ); sb.append( "" + je.getSize() ); if (je.getMethod() == JarEntry.DEFLATED) { sb.append( "/" + je.getCompressedSize() ); } return ( sb.toString() ); } }