Author: ivaynberg
Date: Thu Oct 22 06:43:37 2009
New Revision: 828326

URL: http://svn.apache.org/viewvc?rev=828326&view=rev
Log:
WICKET-2534: File Handle Leak in URLResourceStream
Issue: WICKET-2534

Added:
    
wicket/trunk/wicket/src/main/java/org/apache/wicket/util/io/Connections.java   
(with props)
Modified:
    wicket/trunk/wicket/src/main/java/org/apache/wicket/util/io/Streams.java
    
wicket/trunk/wicket/src/main/java/org/apache/wicket/util/resource/UrlResourceStream.java

Added: 
wicket/trunk/wicket/src/main/java/org/apache/wicket/util/io/Connections.java
URL: 
http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/util/io/Connections.java?rev=828326&view=auto
==============================================================================
--- 
wicket/trunk/wicket/src/main/java/org/apache/wicket/util/io/Connections.java 
(added)
+++ 
wicket/trunk/wicket/src/main/java/org/apache/wicket/util/io/Connections.java 
Thu Oct 22 06:43:37 2009
@@ -0,0 +1,159 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.wicket.util.io;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.JarURLConnection;
+import java.net.URI;
+import java.net.URL;
+import java.net.URLConnection;
+
+/**
+ * {...@link URLConnection} related utilities
+ * 
+ * @author igor.vaynberg
+ */
+public class Connections
+{
+       private Connections()
+       {
+
+       }
+
+       /**
+        * Gets last modified date of the given {...@link URL}
+        * 
+        * @param url
+        * @return last modified timestamp
+        * @throws IOException
+        */
+       public static long getLastModified(URL url) throws IOException
+       {
+
+               URLConnection connection = url.openConnection();
+
+               try
+               {
+                       if (connection instanceof JarURLConnection)
+                       {
+                               JarURLConnection jarUrlConnection = 
(JarURLConnection)connection;
+                               URL jarFileUrl = 
jarUrlConnection.getJarFileURL();
+                               URLConnection jarFileConnection = 
jarFileUrl.openConnection();
+                               try
+                               {
+                                       return 
jarFileConnection.getLastModified();
+                               }
+                               finally
+                               {
+                                       close(jarFileConnection);
+                               }
+                       }
+                       else
+                       {
+                               return connection.getLastModified();
+                       }
+
+               }
+               finally
+               {
+                       close(connection);
+               }
+       }
+
+       /**
+        * Tries to find a file on the harddisk that the url points to
+        * 
+        * @param url
+        * @return file file pointing to the connection
+        * @throws Exception
+        *             if file could not be located
+        */
+       public static File findFile(final URL url) throws Exception
+       {
+               File file = null;
+               URL fileUrl = url;
+               URLConnection connection = null;
+
+               try
+               {
+                       connection = url.openConnection();
+
+                       // if this is a connection to a file inside a jar we 
point the file to the jar
+                       // itself
+                       if (connection instanceof JarURLConnection)
+                       {
+                               fileUrl = 
((JarURLConnection)connection).getJarFileURL();
+                       }
+
+                       file = new File(new URI(fileUrl.toExternalForm()));
+
+                       if (file != null && !file.exists())
+                       {
+                               file = null;
+                       }
+
+                       return file;
+               }
+               finally
+               {
+                       close(connection);
+               }
+       }
+
+       /**
+        * Closes a connection, ignoring any exceptions if they occur
+        * 
+        * @param connection
+        */
+       public static void closeQuietly(URLConnection connection)
+       {
+               try
+               {
+                       close(connection);
+               }
+               catch (Exception e)
+               {
+                       // ignore
+               }
+       }
+
+       /**
+        * Closes a connection
+        * 
+        * @param connection
+        * @throws IOException
+        */
+       public static void close(URLConnection connection) throws IOException
+       {
+               if (connection == null)
+               {
+                       return;
+               }
+
+               if (connection instanceof HttpURLConnection)
+               {
+                       ((HttpURLConnection)connection).disconnect();
+               }
+               else
+               {
+                       connection.getInputStream().close();
+               }
+       }
+
+}

Propchange: 
wicket/trunk/wicket/src/main/java/org/apache/wicket/util/io/Connections.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: 
wicket/trunk/wicket/src/main/java/org/apache/wicket/util/io/Streams.java
URL: 
http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/util/io/Streams.java?rev=828326&r1=828325&r2=828326&view=diff
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/util/io/Streams.java 
(original)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/util/io/Streams.java 
Thu Oct 22 06:43:37 2009
@@ -17,6 +17,7 @@
 package org.apache.wicket.util.io;
 
 import java.io.BufferedReader;
+import java.io.Closeable;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
@@ -44,6 +45,7 @@
  * Utilities methods for working with input and output streams.
  * 
  * @author Jonathan Locke
+ * @author Igor Vaynberg
  */
 public final class Streams
 {
@@ -53,6 +55,22 @@
                + "<!ELEMENT comment (#PCDATA) >" + "<!ELEMENT entry (#PCDATA) 
>" + "<!ATTLIST entry "
                + " key CDATA #REQUIRED>";
 
+       /**
+        * Closes a closeable. Guards against null closables.
+        * 
+        * @param closeable
+        *            closeable to close
+        * @throws IOException
+        *             when close fails
+        */
+       public static void close(Closeable closeable) throws IOException
+       {
+               if (closeable != null)
+               {
+                       closeable.close();
+               }
+       }
+
 
        /**
         * Writes the input stream to the output stream. Input is done without 
a Reader object, meaning

Modified: 
wicket/trunk/wicket/src/main/java/org/apache/wicket/util/resource/UrlResourceStream.java
URL: 
http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/util/resource/UrlResourceStream.java?rev=828326&r1=828325&r2=828326&view=diff
==============================================================================
--- 
wicket/trunk/wicket/src/main/java/org/apache/wicket/util/resource/UrlResourceStream.java
 (original)
+++ 
wicket/trunk/wicket/src/main/java/org/apache/wicket/util/resource/UrlResourceStream.java
 Thu Oct 22 06:43:37 2009
@@ -19,14 +19,12 @@
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
-import java.net.HttpURLConnection;
-import java.net.JarURLConnection;
-import java.net.URI;
 import java.net.URL;
 import java.net.URLConnection;
 
 import org.apache.wicket.Application;
 import org.apache.wicket.protocol.http.WebApplication;
+import org.apache.wicket.util.io.Connections;
 import org.apache.wicket.util.time.Time;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -38,6 +36,7 @@
  * @see org.apache.wicket.util.resource.IResourceStream
  * @see org.apache.wicket.util.watch.IModifiable
  * @author Jonathan Locke
+ * @author Igor Vaynberg
  */
 public class UrlResourceStream extends AbstractResourceStream
        implements
@@ -74,61 +73,36 @@
         */
        public UrlResourceStream(final URL url)
        {
-               // Save URL
+               // save the url
                this.url = url;
+
+               // retrieve the content type and length
                URLConnection connection = null;
                try
                {
                        connection = url.openConnection();
                        contentLength = connection.getContentLength();
                        contentType = connection.getContentType();
-                       lastModified = connection.getLastModified();
-                       try
-                       {
-                               file = new File(new URI(url.toExternalForm()));
-                       }
-                       catch (Exception ex)
-                       {
-                               log.debug("cannot convert url: " + url + " to 
file (" + ex.getMessage() +
-                                       "), falling back to the inputstream for 
polling");
-                       }
-                       if (file != null && !file.exists())
-                       {
-                               file = null;
-                       }
                }
                catch (IOException ex)
                {
-                       // It should be impossible to get here or the original 
URL
-                       // couldn't have been constructed. But we re-throw with 
details
-                       // anyway.
-                       final IllegalArgumentException illegalArgumentException 
= new IllegalArgumentException(
-                               "Invalid URL parameter " + url);
-                       illegalArgumentException.initCause(ex);
-                       throw illegalArgumentException;
+                       throw new IllegalArgumentException("Invalid URL 
parameter " + url, ex);
                }
                finally
                {
-                       // if applicable, disconnect
-                       if (connection != null)
-                       {
-                               if (connection instanceof HttpURLConnection)
-                               {
-                                       
((HttpURLConnection)connection).disconnect();
-                               }
-                               else
-                               {
-                                       try
-                                       {
-                                               
connection.getInputStream().close();
-                                       }
-                                       catch (Exception ex)
-                                       {
-                                               // ignore
-                                       }
-                               }
-                       }
+                       Connections.closeQuietly(connection);
+               }
+
+               try
+               {
+                       file = Connections.findFile(url);
                }
+               catch (Exception e)
+               {
+                       log.debug("cannot convert url: " + url + " to file (" + 
e.getMessage() +
+                               "), falling back to the inputstream for 
polling");
+               }
+
        }
 
        /**
@@ -221,13 +195,15 @@
        {
                if (file != null)
                {
-                       // In case the file has been removed by now
+                       // in case the file has been removed by now
                        if (file.exists() == false)
                        {
                                return null;
                        }
 
                        long lastModified = file.lastModified();
+
+                       // if last modified changed update content length and 
last modified date
                        if (lastModified != this.lastModified)
                        {
                                this.lastModified = lastModified;
@@ -236,38 +212,18 @@
                }
                else
                {
-                       URLConnection urlConnection = null;
-                       boolean close = false;
                        try
                        {
-                               urlConnection = url.openConnection();
-                               long lastModified = this.lastModified;
-                               if (urlConnection instanceof JarURLConnection)
-                               {
-                                       JarURLConnection jarUrlConnection = 
(JarURLConnection)urlConnection;
-                                       URL jarFileUrl = 
jarUrlConnection.getJarFileURL();
-                                       URLConnection jarFileConnection = 
jarFileUrl.openConnection();
-                                       try
-                                       {
-                                               lastModified = 
jarFileConnection.getLastModified();
-                                       }
-                                       finally
-                                       {
-                                               
jarFileConnection.getInputStream().close();
-                                       }
-                               }
-                               else
-                               {
-                                       close = true;
-                                       lastModified = 
urlConnection.getLastModified();
-                               }
+                               long lastModified = 
Connections.getLastModified(url);
 
-                               // update the last modified time.
+                               // if last modified changed update content 
length and last modified date
                                if (lastModified != this.lastModified)
                                {
                                        this.lastModified = lastModified;
-                                       close = true;
-                                       contentLength = 
urlConnection.getContentLength();
+
+                                       URLConnection connection = 
url.openConnection();
+                                       contentLength = 
connection.getContentLength();
+                                       Connections.close(connection);
                                }
                        }
                        catch (IOException e)
@@ -284,31 +240,10 @@
                                        log.warn("getLastModified for " + url + 
" failed: " + e.getMessage());
                                }
 
-                               // Allow modification watcher to detect the 
problem
+                               // allow modification watcher to detect the 
problem
                                return null;
                        }
-                       finally
-                       {
-                               // if applicable, disconnect
-                               if (urlConnection != null)
-                               {
-                                       if (urlConnection instanceof 
HttpURLConnection)
-                                       {
-                                               
((HttpURLConnection)urlConnection).disconnect();
-                                       }
-                                       else if (close)
-                                       {
-                                               try
-                                               {
-                                                       
urlConnection.getInputStream().close();
-                                               }
-                                               catch (Exception ex)
-                                               {
-                                                       // ignore
-                                               }
-                                       }
-                               }
-                       }
+
                }
                return Time.milliseconds(lastModified);
        }


Reply via email to