/* * Written by Dawid Kurzyniec and released to the public domain, as explained * at http://creativecommons.org/licenses/publicdomain */ package edu.emory.mathcs.util.classloader.jar; import java.io.*; import java.net.*; import java.util.regex.*; import edu.emory.mathcs.util.classloader.*; /** * Alternative implementation of URLStreamHandler for JAR files that supports * customizable JAR caching policies. It addresses bugs * 4405789, 4388666, 4639900 in Java Bug Parade. SUN recommends to disable * caches completely as a workaround for those bugs; however, this may * significantly affect performance in case of resources downloaded from the * network. This class is a part of the solution that allows to tailor the * caching policy according to the program needs, with cache-per-classloader * default policy. * * @see edu.emory.mathcs.util.classloader.jar.JarURLConnection * * @author Dawid Kurzyniec * @version 1.0 */ @SuppressWarnings("PMD") public class JarURLStreamHandler extends URLStreamHandler { // "jar:" + url + "!" + /<path>/ + <file>? + "#"<anchor>? private static final Pattern ABSOLUTE_JAR_URL_PATTERN = Pattern.compile("jar:(.*)!(/(?:.*/)?)((?:[^/#]+)?)((?:#.*)?)"); final JarURLConnection.JarOpener opener; /** * Create new JarURLStreamHandler that will use its separate URL cache * managed by a newly created {@link edu.emory.mathcs.util.classloader.jar.JarProxy} instance. */ public JarURLStreamHandler() { this(new JarProxy()); } /** * Create new JarURLStreamHandler that will use specified * JAR opener. * * @param opener JAR opener that handles file download and caching */ public JarURLStreamHandler(JarURLConnection.JarOpener opener) { this.opener = opener; } public URLConnection openConnection(URL url) throws IOException { return new JarURLConnection(url, opener); } protected void parseURL(URL u, String spec, int start, int limit) { Matcher matcher; if ((matcher = ABSOLUTE_JAR_URL_PATTERN.matcher(spec)).matches()) { // spec is an absolute URL String base = matcher.group(1); try { // verify URL baseURL = new URL(base); } catch (MalformedURLException e) { throw new IllegalArgumentException(e.toString()); } String path = matcher.group(2) + matcher.group(3); path = ResourceUtils.canonizePath(path); String ref = matcher.group(4); if (ref.length() == 0) { ref = null; } else { ref = ref.substring(1); } setURL(u, "jar", "", -1, "", "", base + "!" + path, null, ref); } else if ((matcher = ABSOLUTE_JAR_URL_PATTERN.matcher(u.toString())).matches()) { String ref = spec.substring(limit); if (ref.length() == 0) { ref = null; } else { ref = ref.substring(1); } spec = spec.substring(start, limit); String base = matcher.group(1); String path; if (spec.length() > 0 && spec.charAt(0) == '/') { path = spec; } else { String cxtDir = matcher.group(2); path = cxtDir + spec; } path = ResourceUtils.canonizePath(path); setURL(u, "jar", "", -1, "", "", base + "!" + path, null, ref); } else { throw new IllegalArgumentException("Neither URL nor the spec are " + "valid JAR urls"); } } }