This is an automated email from the ASF dual-hosted git repository. thiagohp pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/tapestry-5.git
The following commit(s) were added to refs/heads/master by this push: new 39f6cb203 TAP5-2803: support for global per-thread ES module config callbacks 39f6cb203 is described below commit 39f6cb20315b8b5fa7d9c6953a0863a989ba26cd Author: Thiago H. de Paula Figueiredo <thi...@arsmachina.com.br> AuthorDate: Sat May 3 12:38:44 2025 -0300 TAP5-2803: support for global per-thread ES module config callbacks --- .../services/javascript/EsModuleManagerImpl.java | 42 ++++++++++------ .../javascript/EsModuleConfigurationCallback.java | 28 +++++++++++ .../services/javascript/EsModuleManager.java | 57 ++++++++++++++++++++- .../tapestry5/integration/app1/EsModuleTests.java | 8 +++ .../integration/app1/pages/EsModuleDemo.java | 5 ++ .../integration/app1/services/AppModule.java | 58 +++++++++++++++------- 6 files changed, 163 insertions(+), 35 deletions(-) diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/javascript/EsModuleManagerImpl.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/javascript/EsModuleManagerImpl.java index 9f9bf5aea..97f95a554 100644 --- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/javascript/EsModuleManagerImpl.java +++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/javascript/EsModuleManagerImpl.java @@ -13,6 +13,7 @@ package org.apache.tapestry5.internal.services.javascript; import java.io.IOException; +import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; @@ -27,7 +28,6 @@ import org.apache.tapestry5.http.TapestryHttpSymbolConstants; import org.apache.tapestry5.internal.InternalConstants; import org.apache.tapestry5.internal.services.ajax.EsModuleInitializationImpl; import org.apache.tapestry5.internal.services.assets.ResourceChangeTracker; -import org.apache.tapestry5.ioc.annotations.PostInjection; import org.apache.tapestry5.ioc.annotations.Symbol; import org.apache.tapestry5.ioc.services.ClasspathMatcher; import org.apache.tapestry5.ioc.services.ClasspathScanner; @@ -70,10 +70,12 @@ public class EsModuleManagerImpl implements EsModuleManager private final ResourceChangeTracker resourceChangeTracker; - private final List<EsModuleConfigurationCallback> globalCallbacks; + private final List<EsModuleConfigurationCallback> baseCallbacks; + + private final List<EsModuleConfigurationCallback> globalPerRequestCallbacks; public EsModuleManagerImpl( - List<EsModuleConfigurationCallback> globalCallbacks, + List<EsModuleManagerContribution> contributions, AssetSource assetSource, StreamableResourceSource streamableResourceSource, @Symbol(SymbolConstants.COMPACT_JSON) @@ -86,9 +88,24 @@ public class EsModuleManagerImpl implements EsModuleManager this.compactJSON = compactJSON; this.assetSource = assetSource; this.classpathScanner = classpathScanner; - this.globalCallbacks = globalCallbacks; this.productionMode = productionMode; this.resourceChangeTracker = resourceChangeTracker; + + baseCallbacks = new ArrayList<>(); + globalPerRequestCallbacks = new ArrayList<>(); + + for (EsModuleManagerContribution contribution : contributions) + { + if (contribution.isBase()) + { + baseCallbacks.add(contribution.getCallback()); + } + else + { + globalPerRequestCallbacks.add(contribution.getCallback()); + } + } + importMap = new JSONObject(); extensions = CollectionFactory.newSet("js"); @@ -114,12 +131,14 @@ public class EsModuleManagerImpl implements EsModuleManager imports.put(name, cache.get(name)); } - this.importMap = executeCallbacks(importMap, globalCallbacks); + executeCallbacks(importMap, baseCallbacks); for (String id : imports.keySet()) { cache.put(id, imports.getString(id)); } + + this.importMap = importMap; } @@ -145,12 +164,6 @@ public class EsModuleManagerImpl implements EsModuleManager } } - @PostInjection - public void setupInvalidation(ResourceChangeTracker tracker) - { - - } - @Override public void writeImportMap(Element head, List<EsModuleConfigurationCallback> moduleConfigurationCallbacks) { @@ -160,7 +173,8 @@ public class EsModuleManagerImpl implements EsModuleManager JSONObject newImportMap = new JSONObject( EsModuleConfigurationCallback.IMPORTS_ATTRIBUTE, imports); - newImportMap = executeCallbacks(newImportMap, moduleConfigurationCallbacks); + executeCallbacks(newImportMap, moduleConfigurationCallbacks); + executeCallbacks(newImportMap, globalPerRequestCallbacks); head.element("script") .attribute("type", "importmap") @@ -332,14 +346,12 @@ public class EsModuleManagerImpl implements EsModuleManager script.attribute("type", "module"); } - private JSONObject executeCallbacks(JSONObject importMap, List<EsModuleConfigurationCallback> callbacks) + private void executeCallbacks(JSONObject importMap, List<EsModuleConfigurationCallback> callbacks) { for (EsModuleConfigurationCallback callback : callbacks) { callback.configure(importMap); } - - return importMap; } } diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/EsModuleConfigurationCallback.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/EsModuleConfigurationCallback.java index eb0e6adf9..2916b6374 100644 --- a/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/EsModuleConfigurationCallback.java +++ b/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/EsModuleConfigurationCallback.java @@ -13,6 +13,7 @@ package org.apache.tapestry5.services.javascript; import org.apache.tapestry5.json.JSONObject; +import org.apache.tapestry5.services.javascript.EsModuleManager.EsModuleManagerContribution; /** * Interface used to to change the JSON configuration object which will be used in the @@ -59,4 +60,31 @@ public interface EsModuleConfigurationCallback { object.in(IMPORTS_ATTRIBUTE).put(id, url); } + + /** + * Creates a base contribution (one that contributes a callback used + * when creating the base import map to be used for all requests). + * Utility method to call {@linkplain EsModuleManagerContribution#base(EsModuleConfigurationCallback)} + * @param callback an {@linkplain EsModuleConfigurationCallback} instance. + * @return a corresponding {@linkplain EsModuleManagerContribution}. + */ + public static EsModuleManagerContribution toBaseContribution(EsModuleConfigurationCallback callback) + { + return EsModuleManagerContribution.base(callback); + } + + /** + * Creates a global per-request contribution (one that contributes a callback used + * in all requests after the callbacks added through + * {@linkplain JavaScriptSupport#addEsModuleConfigurationCallback(EsModuleConfigurationCallback)} + * were called). + * Utility method to call {@linkplain EsModuleManagerContribution#globalPerRequest(EsModuleConfigurationCallback)} + * @param callback an {@linkplain EsModuleConfigurationCallback} instance. + * @return a corresponding {@linkplain EsModuleManagerContribution}. + */ + public static EsModuleManagerContribution toGlobalPerRequestContribution(EsModuleConfigurationCallback callback) + { + return EsModuleManagerContribution.globalPerRequest(callback); + } + } diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/EsModuleManager.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/EsModuleManager.java index 19cfec30b..70a3b00b0 100644 --- a/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/EsModuleManager.java +++ b/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/EsModuleManager.java @@ -16,6 +16,7 @@ import java.util.List; import org.apache.tapestry5.dom.Element; import org.apache.tapestry5.ioc.annotations.UsesOrderedConfiguration; +import org.apache.tapestry5.services.javascript.EsModuleManager.EsModuleManagerContribution; /** * Responsible for managing access to the ES modules. This service's distributed @@ -25,7 +26,7 @@ import org.apache.tapestry5.ioc.annotations.UsesOrderedConfiguration; * @since 5.10.0 * @see EsModuleConfigurationCallback */ -@UsesOrderedConfiguration(EsModuleConfigurationCallback.class) +@UsesOrderedConfiguration(EsModuleManagerContribution.class) public interface EsModuleManager { /** @@ -53,5 +54,59 @@ public interface EsModuleManager * specify initialization on the page, based on loading modules, extacting functions from modules, and invoking those functions */ void writeImports(Element root, List<EsModuleInitialization> inits); + + /** + * Encapsulates a contribution to {@linkplain EsModuleManager}. + * + * @since 5.10.0 + * @see EsModuleManager + * @see EsModuleConfigurationCallback + */ + public final class EsModuleManagerContribution + { + private final EsModuleConfigurationCallback callback; + + private final boolean isBase; + + EsModuleManagerContribution(EsModuleConfigurationCallback callback, boolean isBase) + { + super(); + this.callback = callback; + this.isBase = isBase; + } + + /** + * Creates a base contribution (one that contributes a callback used + * when creating the base import map to be used for all requests). + * @param callback an {@linkplain EsModuleConfigurationCallback} instance. + * @return a corresponding {@linkplain EsModuleManagerContribution}. + */ + public static EsModuleManagerContribution base(EsModuleConfigurationCallback callback) + { + return new EsModuleManagerContribution(callback, true); + } + + /** + * Creates a global per-request contribution (one that contributes a callback used + * in all requests after the callbacks added through + * {@linkplain JavaScriptSupport#addEsModuleConfigurationCallback(EsModuleConfigurationCallback)} + * were called). + * @param callback an {@linkplain EsModuleConfigurationCallback} instance. + * @return a corresponding {@linkplain EsModuleManagerContribution}. + */ + public static EsModuleManagerContribution globalPerRequest(EsModuleConfigurationCallback callback) + { + return new EsModuleManagerContribution(callback, false); + } + + public EsModuleConfigurationCallback getCallback() { + return callback; + } + + public boolean isBase() { + return isBase; + } + + } } diff --git a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/EsModuleTests.java b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/EsModuleTests.java index 786d9ce0b..aeb433496 100644 --- a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/EsModuleTests.java +++ b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/EsModuleTests.java @@ -12,10 +12,13 @@ package org.apache.tapestry5.integration.app1; + import static org.apache.tapestry5.integration.app1.services.AppModule.NON_OVERRIDDEN_ES_MODULE_ID; import static org.apache.tapestry5.integration.app1.services.AppModule.NON_OVERRIDDEN_ES_MODULE_URL; import static org.apache.tapestry5.integration.app1.services.AppModule.OVERRIDDEN_ES_MODULE_ID; import static org.apache.tapestry5.integration.app1.services.AppModule.OVERRIDDEN_ES_MODULE_NEW_URL; +import static org.apache.tapestry5.integration.app1.services.AppModule.OVERRIDDEN_GLOBALLY_ES_MODULE_ID; +import static org.apache.tapestry5.integration.app1.services.AppModule.OVERRIDDEN_GLOBALLY_ES_MODULE_NEW_URL; import org.apache.tapestry5.annotations.Import; import org.apache.tapestry5.integration.app1.pages.EsModuleDemo; @@ -83,6 +86,11 @@ public class EsModuleTests extends App1TestCase JSONObject importMap = getImportMap(); assertModuleUrl(NON_OVERRIDDEN_ES_MODULE_ID, NON_OVERRIDDEN_ES_MODULE_URL, importMap); assertModuleUrl(OVERRIDDEN_ES_MODULE_ID, EsModuleDemo.REQUEST_OVERRIDEN_MODULE_URL, importMap); + + // Module first defined through callback added to JavaScriptSupport, + // then overriden by a global per-request callback. + assertModuleUrl(OVERRIDDEN_GLOBALLY_ES_MODULE_ID, OVERRIDDEN_GLOBALLY_ES_MODULE_NEW_URL, importMap); + // Now without import map changed by request callbacks, so we can test // the global import map wasn't affected. diff --git a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/EsModuleDemo.java b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/EsModuleDemo.java index 49c38710d..e6eb761e3 100644 --- a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/EsModuleDemo.java +++ b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/EsModuleDemo.java @@ -79,6 +79,11 @@ public class EsModuleDemo AppModule.OVERRIDDEN_ES_MODULE_ID, REQUEST_OVERRIDEN_MODULE_URL)); } + javaScriptSupport.addEsModuleConfigurationCallback( + o -> EsModuleConfigurationCallback.setImport(o, + AppModule.OVERRIDDEN_GLOBALLY_ES_MODULE_ID, + AppModule.OVERRIDDEN_GLOBALLY_ES_MODULE_ORIGINAL_URL)); + } void onActivate(boolean overrideEsModuleImportAgain) diff --git a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/services/AppModule.java b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/services/AppModule.java index e8b91f4d0..d067f8cac 100644 --- a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/services/AppModule.java +++ b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/services/AppModule.java @@ -14,6 +14,9 @@ package org.apache.tapestry5.integration.app1.services; import static java.lang.annotation.ElementType.FIELD; import static java.lang.annotation.ElementType.PARAMETER; import static java.lang.annotation.RetentionPolicy.RUNTIME; +import static org.apache.tapestry5.services.javascript.EsModuleConfigurationCallback.setImport; +import static org.apache.tapestry5.services.javascript.EsModuleConfigurationCallback.toBaseContribution; +import static org.apache.tapestry5.services.javascript.EsModuleConfigurationCallback.toGlobalPerRequestContribution; import java.io.IOException; import java.lang.annotation.Documented; @@ -60,6 +63,7 @@ import org.apache.tapestry5.services.ResourceDigestGenerator; import org.apache.tapestry5.services.ValueEncoderFactory; import org.apache.tapestry5.services.ValueLabelProvider; import org.apache.tapestry5.services.javascript.EsModuleConfigurationCallback; +import org.apache.tapestry5.services.javascript.EsModuleManager.EsModuleManagerContribution; import org.apache.tapestry5.services.pageload.PageCachingReferenceTypeService; import org.apache.tapestry5.services.pageload.PagePreloader; import org.apache.tapestry5.services.pageload.PreloaderMode; @@ -488,32 +492,48 @@ public class AppModule public static final String OVERRIDDEN_ES_MODULE_ORIGINAL_URL = "/originalURL"; public static final String OVERRIDDEN_ES_MODULE_NEW_URL = "/overridenURL"; + + public static final String OVERRIDDEN_GLOBALLY_ES_MODULE_ID = "globallyPerRequestOverriden"; + + public static final String OVERRIDDEN_GLOBALLY_ES_MODULE_ORIGINAL_URL = "/globallyPerRequestOverridenOriginalURL"; + + public static final String OVERRIDDEN_GLOBALLY_ES_MODULE_NEW_URL = "/globallyPerRequestOverridenURL"; + public static void contributeEsModuleManager( - OrderedConfiguration<EsModuleConfigurationCallback> configuration, + OrderedConfiguration<EsModuleManagerContribution> configuration, AssetSource assetSource) { - final String original = "OriginalCallback"; - final String override = "OverrideCallback"; + final String originalId = "OriginalCallback"; + final String overrideId = "OverrideCallback"; - configuration.add(override, - o -> EsModuleConfigurationCallback.setImport(o, OVERRIDDEN_ES_MODULE_ID, OVERRIDDEN_ES_MODULE_NEW_URL), - "after:" + original); + configuration.add(overrideId, + toBaseContribution(o -> setImport(o, OVERRIDDEN_ES_MODULE_ID, OVERRIDDEN_ES_MODULE_NEW_URL)), + "after:" + originalId); + + configuration.add(originalId, + toBaseContribution( + o -> { + setImport(o, NON_OVERRIDDEN_ES_MODULE_ID, NON_OVERRIDDEN_ES_MODULE_URL); + setImport(o, OVERRIDDEN_ES_MODULE_ID, OVERRIDDEN_ES_MODULE_ORIGINAL_URL); + })); + + final String outsideMetaInfAssetUrl = assetSource + .getClasspathAsset("/org/apache/tapestry5/integration/app1/es-module-outside-metainf.js") + .toClientURL(); + + configuration.add("Outside META-INF", + toBaseContribution(o -> setImport(o, "outside-metainf", outsideMetaInfAssetUrl))); + + configuration.add("External URL", toBaseContribution( + o -> setImport(o, "external/url", "https://example.com/module.js"))); - configuration.add(original, - o -> { - EsModuleConfigurationCallback.setImport(o, NON_OVERRIDDEN_ES_MODULE_ID, NON_OVERRIDDEN_ES_MODULE_URL); - EsModuleConfigurationCallback.setImport(o, OVERRIDDEN_ES_MODULE_ID, OVERRIDDEN_ES_MODULE_ORIGINAL_URL); - }); + configuration.add("Globally per-request overriden", + toGlobalPerRequestContribution( + o -> setImport(o, + OVERRIDDEN_GLOBALLY_ES_MODULE_ID, + OVERRIDDEN_GLOBALLY_ES_MODULE_NEW_URL))); - configuration.add("Outside META-INF", o -> - EsModuleConfigurationCallback.setImport(o, "outside-metainf", - assetSource.getClasspathAsset("/org/apache/tapestry5/integration/app1/es-module-outside-metainf.js").toClientURL()) - ); - - configuration.add("External URL", o -> - EsModuleConfigurationCallback.setImport(o, "external/url", "https://example.com/module.js") - ); }