001 /** 002 * 003 * Copyright 2005 The Apache Software Foundation 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 package org.apache.geronimo.kernel.classloader; 018 019 import java.io.File; 020 import java.io.IOException; 021 import java.io.FileNotFoundException; 022 import java.net.MalformedURLException; 023 import java.net.URL; 024 import java.net.URLConnection; 025 import java.net.URLStreamHandler; 026 import java.util.jar.JarEntry; 027 import java.util.jar.JarFile; 028 029 /** 030 * @version $Rev: 430581 $ $Date: 2006-08-10 16:16:47 -0700 (Thu, 10 Aug 2006) $ 031 */ 032 public class JarFileUrlStreamHandler extends URLStreamHandler { 033 public static URL createUrl(JarFile jarFile, JarEntry jarEntry) throws MalformedURLException { 034 return createUrl(jarFile, jarEntry, new File(jarFile.getName()).toURL()); 035 } 036 037 public static URL createUrl(JarFile jarFile, JarEntry jarEntry, URL codeSource) throws MalformedURLException { 038 JarFileUrlStreamHandler handler = new JarFileUrlStreamHandler(jarFile, jarEntry); 039 URL url = new URL("jar", "", -1, codeSource + "!/" + jarEntry.getName(), handler); 040 handler.setExpectedUrl(url); 041 return url; 042 } 043 044 private URL expectedUrl; 045 private final JarFile jarFile; 046 private final JarEntry jarEntry; 047 048 public JarFileUrlStreamHandler(JarFile jarFile, JarEntry jarEntry) { 049 if (jarFile == null) throw new NullPointerException("jarFile is null"); 050 if (jarEntry == null) throw new NullPointerException("jarEntry is null"); 051 052 this.jarFile = jarFile; 053 this.jarEntry = jarEntry; 054 } 055 056 public void setExpectedUrl(URL expectedUrl) { 057 if (expectedUrl == null) throw new NullPointerException("expectedUrl is null"); 058 this.expectedUrl = expectedUrl; 059 } 060 061 public URLConnection openConnection(URL url) throws IOException { 062 if (expectedUrl == null) throw new IllegalStateException("expectedUrl was not set"); 063 064 // the caller copied the URL reusing a stream handler from a previous call 065 if (!expectedUrl.equals(url)) { 066 // the new url is supposed to be within our context, so it must have a jar protocol 067 if (!url.getProtocol().equals("jar")) { 068 throw new IllegalArgumentException("Unsupported protocol " + url.getProtocol()); 069 } 070 071 // split the path at "!/" into the file part and entry part 072 String path = url.getPath(); 073 String[] chunks = path.split("!/", 2); 074 075 // if we only got only one chunk, it didn't contain the required "!/" delimiter 076 if (chunks.length == 1) { 077 throw new MalformedURLException("Url does not contain a '!' character: " + url); 078 } 079 080 String file = chunks[0]; 081 String entryPath = chunks[1]; 082 083 // this handler only supports jars on the local file system 084 if (!file.startsWith("file:")) { 085 // let the system handler deal with this 086 return new URL(url.toExternalForm()).openConnection(); 087 } 088 file = file.substring("file:".length()); 089 090 // again the new url is supposed to be within our context so it must reference the same jar file 091 if (!jarFile.getName().equals(file)) { 092 // let the system handler deal with this 093 return new URL(url.toExternalForm()).openConnection(); 094 } 095 096 // get the entry 097 JarEntry newEntry = jarFile.getJarEntry(entryPath); 098 if (newEntry == null) { 099 throw new FileNotFoundException("Entry not found: " + url); 100 } 101 return new JarFileUrlConnection(url, jarFile, newEntry); 102 } 103 104 return new JarFileUrlConnection(url, jarFile, jarEntry); 105 } 106 }