Coalesce module inits with the same module name and function name and no arguments
Project: http://git-wip-us.apache.org/repos/asf/tapestry-5/repo Commit: http://git-wip-us.apache.org/repos/asf/tapestry-5/commit/0a3e456f Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/0a3e456f Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/0a3e456f Branch: refs/heads/5.4-js-rewrite Commit: 0a3e456ffe4e7a2ba2aedd047d79d2aab57b3e09 Parents: c7ba52c Author: Howard M. Lewis Ship <[email protected]> Authored: Mon Aug 13 14:35:12 2012 -0700 Committer: Howard M. Lewis Ship <[email protected]> Committed: Mon Aug 13 14:35:12 2012 -0700 ---------------------------------------------------------------------- .../internal/services/DocumentLinkerImpl.java | 39 +------ .../internal/services/ModuleInitsManager.java | 81 +++++++++++++++ .../services/PartialMarkupDocumentLinker.java | 49 ++------- .../services/javascript/Initialization.java | 18 +++- .../services/javascript/JavaScriptSupport.java | 4 +- .../services/DocumentLinkerImplTest.groovy | 28 +++++ 6 files changed, 143 insertions(+), 76 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/0a3e456f/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DocumentLinkerImpl.java ---------------------------------------------------------------------- diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DocumentLinkerImpl.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DocumentLinkerImpl.java index b51a896..80235f3 100644 --- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DocumentLinkerImpl.java +++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DocumentLinkerImpl.java @@ -17,21 +17,18 @@ package org.apache.tapestry5.internal.services; import org.apache.tapestry5.dom.Document; import org.apache.tapestry5.dom.Element; import org.apache.tapestry5.ioc.internal.util.CollectionFactory; -import org.apache.tapestry5.ioc.internal.util.InternalUtils; import org.apache.tapestry5.json.JSONArray; import org.apache.tapestry5.services.javascript.InitializationPriority; import org.apache.tapestry5.services.javascript.ModuleManager; import org.apache.tapestry5.services.javascript.StylesheetLink; -import java.util.ArrayList; import java.util.List; -import java.util.Map; public class DocumentLinkerImpl implements DocumentLinker { private final List<String> libraryURLs = CollectionFactory.newList(); - private final Map<InitializationPriority, List<JSONArray>> priorityToModuleInit = CollectionFactory.newMap(); + private final ModuleInitsManager initsManager = new ModuleInitsManager(); private final List<StylesheetLink> includedStylesheets = CollectionFactory.newList(); @@ -44,8 +41,6 @@ public class DocumentLinkerImpl implements DocumentLinker // Initially false; set to true when a scriptURL or any kind of initialization is added. private boolean hasScriptsOrInitializations; - private int initCount; - /** * @param moduleManager * used to identify the root folder for dynamically loaded modules @@ -81,19 +76,9 @@ public class DocumentLinkerImpl implements DocumentLinker public void addInitialization(InitializationPriority priority, String moduleName, String functionName, JSONArray arguments) { - JSONArray init = new JSONArray(); - - String name = functionName == null ? moduleName : moduleName + ":" + functionName; - - init.put(name); - - init.putAll(arguments); - - InternalUtils.addToMapList(priorityToModuleInit, priority, init); + initsManager.addInitialization(priority, moduleName, functionName, arguments); hasScriptsOrInitializations = true; - - initCount++; } /** @@ -189,22 +174,6 @@ public class DocumentLinkerImpl implements DocumentLinker return container; } - private List<JSONArray> forPriority(InitializationPriority... priorities) - { - List<JSONArray> result = new ArrayList<JSONArray>(initCount); - - for (InitializationPriority p : priorities) - { - List<JSONArray> inits = priorityToModuleInit.get(p); - - if (inits != null) - { - result.addAll(inits); - } - } - - return result; - } /** * Adds {@code <script>} elements for the RequireJS library, then any statically includes JavaScript libraries @@ -220,8 +189,8 @@ public class DocumentLinkerImpl implements DocumentLinker // Eventually, (nearly) everything will be loaded as modules. moduleManager.writeInitialization(body, libraryURLs, - forPriority(InitializationPriority.IMMEDIATE), - forPriority(InitializationPriority.EARLY, InitializationPriority.NORMAL, InitializationPriority.LATE)); + initsManager.forPriority(InitializationPriority.IMMEDIATE), + initsManager.forPriority(InitializationPriority.EARLY, InitializationPriority.NORMAL, InitializationPriority.LATE)); } private static Element createTemporaryContainer(Element headElement, String existingElementName, String newElementName) http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/0a3e456f/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ModuleInitsManager.java ---------------------------------------------------------------------- diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ModuleInitsManager.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ModuleInitsManager.java new file mode 100644 index 0000000..1442ab9 --- /dev/null +++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ModuleInitsManager.java @@ -0,0 +1,81 @@ +// Copyright 2012 The Apache Software Foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package org.apache.tapestry5.internal.services; + +import org.apache.tapestry5.ioc.internal.util.CollectionFactory; +import org.apache.tapestry5.ioc.internal.util.InternalUtils; +import org.apache.tapestry5.json.JSONArray; +import org.apache.tapestry5.services.javascript.InitializationPriority; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +public class ModuleInitsManager +{ + private final Set<String> pureInits = CollectionFactory.newSet(); + + private final Map<InitializationPriority, List<JSONArray>> inits = CollectionFactory.newMap(); + + private int initCount; + + public void addInitialization(InitializationPriority priority, String moduleName, String functionName, JSONArray arguments) + { + assert priority != null; + assert InternalUtils.isNonBlank(moduleName); + + String name = functionName == null ? moduleName : moduleName + ":" + functionName; + + if ((arguments == null || arguments.length() == 0)) + { + if (pureInits.contains(name)) + { + // A degenerate case is a pure init added repeatedly with different priorities. That isn't handled: + // the first priority wins. + return; + } + + pureInits.add(name); + } + + JSONArray init = new JSONArray(); + + init.put(name); + + init.putAll(arguments); + + InternalUtils.addToMapList(inits, priority, init); + + initCount++; + } + + public List<JSONArray> forPriority(InitializationPriority... priorities) + { + List<JSONArray> result = new ArrayList<JSONArray>(initCount); + + for (InitializationPriority p : priorities) + { + List<JSONArray> initsForPriority = inits.get(p); + + if (initsForPriority != null) + { + result.addAll(initsForPriority); + } + } + + return result; + } +} http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/0a3e456f/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PartialMarkupDocumentLinker.java ---------------------------------------------------------------------- diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PartialMarkupDocumentLinker.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PartialMarkupDocumentLinker.java index 0560f6b..fe64a04 100644 --- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PartialMarkupDocumentLinker.java +++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PartialMarkupDocumentLinker.java @@ -15,23 +15,18 @@ package org.apache.tapestry5.internal.services; import org.apache.tapestry5.internal.InternalConstants; -import org.apache.tapestry5.ioc.internal.util.CollectionFactory; -import org.apache.tapestry5.ioc.internal.util.InternalUtils; import org.apache.tapestry5.json.JSONArray; import org.apache.tapestry5.json.JSONObject; import org.apache.tapestry5.services.javascript.InitializationPriority; import org.apache.tapestry5.services.javascript.StylesheetLink; -import java.util.List; -import java.util.Map; - public class PartialMarkupDocumentLinker implements DocumentLinker { private final JSONArray libraryURLs = new JSONArray(); private final JSONArray stylesheets = new JSONArray(); - private final Map<InitializationPriority, List<JSONArray>> initsByPriority = CollectionFactory.newMap(); + private final ModuleInitsManager initsManager = new ModuleInitsManager(); public void addLibrary(String libraryURL) { @@ -58,13 +53,7 @@ public class PartialMarkupDocumentLinker implements DocumentLinker @Override public void addInitialization(InitializationPriority priority, String moduleName, String functionName, JSONArray arguments) { - String qualifiedName = functionName == null ? moduleName : moduleName + ":" + functionName; - - JSONArray init = new JSONArray().put(qualifiedName); - - init.putAll(arguments); - - InternalUtils.addToMapList(initsByPriority, priority, init); + initsManager.addInitialization(priority, moduleName, functionName, arguments); } /** @@ -75,44 +64,26 @@ public class PartialMarkupDocumentLinker implements DocumentLinker */ public void commit(JSONObject reply) { - JSONArray fullInits = new JSONArray(); - - for (InitializationPriority p : InitializationPriority.values()) + if (libraryURLs.length() > 0) { - List<JSONArray> priorityInits = initsByPriority.get(p); - - if (priorityInits != null) - { - for (JSONArray init : priorityInits) - { - fullInits.put(init); - } - } + reply.in(InternalConstants.PARTIAL_KEY).put("libraries", libraryURLs); } - boolean hasWork = libraryURLs.length() > 0 || stylesheets.length() > 0 || fullInits.length() > 0; - - if (!hasWork) + if (stylesheets.length() > 0) { - return; + reply.in(InternalConstants.PARTIAL_KEY).put("stylesheets", stylesheets); } - JSONObject partial = reply.in(InternalConstants.PARTIAL_KEY); - - - if (libraryURLs.length() > 0) - { - partial.put("libraries", libraryURLs); - } + JSONArray fullInits = new JSONArray(); - if (stylesheets.length() > 0) + for (InitializationPriority p : InitializationPriority.values()) { - partial.put("stylesheets", stylesheets); + fullInits.putAll(initsManager.forPriority(p)); } if (fullInits.length() > 0) { - partial.put("inits", fullInits); + reply.in(InternalConstants.PARTIAL_KEY).put("inits", fullInits); } } } http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/0a3e456f/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/Initialization.java ---------------------------------------------------------------------- diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/Initialization.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/Initialization.java index 9fafcf6..b201de8 100644 --- a/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/Initialization.java +++ b/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/Initialization.java @@ -1,3 +1,17 @@ +// Copyright 2012 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; /** @@ -30,7 +44,9 @@ public interface Initialization /** * Specifies the arguments to be passed to the function. Normally, just a single {@link org.apache.tapestry5.json.JSONObject} - * is passed. + * is passed. When multiple Initializations exist with the same function name (or no function name), and no arguments, + * they are coalesced into a single Initialization: it is assumed that an initialization with no parameters needs to + * only be invoked once. * * @param arguments * any number of values. Each value may be one of: null, String, Boolean, Number, http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/0a3e456f/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/JavaScriptSupport.java ---------------------------------------------------------------------- diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/JavaScriptSupport.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/JavaScriptSupport.java index 2fc30bc..f9db282 100644 --- a/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/JavaScriptSupport.java +++ b/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/JavaScriptSupport.java @@ -226,7 +226,9 @@ public interface JavaScriptSupport /** - * Requires a JavaScript module by name. On the c + * Requires a JavaScript module by name. On the client, this will <code>require()</code> the module and + * (optionally) de-reference a function exported by the module (or, treat the module as exporting a single + * implicit function). The function will be invoked. * * @param moduleName * the name of the module to require http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/0a3e456f/tapestry-core/src/test/groovy/org/apache/tapestry5/internal/services/DocumentLinkerImplTest.groovy ---------------------------------------------------------------------- diff --git a/tapestry-core/src/test/groovy/org/apache/tapestry5/internal/services/DocumentLinkerImplTest.groovy b/tapestry-core/src/test/groovy/org/apache/tapestry5/internal/services/DocumentLinkerImplTest.groovy index 4f5efad..f23f1ab 100644 --- a/tapestry-core/src/test/groovy/org/apache/tapestry5/internal/services/DocumentLinkerImplTest.groovy +++ b/tapestry-core/src/test/groovy/org/apache/tapestry5/internal/services/DocumentLinkerImplTest.groovy @@ -361,6 +361,34 @@ class DocumentLinkerImplTest extends InternalBaseTestCase { verify() } + @Test + void module_initialization_with_no_parameters_coalesce() throws Exception { + Document document = new Document() + + Element head = document.newRootElement("html").element("head") + + head.element("meta") + + def manager = mockModuleManager([], [], [new JSONArray("['my/module']"), + new JSONArray("my/other/module:normal", 111, 222)]) + + DocumentLinkerImpl linker = new DocumentLinkerImpl(manager, true, "1.2.3") + + replay() + + linker.addInitialization(InitializationPriority.NORMAL, "my/module", null, null) + linker.addInitialization(InitializationPriority.NORMAL, "my/other/module", "normal", new JSONArray(111, 222)) + linker.addInitialization(InitializationPriority.NORMAL, "my/module", null, new JSONArray()); + + linker.updateDocument(document) + + check document, ''' +<html><head><meta/></head><body><!--MODULE-MANAGER-INITIALIZATION--></body></html> +''' + + verify() + } + private ModuleManager mockModuleManager(scripts, immediateInits, deferredInits) { ModuleManager mock = newMock(ModuleManager);
