Author: mgrigorov
Date: Thu Dec 2 20:04:35 2010
New Revision: 1041559
URL: http://svn.apache.org/viewvc?rev=1041559&view=rev
Log:
WICKET-3176 URLResourceStream loads target content twice.
Make URLResourceStream lazy - it will make the connection to the resource on
first read and will cache the results.
A new connection is being made only for refreshing the last modification time.
Modified:
wicket/trunk/wicket/src/main/java/org/apache/wicket/util/resource/UrlResourceStream.java
wicket/trunk/wicket/src/test/java/org/apache/wicket/util/resource/UrlResourceStreamTest.java
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=1041559&r1=1041558&r2=1041559&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 Dec 2 20:04:35 2010
@@ -49,8 +49,10 @@ public class UrlResourceStream extends A
/** Logging. */
private static final Logger log =
LoggerFactory.getLogger(UrlResourceStream.class);
- /** Resource stream. */
- private transient InputStream inputStream;
+ /**
+ * The meta data for this stream. Lazy loaded on demand.
+ */
+ private transient StreamData streamData;
/** The URL to this resource. */
private final URL url;
@@ -58,14 +60,23 @@ public class UrlResourceStream extends A
/** the handle to the file if it is a file resource */
private File file;
- /** Length of stream. */
- private Bytes contentLength;
+ /**
+ * Meta data class for the stream attributes
+ */
+ private static class StreamData
+ {
+ private URLConnection connection;
+
+ /** Length of stream. */
+ private long contentLength;
- /** Content type for stream. */
- private String contentType;
+ /** Content type for stream. */
+ private String contentType;
- /** Last known time the stream was last modified. */
- private long lastModified;
+ /** Last known time the stream was last modified. */
+ private long lastModified;
+
+ }
/**
* Construct.
@@ -78,23 +89,6 @@ public class UrlResourceStream extends A
// save the url
this.url = url;
- // retrieve the content type and length
- URLConnection connection = null;
- try
- {
- connection = url.openConnection();
- contentLength =
Bytes.bytes(connection.getContentLength());
- contentType = connection.getContentType();
- }
- catch (IOException ex)
- {
- throw new IllegalArgumentException("Invalid URL
parameter " + url, ex);
- }
- finally
- {
- Connections.closeQuietly(connection);
- }
-
try
{
file = new File(new URI(url.toExternalForm()));
@@ -113,16 +107,69 @@ public class UrlResourceStream extends A
}
/**
+ * Lazy loads the stream settings on demand
+ *
+ * @param initialize
+ * a flag indicating whether to load the settings
+ * @return the meta data with the stream settings
+ */
+ private StreamData getData(boolean initialize)
+ {
+ if (streamData == null && initialize)
+ {
+ streamData = new StreamData();
+
+ try
+ {
+ streamData.connection = url.openConnection();
+ streamData.contentLength =
streamData.connection.getContentLength();
+ streamData.contentType =
streamData.connection.getContentType();
+
+ if (streamData.contentType == null ||
+
streamData.contentType.indexOf("unknown") != -1)
+ {
+ if (Application.exists() &&
Application.get() instanceof WebApplication)
+ {
+ // TODO Post 1.2: General: For
non webapplication another method
+ // should be implemented
(getMimeType on application?)
+ streamData.contentType =
WebApplication.get()
+ .getServletContext()
+
.getMimeType(url.getFile());
+ if (streamData.contentType ==
null)
+ {
+ streamData.contentType
= URLConnection.getFileNameMap()
+
.getContentTypeFor(url.getFile());
+ }
+ }
+ else
+ {
+ streamData.contentType =
URLConnection.getFileNameMap().getContentTypeFor(
+ url.getFile());
+ }
+ }
+ }
+ catch (IOException ex)
+ {
+ throw new IllegalArgumentException("Invalid URL
parameter " + url, ex);
+ }
+ }
+
+ return streamData;
+ }
+
+ /**
* Closes this resource.
*
* @throws IOException
*/
public void close() throws IOException
{
- if (inputStream != null)
+ StreamData data = getData(false);
+
+ if (data != null)
{
- inputStream.close();
- inputStream = null;
+ Connections.closeQuietly(data.connection);
+ data.connection = null;
}
}
@@ -132,35 +179,7 @@ public class UrlResourceStream extends A
@Override
public String getContentType()
{
- testContentType();
- return contentType;
- }
-
- /**
- * Method to test the content type on null or unknown. if this is the
case the content type is
- * tried to be resolved throw the servlet context
- */
- private void testContentType()
- {
- if (contentType == null || contentType.contains("unknown"))
- {
- Application application = Application.get();
- if (application instanceof WebApplication)
- {
- // TODO Post 1.2: General: For non
webapplication another method
- // should be implemented (getMimeType on
application?)
- contentType =
((WebApplication)application).getServletContext().getMimeType(
- url.getFile());
- if (contentType == null)
- {
- contentType =
URLConnection.getFileNameMap().getContentTypeFor(url.getFile());
- }
- }
- else
- {
- contentType =
URLConnection.getFileNameMap().getContentTypeFor(url.getFile());
- }
- }
+ return getData(true).contentType;
}
/**
@@ -169,19 +188,15 @@ public class UrlResourceStream extends A
*/
public InputStream getInputStream() throws
ResourceStreamNotFoundException
{
- if (inputStream == null)
+ InputStream inputStream;
+ try
{
- try
- {
- inputStream = url.openStream();
- }
- catch (IOException e)
- {
- throw new
ResourceStreamNotFoundException("Resource " + url +
- " could not be opened", e);
- }
+ inputStream = getData(true).connection.getInputStream();
+ }
+ catch (IOException e)
+ {
+ throw new ResourceStreamNotFoundException("Resource " +
url + " could not be opened", e);
}
-
return inputStream;
}
@@ -202,6 +217,8 @@ public class UrlResourceStream extends A
{
try
{
+ StreamData data = getData(true);
+
if (file != null)
{
// in case the file has been removed by now
@@ -213,9 +230,9 @@ public class UrlResourceStream extends A
long lastModified = file.lastModified();
// if last modified changed update content
length and last modified date
- if (lastModified != this.lastModified)
+ if (lastModified != data.lastModified)
{
- this.lastModified = lastModified;
+ data.lastModified = lastModified;
setContentLength();
}
}
@@ -224,14 +241,14 @@ public class UrlResourceStream extends A
long lastModified =
Connections.getLastModified(url);
// if last modified changed update content
length and last modified date
- if (lastModified != this.lastModified)
+ if (lastModified != data.lastModified)
{
- this.lastModified = lastModified;
+ data.lastModified = lastModified;
setContentLength();
}
}
- return Time.milliseconds(lastModified);
+ return Time.milliseconds(data.lastModified);
}
catch (IOException e)
{
@@ -254,8 +271,9 @@ public class UrlResourceStream extends A
private void setContentLength() throws IOException
{
+ StreamData data = getData(true);
URLConnection connection = url.openConnection();
- contentLength = Bytes.bytes(connection.getContentLength());
+ data.contentLength = connection.getContentLength();
Connections.close(connection);
}
@@ -274,7 +292,8 @@ public class UrlResourceStream extends A
@Override
public Bytes length()
{
- return contentLength;
+ long contentLength = getData(true).contentLength;
+ return Bytes.bytes(contentLength);
}
/**
Modified:
wicket/trunk/wicket/src/test/java/org/apache/wicket/util/resource/UrlResourceStreamTest.java
URL:
http://svn.apache.org/viewvc/wicket/trunk/wicket/src/test/java/org/apache/wicket/util/resource/UrlResourceStreamTest.java?rev=1041559&r1=1041558&r2=1041559&view=diff
==============================================================================
---
wicket/trunk/wicket/src/test/java/org/apache/wicket/util/resource/UrlResourceStreamTest.java
(original)
+++
wicket/trunk/wicket/src/test/java/org/apache/wicket/util/resource/UrlResourceStreamTest.java
Thu Dec 2 20:04:35 2010
@@ -18,6 +18,9 @@ package org.apache.wicket.util.resource;
import java.io.IOException;
import java.net.URL;
+import java.net.URLConnection;
+import java.net.URLStreamHandler;
+import java.util.concurrent.atomic.AtomicInteger;
import junit.framework.TestCase;
@@ -45,4 +48,59 @@ public class UrlResourceStreamTest exten
stream.close();
}
+ /**
+ * https://issues.apache.org/jira/browse/WICKET-3176
+ *
+ * @throws IOException
+ * @throws ResourceStreamNotFoundException
+ */
+ public void testLoadJustOnce() throws IOException,
ResourceStreamNotFoundException
+ {
+ String anyClassInJarFile = "/java/lang/String.class";
+ URL realURL = getClass().getResource(anyClassInJarFile);
+
+ final AtomicInteger counter = new AtomicInteger(0);
+ URL url = new URL(null, "test://anything", new
CountingURLStreamHandler(realURL, counter));
+
+ UrlResourceStream countingStream = new UrlResourceStream(url);
+ // assert the call is not made yet
+ assertEquals(0, counter.get());
+ countingStream.length();
+ // assert the connection is loaded lazily
+ assertEquals(1, counter.get());
+
+ // assert the following calls do not make new connections
+ countingStream.getInputStream();
+ assertEquals(1, counter.get());
+ countingStream.getContentType();
+ assertEquals(1, counter.get());
+ countingStream.getInputStream();
+ assertEquals(1, counter.get());
+ countingStream.close();
+ assertEquals(1, counter.get());
+ }
+
+ /**
+ * {...@link URLStreamHandler} that counts the calls to {...@link
URL#openConnection()}
+ */
+ private static final class CountingURLStreamHandler extends
URLStreamHandler
+ {
+ private final AtomicInteger counter;
+
+ private final URL realURL;
+
+ public CountingURLStreamHandler(URL realURL, AtomicInteger
counter)
+ {
+ this.counter = counter;
+ this.realURL = realURL;
+ }
+
+ @Override
+ protected URLConnection openConnection(URL u) throws IOException
+ {
+ counter.getAndIncrement();
+ return realURL.openConnection();
+ }
+
+ }
}