/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2006-2008, Open Source Geospatial Foundation (OSGeo) * * 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.geotools.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.geotools.util.logging.Logging; /** * A service provider for {@link ImageInputStream} from {@link URL} connection. * * @since 2.4 * * @source $URL$ * @version $Id$ * @author Martin Desruisseaux (IRD) */ 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. * * @since 2.5 */ public UrlInputSpi(final Proxy proxy) { super("Geotools", "2.5", URL.class); this.proxy = proxy; } /** * Returns a brief, human-readable description of this service * provider and its associated implementation. */ 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. */ public ImageInputStream createInputStreamInstance(final Object input, final boolean useCache, final File cacheDir) throws IOException { final URL url = (URL) input; final URLConnection connection = url.openConnection(/*proxy*/); // TODO: uncomment with J2SE 1.5. int retry = RETRY; InputStream stream; while (true) { try { stream = connection.getInputStream(); break; } catch (SocketException exception) { if (--retry < 0) { throw exception; } Logging.getLogger(UrlInputSpi.class).warning(exception.toString()); } /* * 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(UrlInputSpi.class).warning("System.runFinalization() was blocked."); } } return new FileCacheImageInputStream(stream, cacheDir); } }