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, " - "));
+            }
+        });
+    }
+}