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 2013/07/16 23:37:58 UTC
[1/3] git commit: Roll version number forward to 5.4-alpha-11
Updated Branches:
refs/heads/master a8ad6d265 -> eaada44a8
Roll version number forward to 5.4-alpha-11
Project: http://git-wip-us.apache.org/repos/asf/tapestry-5/repo
Commit: http://git-wip-us.apache.org/repos/asf/tapestry-5/commit/476669d8
Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/476669d8
Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/476669d8
Branch: refs/heads/master
Commit: 476669d8175eb5e03c5626fc7e36192df9ce35a9
Parents: a8ad6d2
Author: Howard M. Lewis Ship <hl...@apache.org>
Authored: Tue Jul 16 09:43:04 2013 -0700
Committer: Howard M. Lewis Ship <hl...@apache.org>
Committed: Tue Jul 16 09:43:04 2013 -0700
----------------------------------------------------------------------
build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/476669d8/build.gradle
----------------------------------------------------------------------
diff --git a/build.gradle b/build.gradle
index 417dcf4..8c60182 100755
--- a/build.gradle
+++ b/build.gradle
@@ -34,7 +34,7 @@ project.version = tapestryVersion()
def tapestryVersion() {
def major = "5.4"
- def minor = "-alpha-10"
+ def minor = "-alpha-11"
// When building on the CI server, make sure -SNAPSHOT is appended, as it is a nightly build.
// When building normally, or for a release, no suffix is desired.
[2/3] git commit: Add cross-reference documentation
Posted by hl...@apache.org.
Add cross-reference documentation
Project: http://git-wip-us.apache.org/repos/asf/tapestry-5/repo
Commit: http://git-wip-us.apache.org/repos/asf/tapestry-5/commit/2beaaa9b
Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/2beaaa9b
Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/2beaaa9b
Branch: refs/heads/master
Commit: 2beaaa9b75faa6799b69687914e685515841e782
Parents: 476669d
Author: Howard M. Lewis Ship <hl...@apache.org>
Authored: Tue Jul 16 12:53:54 2013 -0700
Committer: Howard M. Lewis Ship <hl...@apache.org>
Committed: Tue Jul 16 12:53:54 2013 -0700
----------------------------------------------------------------------
.../java/org/apache/tapestry5/ioc/services/SymbolProvider.java | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/2beaaa9b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/SymbolProvider.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/SymbolProvider.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/SymbolProvider.java
index 7d39037..8a1f134 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/SymbolProvider.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/SymbolProvider.java
@@ -1,4 +1,4 @@
-// Copyright 2006, 2008 The Apache Software Foundation
+// Copyright 2006, 2008, 2013 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.
@@ -21,6 +21,9 @@ import org.apache.tapestry5.ioc.annotations.UsesMappedConfiguration;
* <p/>
* This is the service interface for the FactoryDefaults and ApplicationDefaults services; each of these takes a
* configuration mapping symbols to their values.
+ *
+ * @see FactoryDefaults
+ * @see ApplicationDefaults
*/
@UsesMappedConfiguration(String.class)
public interface SymbolProvider
[3/3] git commit: Add a file-system cache ofr single-input-file
comilations (CoffeeScript) that can persist between executions
Posted by hl...@apache.org.
Add a file-system cache ofr single-input-file comilations (CoffeeScript) that can persist between executions
Project: http://git-wip-us.apache.org/repos/asf/tapestry-5/repo
Commit: http://git-wip-us.apache.org/repos/asf/tapestry-5/commit/eaada44a
Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/eaada44a
Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/eaada44a
Branch: refs/heads/master
Commit: eaada44a8e6c83af346343c5d125015fe8ca6459
Parents: 2beaaa9
Author: Howard M. Lewis Ship <hl...@apache.org>
Authored: Tue Jul 16 14:37:49 2013 -0700
Committer: Howard M. Lewis Ship <hl...@apache.org>
Committed: Tue Jul 16 14:37:49 2013 -0700
----------------------------------------------------------------------
tapestry-wro4j/build.gradle | 4 +-
.../tapestry5/internal/wro4j/CacheMode.java | 40 ++++
.../internal/wro4j/ContentChangeTracker.java | 13 +-
.../internal/wro4j/LessResourceTransformer.java | 116 ++--------
.../internal/wro4j/ResourceTransformUtils.java | 8 +-
.../wro4j/ResourceTransformerFactory.java | 24 ++-
.../wro4j/ResourceTransformerFactoryImpl.java | 209 +++++++++++++++----
.../apache/tapestry5/wro4j/WRO4JSymbols.java | 25 +++
.../tapestry5/wro4j/modules/WRO4JModule.java | 25 ++-
9 files changed, 304 insertions(+), 160 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eaada44a/tapestry-wro4j/build.gradle
----------------------------------------------------------------------
diff --git a/tapestry-wro4j/build.gradle b/tapestry-wro4j/build.gradle
index 3c541e7..cd00fbc 100644
--- a/tapestry-wro4j/build.gradle
+++ b/tapestry-wro4j/build.gradle
@@ -38,5 +38,7 @@ jar.manifest {
test {
useJUnit()
- systemProperties "geb.build.reportsDir": "$reporting.baseDir/geb"
+ systemProperties("geb.build.reportsDir": "$reporting.baseDir/geb",
+ "tapestry.compiled-asset-cache-dir": "$buildDir/compiled-asset-cache",
+ "tapestry.production-mode": "false")
}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eaada44a/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/CacheMode.java
----------------------------------------------------------------------
diff --git a/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/CacheMode.java b/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/CacheMode.java
new file mode 100644
index 0000000..1410b3c
--- /dev/null
+++ b/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/CacheMode.java
@@ -0,0 +1,40 @@
+// Copyright 2013 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.wro4j;
+
+/**
+ * Controls caching for {@link ResourceTransformerFactory} in <em>development mode</em>. In production mode, caching at this
+ * level is not needed, because artifacts are also cached later in the pipeline. This caching is all about avoid unwanted
+ */
+public enum CacheMode
+{
+ /**
+ * Cache the content on the file system, in the directory defined by {@link org.apache.tapestry5.wro4j.WRO4JSymbols#CACHE_DIR}.
+ * This allows compilation to be avoided even after a restart, as long as the source file has not changed. This only works
+ * for compilations that operate on a single file (such as CoffeeScript, but not Less, which has an {@code @import} statement).
+ */
+ SINGLE_FILE,
+
+ /**
+ * The source may be multiple files (e.g., Less). Cache in memory, and invalidate the cache if any of the multiple
+ * file's content changes.
+ */
+ MULTIPLE_FILE,
+
+ /**
+ * Do no caching. This is appropriate for extremely cheap compilers.
+ */
+ NONE;
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eaada44a/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/ContentChangeTracker.java
----------------------------------------------------------------------
diff --git a/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/ContentChangeTracker.java b/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/ContentChangeTracker.java
index 770509e..b0e2eb1 100644
--- a/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/ContentChangeTracker.java
+++ b/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/ContentChangeTracker.java
@@ -32,16 +32,9 @@ public class ContentChangeTracker implements ResourceDependencies
public void addDependency(Resource dependency)
{
- try
- {
- long checksum = ResourceTransformUtils.toChecksum(dependency);
-
- checksums.put(dependency, checksum);
- } catch (IOException e)
- {
- throw new RuntimeException(e);
- }
+ long checksum = ResourceTransformUtils.toChecksum(dependency);
+ checksums.put(dependency, checksum);
}
/**
@@ -49,7 +42,7 @@ public class ContentChangeTracker implements ResourceDependencies
*
* @return true if a change has occurred
*/
- public boolean changes() throws IOException
+ public boolean dirty() throws IOException
{
for (Map.Entry<Resource, Long> e : checksums.entrySet())
{
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eaada44a/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/LessResourceTransformer.java
----------------------------------------------------------------------
diff --git a/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/LessResourceTransformer.java b/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/LessResourceTransformer.java
index b5f3709..1fd40d9 100644
--- a/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/LessResourceTransformer.java
+++ b/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/LessResourceTransformer.java
@@ -19,19 +19,12 @@ import com.github.sommeri.less4j.LessCompiler;
import com.github.sommeri.less4j.LessSource;
import com.github.sommeri.less4j.core.DefaultLessCompiler;
import org.apache.commons.io.IOUtils;
-import org.apache.tapestry5.SymbolConstants;
import org.apache.tapestry5.internal.services.assets.BytestreamCache;
-import org.apache.tapestry5.ioc.IOOperation;
-import org.apache.tapestry5.ioc.OperationTracker;
import org.apache.tapestry5.ioc.Resource;
-import org.apache.tapestry5.ioc.annotations.Symbol;
-import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
import org.apache.tapestry5.services.assets.ResourceDependencies;
import org.apache.tapestry5.services.assets.ResourceTransformer;
-import org.slf4j.Logger;
import java.io.*;
-import java.util.Map;
/**
* Direct wrapper around the LessCompiler, so that Less source files may use {@code @import}, which isn't
@@ -41,41 +34,6 @@ public class LessResourceTransformer implements ResourceTransformer
{
private final LessCompiler compiler = new DefaultLessCompiler();
- private final OperationTracker tracker;
-
- private final Logger logger;
-
- private final boolean cacheEnabled;
-
- private final Map<Resource, Cached> cache = CollectionFactory.newConcurrentMap();
-
- static class Cached
- {
- final BytestreamCache compiled;
-
- final ContentChangeTracker tracker;
-
- Cached(BytestreamCache compiled, ContentChangeTracker tracker)
- {
- this.compiled = compiled;
- this.tracker = tracker;
- }
-
- InputStream openStream() throws IOException
- {
- return compiled.openStream();
- }
- }
-
-
- public LessResourceTransformer(OperationTracker tracker, Logger logger, @Symbol(SymbolConstants.PRODUCTION_MODE) boolean productionMode)
- {
- this.tracker = tracker;
- this.logger = logger;
-
- cacheEnabled = !productionMode;
- }
-
public String getTransformedContentType()
{
return "text/css";
@@ -132,72 +90,32 @@ public class LessResourceTransformer implements ResourceTransformer
}
- public InputStream transform(final Resource source, final ResourceDependencies dependencies) throws IOException
+ public InputStream transform(Resource source, ResourceDependencies dependencies) throws IOException
{
- if (cacheEnabled)
- {
- Cached cached = cache.get(source);
- if (cached != null && !cached.tracker.changes())
- {
- logger.info(String.format("Resource %s (and any dependencies) are unchanged; serving compiled Less content from cache",
- source));
+ BytestreamCache compiled = invokeLessCompiler(source, dependencies);
- return cached.openStream();
- }
-
- ContentChangeTracker tracker1 = new ContentChangeTracker();
- tracker1.addDependency(source);
-
- BytestreamCache compiled = invokeLessCompiler(source, new ResourceDependenciesSplitter(dependencies, tracker1));
-
- cached = new Cached(compiled, tracker1);
-
- cache.put(source, cached);
-
- return cached.openStream();
- } else
- {
-
- BytestreamCache compiled = invokeLessCompiler(source, dependencies);
-
- return compiled.openStream();
- }
+ return compiled.openStream();
}
- private BytestreamCache invokeLessCompiler(final Resource source, final ResourceDependencies dependencies) throws IOException
+ private BytestreamCache invokeLessCompiler(Resource source, ResourceDependencies dependencies) throws IOException
{
-
- return tracker.perform(String.format("Compiling %s from Less to CSS", source), new IOOperation<BytestreamCache>()
+ try
{
- public BytestreamCache perform() throws IOException
- {
- long start = System.nanoTime();
-
- try
- {
- LessSource lessSource = new ResourceLessSource(source, dependencies);
-
- LessCompiler.CompilationResult compilationResult = compiler.compile(lessSource);
-
- BytestreamCache result = new BytestreamCache(compilationResult.getCss().getBytes("utf-8"));
+ LessSource lessSource = new ResourceLessSource(source, dependencies);
- logger.info(String.format("Compiled %s to Less in %.2f ms",
- source, ResourceTransformUtils.nanosToMillis(System.nanoTime() - start)));
+ LessCompiler.CompilationResult compilationResult = compiler.compile(lessSource);
- // Currently, ignoring any warnings.
+ // Currently, ignoring any warnings.
- return result;
+ return new BytestreamCache(compilationResult.getCss().getBytes("utf-8"));
- } catch (Less4jException ex)
- {
- throw new IOException(ex);
- } catch (UnsupportedEncodingException ex)
- {
- throw new IOException(ex);
- }
-
- }
- });
+ } catch (Less4jException ex)
+ {
+ throw new IOException(ex);
+ } catch (UnsupportedEncodingException ex)
+ {
+ throw new IOException(ex);
+ }
}
-}
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eaada44a/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/ResourceTransformUtils.java
----------------------------------------------------------------------
diff --git a/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/ResourceTransformUtils.java b/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/ResourceTransformUtils.java
index b236633..d0d9178 100644
--- a/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/ResourceTransformUtils.java
+++ b/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/ResourceTransformUtils.java
@@ -32,7 +32,7 @@ public class ResourceTransformUtils
return ((double) nanos) * NANOS_TO_MILLIS;
}
- public static long toChecksum(Resource resource) throws IOException
+ public static long toChecksum(Resource resource)
{
Adler32 checksum = new Adler32();
@@ -56,11 +56,13 @@ public class ResourceTransformUtils
checksum.update(buffer, 0, length);
}
+ is.close();
+
// Reduces it down to just 32 bits which we express in hex.'
return checksum.getValue();
- } finally
+ } catch (IOException ex)
{
- is.close();
+ throw new RuntimeException(ex);
}
}
}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eaada44a/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/ResourceTransformerFactory.java
----------------------------------------------------------------------
diff --git a/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/ResourceTransformerFactory.java b/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/ResourceTransformerFactory.java
index dde5c36..18436b3 100644
--- a/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/ResourceTransformerFactory.java
+++ b/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/ResourceTransformerFactory.java
@@ -36,10 +36,28 @@ public interface ResourceTransformerFactory
* for debugging: source name, e.g., "CoffeeScript"
* @param targetName
* for debugging: target name, e.g., "JavaScript"
- * @param enableCache
- * if true, the transformer will cache results (this is only used in development mode)
+ * @param cacheMode
+ * Indicates if and how the compiled content should be cached (in development mode only)
* @return transformer
* @see org.apache.tapestry5.wro4j.services.ResourceProcessorSource
*/
- ResourceTransformer createCompiler(String contentType, String processorName, String sourceName, String targetName, boolean enableCache);
+ ResourceTransformer createCompiler(String contentType, String processorName, String sourceName, String targetName, CacheMode cacheMode);
+
+ /**
+ * Constructs a compiler around a another ResourceTransformer implementation. In development mode, the wrapped version
+ * will handle caching, as well as logging output of timing for the real implementation.
+ *
+ * @param sourceName
+ * for debugging: source name, e.g., "Less"
+ * @param targetName
+ * for debugging: target name, e.g., "CSS"
+ * @param transformer
+ * performs the actual work
+ * @param cacheMode
+ * Indicates if and how the compiled content should be cached (in development mode only)
+ * @return transformer
+ * @see org.apache.tapestry5.wro4j.services.ResourceProcessorSource
+ */
+ ResourceTransformer createCompiler(String contentType, String sourceName, String targetName, ResourceTransformer transformer, CacheMode cacheMode);
+
}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eaada44a/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/ResourceTransformerFactoryImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/ResourceTransformerFactoryImpl.java b/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/ResourceTransformerFactoryImpl.java
index f8f3dec..bebbfcf 100644
--- a/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/ResourceTransformerFactoryImpl.java
+++ b/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/ResourceTransformerFactoryImpl.java
@@ -14,21 +14,23 @@
package org.apache.tapestry5.internal.wro4j;
+import org.apache.tapestry5.SymbolConstants;
import org.apache.tapestry5.internal.TapestryInternalUtils;
import org.apache.tapestry5.internal.services.assets.BytestreamCache;
import org.apache.tapestry5.ioc.IOOperation;
import org.apache.tapestry5.ioc.OperationTracker;
import org.apache.tapestry5.ioc.Resource;
+import org.apache.tapestry5.ioc.annotations.PostInjection;
+import org.apache.tapestry5.ioc.annotations.Symbol;
import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
import org.apache.tapestry5.services.assets.ResourceDependencies;
import org.apache.tapestry5.services.assets.ResourceTransformer;
+import org.apache.tapestry5.wro4j.WRO4JSymbols;
import org.apache.tapestry5.wro4j.services.ResourceProcessor;
import org.apache.tapestry5.wro4j.services.ResourceProcessorSource;
import org.slf4j.Logger;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
+import java.io.*;
import java.util.Map;
public class ResourceTransformerFactoryImpl implements ResourceTransformerFactory
@@ -39,28 +41,46 @@ public class ResourceTransformerFactoryImpl implements ResourceTransformerFactor
private final OperationTracker tracker;
- public ResourceTransformerFactoryImpl(Logger logger, ResourceProcessorSource source, OperationTracker tracker)
+ private final boolean productionMode;
+
+ private final File cacheDir;
+
+ public ResourceTransformerFactoryImpl(Logger logger, ResourceProcessorSource source, OperationTracker tracker,
+ @Symbol(SymbolConstants.PRODUCTION_MODE)
+ boolean productionMode,
+ @Symbol(WRO4JSymbols.CACHE_DIR)
+ String cacheDir)
{
this.logger = logger;
this.source = source;
this.tracker = tracker;
- }
+ this.productionMode = productionMode;
+ this.cacheDir = new File(cacheDir);
- static class Compiled
- {
- /**
- * Checksum of the raw source file.
- */
- final long checksum;
+ if (!productionMode)
+ {
+ logger.info(String.format("Using %s to store compiled assets (development mode only).", cacheDir));
+ }
+ }
- private final BytestreamCache bytestreamCache;
+ @PostInjection
+ public void createCacheDir()
+ {
+ cacheDir.mkdirs();
+ }
+ static class Compiled extends ContentChangeTracker
+ {
+ private BytestreamCache bytestreamCache;
- Compiled(long checksum, InputStream stream) throws IOException
+ Compiled(Resource root)
{
- this.checksum = checksum;
+ addDependency(root);
+ }
+ void store(InputStream stream) throws IOException
+ {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
TapestryInternalUtils.copy(stream, bos);
@@ -77,15 +97,46 @@ public class ResourceTransformerFactoryImpl implements ResourceTransformerFactor
}
}
- public ResourceTransformer createCompiler(final String contentType, String processorName, final String sourceName, final String targetName, boolean enableCache)
+
+ public ResourceTransformer createCompiler(final String contentType, String processorName, final String sourceName, final String targetName, CacheMode cacheMode)
{
// This does the real work:
ResourceProcessor resourceProcessor = source.getProcessor(processorName);
// And this adapts it to the API.
- final ResourceTransformer coreCompiler = createCoreCompiler(contentType, sourceName, targetName, resourceProcessor);
+ ResourceTransformer coreCompiler = createCoreCompiler(contentType, sourceName, targetName, resourceProcessor);
+
+ return createCompiler(contentType, sourceName, targetName, coreCompiler, cacheMode);
+
+ }
+
+ public ResourceTransformer createCompiler(String contentType, String sourceName, String targetName, ResourceTransformer transformer, CacheMode cacheMode)
+ {
+ ResourceTransformer trackingCompiler = wrapWithTracking(sourceName, targetName, transformer);
+
+ if (productionMode)
+ {
+ return trackingCompiler;
+ }
+
+ ResourceTransformer timingCompiler = wrapWithTiming(targetName, trackingCompiler);
+
+ switch (cacheMode)
+ {
+ case NONE:
+
+ return timingCompiler;
- return enableCache ? wrapWithCaching(coreCompiler, targetName) : coreCompiler;
+ case SINGLE_FILE:
+
+ return wrapWithFileSystemCaching(timingCompiler, targetName);
+
+ case MULTIPLE_FILE:
+
+ return wrapWithInMemoryCaching(timingCompiler, targetName);
+ }
+
+ return null; //To change body of implemented methods use File | Settings | File Templates.
}
private ResourceTransformer createCoreCompiler(final String contentType, final String sourceName, final String targetName, final ResourceProcessor resourceProcessor)
@@ -101,25 +152,62 @@ public class ResourceTransformerFactoryImpl implements ResourceTransformerFactor
{
final String description = String.format("Compiling %s from %s to %s", source, sourceName, targetName);
+ InputStream result = resourceProcessor.process(description,
+ source.toURL().toString(),
+ source.openStream(), contentType);
+
+ return result;
+
+ }
+ };
+ }
+
+ private ResourceTransformer wrapWithTracking(final String sourceName, final String targetName, final ResourceTransformer core)
+ {
+ return new ResourceTransformer()
+ {
+ public String getTransformedContentType()
+ {
+ return core.getTransformedContentType();
+ }
+
+ public InputStream transform(final Resource source, final ResourceDependencies dependencies) throws IOException
+ {
+ final String description = String.format("Compiling %s from %s to %s", source, sourceName, targetName);
+
return tracker.perform(description, new IOOperation<InputStream>()
{
public InputStream perform() throws IOException
{
- final long startTime = System.nanoTime();
+ return core.transform(source, dependencies);
+ }
+ });
+ }
+ };
+ }
- InputStream result = resourceProcessor.process(description,
- source.toURL().toString(),
- source.openStream(), contentType);
+ private ResourceTransformer wrapWithTiming(final String targetName, final ResourceTransformer coreCompiler)
+ {
+ return new ResourceTransformer()
+ {
+ public String getTransformedContentType()
+ {
+ return coreCompiler.getTransformedContentType();
+ }
- final long elapsedTime = System.nanoTime() - startTime;
+ public InputStream transform(final Resource source, final ResourceDependencies dependencies) throws IOException
+ {
+ final long startTime = System.nanoTime();
- logger.info(String.format("Compiled %s to %s in %.2f ms",
- source, targetName,
- ResourceTransformUtils.nanosToMillis(elapsedTime)));
+ InputStream result = coreCompiler.transform(source, dependencies);
- return result;
- }
- });
+ final long elapsedTime = System.nanoTime() - startTime;
+
+ logger.info(String.format("Compiled %s to %s in %.2f ms",
+ source, targetName,
+ ResourceTransformUtils.nanosToMillis(elapsedTime)));
+
+ return result;
}
};
}
@@ -131,7 +219,7 @@ public class ResourceTransformerFactoryImpl implements ResourceTransformerFactor
* somewhat primitive: a change to *any* resource in a given domain results in the cache of all of those resources
* being discarded.
*/
- private ResourceTransformer wrapWithCaching(final ResourceTransformer core, final String targetName)
+ private ResourceTransformer wrapWithInMemoryCaching(final ResourceTransformer core, final String targetName)
{
return new ResourceTransformer()
{
@@ -144,22 +232,21 @@ public class ResourceTransformerFactoryImpl implements ResourceTransformerFactor
public InputStream transform(Resource source, ResourceDependencies dependencies) throws IOException
{
- long checksum = ResourceTransformUtils.toChecksum(source);
-
Compiled compiled = cache.get(source);
- if (compiled != null && compiled.checksum == checksum)
+ if (compiled != null && !compiled.dirty())
{
- logger.info(String.format("Resource %s is unchanged; serving compiled %s content from cache",
+ logger.info(String.format("Resource %s and dependencies are unchanged; serving compiled %s content from in-memory cache",
source, targetName));
return compiled.openStream();
}
- InputStream is = core.transform(source, dependencies);
+ compiled = new Compiled(source);
+
+ InputStream is = core.transform(source, new ResourceDependenciesSplitter(dependencies, compiled));
- // There's probably a race condition here if the source changes as we are compiling it.
- compiled = new Compiled(checksum, is);
+ compiled.store(is);
cache.put(source, compiled);
@@ -167,4 +254,54 @@ public class ResourceTransformerFactoryImpl implements ResourceTransformerFactor
}
};
}
+
+ private ResourceTransformer wrapWithFileSystemCaching(final ResourceTransformer core, final String targetName)
+ {
+ return new ResourceTransformer()
+ {
+ public String getTransformedContentType()
+ {
+ return core.getTransformedContentType();
+ }
+
+ public InputStream transform(Resource source, ResourceDependencies dependencies) throws IOException
+ {
+ long checksum = ResourceTransformUtils.toChecksum(source);
+
+ String fileName = Long.toHexString(checksum) + "-" + source.getFile();
+
+ File cacheFile = new File(cacheDir, fileName);
+
+ if (cacheFile.exists())
+ {
+ logger.debug(String.format("Serving up compiled %s content for %s from file system cache", targetName, source));
+
+ return new BufferedInputStream(new FileInputStream(cacheFile));
+ }
+
+ InputStream compiled = core.transform(source, dependencies);
+
+ // We need the InputStream twice; once to return, and once to write out to the cache file for later.
+
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+
+ TapestryInternalUtils.copy(compiled, bos);
+
+ BytestreamCache cache = new BytestreamCache(bos);
+
+ writeToCacheFile(cacheFile, cache.openStream());
+
+ return cache.openStream();
+ }
+ };
+ }
+
+ private void writeToCacheFile(File file, InputStream stream) throws IOException
+ {
+ OutputStream outputStream = new BufferedOutputStream(new FileOutputStream(file));
+
+ TapestryInternalUtils.copy(stream, outputStream);
+
+ outputStream.close();
+ }
}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eaada44a/tapestry-wro4j/src/main/java/org/apache/tapestry5/wro4j/WRO4JSymbols.java
----------------------------------------------------------------------
diff --git a/tapestry-wro4j/src/main/java/org/apache/tapestry5/wro4j/WRO4JSymbols.java b/tapestry-wro4j/src/main/java/org/apache/tapestry5/wro4j/WRO4JSymbols.java
new file mode 100644
index 0000000..96e8b2e
--- /dev/null
+++ b/tapestry-wro4j/src/main/java/org/apache/tapestry5/wro4j/WRO4JSymbols.java
@@ -0,0 +1,25 @@
+// Copyright 2013 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.wro4j;
+
+public class WRO4JSymbols
+{
+ /**
+ * Directory that stores cached copies of compiled CoffeeScript files. The directory will be created
+ * as necessary. This allows compilation (e.g., CoffeeScript to JavaScript) to be avoided after a restart.
+ * The default is from the {@code java.io.tmpdir} system property (which is not necessarily stable between executions).
+ */
+ public static final String CACHE_DIR = "tapestry.compiled-asset-cache-dir";
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eaada44a/tapestry-wro4j/src/main/java/org/apache/tapestry5/wro4j/modules/WRO4JModule.java
----------------------------------------------------------------------
diff --git a/tapestry-wro4j/src/main/java/org/apache/tapestry5/wro4j/modules/WRO4JModule.java b/tapestry-wro4j/src/main/java/org/apache/tapestry5/wro4j/modules/WRO4JModule.java
index 5b35c23..e272448 100644
--- a/tapestry-wro4j/src/main/java/org/apache/tapestry5/wro4j/modules/WRO4JModule.java
+++ b/tapestry-wro4j/src/main/java/org/apache/tapestry5/wro4j/modules/WRO4JModule.java
@@ -17,19 +17,20 @@ package org.apache.tapestry5.wro4j.modules;
import com.github.sommeri.less4j.LessCompiler;
import com.github.sommeri.less4j.core.parser.AntlrException;
import org.apache.tapestry5.MarkupWriter;
-import org.apache.tapestry5.SymbolConstants;
import org.apache.tapestry5.internal.wro4j.*;
import org.apache.tapestry5.ioc.MappedConfiguration;
import org.apache.tapestry5.ioc.ServiceBinder;
import org.apache.tapestry5.ioc.annotations.Contribute;
import org.apache.tapestry5.ioc.annotations.Primary;
-import org.apache.tapestry5.ioc.annotations.Symbol;
import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
import org.apache.tapestry5.ioc.internal.util.InternalUtils;
+import org.apache.tapestry5.ioc.services.FactoryDefaults;
+import org.apache.tapestry5.ioc.services.SymbolProvider;
import org.apache.tapestry5.services.ObjectRenderer;
import org.apache.tapestry5.services.assets.ResourceMinimizer;
import org.apache.tapestry5.services.assets.ResourceTransformer;
import org.apache.tapestry5.services.assets.StreamableResourceSource;
+import org.apache.tapestry5.wro4j.WRO4JSymbols;
import org.apache.tapestry5.wro4j.services.ResourceProcessorSource;
import ro.isdc.wro.extensions.processor.js.GoogleClosureCompressorProcessor;
import ro.isdc.wro.extensions.processor.js.RhinoCoffeeScriptProcessor;
@@ -51,6 +52,13 @@ public class WRO4JModule
binder.bind(ResourceTransformerFactory.class, ResourceTransformerFactoryImpl.class);
}
+ @Contribute(SymbolProvider.class)
+ @FactoryDefaults
+ public static void setupDefaultCacheDirectory(MappedConfiguration<String, Object> configuration)
+ {
+ configuration.add(WRO4JSymbols.CACHE_DIR, "${java.io.tmpdir}");
+ }
+
/**
* Configures the default set of processors.
* <dl>
@@ -70,15 +78,16 @@ public class WRO4JModule
}
@Contribute(StreamableResourceSource.class)
- public static void provideCompilers(MappedConfiguration<String, ResourceTransformer> configuration, ResourceTransformerFactory factory,
- @Symbol(SymbolConstants.PRODUCTION_MODE)
- boolean productionMode)
+ public static void provideCompilers(MappedConfiguration<String, ResourceTransformer> configuration, ResourceTransformerFactory factory)
{
+ // contribution ids are file extensions:
+
configuration.add("coffee",
- factory.createCompiler("text/javascript", "CoffeeScriptCompiler", "CoffeeScript", "JavaScript", !productionMode));
+ factory.createCompiler("text/javascript", "CoffeeScriptCompiler", "CoffeeScript", "JavaScript", CacheMode.SINGLE_FILE));
- // Had to create our own wrapper around Less4J to handle @imports correctly.
- configuration.addInstance("less", LessResourceTransformer.class);
+ configuration.add("less",
+ factory.createCompiler("text/css", "Less", "CSS", new LessResourceTransformer(),
+ CacheMode.MULTIPLE_FILE));
}
@Contribute(ResourceMinimizer.class)
[3/3] git commit: Add a file-system cache ofr single-input-file
comilations (CoffeeScript) that can persist between executions
Posted by hl...@apache.org.
Add a file-system cache ofr single-input-file comilations (CoffeeScript) that can persist between executions
Project: http://git-wip-us.apache.org/repos/asf/tapestry-5/repo
Commit: http://git-wip-us.apache.org/repos/asf/tapestry-5/commit/eaada44a
Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/eaada44a
Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/eaada44a
Branch: refs/heads/master
Commit: eaada44a8e6c83af346343c5d125015fe8ca6459
Parents: 2beaaa9
Author: Howard M. Lewis Ship <hl...@apache.org>
Authored: Tue Jul 16 14:37:49 2013 -0700
Committer: Howard M. Lewis Ship <hl...@apache.org>
Committed: Tue Jul 16 14:37:49 2013 -0700
----------------------------------------------------------------------
tapestry-wro4j/build.gradle | 4 +-
.../tapestry5/internal/wro4j/CacheMode.java | 40 ++++
.../internal/wro4j/ContentChangeTracker.java | 13 +-
.../internal/wro4j/LessResourceTransformer.java | 116 ++--------
.../internal/wro4j/ResourceTransformUtils.java | 8 +-
.../wro4j/ResourceTransformerFactory.java | 24 ++-
.../wro4j/ResourceTransformerFactoryImpl.java | 209 +++++++++++++++----
.../apache/tapestry5/wro4j/WRO4JSymbols.java | 25 +++
.../tapestry5/wro4j/modules/WRO4JModule.java | 25 ++-
9 files changed, 304 insertions(+), 160 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eaada44a/tapestry-wro4j/build.gradle
----------------------------------------------------------------------
diff --git a/tapestry-wro4j/build.gradle b/tapestry-wro4j/build.gradle
index 3c541e7..cd00fbc 100644
--- a/tapestry-wro4j/build.gradle
+++ b/tapestry-wro4j/build.gradle
@@ -38,5 +38,7 @@ jar.manifest {
test {
useJUnit()
- systemProperties "geb.build.reportsDir": "$reporting.baseDir/geb"
+ systemProperties("geb.build.reportsDir": "$reporting.baseDir/geb",
+ "tapestry.compiled-asset-cache-dir": "$buildDir/compiled-asset-cache",
+ "tapestry.production-mode": "false")
}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eaada44a/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/CacheMode.java
----------------------------------------------------------------------
diff --git a/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/CacheMode.java b/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/CacheMode.java
new file mode 100644
index 0000000..1410b3c
--- /dev/null
+++ b/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/CacheMode.java
@@ -0,0 +1,40 @@
+// Copyright 2013 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.wro4j;
+
+/**
+ * Controls caching for {@link ResourceTransformerFactory} in <em>development mode</em>. In production mode, caching at this
+ * level is not needed, because artifacts are also cached later in the pipeline. This caching is all about avoid unwanted
+ */
+public enum CacheMode
+{
+ /**
+ * Cache the content on the file system, in the directory defined by {@link org.apache.tapestry5.wro4j.WRO4JSymbols#CACHE_DIR}.
+ * This allows compilation to be avoided even after a restart, as long as the source file has not changed. This only works
+ * for compilations that operate on a single file (such as CoffeeScript, but not Less, which has an {@code @import} statement).
+ */
+ SINGLE_FILE,
+
+ /**
+ * The source may be multiple files (e.g., Less). Cache in memory, and invalidate the cache if any of the multiple
+ * file's content changes.
+ */
+ MULTIPLE_FILE,
+
+ /**
+ * Do no caching. This is appropriate for extremely cheap compilers.
+ */
+ NONE;
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eaada44a/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/ContentChangeTracker.java
----------------------------------------------------------------------
diff --git a/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/ContentChangeTracker.java b/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/ContentChangeTracker.java
index 770509e..b0e2eb1 100644
--- a/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/ContentChangeTracker.java
+++ b/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/ContentChangeTracker.java
@@ -32,16 +32,9 @@ public class ContentChangeTracker implements ResourceDependencies
public void addDependency(Resource dependency)
{
- try
- {
- long checksum = ResourceTransformUtils.toChecksum(dependency);
-
- checksums.put(dependency, checksum);
- } catch (IOException e)
- {
- throw new RuntimeException(e);
- }
+ long checksum = ResourceTransformUtils.toChecksum(dependency);
+ checksums.put(dependency, checksum);
}
/**
@@ -49,7 +42,7 @@ public class ContentChangeTracker implements ResourceDependencies
*
* @return true if a change has occurred
*/
- public boolean changes() throws IOException
+ public boolean dirty() throws IOException
{
for (Map.Entry<Resource, Long> e : checksums.entrySet())
{
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eaada44a/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/LessResourceTransformer.java
----------------------------------------------------------------------
diff --git a/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/LessResourceTransformer.java b/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/LessResourceTransformer.java
index b5f3709..1fd40d9 100644
--- a/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/LessResourceTransformer.java
+++ b/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/LessResourceTransformer.java
@@ -19,19 +19,12 @@ import com.github.sommeri.less4j.LessCompiler;
import com.github.sommeri.less4j.LessSource;
import com.github.sommeri.less4j.core.DefaultLessCompiler;
import org.apache.commons.io.IOUtils;
-import org.apache.tapestry5.SymbolConstants;
import org.apache.tapestry5.internal.services.assets.BytestreamCache;
-import org.apache.tapestry5.ioc.IOOperation;
-import org.apache.tapestry5.ioc.OperationTracker;
import org.apache.tapestry5.ioc.Resource;
-import org.apache.tapestry5.ioc.annotations.Symbol;
-import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
import org.apache.tapestry5.services.assets.ResourceDependencies;
import org.apache.tapestry5.services.assets.ResourceTransformer;
-import org.slf4j.Logger;
import java.io.*;
-import java.util.Map;
/**
* Direct wrapper around the LessCompiler, so that Less source files may use {@code @import}, which isn't
@@ -41,41 +34,6 @@ public class LessResourceTransformer implements ResourceTransformer
{
private final LessCompiler compiler = new DefaultLessCompiler();
- private final OperationTracker tracker;
-
- private final Logger logger;
-
- private final boolean cacheEnabled;
-
- private final Map<Resource, Cached> cache = CollectionFactory.newConcurrentMap();
-
- static class Cached
- {
- final BytestreamCache compiled;
-
- final ContentChangeTracker tracker;
-
- Cached(BytestreamCache compiled, ContentChangeTracker tracker)
- {
- this.compiled = compiled;
- this.tracker = tracker;
- }
-
- InputStream openStream() throws IOException
- {
- return compiled.openStream();
- }
- }
-
-
- public LessResourceTransformer(OperationTracker tracker, Logger logger, @Symbol(SymbolConstants.PRODUCTION_MODE) boolean productionMode)
- {
- this.tracker = tracker;
- this.logger = logger;
-
- cacheEnabled = !productionMode;
- }
-
public String getTransformedContentType()
{
return "text/css";
@@ -132,72 +90,32 @@ public class LessResourceTransformer implements ResourceTransformer
}
- public InputStream transform(final Resource source, final ResourceDependencies dependencies) throws IOException
+ public InputStream transform(Resource source, ResourceDependencies dependencies) throws IOException
{
- if (cacheEnabled)
- {
- Cached cached = cache.get(source);
- if (cached != null && !cached.tracker.changes())
- {
- logger.info(String.format("Resource %s (and any dependencies) are unchanged; serving compiled Less content from cache",
- source));
+ BytestreamCache compiled = invokeLessCompiler(source, dependencies);
- return cached.openStream();
- }
-
- ContentChangeTracker tracker1 = new ContentChangeTracker();
- tracker1.addDependency(source);
-
- BytestreamCache compiled = invokeLessCompiler(source, new ResourceDependenciesSplitter(dependencies, tracker1));
-
- cached = new Cached(compiled, tracker1);
-
- cache.put(source, cached);
-
- return cached.openStream();
- } else
- {
-
- BytestreamCache compiled = invokeLessCompiler(source, dependencies);
-
- return compiled.openStream();
- }
+ return compiled.openStream();
}
- private BytestreamCache invokeLessCompiler(final Resource source, final ResourceDependencies dependencies) throws IOException
+ private BytestreamCache invokeLessCompiler(Resource source, ResourceDependencies dependencies) throws IOException
{
-
- return tracker.perform(String.format("Compiling %s from Less to CSS", source), new IOOperation<BytestreamCache>()
+ try
{
- public BytestreamCache perform() throws IOException
- {
- long start = System.nanoTime();
-
- try
- {
- LessSource lessSource = new ResourceLessSource(source, dependencies);
-
- LessCompiler.CompilationResult compilationResult = compiler.compile(lessSource);
-
- BytestreamCache result = new BytestreamCache(compilationResult.getCss().getBytes("utf-8"));
+ LessSource lessSource = new ResourceLessSource(source, dependencies);
- logger.info(String.format("Compiled %s to Less in %.2f ms",
- source, ResourceTransformUtils.nanosToMillis(System.nanoTime() - start)));
+ LessCompiler.CompilationResult compilationResult = compiler.compile(lessSource);
- // Currently, ignoring any warnings.
+ // Currently, ignoring any warnings.
- return result;
+ return new BytestreamCache(compilationResult.getCss().getBytes("utf-8"));
- } catch (Less4jException ex)
- {
- throw new IOException(ex);
- } catch (UnsupportedEncodingException ex)
- {
- throw new IOException(ex);
- }
-
- }
- });
+ } catch (Less4jException ex)
+ {
+ throw new IOException(ex);
+ } catch (UnsupportedEncodingException ex)
+ {
+ throw new IOException(ex);
+ }
}
-}
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eaada44a/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/ResourceTransformUtils.java
----------------------------------------------------------------------
diff --git a/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/ResourceTransformUtils.java b/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/ResourceTransformUtils.java
index b236633..d0d9178 100644
--- a/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/ResourceTransformUtils.java
+++ b/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/ResourceTransformUtils.java
@@ -32,7 +32,7 @@ public class ResourceTransformUtils
return ((double) nanos) * NANOS_TO_MILLIS;
}
- public static long toChecksum(Resource resource) throws IOException
+ public static long toChecksum(Resource resource)
{
Adler32 checksum = new Adler32();
@@ -56,11 +56,13 @@ public class ResourceTransformUtils
checksum.update(buffer, 0, length);
}
+ is.close();
+
// Reduces it down to just 32 bits which we express in hex.'
return checksum.getValue();
- } finally
+ } catch (IOException ex)
{
- is.close();
+ throw new RuntimeException(ex);
}
}
}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eaada44a/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/ResourceTransformerFactory.java
----------------------------------------------------------------------
diff --git a/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/ResourceTransformerFactory.java b/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/ResourceTransformerFactory.java
index dde5c36..18436b3 100644
--- a/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/ResourceTransformerFactory.java
+++ b/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/ResourceTransformerFactory.java
@@ -36,10 +36,28 @@ public interface ResourceTransformerFactory
* for debugging: source name, e.g., "CoffeeScript"
* @param targetName
* for debugging: target name, e.g., "JavaScript"
- * @param enableCache
- * if true, the transformer will cache results (this is only used in development mode)
+ * @param cacheMode
+ * Indicates if and how the compiled content should be cached (in development mode only)
* @return transformer
* @see org.apache.tapestry5.wro4j.services.ResourceProcessorSource
*/
- ResourceTransformer createCompiler(String contentType, String processorName, String sourceName, String targetName, boolean enableCache);
+ ResourceTransformer createCompiler(String contentType, String processorName, String sourceName, String targetName, CacheMode cacheMode);
+
+ /**
+ * Constructs a compiler around a another ResourceTransformer implementation. In development mode, the wrapped version
+ * will handle caching, as well as logging output of timing for the real implementation.
+ *
+ * @param sourceName
+ * for debugging: source name, e.g., "Less"
+ * @param targetName
+ * for debugging: target name, e.g., "CSS"
+ * @param transformer
+ * performs the actual work
+ * @param cacheMode
+ * Indicates if and how the compiled content should be cached (in development mode only)
+ * @return transformer
+ * @see org.apache.tapestry5.wro4j.services.ResourceProcessorSource
+ */
+ ResourceTransformer createCompiler(String contentType, String sourceName, String targetName, ResourceTransformer transformer, CacheMode cacheMode);
+
}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eaada44a/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/ResourceTransformerFactoryImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/ResourceTransformerFactoryImpl.java b/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/ResourceTransformerFactoryImpl.java
index f8f3dec..bebbfcf 100644
--- a/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/ResourceTransformerFactoryImpl.java
+++ b/tapestry-wro4j/src/main/java/org/apache/tapestry5/internal/wro4j/ResourceTransformerFactoryImpl.java
@@ -14,21 +14,23 @@
package org.apache.tapestry5.internal.wro4j;
+import org.apache.tapestry5.SymbolConstants;
import org.apache.tapestry5.internal.TapestryInternalUtils;
import org.apache.tapestry5.internal.services.assets.BytestreamCache;
import org.apache.tapestry5.ioc.IOOperation;
import org.apache.tapestry5.ioc.OperationTracker;
import org.apache.tapestry5.ioc.Resource;
+import org.apache.tapestry5.ioc.annotations.PostInjection;
+import org.apache.tapestry5.ioc.annotations.Symbol;
import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
import org.apache.tapestry5.services.assets.ResourceDependencies;
import org.apache.tapestry5.services.assets.ResourceTransformer;
+import org.apache.tapestry5.wro4j.WRO4JSymbols;
import org.apache.tapestry5.wro4j.services.ResourceProcessor;
import org.apache.tapestry5.wro4j.services.ResourceProcessorSource;
import org.slf4j.Logger;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
+import java.io.*;
import java.util.Map;
public class ResourceTransformerFactoryImpl implements ResourceTransformerFactory
@@ -39,28 +41,46 @@ public class ResourceTransformerFactoryImpl implements ResourceTransformerFactor
private final OperationTracker tracker;
- public ResourceTransformerFactoryImpl(Logger logger, ResourceProcessorSource source, OperationTracker tracker)
+ private final boolean productionMode;
+
+ private final File cacheDir;
+
+ public ResourceTransformerFactoryImpl(Logger logger, ResourceProcessorSource source, OperationTracker tracker,
+ @Symbol(SymbolConstants.PRODUCTION_MODE)
+ boolean productionMode,
+ @Symbol(WRO4JSymbols.CACHE_DIR)
+ String cacheDir)
{
this.logger = logger;
this.source = source;
this.tracker = tracker;
- }
+ this.productionMode = productionMode;
+ this.cacheDir = new File(cacheDir);
- static class Compiled
- {
- /**
- * Checksum of the raw source file.
- */
- final long checksum;
+ if (!productionMode)
+ {
+ logger.info(String.format("Using %s to store compiled assets (development mode only).", cacheDir));
+ }
+ }
- private final BytestreamCache bytestreamCache;
+ @PostInjection
+ public void createCacheDir()
+ {
+ cacheDir.mkdirs();
+ }
+ static class Compiled extends ContentChangeTracker
+ {
+ private BytestreamCache bytestreamCache;
- Compiled(long checksum, InputStream stream) throws IOException
+ Compiled(Resource root)
{
- this.checksum = checksum;
+ addDependency(root);
+ }
+ void store(InputStream stream) throws IOException
+ {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
TapestryInternalUtils.copy(stream, bos);
@@ -77,15 +97,46 @@ public class ResourceTransformerFactoryImpl implements ResourceTransformerFactor
}
}
- public ResourceTransformer createCompiler(final String contentType, String processorName, final String sourceName, final String targetName, boolean enableCache)
+
+ public ResourceTransformer createCompiler(final String contentType, String processorName, final String sourceName, final String targetName, CacheMode cacheMode)
{
// This does the real work:
ResourceProcessor resourceProcessor = source.getProcessor(processorName);
// And this adapts it to the API.
- final ResourceTransformer coreCompiler = createCoreCompiler(contentType, sourceName, targetName, resourceProcessor);
+ ResourceTransformer coreCompiler = createCoreCompiler(contentType, sourceName, targetName, resourceProcessor);
+
+ return createCompiler(contentType, sourceName, targetName, coreCompiler, cacheMode);
+
+ }
+
+ public ResourceTransformer createCompiler(String contentType, String sourceName, String targetName, ResourceTransformer transformer, CacheMode cacheMode)
+ {
+ ResourceTransformer trackingCompiler = wrapWithTracking(sourceName, targetName, transformer);
+
+ if (productionMode)
+ {
+ return trackingCompiler;
+ }
+
+ ResourceTransformer timingCompiler = wrapWithTiming(targetName, trackingCompiler);
+
+ switch (cacheMode)
+ {
+ case NONE:
+
+ return timingCompiler;
- return enableCache ? wrapWithCaching(coreCompiler, targetName) : coreCompiler;
+ case SINGLE_FILE:
+
+ return wrapWithFileSystemCaching(timingCompiler, targetName);
+
+ case MULTIPLE_FILE:
+
+ return wrapWithInMemoryCaching(timingCompiler, targetName);
+ }
+
+ return null; //To change body of implemented methods use File | Settings | File Templates.
}
private ResourceTransformer createCoreCompiler(final String contentType, final String sourceName, final String targetName, final ResourceProcessor resourceProcessor)
@@ -101,25 +152,62 @@ public class ResourceTransformerFactoryImpl implements ResourceTransformerFactor
{
final String description = String.format("Compiling %s from %s to %s", source, sourceName, targetName);
+ InputStream result = resourceProcessor.process(description,
+ source.toURL().toString(),
+ source.openStream(), contentType);
+
+ return result;
+
+ }
+ };
+ }
+
+ private ResourceTransformer wrapWithTracking(final String sourceName, final String targetName, final ResourceTransformer core)
+ {
+ return new ResourceTransformer()
+ {
+ public String getTransformedContentType()
+ {
+ return core.getTransformedContentType();
+ }
+
+ public InputStream transform(final Resource source, final ResourceDependencies dependencies) throws IOException
+ {
+ final String description = String.format("Compiling %s from %s to %s", source, sourceName, targetName);
+
return tracker.perform(description, new IOOperation<InputStream>()
{
public InputStream perform() throws IOException
{
- final long startTime = System.nanoTime();
+ return core.transform(source, dependencies);
+ }
+ });
+ }
+ };
+ }
- InputStream result = resourceProcessor.process(description,
- source.toURL().toString(),
- source.openStream(), contentType);
+ private ResourceTransformer wrapWithTiming(final String targetName, final ResourceTransformer coreCompiler)
+ {
+ return new ResourceTransformer()
+ {
+ public String getTransformedContentType()
+ {
+ return coreCompiler.getTransformedContentType();
+ }
- final long elapsedTime = System.nanoTime() - startTime;
+ public InputStream transform(final Resource source, final ResourceDependencies dependencies) throws IOException
+ {
+ final long startTime = System.nanoTime();
- logger.info(String.format("Compiled %s to %s in %.2f ms",
- source, targetName,
- ResourceTransformUtils.nanosToMillis(elapsedTime)));
+ InputStream result = coreCompiler.transform(source, dependencies);
- return result;
- }
- });
+ final long elapsedTime = System.nanoTime() - startTime;
+
+ logger.info(String.format("Compiled %s to %s in %.2f ms",
+ source, targetName,
+ ResourceTransformUtils.nanosToMillis(elapsedTime)));
+
+ return result;
}
};
}
@@ -131,7 +219,7 @@ public class ResourceTransformerFactoryImpl implements ResourceTransformerFactor
* somewhat primitive: a change to *any* resource in a given domain results in the cache of all of those resources
* being discarded.
*/
- private ResourceTransformer wrapWithCaching(final ResourceTransformer core, final String targetName)
+ private ResourceTransformer wrapWithInMemoryCaching(final ResourceTransformer core, final String targetName)
{
return new ResourceTransformer()
{
@@ -144,22 +232,21 @@ public class ResourceTransformerFactoryImpl implements ResourceTransformerFactor
public InputStream transform(Resource source, ResourceDependencies dependencies) throws IOException
{
- long checksum = ResourceTransformUtils.toChecksum(source);
-
Compiled compiled = cache.get(source);
- if (compiled != null && compiled.checksum == checksum)
+ if (compiled != null && !compiled.dirty())
{
- logger.info(String.format("Resource %s is unchanged; serving compiled %s content from cache",
+ logger.info(String.format("Resource %s and dependencies are unchanged; serving compiled %s content from in-memory cache",
source, targetName));
return compiled.openStream();
}
- InputStream is = core.transform(source, dependencies);
+ compiled = new Compiled(source);
+
+ InputStream is = core.transform(source, new ResourceDependenciesSplitter(dependencies, compiled));
- // There's probably a race condition here if the source changes as we are compiling it.
- compiled = new Compiled(checksum, is);
+ compiled.store(is);
cache.put(source, compiled);
@@ -167,4 +254,54 @@ public class ResourceTransformerFactoryImpl implements ResourceTransformerFactor
}
};
}
+
+ private ResourceTransformer wrapWithFileSystemCaching(final ResourceTransformer core, final String targetName)
+ {
+ return new ResourceTransformer()
+ {
+ public String getTransformedContentType()
+ {
+ return core.getTransformedContentType();
+ }
+
+ public InputStream transform(Resource source, ResourceDependencies dependencies) throws IOException
+ {
+ long checksum = ResourceTransformUtils.toChecksum(source);
+
+ String fileName = Long.toHexString(checksum) + "-" + source.getFile();
+
+ File cacheFile = new File(cacheDir, fileName);
+
+ if (cacheFile.exists())
+ {
+ logger.debug(String.format("Serving up compiled %s content for %s from file system cache", targetName, source));
+
+ return new BufferedInputStream(new FileInputStream(cacheFile));
+ }
+
+ InputStream compiled = core.transform(source, dependencies);
+
+ // We need the InputStream twice; once to return, and once to write out to the cache file for later.
+
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+
+ TapestryInternalUtils.copy(compiled, bos);
+
+ BytestreamCache cache = new BytestreamCache(bos);
+
+ writeToCacheFile(cacheFile, cache.openStream());
+
+ return cache.openStream();
+ }
+ };
+ }
+
+ private void writeToCacheFile(File file, InputStream stream) throws IOException
+ {
+ OutputStream outputStream = new BufferedOutputStream(new FileOutputStream(file));
+
+ TapestryInternalUtils.copy(stream, outputStream);
+
+ outputStream.close();
+ }
}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eaada44a/tapestry-wro4j/src/main/java/org/apache/tapestry5/wro4j/WRO4JSymbols.java
----------------------------------------------------------------------
diff --git a/tapestry-wro4j/src/main/java/org/apache/tapestry5/wro4j/WRO4JSymbols.java b/tapestry-wro4j/src/main/java/org/apache/tapestry5/wro4j/WRO4JSymbols.java
new file mode 100644
index 0000000..96e8b2e
--- /dev/null
+++ b/tapestry-wro4j/src/main/java/org/apache/tapestry5/wro4j/WRO4JSymbols.java
@@ -0,0 +1,25 @@
+// Copyright 2013 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.wro4j;
+
+public class WRO4JSymbols
+{
+ /**
+ * Directory that stores cached copies of compiled CoffeeScript files. The directory will be created
+ * as necessary. This allows compilation (e.g., CoffeeScript to JavaScript) to be avoided after a restart.
+ * The default is from the {@code java.io.tmpdir} system property (which is not necessarily stable between executions).
+ */
+ public static final String CACHE_DIR = "tapestry.compiled-asset-cache-dir";
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eaada44a/tapestry-wro4j/src/main/java/org/apache/tapestry5/wro4j/modules/WRO4JModule.java
----------------------------------------------------------------------
diff --git a/tapestry-wro4j/src/main/java/org/apache/tapestry5/wro4j/modules/WRO4JModule.java b/tapestry-wro4j/src/main/java/org/apache/tapestry5/wro4j/modules/WRO4JModule.java
index 5b35c23..e272448 100644
--- a/tapestry-wro4j/src/main/java/org/apache/tapestry5/wro4j/modules/WRO4JModule.java
+++ b/tapestry-wro4j/src/main/java/org/apache/tapestry5/wro4j/modules/WRO4JModule.java
@@ -17,19 +17,20 @@ package org.apache.tapestry5.wro4j.modules;
import com.github.sommeri.less4j.LessCompiler;
import com.github.sommeri.less4j.core.parser.AntlrException;
import org.apache.tapestry5.MarkupWriter;
-import org.apache.tapestry5.SymbolConstants;
import org.apache.tapestry5.internal.wro4j.*;
import org.apache.tapestry5.ioc.MappedConfiguration;
import org.apache.tapestry5.ioc.ServiceBinder;
import org.apache.tapestry5.ioc.annotations.Contribute;
import org.apache.tapestry5.ioc.annotations.Primary;
-import org.apache.tapestry5.ioc.annotations.Symbol;
import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
import org.apache.tapestry5.ioc.internal.util.InternalUtils;
+import org.apache.tapestry5.ioc.services.FactoryDefaults;
+import org.apache.tapestry5.ioc.services.SymbolProvider;
import org.apache.tapestry5.services.ObjectRenderer;
import org.apache.tapestry5.services.assets.ResourceMinimizer;
import org.apache.tapestry5.services.assets.ResourceTransformer;
import org.apache.tapestry5.services.assets.StreamableResourceSource;
+import org.apache.tapestry5.wro4j.WRO4JSymbols;
import org.apache.tapestry5.wro4j.services.ResourceProcessorSource;
import ro.isdc.wro.extensions.processor.js.GoogleClosureCompressorProcessor;
import ro.isdc.wro.extensions.processor.js.RhinoCoffeeScriptProcessor;
@@ -51,6 +52,13 @@ public class WRO4JModule
binder.bind(ResourceTransformerFactory.class, ResourceTransformerFactoryImpl.class);
}
+ @Contribute(SymbolProvider.class)
+ @FactoryDefaults
+ public static void setupDefaultCacheDirectory(MappedConfiguration<String, Object> configuration)
+ {
+ configuration.add(WRO4JSymbols.CACHE_DIR, "${java.io.tmpdir}");
+ }
+
/**
* Configures the default set of processors.
* <dl>
@@ -70,15 +78,16 @@ public class WRO4JModule
}
@Contribute(StreamableResourceSource.class)
- public static void provideCompilers(MappedConfiguration<String, ResourceTransformer> configuration, ResourceTransformerFactory factory,
- @Symbol(SymbolConstants.PRODUCTION_MODE)
- boolean productionMode)
+ public static void provideCompilers(MappedConfiguration<String, ResourceTransformer> configuration, ResourceTransformerFactory factory)
{
+ // contribution ids are file extensions:
+
configuration.add("coffee",
- factory.createCompiler("text/javascript", "CoffeeScriptCompiler", "CoffeeScript", "JavaScript", !productionMode));
+ factory.createCompiler("text/javascript", "CoffeeScriptCompiler", "CoffeeScript", "JavaScript", CacheMode.SINGLE_FILE));
- // Had to create our own wrapper around Less4J to handle @imports correctly.
- configuration.addInstance("less", LessResourceTransformer.class);
+ configuration.add("less",
+ factory.createCompiler("text/css", "Less", "CSS", new LessResourceTransformer(),
+ CacheMode.MULTIPLE_FILE));
}
@Contribute(ResourceMinimizer.class)
[2/3] git commit: Add cross-reference documentation
Posted by hl...@apache.org.
Add cross-reference documentation
Project: http://git-wip-us.apache.org/repos/asf/tapestry-5/repo
Commit: http://git-wip-us.apache.org/repos/asf/tapestry-5/commit/2beaaa9b
Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/2beaaa9b
Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/2beaaa9b
Branch: refs/heads/master
Commit: 2beaaa9b75faa6799b69687914e685515841e782
Parents: 476669d
Author: Howard M. Lewis Ship <hl...@apache.org>
Authored: Tue Jul 16 12:53:54 2013 -0700
Committer: Howard M. Lewis Ship <hl...@apache.org>
Committed: Tue Jul 16 12:53:54 2013 -0700
----------------------------------------------------------------------
.../java/org/apache/tapestry5/ioc/services/SymbolProvider.java | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/2beaaa9b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/SymbolProvider.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/SymbolProvider.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/SymbolProvider.java
index 7d39037..8a1f134 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/SymbolProvider.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/SymbolProvider.java
@@ -1,4 +1,4 @@
-// Copyright 2006, 2008 The Apache Software Foundation
+// Copyright 2006, 2008, 2013 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.
@@ -21,6 +21,9 @@ import org.apache.tapestry5.ioc.annotations.UsesMappedConfiguration;
* <p/>
* This is the service interface for the FactoryDefaults and ApplicationDefaults services; each of these takes a
* configuration mapping symbols to their values.
+ *
+ * @see FactoryDefaults
+ * @see ApplicationDefaults
*/
@UsesMappedConfiguration(String.class)
public interface SymbolProvider