/**************************************************************************
* Copyright (c) 2001 by Punch Telematix. All rights reserved. *
* *
* Redistribution and use in source and binary forms, with or without *
* modification, are permitted provided that the following conditions *
* are met: *
* 1. Redistributions of source code must retain the above copyright *
* notice, this list of conditions and the following disclaimer. *
* 2. 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. *
* 3. Neither the name of Punch Telematix nor the names of *
* other contributors may be used to endorse or promote products *
* derived from this software without specific prior written permission.*
* *
* THIS SOFTWARE IS PROVIDED ``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 PUNCH TELEMATIX OR OTHER 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 wonka.net.jar;
import java.io.IOException;
import java.io.InputStream;
import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.util.*;
import java.util.jar.*;
import java.net.URL;
import java.net.JarURLConnection;
import java.net.MalformedURLException;
import java.security.Permission;
/**
** Basic implementation of JarURLConnection.
** a Jar url has the following structure 'jar:<url>[!/[entryname]] (where [abc...] means optional)
** the included url says where the jarfile is located (and how you could retrieve it (protocol to use));
** most common cases the url is a file- or http-url. Since the JarFile class(the constructors) expects the jarfile to be on
** a local disk. This implies that getJarFile() will throw an IOException. Use getInputStream() instead to get a InputStream
** to retrieve the bytes of an Entry (or a the whole JarFile if no entry specified).
**
** the jar url contains a other url. This could be another JAR url allowing nested definitions. (this didn't work on blackdown though)!
*/
public class BasicJarURLConnection extends JarURLConnection {
private static WeakHashMap jarFileCache = new WeakHashMap();
private synchronized JarFile addJarToCache(String name) throws IOException {
JarFile jar = getCachedJarFile(name);
if(jar == null){
jar = new JarFile(name);
jarFileCache.put(jar,name);
}
return jar;
}
private synchronized JarFile getCachedJarFile(String name){
Iterator it = jarFileCache.entrySet().iterator();
while(it.hasNext()){
Map.Entry entry = (Map.Entry) it.next();
if(name.equals(entry.getValue())){
return (JarFile)entry.getKey();
}
}
return null;
}
private JarFile jar;
private byte [] bytes;
private ImmutableJarEntry je;
private ImmutableManifest man;
public BasicJarURLConnection(URL url) throws MalformedURLException {
super(url);
}
public synchronized void connect() throws IOException {
if (!connected) {
URL jarurl = getJarFileURL();
jarFileURLConnection = jarurl.openConnection();
String name = getEntryName();
if (jarurl.getProtocol().equals("file")) {
String filename = jarurl.getFile();
jar = getCachedJarFile(filename);
if(jar == null){
jar = addJarToCache(filename);
}
man = new ImmutableManifest(jar.getManifest());
if (name == null)
je = null;
else
{
JarEntry jeTemp = jar.getJarEntry(name);
if (jeTemp == null)
throw new FileNotFoundException(jarurl+"!/"+name+" does not exist");
else
je = new ImmutableJarEntry(jeTemp);
}
}
else {
JarInputStream jin = new JarInputStream(jarFileURLConnection.getInputStream(),true);
je = new ImmutableJarEntry(jin.getNextJarEntry());
if (name == null) {
man = new ImmutableManifest(jin.getManifest());
je = null;
}
else {
while(je != null) {
if (name.equals(je.getName())) {
man = new ImmutableManifest(jin.getManifest());
setBytes(jin);
break;
}
je = new ImmutableJarEntry(jin.getNextJarEntry());
}
if (je == null) {
throw new IOException("no entry found with name "+name+" in JAR archive "+jarurl);
}
}
}
connected = true;
}
}
public Permission getPermission() throws IOException {
if (!connected) {
connect();
}
return jarFileURLConnection.getPermission();
}
public InputStream getInputStream() throws IOException {
if (!connected) {
connect();
}
if (jar != null){
if (getEntryName() != null) {
return jar.getInputStream(je);
}
return new FileInputStream(getJarFileURL().getFile());
}
if (getEntryName() != null) {
return new ByteArrayInputStream(bytes);
}
return jarFileURLConnection.getInputStream();
}
public JarFile getJarFile() throws IOException {
if (!connected) {
connect();
}
if(jar == null) {
throw new IOException("jar file not on local disk");
}
return jar;
}
private void setBytes(InputStream jin) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bytes = new byte[1024];
int i = jin.read(bytes,0,1024);
while(i != -1) {
baos.write(bytes,0,i);
i = jin.read(bytes,0,1024);
}
bytes = baos.toByteArray();
}
//Inherited from JarURLConnection but overridden
public JarEntry getJarEntry() throws IOException {
if (!connected) {
connect();
}
return je;
}
public Manifest getManifest() throws IOException {
if (!connected) {
connect();
}
return man;
}
}