You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by hl...@apache.org on 2010/04/28 04:44:18 UTC
svn commit: r938755 - in
/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets:
BytestreamCache.java StackAssetRequestHandler.java
Author: hlship
Date: Wed Apr 28 02:44:18 2010
New Revision: 938755
URL: http://svn.apache.org/viewvc?rev=938755&view=rev
Log:
TAP5-1116: Live lock when using compressed and virtual assets due to ByteArrayOutputStream being synchronized
Added:
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/BytestreamCache.java (with props)
Modified:
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/StackAssetRequestHandler.java
Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/BytestreamCache.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/BytestreamCache.java?rev=938755&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/BytestreamCache.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/BytestreamCache.java Wed Apr 28 02:44:18 2010
@@ -0,0 +1,51 @@
+// Copyright 2010 The Apache Software Foundation
+//
+// 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 org.apache.tapestry5.internal.services.assets;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * A wrapper around a byte-stream, represented internally as a byte array. Part of the fix
+ * to TAP5-1116, avoiding a live lock due to ByteArrayOutputStream.writeTo() being a synchronized
+ * method.
+ *
+ * @since 5.2.0
+ */
+public class BytestreamCache
+{
+ private final byte[] streamData;
+
+ public BytestreamCache(byte[] streamData)
+ {
+ this.streamData = streamData;
+ }
+
+ public BytestreamCache(ByteArrayOutputStream os)
+ {
+ this(os.toByteArray());
+ }
+
+ public void writeTo(OutputStream os) throws IOException
+ {
+ os.write(streamData, 0, streamData.length);
+ }
+
+ public int size()
+ {
+ return streamData.length;
+ }
+}
Propchange: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/BytestreamCache.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/StackAssetRequestHandler.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/StackAssetRequestHandler.java?rev=938755&r1=938754&r2=938755&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/StackAssetRequestHandler.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/StackAssetRequestHandler.java Wed Apr 28 02:44:18 2010
@@ -60,9 +60,9 @@ public class StackAssetRequestHandler im
private final Pattern pathPattern = Pattern.compile("^(.+)/(.+)\\.js$");
// Two caches, keyed on extra path. Both are accessed only from synchronized blocks.
- private final Map<String, ByteArrayOutputStream> uncompressedCache = CollectionFactory.newCaseInsensitiveMap();
+ private final Map<String, BytestreamCache> uncompressedCache = CollectionFactory.newCaseInsensitiveMap();
- private final Map<String, ByteArrayOutputStream> compressedCache = CollectionFactory.newCaseInsensitiveMap();
+ private final Map<String, BytestreamCache> compressedCache = CollectionFactory.newCaseInsensitiveMap();
public StackAssetRequestHandler(ResourceCache resourceCache, JavascriptStackSource javascriptStackSource,
LocalizationSetter localizationSetter, ResponseCompressionAnalyzer compressionAnalyzer,
@@ -81,7 +81,7 @@ public class StackAssetRequestHandler im
{
boolean compress = compressionAnalyzer.isGZipSupported();
- ByteArrayOutputStream stream = getStream(extraPath, compress);
+ BytestreamCache cachedStream = getStream(extraPath, compress);
// The whole point of this is to force the client to aggressively cache the combined, virtual
// stack asset.
@@ -92,7 +92,7 @@ public class StackAssetRequestHandler im
if (productionMode)
response.setDateHeader("Expires", lastModified + InternalConstants.TEN_YEARS);
- response.setContentLength(stream.size());
+ response.setContentLength(cachedStream.size());
// Inform the upper layers that we are controlled compression here.
request.setAttribute(InternalConstants.SUPPRESS_COMPRESSION, true);
@@ -105,7 +105,7 @@ public class StackAssetRequestHandler im
OutputStream output = response.getOutputStream("text/javascript");
- stream.writeTo(output);
+ cachedStream.writeTo(output);
output.close();
@@ -119,18 +119,18 @@ public class StackAssetRequestHandler im
compressedCache.clear();
}
- private ByteArrayOutputStream getStream(String extraPath, boolean compressed) throws IOException
+ private BytestreamCache getStream(String extraPath, boolean compressed) throws IOException
{
return compressed ? getCompressedStream(extraPath) : getUncompressedStream(extraPath);
}
- private synchronized ByteArrayOutputStream getCompressedStream(String extraPath) throws IOException
+ private synchronized BytestreamCache getCompressedStream(String extraPath) throws IOException
{
- ByteArrayOutputStream result = compressedCache.get(extraPath);
+ BytestreamCache result = compressedCache.get(extraPath);
if (result == null)
{
- ByteArrayOutputStream uncompressed = getUncompressedStream(extraPath);
+ BytestreamCache uncompressed = getUncompressedStream(extraPath);
result = compressStream(uncompressed);
compressedCache.put(extraPath, result);
}
@@ -138,9 +138,9 @@ public class StackAssetRequestHandler im
return result;
}
- private synchronized ByteArrayOutputStream getUncompressedStream(String extraPath) throws IOException
+ private synchronized BytestreamCache getUncompressedStream(String extraPath) throws IOException
{
- ByteArrayOutputStream result = uncompressedCache.get(extraPath);
+ BytestreamCache result = uncompressedCache.get(extraPath);
if (result == null)
{
@@ -151,7 +151,7 @@ public class StackAssetRequestHandler im
return result;
}
- private ByteArrayOutputStream assembleStackContent(String extraPath) throws IOException
+ private BytestreamCache assembleStackContent(String extraPath) throws IOException
{
Matcher matcher = pathPattern.matcher(extraPath);
@@ -164,7 +164,7 @@ public class StackAssetRequestHandler im
return assembleStackContent(localeName, stackName);
}
- private ByteArrayOutputStream assembleStackContent(String localeName, String stackName) throws IOException
+ private BytestreamCache assembleStackContent(String localeName, String stackName) throws IOException
{
localizationSetter.setNonPeristentLocaleFromLocaleName(localeName);
@@ -174,10 +174,10 @@ public class StackAssetRequestHandler im
return assembleStackContent(libraries);
}
- private ByteArrayOutputStream assembleStackContent(List<Asset> libraries) throws IOException
+ private BytestreamCache assembleStackContent(List<Asset> libraries) throws IOException
{
- ByteArrayOutputStream result = new ByteArrayOutputStream();
- OutputStreamWriter osw = new OutputStreamWriter(result, "UTF-8");
+ ByteArrayOutputStream stream = new ByteArrayOutputStream();
+ OutputStreamWriter osw = new OutputStreamWriter(stream, "UTF-8");
PrintWriter writer = new PrintWriter(osw, true);
JSONArray paths = new JSONArray();
@@ -190,14 +190,14 @@ public class StackAssetRequestHandler im
writer.format("\n/* %s */;\n", path);
- streamLibraryContent(library, result);
+ streamLibraryContent(library, stream);
}
writer.format("\n;/**/\nTapestry.markScriptLibrariesLoaded(%s);\n", paths);
writer.close();
- return result;
+ return new BytestreamCache(stream);
}
private void streamLibraryContent(Asset library, OutputStream outputStream) throws IOException
@@ -211,16 +211,16 @@ public class StackAssetRequestHandler im
TapestryInternalUtils.copy(inputStream, outputStream);
}
- private ByteArrayOutputStream compressStream(ByteArrayOutputStream uncompressed) throws IOException
+ private BytestreamCache compressStream(BytestreamCache uncompressed) throws IOException
{
- ByteArrayOutputStream result = new ByteArrayOutputStream();
- OutputStream compressor = new GZIPOutputStream(result);
+ ByteArrayOutputStream compressed = new ByteArrayOutputStream();
+ OutputStream compressor = new GZIPOutputStream(compressed);
uncompressed.writeTo(compressor);
compressor.close();
- return result;
+ return new BytestreamCache(compressed);
}
}