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 2011/04/05 23:46:42 UTC

svn commit: r1089250 - in /tapestry/tapestry5/trunk/tapestry-core/src: main/java/org/apache/tapestry5/services/javascript/ test/conf/ test/groovy/org/apache/tapestry5/services/ test/groovy/org/apache/tapestry5/services/javascript/

Author: hlship
Date: Tue Apr  5 21:46:42 2011
New Revision: 1089250

URL: http://svn.apache.org/viewvc?rev=1089250&view=rev
Log:
TAP5-1502: Make it easier to create JavaScript Stacks using a standard implementation with an OrderedConfiguration

Added:
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/ExtensibleJavaScriptStack.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/StackExtension.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/StackExtensionType.java
    tapestry/tapestry5/trunk/tapestry-core/src/test/groovy/org/apache/tapestry5/services/
    tapestry/tapestry5/trunk/tapestry-core/src/test/groovy/org/apache/tapestry5/services/javascript/
    tapestry/tapestry5/trunk/tapestry-core/src/test/groovy/org/apache/tapestry5/services/javascript/ExtensibleJavaScriptStackTest.groovy
Modified:
    tapestry/tapestry5/trunk/tapestry-core/src/test/conf/testng.xml

Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/ExtensibleJavaScriptStack.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/ExtensibleJavaScriptStack.java?rev=1089250&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/ExtensibleJavaScriptStack.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/ExtensibleJavaScriptStack.java Tue Apr  5 21:46:42 2011
@@ -0,0 +1,127 @@
+// Copyright 2011 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.services.javascript;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.tapestry5.Asset;
+import org.apache.tapestry5.func.F;
+import org.apache.tapestry5.func.Flow;
+import org.apache.tapestry5.func.Mapper;
+import org.apache.tapestry5.func.Predicate;
+import org.apache.tapestry5.ioc.ServiceBinder;
+import org.apache.tapestry5.ioc.ServiceBindingOptions;
+import org.apache.tapestry5.ioc.annotations.UsesOrderedConfiguration;
+import org.apache.tapestry5.ioc.internal.util.InternalUtils;
+import org.apache.tapestry5.services.AssetSource;
+
+/**
+ * An extensible implementation of {@link JavaScriptStack} that can be used as the implementation of a service.
+ * The contributions to the service are used to supply the libraries, stylesheets, and initialization for a
+ * JavaScriptStack, allowing the stack to be more dynamically configured. In practice, one will use
+ * {@link ServiceBinder#bind(Class, Class)} and {@link ServiceBindingOptions#withMarker(Class...)} to construct the
+ * service, then use the marker annotation to inject the service when contributing the service into to the
+ * {@link JavaScriptStackSource}.
+ * <p>
+ * A limitation of this implementation is that the contributed assets are not localized at all.
+ * 
+ * @since 5.3.0
+ * @see StackExtension
+ */
+@UsesOrderedConfiguration(StackExtension.class)
+public class ExtensibleJavaScriptStack implements JavaScriptStack
+{
+    private final AssetSource assetSource;
+
+    private final List<Asset> libraries;
+
+    private final List<StylesheetLink> stylesheets;
+
+    private final String initialization;
+
+    private final Predicate<StackExtension> by(final StackExtensionType type)
+    {
+        return new Predicate<StackExtension>()
+        {
+            public boolean accept(StackExtension element)
+            {
+                return element.type == type;
+            }
+        };
+    }
+
+    private final Mapper<StackExtension, String> extractValue = new Mapper<StackExtension, String>()
+    {
+        public String map(StackExtension element)
+        {
+            return element.value;
+        };
+    };
+
+    private final Mapper<String, Asset> stringToAsset = new Mapper<String, Asset>()
+    {
+        public Asset map(String value)
+        {
+            return assetSource.getExpandedAsset(value);
+        };
+    };
+
+    private final Mapper<Asset, StylesheetLink> assetToStylesheetLink = new Mapper<Asset, StylesheetLink>()
+    {
+        public StylesheetLink map(Asset asset)
+        {
+            return new StylesheetLink(asset);
+        };
+    };
+
+    public ExtensibleJavaScriptStack(AssetSource assetSource, List<StackExtension> configuration)
+    {
+        this.assetSource = assetSource;
+
+        Flow<StackExtension> extensions = F.flow(configuration);
+
+        libraries = extensions.filter(by(StackExtensionType.LIBRARY)).map(extractValue).map(stringToAsset).toList();
+
+        stylesheets = extensions.filter(by(StackExtensionType.STYLESHEET)).map(extractValue).map(stringToAsset)
+                .map(assetToStylesheetLink).toList();
+
+        List<String> initializations = extensions.filter(by(StackExtensionType.INITIALIZATION)).map(extractValue)
+                .toList();
+
+        initialization = initializations.isEmpty() ? null : InternalUtils.join(initializations, "\n");
+    }
+
+    public List<String> getStacks()
+    {
+        return Collections.emptyList();
+    }
+
+    public List<Asset> getJavaScriptLibraries()
+    {
+        return libraries;
+    }
+
+    public List<StylesheetLink> getStylesheets()
+    {
+        return stylesheets;
+    }
+
+    public String getInitialization()
+    {
+        return initialization;
+    }
+
+}

Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/StackExtension.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/StackExtension.java?rev=1089250&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/StackExtension.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/StackExtension.java Tue Apr  5 21:46:42 2011
@@ -0,0 +1,37 @@
+// Copyright 2011 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.services.javascript;
+
+/**
+ * A contribution to an extensible {@link JavaScriptStack}. Such a stack is created in terms of all the contributions.
+ * 
+ * @since 5.3.0
+ * @see ExtensibleJavaScriptStack
+ */
+public class StackExtension
+{
+    /** The type of extension. */
+    public final StackExtensionType type;
+
+    /** The value contributed; will have symbols expanded, then be converted to the appropriate type. */
+    public final String value;
+
+    public StackExtension(StackExtensionType type, String value)
+    {
+        this.type = type;
+        this.value = value;
+    }
+
+}

Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/StackExtensionType.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/StackExtensionType.java?rev=1089250&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/StackExtensionType.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/StackExtensionType.java Tue Apr  5 21:46:42 2011
@@ -0,0 +1,43 @@
+// Copyright 2011 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.services.javascript;
+
+import org.apache.tapestry5.ioc.services.SymbolSource;
+import org.apache.tapestry5.services.AssetSource;
+
+/**
+ * Defines the types of extensions to a JavaScript stack that can be contributed to an extensible JavaScript stack.
+ * 
+ * @since 5.3.0
+ * @see StackExtension
+ * @see ExtensibleJavaScriptStack
+ */
+public enum StackExtensionType
+{
+    /**
+     * A JavaScript library. The extension value will be converted using {@link AssetSource#getExpandedAsset(String)},
+     * meaning that {@linkplain SymbolSource symbols} will be expanded.
+     */
+    LIBRARY,
+
+    /**
+     * A stylesheet. The extension value will be converted using {@link AssetSource#getExpandedAsset(String)},
+     * meaning that {@linkplain SymbolSource symbols} will be expanded.
+     */
+    STYLESHEET,
+
+    /** Extra JavaScript initialization (rarely used). No symbol expansion takes place. */
+    INITIALIZATION;
+}

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/conf/testng.xml
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/conf/testng.xml?rev=1089250&r1=1089249&r2=1089250&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/conf/testng.xml (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/conf/testng.xml Tue Apr  5 21:46:42 2011
@@ -23,6 +23,7 @@
       <package name="org.apache.tapestry5.dom"/>
       <package name="org.apache.tapestry5.runtime"/>
       <package name="org.apache.tapestry5.services"/>
+      <package name="org.apache.tapestry5.services.javascript"/>
       <package name="org.apache.tapestry5.util"/>
       <package name="org.apache.tapestry5.validator"/>
       <package name="org.apache.tapestry5.internal"/>

Added: tapestry/tapestry5/trunk/tapestry-core/src/test/groovy/org/apache/tapestry5/services/javascript/ExtensibleJavaScriptStackTest.groovy
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/groovy/org/apache/tapestry5/services/javascript/ExtensibleJavaScriptStackTest.groovy?rev=1089250&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/groovy/org/apache/tapestry5/services/javascript/ExtensibleJavaScriptStackTest.groovy (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/groovy/org/apache/tapestry5/services/javascript/ExtensibleJavaScriptStackTest.groovy Tue Apr  5 21:46:42 2011
@@ -0,0 +1,98 @@
+// Copyright 2011 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.services.javascript;
+
+import org.apache.tapestry5.Asset;
+import org.apache.tapestry5.services.AssetSource;
+import org.apache.tapestry5.test.TapestryTestCase;
+import org.testng.annotations.Test;
+
+/** @since 5.3.0 */
+class ExtensibleJavaScriptStackTest extends TapestryTestCase {
+
+    @Test
+    void contributed_libraries_are_expanded() {
+        def lib1path = '${lib1}/lib.js'
+        Asset lib1 = mockAsset()
+        def lib2path = '${lib2}/lib.js'
+        Asset lib2 = mockAsset()
+
+        AssetSource mockSource = mockAssetSource()
+
+        expect(mockSource.getExpandedAsset(lib1path)).andReturn(lib1)
+        expect(mockSource.getExpandedAsset(lib2path)).andReturn(lib2)
+
+        replay()
+
+        ExtensibleJavaScriptStack stack = new ExtensibleJavaScriptStack(mockSource, [
+            new StackExtension (StackExtensionType.LIBRARY, lib1path),
+            new StackExtension (StackExtensionType.LIBRARY, lib2path),
+        ])
+
+        assert stack.stacks.empty
+        assert stack.javaScriptLibraries == [lib1, lib2]
+        assert stack.stylesheets.empty
+        assert stack.initialization == null
+
+        verify()
+    }
+
+    @Test
+    void contributed_stylesheets_are_expanded() {
+        def stylesheet1path = '${stylesheet1}/stylesheet.css'
+        def stylesheet1URL = "/foo/ss1/stylesheet.css"
+        Asset stylesheet1 = mockAsset()
+        def stylesheet2path = '${stylesheet2}/stylesheet.js'
+        def stylesheet2URL = '/foo/ss2/stylesheet.css'
+
+        Asset stylesheet2 = mockAsset()
+
+        AssetSource mockSource = mockAssetSource()
+
+        expect(mockSource.getExpandedAsset(stylesheet1path)).andReturn(stylesheet1)
+        expect(mockSource.getExpandedAsset(stylesheet2path)).andReturn(stylesheet2)
+
+        expect(stylesheet1.toClientURL()).andReturn(stylesheet1URL).atLeastOnce()
+        expect(stylesheet2.toClientURL()).andReturn(stylesheet2URL).atLeastOnce()
+
+        replay()
+
+        ExtensibleJavaScriptStack stack = new ExtensibleJavaScriptStack(mockSource, [
+            new StackExtension (StackExtensionType.STYLESHEET, stylesheet1path),
+            new StackExtension (StackExtensionType.STYLESHEET, stylesheet2path),
+        ])
+
+        assert stack.stacks.empty
+        assert stack.javaScriptLibraries.empty
+        assert stack.stylesheets == [
+            new StylesheetLink(stylesheet1),
+            new StylesheetLink(stylesheet2)
+        ]
+
+        assert stack.initialization == null
+
+        verify()
+    }
+
+    @Test
+    void initializations_are_combined() {
+        ExtensibleJavaScriptStack stack = new ExtensibleJavaScriptStack(null, [
+            new StackExtension (StackExtensionType.INITIALIZATION, "doThis();"),
+            new StackExtension (StackExtensionType.INITIALIZATION, "doThat();"),
+        ])
+
+        assert stack.initialization == "doThis();\ndoThat();"
+    }
+}