/* * Geotoolkit.org - An Open Source Java GIS Toolkit * http://www.geotoolkit.org * * (C) 2006-2012, Open Source Geospatial Foundation (OSGeo) * (C) 2009-2012, Geomatys * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. */ package org.geotoolkit.image.io.stream; import java.util.Locale; import java.io.File; import java.io.InputStream; import java.io.IOException; import java.net.Proxy; import java.net.URL; import java.net.URLConnection; import java.net.SocketException; import javax.imageio.spi.ImageInputStreamSpi; import javax.imageio.stream.ImageInputStream; import javax.imageio.stream.FileCacheImageInputStream; import org.apache.sis.util.logging.Logging; /** * A service provider for creating {@link ImageInputStream}s from {@link URL}s. * * @author Martin Desruisseaux (IRD) * @version 3.00 * * @since 2.4 * @module */ public class UrlInputSpi extends ImageInputStreamSpi { /** * Maximum number of retries when a connection failed. */ private static final int RETRY = 3; /** * The proxy. */ private final Proxy proxy; /** * Creates a new instance with no proxy. */ public UrlInputSpi() { this(Proxy.NO_PROXY); } /** * Creates a new instance with the specified proxy. * * @param proxy The proxy to use. * * @since 2.5 */ public UrlInputSpi(final Proxy proxy) { super("Geotoolkit.org", "3.00", URL.class); this.proxy = proxy; } /** * Returns a brief, human-readable description of this service * provider and its associated implementation. */ @Override public String getDescription(final Locale locale) { return "Stream from a URL."; // TODO: localize } /** * Returns {@code true} since the input stream requires the use of a cache file. */ @Override public boolean needsCacheFile() { return true; } /** * Constructs an input stream for an URL. * * @throws IOException If the stream can not be created. */ @Override public ImageInputStream createInputStreamInstance(final Object input, final boolean useCache, final File cacheDir) throws IOException { final URL url = (URL) input; final URLConnection connection = Proxy.NO_PROXY.equals(proxy) ? null : url.openConnection(proxy); int retry = RETRY; InputStream stream; while (true) { /* * If there is no proxy, then get the input stream with URL.openStream() instead * than using the connection because URL.openConnection() is not supported for URL * to an entry inside a JAR file, while URL.openStream() is. */ try { stream = (connection != null) ? connection.getInputStream() : url.openStream(); break; } catch (SocketException exception) { if (--retry < 0) { throw exception; } Logging.recoverableException(null, UrlInputSpi.class, "createInputStreamInstance", exception); } /* * Failed to get the connection. After we logged a warning, wait a little bit, run * the finalization and try again. Experience suggests that running the finalizers * sometime help, but also sometime freeze the system. FinalizationStopper may help * to unfreeze the system after a timeout. */ try { Thread.sleep(1000); } catch (InterruptedException ignore) { // Someone doesn't want to let us sleep. Go back to work... } System.gc(); Thread.interrupted(); // Clears the interrupted flag. final FinalizationStopper stopper = new FinalizationStopper(4000); System.runFinalization(); stopper.cancel(); // Thread.interrupted() must be first in order to clear the flag. if (Thread.interrupted() || stopper.interrupted) { Logging.getLogger("org.geotoolkit.image.io.stream").warning("System.runFinalization() was blocked."); } } return new FileCacheImageInputStream(stream, cacheDir); } }