| /* |
| * Copyright 2014 Google Inc. |
| * |
| * 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 com.google.gwt.dev.url; |
| |
| import java.io.IOException; |
| import java.net.URL; |
| import java.net.URLStreamHandler; |
| import java.net.URLStreamHandlerFactory; |
| |
| /** |
| * A factory that constructs URL Stream Handlers and extends Jar protocol handling by making it |
| * possible to close all InputStreams for a given Zip file. |
| * <p> |
| * This closing functionality makes it possible to run untrusted plugin code (for example |
| * Generators) and still guarantee that there will be no accidental attempts to read from old and |
| * deleted Zip files using stale InputStreams. |
| */ |
| public class CloseableJarHandlerFactory implements URLStreamHandlerFactory { |
| |
| /** |
| * Takes over the URL connection opening system so that Zip file connections can be gathered and |
| * then closed before Zip files are replaced on disk. This avoids a JVM crash on Linux that can |
| * occur if a third party plugin (ie. Generator) fails to close its InputStreams. |
| */ |
| private static CloseableJarHandlerFactory closeableJarHandlerFactory; |
| |
| /** |
| * Closes all InputStreams that were created by the URL system that point at the given Jar file. |
| */ |
| public static void closeStreams(String jarFilePath) throws IOException { |
| closeableJarHandlerFactory.closeableJarHandler.closeStreams(jarFilePath); |
| } |
| |
| /** |
| * Ensures that the standard UrlStreamHandlerFactory has been replaced. |
| */ |
| public static synchronized void installOverride() { |
| if (closeableJarHandlerFactory == null) { |
| closeableJarHandlerFactory = new CloseableJarHandlerFactory(); |
| URL.setURLStreamHandlerFactory(closeableJarHandlerFactory); |
| } |
| } |
| |
| private static URLStreamHandler createHandlerForProtocol(String protocol) { |
| String className = String.format("sun.net.www.protocol.%s.Handler", protocol); |
| try { |
| return (URLStreamHandler) Class.forName(className).newInstance(); |
| } catch (ClassNotFoundException e) { |
| throw new RuntimeException("Couldn't find handler for protocol: " + protocol); |
| } catch (InstantiationException e) { |
| throw new RuntimeException("Handler isn't not instantiable for protocol: " + protocol); |
| } catch (IllegalAccessException e) { |
| throw new RuntimeException("Handler isn't not accessible for protocol: " + protocol); |
| } |
| } |
| |
| private CloseableJarHandler closeableJarHandler = new CloseableJarHandler(); |
| |
| private CloseableJarHandlerFactory() { |
| // Force access through the public static functions. |
| } |
| |
| @Override |
| public URLStreamHandler createURLStreamHandler(String protocol) { |
| if (protocol.equals("jar")) { |
| // Override the url stream handler for Jar files. |
| return closeableJarHandler; |
| } else { |
| // Regular url stream handling for other protocols. |
| return createHandlerForProtocol(protocol); |
| } |
| } |
| } |