You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by hl...@apache.org on 2013/09/12 03:25:43 UTC

[1/3] git commit: Fix issue where servlet container 500 could occur if a page was not loadable

Updated Branches:
  refs/heads/master 41d7d4e40 -> 41e501344


Fix issue where servlet container 500 could occur if a page was not loadable


Project: http://git-wip-us.apache.org/repos/asf/tapestry-5/repo
Commit: http://git-wip-us.apache.org/repos/asf/tapestry-5/commit/88008b23
Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/88008b23
Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/88008b23

Branch: refs/heads/master
Commit: 88008b23bd2cb2ce39bca0d0cd2ff55af114a577
Parents: 41d7d4e
Author: Howard M. Lewis Ship <hl...@apache.org>
Authored: Wed Sep 11 18:10:55 2013 -0700
Committer: Howard M. Lewis Ship <hl...@apache.org>
Committed: Wed Sep 11 18:10:55 2013 -0700

----------------------------------------------------------------------
 .../tapestry5/corelib/pages/ExceptionReport.java   |  9 ++++++++-
 .../tapestry5/internal/InternalConstants.java      | 13 ++++++++++++-
 .../internal/services/RequestPageCacheImpl.java    | 13 ++++++++++++-
 .../tapestry5/corelib/pages/ExceptionReport.tml    | 17 ++++++++++-------
 4 files changed, 42 insertions(+), 10 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/88008b23/tapestry-core/src/main/java/org/apache/tapestry5/corelib/pages/ExceptionReport.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/corelib/pages/ExceptionReport.java b/tapestry-core/src/main/java/org/apache/tapestry5/corelib/pages/ExceptionReport.java
index 4a2bbc2..746bdfd 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/corelib/pages/ExceptionReport.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/corelib/pages/ExceptionReport.java
@@ -20,6 +20,7 @@ import org.apache.tapestry5.alerts.AlertManager;
 import org.apache.tapestry5.annotations.ContentType;
 import org.apache.tapestry5.annotations.Import;
 import org.apache.tapestry5.annotations.Property;
+import org.apache.tapestry5.internal.InternalConstants;
 import org.apache.tapestry5.internal.services.PageActivationContextCollector;
 import org.apache.tapestry5.internal.services.ReloadHelper;
 import org.apache.tapestry5.ioc.annotations.Inject;
@@ -102,11 +103,17 @@ public class ExceptionReport implements ExceptionReporter
 
     private final String pathSeparator = System.getProperty(PATH_SEPARATOR_PROPERTY);
 
+    public boolean isShowActions() {
+        return failurePage != null && ! request.isXHR();
+    }
+
     public void reportException(Throwable exception)
     {
         rootException = exception;
 
-        failurePage = request.isXHR() ? null : requestGlobals.getActivePageName();
+        failurePage = (request.getAttribute(InternalConstants.ACTIVE_PAGE_LOADED) == null)
+                ? null
+                : requestGlobals.getActivePageName();
 
         rootURL = baseURLSource.getBaseURL(request.isSecure());
     }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/88008b23/tapestry-core/src/main/java/org/apache/tapestry5/internal/InternalConstants.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/InternalConstants.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/InternalConstants.java
index 4134907..6d179fd 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/InternalConstants.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/InternalConstants.java
@@ -68,7 +68,7 @@ public final class InternalConstants
     public static final String CONTENT_TYPE_ATTRIBUTE_NAME = "content-type";
 
     public static final String CHARSET_CONTENT_TYPE_PARAMETER = "charset";
-    
+
     /**
      * As above but to store the name of the page. Necessary for determining the correct
      * {@link MarkupModel} for the response.
@@ -169,4 +169,15 @@ public final class InternalConstants
      * @since 5.4
      */
     public static final String PARTIAL_KEY = "_tapestry";
+
+    /**
+     * Request attribute, set to true once the active page (as identified in the incoming
+     * component event or page render request) has been successfully loaded. This is very important
+     * to the {@link org.apache.tapestry5.corelib.pages.ExceptionReport} page, which can possibly
+     * fail (resulting in a servlet container 500 response) if the page can't be loaded (because
+     * if the page can't be loaded, then a link to the page can't be created).
+     *
+     * @since 5.4
+     */
+    public static final String ACTIVE_PAGE_LOADED = "tapestry.active-page-loaded";
 }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/88008b23/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/RequestPageCacheImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/RequestPageCacheImpl.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/RequestPageCacheImpl.java
index fbf8fb5..7af9671 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/RequestPageCacheImpl.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/RequestPageCacheImpl.java
@@ -14,6 +14,7 @@
 
 package org.apache.tapestry5.internal.services;
 
+import org.apache.tapestry5.internal.InternalConstants;
 import org.apache.tapestry5.internal.structure.Page;
 import org.apache.tapestry5.ioc.ScopeConstants;
 import org.apache.tapestry5.ioc.annotations.PostInjection;
@@ -22,6 +23,7 @@ import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
 import org.apache.tapestry5.ioc.services.PerthreadManager;
 import org.apache.tapestry5.ioc.util.ExceptionUtils;
 import org.apache.tapestry5.services.ComponentClassResolver;
+import org.apache.tapestry5.services.RequestGlobals;
 import org.slf4j.Logger;
 
 import java.util.Map;
@@ -41,13 +43,16 @@ public class RequestPageCacheImpl implements RequestPageCache, Runnable
 
     private final PageSource pageSource;
 
+    private final RequestGlobals requestGlobals;
+
     private final Map<String, Page> cache = CollectionFactory.newMap();
 
-    public RequestPageCacheImpl(Logger logger, ComponentClassResolver resolver, PageSource pageSource)
+    public RequestPageCacheImpl(Logger logger, ComponentClassResolver resolver, PageSource pageSource, RequestGlobals requestGlobals)
     {
         this.logger = logger;
         this.resolver = resolver;
         this.pageSource = pageSource;
+        this.requestGlobals = requestGlobals;
     }
 
     @PostInjection
@@ -92,6 +97,12 @@ public class RequestPageCacheImpl implements RequestPageCache, Runnable
             cache.put(canonical, page);
         }
 
+        // A bit of a hack but whatever.
+        if (canonical.equals(requestGlobals.getActivePageName()))
+        {
+            requestGlobals.getRequest().setAttribute(InternalConstants.ACTIVE_PAGE_LOADED, true);
+        }
+
         return page;
     }
 }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/88008b23/tapestry-core/src/main/resources/org/apache/tapestry5/corelib/pages/ExceptionReport.tml
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/resources/org/apache/tapestry5/corelib/pages/ExceptionReport.tml b/tapestry-core/src/main/resources/org/apache/tapestry5/corelib/pages/ExceptionReport.tml
index 1ae084c..c26ebf1 100644
--- a/tapestry-core/src/main/resources/org/apache/tapestry5/corelib/pages/ExceptionReport.tml
+++ b/tapestry-core/src/main/resources/org/apache/tapestry5/corelib/pages/ExceptionReport.tml
@@ -36,7 +36,7 @@
                 <div class="panel-body">
                     ${rootException.message}
                 </div>
-                <t:if test="! productionMode">
+                <t:if test="showActions">
 
                     <div class="panel-footer">
 
@@ -67,12 +67,15 @@
 
             <t:if test="! productionMode">
 
-                <p class="help-text col-md-12"><strong>with reload</strong>: Force a reload of component
-                    classes. This is
-                    often
-                    necessary
-                    after fixing a class that previously failed to compile due to errors.
-                </p>
+                <t:if test="showActions">
+
+                    <p class="help-text col-md-12"><strong>with reload</strong>: Force a reload of component
+                        classes. This is
+                        often
+                        necessary
+                        after fixing a class that previously failed to compile due to errors.
+                    </p>
+                </t:if>
 
                 <t:exceptiondisplay exception="rootException"/>
 


[2/3] git commit: TAP5-2169: Always import the core stack

Posted by hl...@apache.org.
TAP5-2169: Always import the core stack


Project: http://git-wip-us.apache.org/repos/asf/tapestry-5/repo
Commit: http://git-wip-us.apache.org/repos/asf/tapestry-5/commit/ec83d78d
Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/ec83d78d
Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/ec83d78d

Branch: refs/heads/master
Commit: ec83d78d77c7dfde8688dd1f4db351414f42be7f
Parents: 88008b2
Author: Howard M. Lewis Ship <hl...@apache.org>
Authored: Wed Sep 11 18:24:29 2013 -0700
Committer: Howard M. Lewis Ship <hl...@apache.org>
Committed: Wed Sep 11 18:24:29 2013 -0700

----------------------------------------------------------------------
 54_RELEASE_NOTES.md                             | 20 +++++++++-----------
 .../tapestry5/modules/TapestryModule.java       | 14 ++++++++++++++
 2 files changed, 23 insertions(+), 11 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/ec83d78d/54_RELEASE_NOTES.md
----------------------------------------------------------------------
diff --git a/54_RELEASE_NOTES.md b/54_RELEASE_NOTES.md
index 6d8b8b6..521e8a5 100644
--- a/54_RELEASE_NOTES.md
+++ b/54_RELEASE_NOTES.md
@@ -206,8 +206,8 @@ Tapestry now includes a default copy of Bootstrap 3, in addition to its own defa
 The Tapestry CSS from prior releases has been largely eliminated; instead
 components now refer to standard Bootstrap CSS classes.
 
-The Bootstrap CSS is now only present if the `core` JavaScript stack is imported. You may need to change your application's
-layout component to do so explicitly, by adding `@Import(stack="core")` to the class.
+Tapestry now automatically imports the "core" stack for all pages (in previously releases, the "core" stack
+was only imported if the page made use of JavaScript). Because of this, the Boostrap CSS will always be available.
 
 ValidationDecorator and ValidationDecoratorFactory are deprecated in 5.4 and will be removed in 5.5. The default
 implementation of ValidationDecorator now does nothing. All the logic related to presentation of errors has moved
@@ -226,7 +226,7 @@ do establish dependencies: to Bootstrap's "transition" module to enable animatio
 
 ## Form element components
 
-TextField, PasswordField, TextArea, and Select now render the CSS class attribute "form-control"; you may add additional
+TextField, PasswordField, TextArea, and Select now render the CSS class attribute `form-control`; you may add additional
 CSS class names with the `class` informal parameter.  Generally, you will want to add an enclosing element with
 `col-md-x` CSS class control the size of the element (otherwise it will stretch to 100% of the available width).
 
@@ -237,7 +237,7 @@ with the `class` informal parameter.
 
 ## Error Component
 
-When Tapestry must present a validation exception, it will often dynamically create the `<p class="help-block">`
+When Tapestry must present a validation exception, it will often dynamically create the `p.help-block`
 needed to display the message; it does a reasonable job of positioning the new element just after the field, or
 just after the `.input-group` containing the field. The Error component can be used to explicitly place this element.
 
@@ -254,13 +254,11 @@ div.form-group, which is provided around the editor for each property.
 This service, primarily used by built-in components in Tapestry 5.3, is no longer useful in 5.4. The service
 still exists, but the methods do nothing, and the service and interface will be removed in 5.5.
 
-## JavaScriptSupport
+## JavaScriptSupport    Extended
 
-In prior releases, adding _any_ JavaScript to the application would implicitly import the `core` JavaScript stack.
-This no longer occurs; in most cases, the core stack is provided automatically by other components.
-
-You may want to consider adding `@Import(stack="core")` to your applications' main layout component, especially
-if you want to leverage the built-in Twitter Bootstrap CSS, which is provided as part of the core stack.
+New methods have been added to allow JavaScript modules to be "required" into the page; it is possible to invoke
+the exported function of a module with JSON-compatible parameters; a module may also export multiple names functions that
+can be invoked.
 
 ## Palette Component
 
@@ -315,7 +313,7 @@ used or implemented by application code.
 MutableComponentModel has been modified, adding a new `doHandleActivationEventContext()' method to help check
 activation context exactness; this interface is rarely, if ever, used or implemented by application code.
 
-## Module classes moved to new modules
+## IoC Module classes moved to new packages
 
 Traditionally, Tapestry IoC Module classes have lived in the same package as the service interfaces they define, and
 at the same time reference implementation classes in a separate (usually internal) package. This is not a desirable

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/ec83d78d/tapestry-core/src/main/java/org/apache/tapestry5/modules/TapestryModule.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/modules/TapestryModule.java b/tapestry-core/src/main/java/org/apache/tapestry5/modules/TapestryModule.java
index 8b2c2cb..adb64d8 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/modules/TapestryModule.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/modules/TapestryModule.java
@@ -74,6 +74,7 @@ import org.apache.tapestry5.services.*;
 import org.apache.tapestry5.services.ajax.AjaxResponseRenderer;
 import org.apache.tapestry5.services.dynamic.DynamicTemplate;
 import org.apache.tapestry5.services.dynamic.DynamicTemplateParser;
+import org.apache.tapestry5.services.javascript.JavaScriptSupport;
 import org.apache.tapestry5.services.javascript.ModuleManager;
 import org.apache.tapestry5.services.linktransform.ComponentEventLinkTransformer;
 import org.apache.tapestry5.services.linktransform.LinkTransformer;
@@ -1710,6 +1711,8 @@ public final class TapestryModule
      * <dd>Provides {@link org.apache.tapestry5.ValidationDecorator} (via {@link ValidationDecoratorFactory#newInstance(org.apache.tapestry5.MarkupWriter)})</dd>
      * <dt>PageNameMeta (since 5.4)</dt>
      * <dd>Renders a {@code <meta/>} tag describing the active page name (development mode only)</dd>
+     * <dt>ImportCoreStack (since 5.4) </dt>
+     * <dd>Imports to "core" stack (necessary to get the Bootstrap CSS, if nothing else).</dd>
      * </dl>
      */
     public void contributeMarkupRenderer(OrderedConfiguration<MarkupRendererFilter> configuration,
@@ -1790,10 +1793,21 @@ public final class TapestryModule
             }
         };
 
+        MarkupRendererFilter importCoreStack = new MarkupRendererFilter()
+        {
+            public void renderMarkup(MarkupWriter writer, MarkupRenderer renderer)
+            {
+                renderer.renderMarkup(writer);
+
+                environment.peekRequired(JavaScriptSupport.class).importStack(InternalConstants.CORE_STACK_NAME);
+            }
+        };
+
         configuration.add("DocumentLinker", documentLinker);
         configuration.add("ClientBehaviorSupport", clientBehaviorSupport, "after:JavaScriptSupport");
         configuration.add("Heartbeat", heartbeat);
         configuration.add("ValidationDecorator", defaultValidationDecorator);
+        configuration.add("ImportCoreStack", importCoreStack);
 
         if (productionMode)
         {


[3/3] git commit: Advance version number to 5.4-alpha-21

Posted by hl...@apache.org.
Advance version number to 5.4-alpha-21


Project: http://git-wip-us.apache.org/repos/asf/tapestry-5/repo
Commit: http://git-wip-us.apache.org/repos/asf/tapestry-5/commit/41e50134
Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/41e50134
Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/41e50134

Branch: refs/heads/master
Commit: 41e50134495061789c69b45e66ce819ea92d92de
Parents: ec83d78
Author: Howard M. Lewis Ship <hl...@apache.org>
Authored: Wed Sep 11 18:25:34 2013 -0700
Committer: Howard M. Lewis Ship <hl...@apache.org>
Committed: Wed Sep 11 18:25:34 2013 -0700

----------------------------------------------------------------------
 build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/41e50134/build.gradle
----------------------------------------------------------------------
diff --git a/build.gradle b/build.gradle
index 626422b..0a65e97 100755
--- a/build.gradle
+++ b/build.gradle
@@ -36,7 +36,7 @@ project.version = tapestryVersion()
 def tapestryVersion() {
 
     def major = "5.4"
-    def minor = "-alpha-21"
+    def minor = "-alpha-22"
 
     // When building on the CI server, make sure -SNAPSHOT is appended, as it is a nightly build.
     // When building normally, or for a release, no suffix is desired.


[3/3] git commit: Advance version number to 5.4-alpha-21

Posted by hl...@apache.org.
Advance version number to 5.4-alpha-21


Project: http://git-wip-us.apache.org/repos/asf/tapestry-5/repo
Commit: http://git-wip-us.apache.org/repos/asf/tapestry-5/commit/41e50134
Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/41e50134
Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/41e50134

Branch: refs/heads/master
Commit: 41e50134495061789c69b45e66ce819ea92d92de
Parents: ec83d78
Author: Howard M. Lewis Ship <hl...@apache.org>
Authored: Wed Sep 11 18:25:34 2013 -0700
Committer: Howard M. Lewis Ship <hl...@apache.org>
Committed: Wed Sep 11 18:25:34 2013 -0700

----------------------------------------------------------------------
 build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/41e50134/build.gradle
----------------------------------------------------------------------
diff --git a/build.gradle b/build.gradle
index 626422b..0a65e97 100755
--- a/build.gradle
+++ b/build.gradle
@@ -36,7 +36,7 @@ project.version = tapestryVersion()
 def tapestryVersion() {
 
     def major = "5.4"
-    def minor = "-alpha-21"
+    def minor = "-alpha-22"
 
     // When building on the CI server, make sure -SNAPSHOT is appended, as it is a nightly build.
     // When building normally, or for a release, no suffix is desired.


[2/3] git commit: TAP5-2169: Always import the core stack

Posted by hl...@apache.org.
TAP5-2169: Always import the core stack


Project: http://git-wip-us.apache.org/repos/asf/tapestry-5/repo
Commit: http://git-wip-us.apache.org/repos/asf/tapestry-5/commit/ec83d78d
Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/ec83d78d
Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/ec83d78d

Branch: refs/heads/master
Commit: ec83d78d77c7dfde8688dd1f4db351414f42be7f
Parents: 88008b2
Author: Howard M. Lewis Ship <hl...@apache.org>
Authored: Wed Sep 11 18:24:29 2013 -0700
Committer: Howard M. Lewis Ship <hl...@apache.org>
Committed: Wed Sep 11 18:24:29 2013 -0700

----------------------------------------------------------------------
 54_RELEASE_NOTES.md                             | 20 +++++++++-----------
 .../tapestry5/modules/TapestryModule.java       | 14 ++++++++++++++
 2 files changed, 23 insertions(+), 11 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/ec83d78d/54_RELEASE_NOTES.md
----------------------------------------------------------------------
diff --git a/54_RELEASE_NOTES.md b/54_RELEASE_NOTES.md
index 6d8b8b6..521e8a5 100644
--- a/54_RELEASE_NOTES.md
+++ b/54_RELEASE_NOTES.md
@@ -206,8 +206,8 @@ Tapestry now includes a default copy of Bootstrap 3, in addition to its own defa
 The Tapestry CSS from prior releases has been largely eliminated; instead
 components now refer to standard Bootstrap CSS classes.
 
-The Bootstrap CSS is now only present if the `core` JavaScript stack is imported. You may need to change your application's
-layout component to do so explicitly, by adding `@Import(stack="core")` to the class.
+Tapestry now automatically imports the "core" stack for all pages (in previously releases, the "core" stack
+was only imported if the page made use of JavaScript). Because of this, the Boostrap CSS will always be available.
 
 ValidationDecorator and ValidationDecoratorFactory are deprecated in 5.4 and will be removed in 5.5. The default
 implementation of ValidationDecorator now does nothing. All the logic related to presentation of errors has moved
@@ -226,7 +226,7 @@ do establish dependencies: to Bootstrap's "transition" module to enable animatio
 
 ## Form element components
 
-TextField, PasswordField, TextArea, and Select now render the CSS class attribute "form-control"; you may add additional
+TextField, PasswordField, TextArea, and Select now render the CSS class attribute `form-control`; you may add additional
 CSS class names with the `class` informal parameter.  Generally, you will want to add an enclosing element with
 `col-md-x` CSS class control the size of the element (otherwise it will stretch to 100% of the available width).
 
@@ -237,7 +237,7 @@ with the `class` informal parameter.
 
 ## Error Component
 
-When Tapestry must present a validation exception, it will often dynamically create the `<p class="help-block">`
+When Tapestry must present a validation exception, it will often dynamically create the `p.help-block`
 needed to display the message; it does a reasonable job of positioning the new element just after the field, or
 just after the `.input-group` containing the field. The Error component can be used to explicitly place this element.
 
@@ -254,13 +254,11 @@ div.form-group, which is provided around the editor for each property.
 This service, primarily used by built-in components in Tapestry 5.3, is no longer useful in 5.4. The service
 still exists, but the methods do nothing, and the service and interface will be removed in 5.5.
 
-## JavaScriptSupport
+## JavaScriptSupport    Extended
 
-In prior releases, adding _any_ JavaScript to the application would implicitly import the `core` JavaScript stack.
-This no longer occurs; in most cases, the core stack is provided automatically by other components.
-
-You may want to consider adding `@Import(stack="core")` to your applications' main layout component, especially
-if you want to leverage the built-in Twitter Bootstrap CSS, which is provided as part of the core stack.
+New methods have been added to allow JavaScript modules to be "required" into the page; it is possible to invoke
+the exported function of a module with JSON-compatible parameters; a module may also export multiple names functions that
+can be invoked.
 
 ## Palette Component
 
@@ -315,7 +313,7 @@ used or implemented by application code.
 MutableComponentModel has been modified, adding a new `doHandleActivationEventContext()' method to help check
 activation context exactness; this interface is rarely, if ever, used or implemented by application code.
 
-## Module classes moved to new modules
+## IoC Module classes moved to new packages
 
 Traditionally, Tapestry IoC Module classes have lived in the same package as the service interfaces they define, and
 at the same time reference implementation classes in a separate (usually internal) package. This is not a desirable

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/ec83d78d/tapestry-core/src/main/java/org/apache/tapestry5/modules/TapestryModule.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/modules/TapestryModule.java b/tapestry-core/src/main/java/org/apache/tapestry5/modules/TapestryModule.java
index 8b2c2cb..adb64d8 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/modules/TapestryModule.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/modules/TapestryModule.java
@@ -74,6 +74,7 @@ import org.apache.tapestry5.services.*;
 import org.apache.tapestry5.services.ajax.AjaxResponseRenderer;
 import org.apache.tapestry5.services.dynamic.DynamicTemplate;
 import org.apache.tapestry5.services.dynamic.DynamicTemplateParser;
+import org.apache.tapestry5.services.javascript.JavaScriptSupport;
 import org.apache.tapestry5.services.javascript.ModuleManager;
 import org.apache.tapestry5.services.linktransform.ComponentEventLinkTransformer;
 import org.apache.tapestry5.services.linktransform.LinkTransformer;
@@ -1710,6 +1711,8 @@ public final class TapestryModule
      * <dd>Provides {@link org.apache.tapestry5.ValidationDecorator} (via {@link ValidationDecoratorFactory#newInstance(org.apache.tapestry5.MarkupWriter)})</dd>
      * <dt>PageNameMeta (since 5.4)</dt>
      * <dd>Renders a {@code <meta/>} tag describing the active page name (development mode only)</dd>
+     * <dt>ImportCoreStack (since 5.4) </dt>
+     * <dd>Imports to "core" stack (necessary to get the Bootstrap CSS, if nothing else).</dd>
      * </dl>
      */
     public void contributeMarkupRenderer(OrderedConfiguration<MarkupRendererFilter> configuration,
@@ -1790,10 +1793,21 @@ public final class TapestryModule
             }
         };
 
+        MarkupRendererFilter importCoreStack = new MarkupRendererFilter()
+        {
+            public void renderMarkup(MarkupWriter writer, MarkupRenderer renderer)
+            {
+                renderer.renderMarkup(writer);
+
+                environment.peekRequired(JavaScriptSupport.class).importStack(InternalConstants.CORE_STACK_NAME);
+            }
+        };
+
         configuration.add("DocumentLinker", documentLinker);
         configuration.add("ClientBehaviorSupport", clientBehaviorSupport, "after:JavaScriptSupport");
         configuration.add("Heartbeat", heartbeat);
         configuration.add("ValidationDecorator", defaultValidationDecorator);
+        configuration.add("ImportCoreStack", importCoreStack);
 
         if (productionMode)
         {