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/08/26 08:57:51 UTC
[17/21] Complete the rename of the module and the packages
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/6e42b37c/tapestry-webresources/src/main/java/org/apache/tapestry5/internal/webresources/RhinoExecutorPool.java
----------------------------------------------------------------------
diff --git a/tapestry-webresources/src/main/java/org/apache/tapestry5/internal/webresources/RhinoExecutorPool.java b/tapestry-webresources/src/main/java/org/apache/tapestry5/internal/webresources/RhinoExecutorPool.java
new file mode 100644
index 0000000..efc9de8
--- /dev/null
+++ b/tapestry-webresources/src/main/java/org/apache/tapestry5/internal/webresources/RhinoExecutorPool.java
@@ -0,0 +1,147 @@
+package org.apache.tapestry5.internal.webresources;
+
+import org.apache.tapestry5.ioc.Invokable;
+import org.apache.tapestry5.ioc.OperationTracker;
+import org.apache.tapestry5.ioc.Resource;
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.ioc.internal.util.InternalUtils;
+import org.apache.tapestry5.ioc.util.ExceptionUtils;
+import org.apache.tapestry5.ioc.util.Stack;
+import org.mozilla.javascript.Context;
+import org.mozilla.javascript.ContextFactory;
+import org.mozilla.javascript.NativeFunction;
+import org.mozilla.javascript.ScriptableObject;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.util.List;
+
+/**
+ * Manages a pool of initialized {@link RhinoExecutor} instances. The instances are initialized for a particular
+ */
+public class RhinoExecutorPool
+{
+ private final OperationTracker tracker;
+
+ private final List<Resource> scripts;
+
+ private final Stack<RhinoExecutor> executors = CollectionFactory.newStack();
+
+ private final ContextFactory contextFactory = new ContextFactory();
+
+ public RhinoExecutorPool(OperationTracker tracker, List<Resource> scripts)
+ {
+ this.tracker = tracker;
+ this.scripts = scripts;
+ }
+
+ /**
+ * Gets or creates an available executor. It is expected that {@link #put(RhinoExecutor)} will
+ * be invoked after the executor completes.
+ *
+ * @return executor
+ */
+ public synchronized RhinoExecutor get()
+ {
+
+ if (executors.isEmpty())
+ {
+ return createExecutor();
+ }
+
+ return executors.pop();
+ }
+
+ private synchronized void put(RhinoExecutor executor)
+ {
+ executors.push(executor);
+ }
+
+ private RhinoExecutor createExecutor()
+ {
+ return tracker.invoke(String.format("Creating Rhino executor for source(s) %s.",
+ InternalUtils.join(scripts)),
+ new Invokable<RhinoExecutor>()
+ {
+ public RhinoExecutor invoke()
+ {
+ final Context context = contextFactory.enterContext();
+
+ final ScriptableObject scope = context.initStandardObjects();
+
+ try
+ {
+ context.setOptimizationLevel(-1);
+
+ for (Resource script : scripts)
+ {
+ loadScript(context, scope, script);
+ }
+
+ } finally
+ {
+ Context.exit();
+ }
+
+ return new RhinoExecutor()
+ {
+ public ScriptableObject invokeFunction(String functionName, Object... arguments)
+ {
+ contextFactory.enterContext(context);
+
+ try
+ {
+ NativeFunction function = (NativeFunction) scope.get(functionName, scope);
+
+ return (ScriptableObject) function.call(context, scope, null, arguments);
+ } finally
+ {
+ Context.exit();
+ }
+ }
+
+ public void discard()
+ {
+ put(this);
+ }
+ };
+ }
+ });
+ }
+
+ private void loadScript(final Context context, final ScriptableObject scope, final Resource script)
+ {
+ tracker.run(String.format("Loading script %s.", script),
+ new Runnable()
+ {
+ public void run()
+ {
+ InputStream in = null;
+ Reader r = null;
+
+ try
+ {
+ in = script.openStream();
+ r = new InputStreamReader(in);
+
+ context.evaluateReader(scope, r, script.toString(), 1, null);
+ } catch (IOException ex)
+ {
+ throw new RuntimeException(String.format("Unable to read script %s: %s",
+ script,
+ ExceptionUtils.toMessage(ex)
+ ), ex);
+ } finally
+ {
+ InternalUtils.close(r);
+ InternalUtils.close(in);
+ }
+ }
+ });
+
+ }
+
+
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/6e42b37c/tapestry-webresources/src/main/java/org/apache/tapestry5/webresources/WebResourcesSymbols.java
----------------------------------------------------------------------
diff --git a/tapestry-webresources/src/main/java/org/apache/tapestry5/webresources/WebResourcesSymbols.java b/tapestry-webresources/src/main/java/org/apache/tapestry5/webresources/WebResourcesSymbols.java
new file mode 100644
index 0000000..82bd018
--- /dev/null
+++ b/tapestry-webresources/src/main/java/org/apache/tapestry5/webresources/WebResourcesSymbols.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.webresources;
+
+public class WebResourcesSymbols
+{
+ /**
+ * 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/6e42b37c/tapestry-webresources/src/main/java/org/apache/tapestry5/webresources/modules/WebResourcesModule.java
----------------------------------------------------------------------
diff --git a/tapestry-webresources/src/main/java/org/apache/tapestry5/webresources/modules/WebResourcesModule.java b/tapestry-webresources/src/main/java/org/apache/tapestry5/webresources/modules/WebResourcesModule.java
new file mode 100644
index 0000000..1948873
--- /dev/null
+++ b/tapestry-webresources/src/main/java/org/apache/tapestry5/webresources/modules/WebResourcesModule.java
@@ -0,0 +1,126 @@
+// 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.webresources.modules;
+
+import com.github.sommeri.less4j.LessCompiler;
+import com.github.sommeri.less4j.core.parser.AntlrException;
+import org.apache.tapestry5.MarkupWriter;
+import org.apache.tapestry5.internal.webresources.*;
+import org.apache.tapestry5.ioc.MappedConfiguration;
+import org.apache.tapestry5.ioc.ServiceBinder;
+import org.apache.tapestry5.ioc.annotations.Autobuild;
+import org.apache.tapestry5.ioc.annotations.Contribute;
+import org.apache.tapestry5.ioc.annotations.Primary;
+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.webresources.WebResourcesSymbols;
+
+import java.util.List;
+
+/**
+ * Configures use of various transformers and mimimizers to support:
+ * <ul>
+ * <li>Less to CSS</li>
+ * <li>CoffeeScript to JavaScript</li>
+ * <li>CSS minimization via YUI Compressor</li>
+ * <li>JavaScript minimization via Google Closure</li>
+ * </ul>
+ *
+ * @since 5.4
+ */
+public class WebResourcesModule
+{
+ public static void bind(ServiceBinder binder)
+ {
+ binder.bind(ResourceTransformerFactory.class, ResourceTransformerFactoryImpl.class);
+ }
+
+ @Contribute(SymbolProvider.class)
+ @FactoryDefaults
+ public static void setupDefaultCacheDirectory(MappedConfiguration<String, Object> configuration)
+ {
+ configuration.add(WebResourcesSymbols.CACHE_DIR, "${java.io.tmpdir}");
+ }
+
+
+ @Contribute(StreamableResourceSource.class)
+ public static void provideCompilers(MappedConfiguration<String, ResourceTransformer> configuration, ResourceTransformerFactory factory,
+ @Autobuild CoffeeScriptCompiler coffeeScriptCompiler)
+ {
+ // contribution ids are file extensions:
+
+ configuration.add("coffee",
+ factory.createCompiler("text/javascript", "CoffeeScript", "JavaScript",
+ coffeeScriptCompiler,
+ CacheMode.SINGLE_FILE));
+
+ configuration.add("less",
+ factory.createCompiler("text/css", "Less", "CSS", new LessResourceTransformer(),
+ CacheMode.MULTIPLE_FILE));
+ }
+
+ @Contribute(ResourceMinimizer.class)
+ @Primary
+ public static void setupDefaultResourceMinimizers(MappedConfiguration<String, ResourceMinimizer> configuration)
+ {
+ configuration.addInstance("text/css", CSSMinimizer.class);
+ configuration.addInstance("text/javascript", GoogleClosureMinimizer.class);
+ }
+
+ /**
+ * Alas {@link AntlrException}s do not have a useful toString() which makes them useless in the exception report;
+ * here we provide an {@link ObjectRenderer} that breaks them apart into useful strings. Eventually we may be
+ * able to synthesize a {@link org.apache.tapestry5.ioc.Location} from them as well and show some of the source .less file.
+ */
+ @Contribute(ObjectRenderer.class)
+ @Primary
+ public static void provideLessCompilerProblemRenderer(MappedConfiguration<Class, ObjectRenderer> configuration)
+ {
+ configuration.add(LessCompiler.Problem.class, new ObjectRenderer<LessCompiler.Problem>()
+ {
+ public void render(LessCompiler.Problem problem, MarkupWriter writer)
+ {
+ List<String> strings = CollectionFactory.newList();
+
+ if (InternalUtils.isNonBlank(problem.getMessage()))
+ {
+ strings.add(problem.getMessage());
+ }
+
+ // Inside WRO4J we see that the LessSource is a StringSource with no useful toString(), so
+ // it is omitted. We may need to create our own processors, stripping away a couple of layers of
+ // WRO4J to get proper exception reporting!
+
+ if (problem.getLine() > 0)
+ {
+ strings.add("line " + problem.getLine());
+ }
+
+ if (problem.getCharacter() > 0)
+ {
+ strings.add("position " + problem.getCharacter());
+ }
+
+ writer.write(InternalUtils.join(strings, " - "));
+ }
+ });
+ }
+}