Modified: websites/production/tapestry/content/security-faq.html ============================================================================== --- websites/production/tapestry/content/security-faq.html (original) +++ websites/production/tapestry/content/security-faq.html Tue Sep 26 19:20:27 2017 @@ -27,16 +27,6 @@ </title> <link type="text/css" rel="stylesheet" href="/resources/space.css" /> - <link href='/resources/highlighter/styles/shCoreCXF.css' rel='stylesheet' type='text/css' /> - <link href='/resources/highlighter/styles/shThemeCXF.css' rel='stylesheet' type='text/css' /> - <script src='/resources/highlighter/scripts/shCore.js' type='text/javascript'></script> - <script src='/resources/highlighter/scripts/shBrushJava.js' type='text/javascript'></script> - <script src='/resources/highlighter/scripts/shBrushXml.js' type='text/javascript'></script> - <script src='/resources/highlighter/scripts/shBrushPlain.js' type='text/javascript'></script> - <script> - SyntaxHighlighter.defaults['toolbar'] = false; - SyntaxHighlighter.all(); - </script> <link href="/styles/style.css" rel="stylesheet" type="text/css"/> @@ -77,56 +67,12 @@ </div> <div id="content"> - <div id="ConfluenceContent"><h2 id="SecurityFAQ-SecurityFAQ">Security FAQ</h2><p> </p><div class="aui-label" style="float:right" title="Related Articles"> - - - - - - - - -<h3>Related Articles</h3> - -<ul class="content-by-label"><li> - <div> - <span class="icon aui-icon aui-icon-small aui-iconfont-page-default" title="Page">Page:</span> </div> - - <div class="details"> - <a href="security-faq.html">Security FAQ</a> - - - </div> - </li><li> - <div> - <span class="icon aui-icon aui-icon-small aui-iconfont-page-default" title="Page">Page:</span> </div> - - <div class="details"> - <a href="https.html">HTTPS</a> - - - </div> - </li><li> - <div> - <span class="icon aui-icon aui-icon-small aui-iconfont-page-default" title="Page">Page:</span> </div> - - <div class="details"> - <a href="security.html">Security</a> - - - </div> - </li></ul> -</div> - - -<h3 id="SecurityFAQ-Thebuilt-inDashboardpagearevisibleinmyproductionapplicationandIdon'twantthemtobe,whatcanIdo?">The built-in Dashboard page are visible in my production application and I don't want them to be, what can I do?</h3><p>First off all, don't panic: the <a href="development-dashboard.html">Developer Dashboard</a> page is marked with the @<a class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/WhitelistAccessOnly.html">WhitelistAccessOnly</a> annotation, which makes it invisible to clients that are not on the whitelist. Try accessing the page from a different workstation and you may find that the pages are not visible after all.</p><p>Sometimes, in production, a firewall or proxy may make it look like the client web browser originates from localhost; in that situation, you may want to disable the logic that puts localhost onto the whitelist. This determination is made by the contributions to the <a class="external-link " href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/security/ClientWhitelist.html">ClientWhitelist</a> service. Tapestry makes a contribution with id "LocalhostOnly", which one of your modules can override:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl"> -<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;"> @Contribute(ClientWhitelist.class) + <div id="ConfluenceContent"><p><plain-text-body>{scrollbar}</plain-text-body></p><h2 id="SecurityFAQ-SecurityFAQ">Security FAQ</h2><p> </p><parameter ac:name="style">float:right</parameter><parameter ac:name="title">Related Articles</parameter><parameter ac:name="class">aui-label</parameter><rich-text-body><parameter ac:name="showLabels">false</parameter><parameter ac:name="showSpace">false</parameter><parameter ac:name="title">Related Articles</parameter><parameter ac:name="cql">label = "security" and space = currentSpace()</parameter></rich-text-body><h3 id="SecurityFAQ-Thebuilt-inDashboardpagearevisibleinmyproductionapplicationandIdon'twantthemtobe,whatcanIdo?">The built-in Dashboard page are visible in my production application and I don't want them to be, what can I do?</h3><p>First off all, don't panic: the <a href="development-dashboard.html">Developer Dashboard</a> page is marked with the @<a class="external-link" href="http://tapestry.apache.org/curre nt/apidocs/org/apache/tapestry5/annotations/WhitelistAccessOnly.html">WhitelistAccessOnly</a> annotation, which makes it invisible to clients that are not on the whitelist. Try accessing the page from a different workstation and you may find that the pages are not visible after all.</p><p>Sometimes, in production, a firewall or proxy may make it look like the client web browser originates from localhost; in that situation, you may want to disable the logic that puts localhost onto the whitelist. This determination is made by the contributions to the <a class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/security/ClientWhitelist.html">ClientWhitelist</a> service. Tapestry makes a contribution with id "LocalhostOnly", which one of your modules can override:</p><plain-text-body> @Contribute(ClientWhitelist.class) public static void turnOffLocalhostInProduction(OrderedConfiguration<WhitelistAnalyzer> configuration, @Symbol(SymbolConstants.PRODUCTION_MODE) boolean productionMode) { if (productionMode) { configuration.override("LocalhostOnly", null); } } -</pre> -</div></div><p></p></div> +</plain-text-body><p><plain-text-body>{scrollbar}</plain-text-body></p></div> </div> <div class="clearer"></div>
Modified: websites/production/tapestry/content/security.html ============================================================================== --- websites/production/tapestry/content/security.html (original) +++ websites/production/tapestry/content/security.html Tue Sep 26 19:20:27 2017 @@ -27,16 +27,6 @@ </title> <link type="text/css" rel="stylesheet" href="/resources/space.css" /> - <link href='/resources/highlighter/styles/shCoreCXF.css' rel='stylesheet' type='text/css' /> - <link href='/resources/highlighter/styles/shThemeCXF.css' rel='stylesheet' type='text/css' /> - <script src='/resources/highlighter/scripts/shCore.js' type='text/javascript'></script> - <script src='/resources/highlighter/scripts/shBrushJava.js' type='text/javascript'></script> - <script src='/resources/highlighter/scripts/shBrushXml.js' type='text/javascript'></script> - <script src='/resources/highlighter/scripts/shBrushPlain.js' type='text/javascript'></script> - <script> - SyntaxHighlighter.defaults['toolbar'] = false; - SyntaxHighlighter.all(); - </script> <link href="/styles/style.css" rel="stylesheet" type="text/css"/> @@ -77,61 +67,10 @@ </div> <div id="content"> - <div id="ConfluenceContent"><p>Tapestry has a number of <strong>security</strong> features designed to harden your application against unwanted intrusion and denial of service.</p><p> </p><div class="aui-label" style="float:right" title="Related Articles"> - - - - - - - - -<h3>Related Articles</h3> - -<ul class="content-by-label"><li> - <div> - <span class="icon aui-icon aui-icon-small aui-iconfont-page-default" title="Page">Page:</span> </div> - - <div class="details"> - <a href="security.html">Security</a> - - - </div> - </li><li> - <div> - <span class="icon aui-icon aui-icon-small aui-iconfont-page-default" title="Page">Page:</span> </div> - - <div class="details"> - <a href="integrating-with-spring-framework.html">Integrating with Spring Framework</a> - - - </div> - </li><li> - <div> - <span class="icon aui-icon aui-icon-small aui-iconfont-page-default" title="Page">Page:</span> </div> - - <div class="details"> - <a href="security-faq.html">Security FAQ</a> - - - </div> - </li><li> - <div> - <span class="icon aui-icon aui-icon-small aui-iconfont-page-default" title="Page">Page:</span> </div> - - <div class="details"> - <a href="https.html">HTTPS</a> - - - </div> - </li></ul> -</div> - - -<p> </p><h2 id="Security-HTTPS-onlyPages">HTTPS-only Pages</h2><p>Main Article: <a href="https.html">HTTPS</a></p><p>Tapestry provides several annotations and configuration settings that you can use to <span style="text-align: justify;line-height: 1.4285715;">ensure that all access to certain pages (or all pages) occurs only via the encrypted HTTPS protocol</span><span style="text-align: justify;line-height: 1.4285715;">. See <a href="https.html">HTTPS</a> for details.</span></p><h2 id="Security-ControllingPageAccess"><span style="text-align: justify;line-height: 1.4285715;">Controlling Page Access</span></h2><p></p><div class="navmenu" style="float:right; background:#eee; margin:3px; padding:0 1em"> -<p> <strong>JumpStart Demo:</strong><br clear="none"> - <a class="external-link" href="http://jumpstart.doublenegative.com.au/jumpstart/examples/infrastructure/protectingpages" rel="nofollow">Protecting Pages</a></p></div><span style="text-align: justify;line-height: 1.4285715;">For simple access control needs, you can contribute a <span><a class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/ComponentRequestFilter.html">ComponentRequestFilter</a> with your custom logic that decides which pages should be accessed by which users. The <a class="external-link" href="https://tapestry-app.apache.org/hotels/">Tapestry Hotel Booking </a>app demonstrates this approach with an <code>@AnonymousAccess</code> annotation along with a ComponentRequestFilter named <code>AuthenticationFilter.java</code>. The filter enforces security by intercepting all requests to pages that don't have that annotation, and it redirects those requests to the login page. <a class="external-link" href="http: //jumpstart.doublenegative.com.au/jumpstart/examples/infrastructure/protectingpages" rel="nofollow">JumpStart</a> has a similar demo.<br clear="none"></span></span><p><span style="line-height: 1.4285715;text-align: justify;">For more advanced needs see the Security Framework Integration section below.</span></p><h2 id="Security-White-listedPages">White-listed Pages</h2><p>Pages whose component classes are annotated with @<a class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/WhitelistAccessOnly.html">WhitelistAccessOnly</a> will only be displayed to users (clients) that are on the <em>whitelist</em>. By default the whitelist consists only of clients whose fully-qualified domain name is "localhost" (or the IP address equivalent, 127.0.0.1 or 0:0:0:0:0:0:0:1), but you can customize this by contributing to the ClientWhitelist service in your application's module class (usually AppModule.java):</p><div class=" code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>AppModule.java (partial) – simple inline example</b></div><div class="codeContent panelContent pdl"> -<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;"> @Contribute(ClientWhitelist.class) + <div id="ConfluenceContent"><p>Tapestry has a number of <strong>security</strong> features designed to harden your application against unwanted intrusion and denial of service.</p><p> </p><parameter ac:name="style">float:right</parameter><parameter ac:name="title">Related Articles</parameter><parameter ac:name="class">aui-label</parameter><rich-text-body><parameter ac:name="showLabels">false</parameter><parameter ac:name="showSpace">false</parameter><parameter ac:name="title">Related Articles</parameter><parameter ac:name="cql">label in ("spring","security") and space = currentSpace()</parameter></rich-text-body><p> </p><h2 id="Security-HTTPS-onlyPages">HTTPS-only Pages</h2><p>Main Article: <a href="https.html">HTTPS</a></p><p>Tapestry provides several annotations and configuration settings that you can use to <span style="text-align: justify;line-height: 1.4285715;">ensure that all access to certain pages (or all pages) occurs only via the encrypted HTTPS protocol</span><span style="text-align: justify;line-height: 1.4285715;">. See <a href="https.html">HTTPS</a> for details.</span></p><h2 id="Security-ControllingPageAccess"><span style="text-align: justify;line-height: 1.4285715;">Controlling Page Access</span></h2><p><plain-text-body>{float:right|background=#eee|padding=0 1em} + *JumpStart Demo:* + [Protecting Pages|http://jumpstart.doublenegative.com.au/jumpstart/examples/infrastructure/protectingpages] +{float}</plain-text-body><span style="text-align: justify;line-height: 1.4285715;">For simple access control needs, you can contribute a <span><a class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/ComponentRequestFilter.html">ComponentRequestFilter</a> with your custom logic that decides which pages should be accessed by which users. The <a class="external-link" href="https://tapestry-app.apache.org/hotels/">Tapestry Hotel Booking </a>app demonstrates this approach with an <code>@AnonymousAccess</code> annotation along with a ComponentRequestFilter named <code>AuthenticationFilter.java</code>. The filter enforces security by intercepting all requests to pages that don't have that annotation, and it redirects those requests to the login page. <a class="external-link" href="http://jumpstart.doublenegative.com.au/jumpstart/examples/infrastructure/protectingpages" rel="nofollow">JumpStart</a> has a similar demo.<br clear="no ne"></span></span></p><p><span style="line-height: 1.4285715;text-align: justify;">For more advanced needs see the Security Framework Integration section below.</span></p><h2 id="Security-White-listedPages">White-listed Pages</h2><p>Pages whose component classes are annotated with @<a class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/WhitelistAccessOnly.html">WhitelistAccessOnly</a> will only be displayed to users (clients) that are on the <em>whitelist</em>. By default the whitelist consists only of clients whose fully-qualified domain name is "localhost" (or the IP address equivalent, 127.0.0.1 or 0:0:0:0:0:0:0:1), but you can customize this by contributing to the ClientWhitelist service in your application's module class (usually AppModule.java):</p><parameter ac:name="language">java</parameter><parameter ac:name="title">AppModule.java (partial) -- simple inline example</parameter><plain-text-body> @Contribute(ClientWhitelist.class) public static void provideWhitelistAnalyzer(OrderedConfiguration<WhitelistAnalyzer> configuration) { configuration.add("MyCustomAnalyzer", new WhitelistAnalyzer() @@ -142,10 +81,7 @@ return true; } }, "before:*"); - }</pre> -</div></div><p> </p><p>Sometimes, in production, a firewall or proxy may make it look like the client web browser originates from localhost, with the consequence that whitelisted pages may be visible to all users. See the <a href="security.html">Security FAQ</a> for how to deal with this.</p><h2 id="Security-AssetSecurity">Asset Security</h2><p>Main Article: <a href="assets.html">Assets</a></p><p>Tapestry serves assets (static content such as CSS files, images, and JavaScript, many of which are on the classpath alongside your compiled class files) to the client. Because of this, great care has gone into ensuring that certain file types cannot be served to the client. By default, file ending with ".class', ".tml" and ".properties" can be served to the client only if the request includes the file's MD5 checksum. As you would expect, that blacklist can be extended. See <a href="assets.html">Asset Security</a> for more information.</p><h2 id="Security-Protect ingSerializedObjectDataontheClient">Protecting Serialized Object Data on the Client</h2><p><span style="color: rgb(0,0,0);">As of version 5.3.6, Tapestry integrates a </span><a class="external-link" href="http://en.wikipedia.org/wiki/HMAC" rel="nofollow" style="text-decoration: underline;text-align: justify;">hash-based message authentication code</a><span style="color: rgb(0,0,0);"> (HMAC) into serialized Java object data that it sends to the client (generally, this means the </span><code style="text-align: justify;">t:formdata</code><span style="color: rgb(0,0,0);"> hidden field used by the Form component). This ensures that the hidden binary object data is guaranteed to be unaltered when it returns to the server upon form (or AJAX) submission. The HMAC pass phrase is set using the <a href="configuration.html">tapestry.hmac-passphrase</a> configuration symbol. If you don't set that value, you'll see a warning message in the browser, like this: </spa n></p><div class="preformatted panel" style="border-width: 1px;"><div class="preformattedContent panelContent"> -<pre>The symbol 'tapestry.hmac-passphrase' has not been configured. This is used to configure hash-based message authentication of Tapestry data stored in forms, or in the URL. You application is less secure, and more vulnerable to denial-of-service attacks, when this symbol is not configured.</pre> -</div></div><p><span style="color: rgb(0,0,0);">The solution is to set the tapestry.hmac-passphrase to some value (any fixed, private string, such as 30 to 40 random-looking characters, will do) in your application's module class (usually AppModule.java).</span></p><h2 id="Security-CrossSiteRequestForgery(CSRF)"><span style="color: rgb(83,145,38);font-size: 20.0px;line-height: 1.5;">Cross Site Request Forgery (CSRF)</span></h2><p>Cross Site Request Forgery is a type of security vulnerability in which legitimate, authorized users may be made to unwittingly submit malicious requests to your web application.</p><p><a class="external-link" href="https://github.com/porscheinformatik/tapestry-csrf-protection" rel="nofollow">Tapestry-csrf-protection</a> is a 3rd party module that has several features for preventing CSRF attacks. It protects all <span>component event handlers (event links, forms, etc.) by adding a </span><span>CSRF token to event links and adds a CSRF token as a hidden field to all forms. </span><span>Tokens are generated on a per-session basis.</span></p><h2 id="Security-SecurityFrameworkIntegration"><span style="line-height: 1.5;">Security Framework Integration</span></h2><p>Tapestry does not lock you into a specific authentication/authorization implementation. There are integration modules available for the more popular open source Java security frameworks. A popular choice among Tapestry users is <a class="external-link" href="http://www.tynamo.org/tapestry-security+guide/" rel="nofollow">tapestry-security (based on Apache Shiro) from Tynamo.org</a>. It is always kept up-to-date with the latest Tapestry versions and offers several supporting security modules (e.g. <a class="external-link" href="http://www.tynamo.org/tapestry-security-jpa+guide/" rel="nofollow">tapestry-security-jpa</a>, <a class="external-link" href="http://www.tynamo.org/tynamo-federatedaccounts+guide/" rel="nofollow">tynamo-federatedaccounts</a>). There's also an <a class="external-link" href="http://www.localhost.nu/java/tapestry-spring-security" rel="nofollow">integration module available for Spring Security</a> but lately, it hasn't kept up with the latest versions of Tapestry 5.</p><p>Additional information:</p><ul><li><a class="external-link" href="http://www.tynamo.org/tynamo-federatedaccounts+guide/" rel="nofollow">Tynamo-federatedaccounts</a> <span style="color: rgb(0,0,0);">is an add-on to the </span><a class="external-link" href="http://www.tynamo.org/tapestry-security+guide/" rel="nofollow">tapestry-security</a><span style="color: rgb(0,0,0);"> module, providing federated (third-party) authentication with Facebook, Twitter or Google.</span></li></ul><ul><li><span style="line-height: 1.4285715;">To include OpenID with Spring Security in your application, see the following Wiki entry: </span><a class="external-link" href="http://wiki.apache.org/tapestry/Tapestry5HowToSpringSecurityAndOpenId" style="l ine-height: 1.4285715;">http://wiki.apache.org/tapestry/Tapestry5HowToSpringSecurityAndOpenId</a></li></ul><p> </p></div> + }</plain-text-body><p> </p><p>Sometimes, in production, a firewall or proxy may make it look like the client web browser originates from localhost, with the consequence that whitelisted pages may be visible to all users. See the <a href="security.html">Security FAQ</a> for how to deal with this.</p><h2 id="Security-AssetSecurity">Asset Security</h2><p>Main Article: <a href="assets.html">Assets</a></p><p>Tapestry serves assets (static content such as CSS files, images, and JavaScript, many of which are on the classpath alongside your compiled class files) to the client. Because of this, great care has gone into ensuring that certain file types cannot be served to the client. By default, file ending with ".class', ".tml" and ".properties" can be served to the client only if the request includes the file's MD5 checksum. As you would expect, that blacklist can be extended. See <a href="assets.html">Asset Security</a> for more information.</p><h2 id="Secur ity-ProtectingSerializedObjectDataontheClient">Protecting Serialized Object Data on the Client</h2><p><span style="color: rgb(0,0,0);">As of version 5.3.6, Tapestry integrates a </span><a class="external-link" href="http://en.wikipedia.org/wiki/HMAC" rel="nofollow" style="text-decoration: underline;text-align: justify;">hash-based message authentication code</a><span style="color: rgb(0,0,0);"> (HMAC) into serialized Java object data that it sends to the client (generally, this means the </span><code style="text-align: justify;">t:formdata</code><span style="color: rgb(0,0,0);"> hidden field used by the Form component). This ensures that the hidden binary object data is guaranteed to be unaltered when it returns to the server upon form (or AJAX) submission. The HMAC pass phrase is set using the <a href="configuration.html">tapestry.hmac-passphrase</a> configuration symbol. If you don't set that value, you'll see a warning message in the browser, like this:  </span></p><plain-text-body>The symbol 'tapestry.hmac-passphrase' has not been configured. This is used to configure hash-based message authentication of Tapestry data stored in forms, or in the URL. You application is less secure, and more vulnerable to denial-of-service attacks, when this symbol is not configured.</plain-text-body><p><span style="color: rgb(0,0,0);">The solution is to set the tapestry.hmac-passphrase to some value (any fixed, private string, such as 30 to 40 random-looking characters, will do) in your application's module class (usually AppModule.java).</span></p><h2 id="Security-CrossSiteRequestForgery(CSRF)"><span style="color: rgb(83,145,38);font-size: 20.0px;line-height: 1.5;">Cross Site Request Forgery (CSRF)</span></h2><p>Cross Site Request Forgery is a type of security vulnerability in which legitimate, authorized users may be made to unwittingly submit malicious requests to your web application.</p><p><a class="external-link" href="https://github.co m/porscheinformatik/tapestry-csrf-protection" rel="nofollow">Tapestry-csrf-protection</a> is a 3rd party module that has several features for preventing CSRF attacks. It protects all <span>component event handlers (event links, forms, etc.) by adding a </span><span>CSRF token to event links and adds a CSRF token as a hidden field to all forms. </span><span>Tokens are generated on a per-session basis.</span></p><h2 id="Security-SecurityFrameworkIntegration"><span style="line-height: 1.5;">Security Framework Integration</span></h2><p>Tapestry does not lock you into a specific authentication/authorization implementation. There are integration modules available for the more popular open source Java security frameworks. A popular choice among Tapestry users is <a class="external-link" href="http://www.tynamo.org/tapestry-security+guide/" rel="nofollow">tapestry-security (based on Apache Shiro) from Tynamo.org</a>. It is always kept up-to-date with the latest Tapestry versions and offers several supporting security modules (e.g. <a class="external-link" href="http://www.tynamo.org/tapestry-security-jpa+guide/" rel="nofollow">tapestry-security-jpa</a>, <a class="external-link" href="http://www.tynamo.org/tynamo-federatedaccounts+guide/" rel="nofollow">tynamo-federatedaccounts</a>). There's also an <a class="external-link" href="http://www.localhost.nu/java/tapestry-spring-security" rel="nofollow">integration module available for Spring Security</a> but lately, it hasn't kept up with the latest versions of Tapestry 5.</p><p>Additional information:</p><ul><li><a class="external-link" href="http://www.tynamo.org/tynamo-federatedaccounts+guide/" rel="nofollow">Tynamo-federatedaccounts</a> <span style="color: rgb(0,0,0);">is an add-on to the </span><a class="external-link" href="http://www.tynamo.org/tapestry-security+guide/" rel="nofollow">tapestry-security</a><span style="color: rgb(0,0,0);"> module, providing federated (third-pa rty) authentication with Facebook, Twitter or Google.</span></li></ul><ul><li><span style="line-height: 1.4285715;">To include OpenID with Spring Security in your application, see the following Wiki entry: </span><a class="external-link" href="http://wiki.apache.org/tapestry/Tapestry5HowToSpringSecurityAndOpenId" style="line-height: 1.4285715;">http://wiki.apache.org/tapestry/Tapestry5HowToSpringSecurityAndOpenId</a></li></ul><p> </p></div> </div> <div class="clearer"></div> Modified: websites/production/tapestry/content/specific-errors-faq.html ============================================================================== --- websites/production/tapestry/content/specific-errors-faq.html (original) +++ websites/production/tapestry/content/specific-errors-faq.html Tue Sep 26 19:20:27 2017 @@ -27,16 +27,6 @@ </title> <link type="text/css" rel="stylesheet" href="/resources/space.css" /> - <link href='/resources/highlighter/styles/shCoreCXF.css' rel='stylesheet' type='text/css' /> - <link href='/resources/highlighter/styles/shThemeCXF.css' rel='stylesheet' type='text/css' /> - <script src='/resources/highlighter/scripts/shCore.js' type='text/javascript'></script> - <script src='/resources/highlighter/scripts/shBrushJava.js' type='text/javascript'></script> - <script src='/resources/highlighter/scripts/shBrushXml.js' type='text/javascript'></script> - <script src='/resources/highlighter/scripts/shBrushPlain.js' type='text/javascript'></script> - <script> - SyntaxHighlighter.defaults['toolbar'] = false; - SyntaxHighlighter.all(); - </script> <link href="/styles/style.css" rel="stylesheet" type="text/css"/> @@ -77,50 +67,7 @@ </div> <div id="content"> - <div id="ConfluenceContent"><div class="aui-label" style="float:right" title="Related Articles"> - - - - - - - - -<h3>Related Articles</h3> - -<ul class="content-by-label"><li> - <div> - <span class="icon aui-icon aui-icon-small aui-iconfont-page-default" title="Page">Page:</span> </div> - - <div class="details"> - <a href="error-page-recipe.html">Error Page Recipe</a> - - - </div> - </li><li> - <div> - <span class="icon aui-icon aui-icon-small aui-iconfont-page-default" title="Page">Page:</span> </div> - - <div class="details"> - <a href="specific-errors-faq.html">Specific Errors FAQ</a> - - - </div> - </li><li> - <div> - <span class="icon aui-icon aui-icon-small aui-iconfont-page-default" title="Page">Page:</span> </div> - - <div class="details"> - <a href="overriding-exception-reporting.html">Overriding Exception Reporting</a> - - - </div> - </li></ul> -</div> - - -<h3 id="SpecificErrorsFAQ-WhydoIgettheexception"Noserviceimplementstheinterfaceorg.apache.tapestry5.internal.InternalComponentResources"whentryingtousetheBeanEditFormcomponent?">Why do I get the exception "No service implements the interface org.apache.tapestry5.internal.InternalComponentResources" when trying to use the BeanEditForm component?</h3><p>This can occur when you choose the wrong package for your data object, the object edited by the BeanEditForm component. If you place it in the same package as your pages, Tapestry will treat it like a page, and perform a number of transformation on it, including adding a new constructor.</p><p>Only component classes should go in the Tapestry-controlled packages (<code>pages</code>, <code>components</code>, <code>mixins</code> and <code>base</code> under your application's root package). By convention, simple data objects should go in a <code>data</code> package, and Hibernate entities should go in an <code>entities</code> pac kage.</p><div class="confluence-information-macro confluence-information-macro-note"><span class="aui-icon aui-icon-small aui-iconfont-warning confluence-information-macro-icon"></span><div class="confluence-information-macro-body"><p>This is likely a bit different in 5.3 than in 5.2 (because 5.3 builds a very different constructor into the component) and needs to be tested in 5.3 to see what exact exception will occur.</p></div></div><h3 id="SpecificErrorsFAQ-Igetanerrorabout"Pagedidnotgenerateanymarkupwhenrendered."butIhaveatemplate,whathappened?">I get an error about "Page did not generate any markup when rendered." but I have a template, what happened?</h3><p>The most common error here is that the case of the page class did not match the case of the template. For example, you might name your class ViewOrders, but name the template vieworders.tml. The correct name for the template is ViewOrders.tml, matching the case of the Java class name.</p><p>Worse, you may find tha t your application works during development (under Windows, which is case insensitive) but does not work when deployed on a Linux or Unix server, which may be case sensitive.</p><p>The other cause of this may be that your template files simply are not being packaged up correctly with the rest of your application. When in doubt, use the Java <code>jar</code> command to see exactly whats inside your WAR file. Your page templates should either be in the root folder of the WAR, or package with the corresponding .class file.</p><h3 id="SpecificErrorsFAQ-MyapplicationfailswiththeerrorPermGen,howdoIfixthis?">My application fails with the error <strong>PermGen</strong>, how do I fix this?</h3><p>PermGen refers to the part of the Java memory space devoted to permanent objects, which are mostly loaded classes. When developing under Tapestry, many more classes and class loaders are created than normal; this is part of live class reloading. Because of this, you will want to increase the amount of memory Java devotes to this.</p><p>The solution is to add <code>-XX:MaxPermSize=512m</code> to your command line. You may also want to increase the regular amount of heap space with <code>-Xmx600M</code>. Of course, you may need to adjust the amount of memory in each category to match your actual application, but these are good starting values.</p><p>Java Virtual Machine arguments can be specified inside an Eclipse launch configuration:</p><p><span class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image confluence-thumbnail" src="specific-errors-faq.data/eclipse-permgen.png"></span></p><h3 id="SpecificErrorsFAQ-WhydoIsometimesgetajava.lang.NoSuchMethodErrorexceptionafterreloadingmypage?">Why do I sometimes get a <code>java.lang.NoSuchMethodError</code> exception after reloading my page?</h3><p>Tapestry's live class reloading is not perfect. <span style="line-height: 1.4285715;">It tends to use a lot of Java ClassLoaders on top of the normal ClassLoader s used by the Java Virtual Machine and the servlet container. When you change non-component classes and interfaces that are referenced by components and pages, such as to add or change a method, only the component classes are reloaded. The non-component classes are frozen as they were when they were </span><em style="line-height: 1.4285715;">first</em><span style="line-height: 1.4285715;"> loaded.</span></p><p>Unfortunately, this is one of the areas where you must restart your application entirely in order to force the new versions of the non-component classes to be loaded into memory.</p><h3 id="SpecificErrorsFAQ-Whydomylogscontain"java.lang.RuntimeException:FormsrequirethattherequestmethodbePOSTandthatthet:formdataqueryparameterhavevalues"?">Why do my logs contain "java.lang.RuntimeException: Forms require that the request method be POST and that the t:formdata query parameter have values"?</h3><p>This is caused by someone (or something) submitting the URL of your form u sing an HTTP GET instead of POST. Tapestry forms must always use POST actions.</p><p>Some known scenarios that cause this error:</p><ul><li>Bots crawling your site</li><li>Web browser auto-complete functions trying to be helpful</li><li>Users with browser developer tools manually modifying the form from a POST to a GET to see what will happen.</li><li>Users getting a validation error on a form, then re-submitting the form by clicking in the URL address field and hitting Enter.</li><li>In Tapestry versions before 5.4, (rarely) the use of property names for form fields where the property name matches a JavaScript property (see <a class="external-link" href="https://issues.apache.org/jira/browse/TAP5-2066">TAP5-2066</a>).</li></ul><p>In every known scenario except the last, these errors are harmless and you probably want to redirect the user to the page the form is on – and avoid logging an error. That's not too hard to do. Just add code like the following to your module class ( usually AppModule.java):</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>AppModule.java (partial)</b></div><div class="codeContent panelContent pdl"> -<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;"> /** + <div id="ConfluenceContent"><p><plain-text-body>{scrollbar}</plain-text-body></p><parameter ac:name="style">float:right</parameter><parameter ac:name="title">Related Articles</parameter><parameter ac:name="class">aui-label</parameter><rich-text-body><parameter ac:name="showLabels">false</parameter><parameter ac:name="showSpace">false</parameter><parameter ac:name="title">Related Articles</parameter><parameter ac:name="cql">label = "errors" and space = currentSpace()</parameter></rich-text-body><h3 id="SpecificErrorsFAQ-WhydoIgettheexception"Noserviceimplementstheinterfaceorg.apache.tapestry5.internal.InternalComponentResources"whentryingtousetheBeanEditFormcomponent?">Why do I get the exception "No service implements the interface org.apache.tapestry5.internal.InternalComponentResources" when trying to use the BeanEditForm component?</h3><p>This can occur when you choose the wrong package for your data object, the object edited by the BeanEditForm component . If you place it in the same package as your pages, Tapestry will treat it like a page, and perform a number of transformation on it, including adding a new constructor.</p><p>Only component classes should go in the Tapestry-controlled packages (<code>pages</code>, <code>components</code>, <code>mixins</code> and <code>base</code> under your application's root package). By convention, simple data objects should go in a <code>data</code> package, and Hibernate entities should go in an <code>entities</code> package.</p><rich-text-body><p>This is likely a bit different in 5.3 than in 5.2 (because 5.3 builds a very different constructor into the component) and needs to be tested in 5.3 to see what exact exception will occur.</p></rich-text-body><h3 id="SpecificErrorsFAQ-Igetanerrorabout"Pagedidnotgenerateanymarkupwhenrendered."butIhaveatemplate,whathappened?">I get an error about "Page did not generate any markup when rendered." but I have a template, what happened?</h3><p>Th e most common error here is that the case of the page class did not match the case of the template. For example, you might name your class ViewOrders, but name the template vieworders.tml. The correct name for the template is ViewOrders.tml, matching the case of the Java class name.</p><p>Worse, you may find that your application works during development (under Windows, which is case insensitive) but does not work when deployed on a Linux or Unix server, which may be case sensitive.</p><p>The other cause of this may be that your template files simply are not being packaged up correctly with the rest of your application. When in doubt, use the Java <code>jar</code> command to see exactly whats inside your WAR file. Your page templates should either be in the root folder of the WAR, or package with the corresponding .class file.</p><h3 id="SpecificErrorsFAQ-MyapplicationfailswiththeerrorPermGen,howdoIfixthis?">My application fails with the error <strong>PermGen</strong>, how do I fix this?</h3><p>PermGen refers to the part of the Java memory space devoted to permanent objects, which are mostly loaded classes. When developing under Tapestry, many more classes and class loaders are created than normal; this is part of live class reloading. Because of this, you will want to increase the amount of memory Java devotes to this.</p><p>The solution is to add <code>-XX:MaxPermSize=512m</code> to your command line. You may also want to increase the regular amount of heap space with <code>-Xmx600M</code>. Of course, you may need to adjust the amount of memory in each category to match your actual application, but these are good starting values.</p><p>Java Virtual Machine arguments can be specified inside an Eclipse launch configuration:</p><p><span class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image confluence-thumbnail" src="specific-errors-faq.data/eclipse-permgen.png"></span></p><h3 id="SpecificErrorsFAQ-WhydoIsometimesgetajava.lang.NoSuchMeth odErrorexceptionafterreloadingmypage?">Why do I sometimes get a <code>java.lang.NoSuchMethodError</code> exception after reloading my page?</h3><p>Tapestry's live class reloading is not perfect. <span style="line-height: 1.4285715;">It tends to use a lot of Java ClassLoaders on top of the normal ClassLoaders used by the Java Virtual Machine and the servlet container. When you change non-component classes and interfaces that are referenced by components and pages, such as to add or change a method, only the component classes are reloaded. The non-component classes are frozen as they were when they were </span><em style="line-height: 1.4285715;">first</em><span style="line-height: 1.4285715;"> loaded.</span></p><p>Unfortunately, this is one of the areas where you must restart your application entirely in order to force the new versions of the non-component classes to be loaded into memory.</p><h3 id="SpecificErrorsFAQ-Whydomylogscontain"java.lang.RuntimeException:Formsrequir ethattherequestmethodbePOSTandthatthet:formdataqueryparameterhavevalues"?">Why do my logs contain "java.lang.RuntimeException: Forms require that the request method be POST and that the t:formdata query parameter have values"?</h3><p>This is caused by someone (or something) submitting the URL of your form using an HTTP GET instead of POST. Tapestry forms must always use POST actions.</p><p>Some known scenarios that cause this error:</p><ul><li>Bots crawling your site</li><li>Web browser auto-complete functions trying to be helpful</li><li>Users with browser developer tools manually modifying the form from a POST to a GET to see what will happen.</li><li>Users getting a validation error on a form, then re-submitting the form by clicking in the URL address field and hitting Enter.</li><li>In Tapestry versions before 5.4, (rarely) the use of property names for form fields where the property name matches a JavaScript property (see <a class="external-link" href="https://issues.apac he.org/jira/browse/TAP5-2066">TAP5-2066</a>).</li></ul><p>In every known scenario except the last, these errors are harmless and you probably want to redirect the user to the page the form is on – and avoid logging an error. That's not too hard to do. Just add code like the following to your module class (usually AppModule.java):</p><parameter ac:name="language">java</parameter><parameter ac:name="title">AppModule.java (partial)</parameter><plain-text-body> /** * Redirect the user to the intended page when browsing through * tapestry forms through browser history or over-eager autocomplete */ @@ -145,8 +92,7 @@ response.sendRedirect(uri); } }; - }</pre> -</div></div><p><em>Thanks to <a class="external-link" href="http://mail-archives.apache.org/mod_mbox/tapestry-users/201110.mbox/%3c1319823993429-4946765.p...@n5.nabble.com%3E">Lenny Primak</a> for the above code. A slightly less fragile approach is <a class="external-link" href="https://mail-archives.apache.org/mod_mbox/tapestry-users/201509.mbox/%3ccae26fnjevncyv52kms-kpsewwnaln9pg6lg60xzkxuhs0ut...@mail.gmail.com%3E">described here</a>. When <a class="external-link" href="https://issues.apache.org/jira/browse/TAP5-1733">TAP5-1733</a> is fixed a much less fragile solution may be possible.</em></p><p> </p></div> + }</plain-text-body><p><em>Thanks to <a class="external-link" href="http://mail-archives.apache.org/mod_mbox/tapestry-users/201110.mbox/%3c1319823993429-4946765.p...@n5.nabble.com%3E">Lenny Primak</a> for the above code. A slightly less fragile approach is <a class="external-link" href="https://mail-archives.apache.org/mod_mbox/tapestry-users/201509.mbox/%3ccae26fnjevncyv52kms-kpsewwnaln9pg6lg60xzkxuhs0ut...@mail.gmail.com%3E">described here</a>. When <a class="external-link" href="https://issues.apache.org/jira/browse/TAP5-1733">TAP5-1733</a> is fixed a much less fragile solution may be possible.</em></p><p> <plain-text-body>{scrollbar}</plain-text-body></p></div> </div> <div class="clearer"></div> Modified: websites/production/tapestry/content/switching-cases.html ============================================================================== --- websites/production/tapestry/content/switching-cases.html (original) +++ websites/production/tapestry/content/switching-cases.html Tue Sep 26 19:20:27 2017 @@ -27,16 +27,6 @@ </title> <link type="text/css" rel="stylesheet" href="/resources/space.css" /> - <link href='/resources/highlighter/styles/shCoreCXF.css' rel='stylesheet' type='text/css' /> - <link href='/resources/highlighter/styles/shThemeCXF.css' rel='stylesheet' type='text/css' /> - <script src='/resources/highlighter/scripts/shCore.js' type='text/javascript'></script> - <script src='/resources/highlighter/scripts/shBrushJava.js' type='text/javascript'></script> - <script src='/resources/highlighter/scripts/shBrushXml.js' type='text/javascript'></script> - <script src='/resources/highlighter/scripts/shBrushPlain.js' type='text/javascript'></script> - <script> - SyntaxHighlighter.defaults['toolbar'] = false; - SyntaxHighlighter.all(); - </script> <link href="/styles/style.css" rel="stylesheet" type="text/css"/> @@ -77,10 +67,10 @@ </div> <div id="content"> - <div id="ConfluenceContent"><p> </p><h1 id="SwitchingCases-SwitchingCases">Switching Cases</h1><p>With Tapestry's <code>If</code> component you can only test one condition at a time. In order to distinguish multiple cases, you'd have to write complex nested if/else constructs in your page template and have a checker method for each test inside your page class.</p><div class="navmenu" style="float:right; background:#eee; margin:3px; padding:0 1em"> -<p> <strong>JumpStart Demo:</strong><br clear="none"> - <a class="external-link" href="http://jumpstart.doublenegative.com.au/jumpstart/examples/lang/ifnotnegateswitchelseunless" rel="nofollow">If, Not, Negate, Switch, Else, Unless</a></p></div>In cases where you have to distinguish multiple cases, the <code>Delegate</code> component comes in. It delegates rendering to some other component, for example a <code>Block</code>. For each case you have, you basically wrap the content inside a <code>Block</code> that doesn't get rendered by default. You then place a Delegate component on your page and point it to a method inside your page class that will decide which of your Blocks should be rendered.<p>Imagine for example a use case, where you want to distinguish between 4 cases and you have an int property called <code>whichCase</code> that should be tested against. Your page template would look as follows:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"> <b>SwitchMe.tml</b></div><div class="codeContent panelContent pdl"> -<pre class="brush: xml; gutter: false; theme: Default" style="font-size:12px;"><html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_1_0.xsd"> + <div id="ConfluenceContent"><p> </p><parameter ac:name="hidden">true</parameter><parameter ac:name="atlassian-macro-output-type">BLOCK</parameter><rich-text-body><p>Performing the equivalent of a "switch" statement in your component template using blocks and a delegate</p></rich-text-body><h1 id="SwitchingCases-SwitchingCases">Switching Cases</h1><p>With Tapestry's <code>If</code> component you can only test one condition at a time. In order to distinguish multiple cases, you'd have to write complex nested if/else constructs in your page template and have a checker method for each test inside your page class.<plain-text-body>{float:right|background=#eee|padding=0 1em} + *JumpStart Demo:* + [If, Not, Negate, Switch, Else, Unless|http://jumpstart.doublenegative.com.au/jumpstart/examples/lang/ifnotnegateswitchelseunless] +{float}</plain-text-body>In cases where you have to distinguish multiple cases, the <code>Delegate</code> component comes in. It delegates rendering to some other component, for example a <code>Block</code>. For each case you have, you basically wrap the content inside a <code>Block</code> that doesn't get rendered by default. You then place a Delegate component on your page and point it to a method inside your page class that will decide which of your Blocks should be rendered.</p><p>Imagine for example a use case, where you want to distinguish between 4 cases and you have an int property called <code>whichCase</code> that should be tested against. Your page template would look as follows:</p><parameter ac:name="language">xml</parameter><parameter ac:name="title">SwitchMe.tml</parameter><plain-text-body><html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_1_0.xsd"> <body> <h1>Switch</h1> @@ -103,9 +93,7 @@ </t:block> </body> </html> -</pre> -</div></div><p>You can see, that the <code>Delegate</code> component's <code>to</code> parameter is bound to the case property of your page class. In your page class you therefore have a <code>getCase()</code> method that is responsible for telling the <code>Delegate</code> component which component should be rendered. For that we are injecting references to the <code>Block}}s defined in your page template into the page class and return the according {{Block</code> in the <code>getCase()</code> method.</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>SwitchMe.java</b></div><div class="codeContent panelContent pdl"> -<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">public class SwitchMe +</plain-text-body><p>You can see, that the <code>Delegate</code> component's <code>to</code> parameter is bound to the case property of your page class. In your page class you therefore have a <code>getCase()</code> method that is responsible for telling the <code>Delegate</code> component which component should be rendered. For that we are injecting references to the <code>Block}}s defined in your page template into the page class and return the according {{Block</code> in the <code>getCase()</code> method.</p><parameter ac:name="language">java</parameter><parameter ac:name="title">SwitchMe.java</parameter><plain-text-body>public class SwitchMe { @Persist private int whichCase; @@ -130,8 +118,7 @@ } } } -</pre> -</div></div><p>Happy switching!</p></div> +</plain-text-body><p>Happy switching!</p></div> </div> <div class="clearer"></div> Modified: websites/production/tapestry/content/tapestry-inversion-of-control-faq.html ============================================================================== --- websites/production/tapestry/content/tapestry-inversion-of-control-faq.html (original) +++ websites/production/tapestry/content/tapestry-inversion-of-control-faq.html Tue Sep 26 19:20:27 2017 @@ -27,16 +27,6 @@ </title> <link type="text/css" rel="stylesheet" href="/resources/space.css" /> - <link href='/resources/highlighter/styles/shCoreCXF.css' rel='stylesheet' type='text/css' /> - <link href='/resources/highlighter/styles/shThemeCXF.css' rel='stylesheet' type='text/css' /> - <script src='/resources/highlighter/scripts/shCore.js' type='text/javascript'></script> - <script src='/resources/highlighter/scripts/shBrushJava.js' type='text/javascript'></script> - <script src='/resources/highlighter/scripts/shBrushXml.js' type='text/javascript'></script> - <script src='/resources/highlighter/scripts/shBrushPlain.js' type='text/javascript'></script> - <script> - SyntaxHighlighter.defaults['toolbar'] = false; - SyntaxHighlighter.all(); - </script> <link href="/styles/style.css" rel="stylesheet" type="text/css"/> @@ -77,59 +67,7 @@ </div> <div id="content"> - <div id="ConfluenceContent"><h2 id="TapestryInversionofControlFAQ-TapestryInversionofControlContainer">Tapestry Inversion of Control Container</h2><p>Main article: <a href="ioc.html">Tapestry IoC</a></p><p> </p><div class="aui-label" style="float:right" title="Related Articles"> - - - - - - - - -<h3>Related Articles</h3> - -<ul class="content-by-label"><li> - <div> - <span class="icon aui-icon aui-icon-small aui-iconfont-page-default" title="Page">Page:</span> </div> - - <div class="details"> - <a href="ioc.html">IOC</a> - - - </div> - </li><li> - <div> - <span class="icon aui-icon aui-icon-small aui-iconfont-page-default" title="Page">Page:</span> </div> - - <div class="details"> - <a href="ioc-cookbook.html">IoC cookbook</a> - - - </div> - </li><li> - <div> - <span class="icon aui-icon aui-icon-small aui-iconfont-page-default" title="Page">Page:</span> </div> - - <div class="details"> - <a href="tapestry-ioc-overview.html">Tapestry IoC Overview</a> - - - </div> - </li><li> - <div> - <span class="icon aui-icon aui-icon-small aui-iconfont-page-default" title="Page">Page:</span> </div> - - <div class="details"> - <a href="tapestry-inversion-of-control-faq.html">Tapestry Inversion of Control FAQ</a> - - - </div> - </li></ul> -</div> - - -<h3 id="TapestryInversionofControlFAQ-WhydoIneedtodefineaninterfaceformyservices?Whycan'tIjustusetheclassitself?">Why do I need to define an interface for my services? Why can't I just use the class itself?</h3><p>First of all: you can do exactly this, but you lose some of the functionality that Tapestry's IoC container provides.</p><p>The reason for the split is so that Tapestry can provide functionality for your service around the core service implementation. It does this by creating <em>proxies</em>: Java classes that implement the service interface. The methods of the proxy will ultimately invoke the methods of your service implementation.</p><p>One of the primary purposes for proxies is to encapsulate the service's life cycle: most services are singletons that are created <em>just in time</em>. Just in time means only as soon as you invoke a method. What's going on is that the life cycle proxy (the object that gets injected into pages, components or other service implementation s) checks on each method invocation to see if the actual service exists yet. If not, it instantiates and configures it (using proper locking to ensure thread safety), then delegates the method invocation to the service.</p><p>If you bind a service class (not a service interface and class), then the service is fully instantiated the first time it is injected, rather than at that first method invocation. Further, you can't use decorations or method advice on such a service.</p><p>The final reason for the service interface / implementation split is to nudge you towards always coding to an interface, which has manifest benefits for code structure, robustness, and testability.</p><h3 id="TapestryInversionofControlFAQ-Myservicestartsathread;howdoIknowwhentheapplicationisshuttingdown,tostopthatthread?">My service starts a thread; how do I know when the application is shutting down, to stop that thread?</h3><p>This same concern applies to any long-lived resource (a thread, a database connec tion, a JMS queue connection) that a service may hold onto. Your code needs to know when the application has been undeployed and shutdown. This is actually quite easy, by adding some post-injection logic to your implementation class.</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl"> -<pre class="brush: java; gutter: true; theme: Default" style="font-size:12px;">public class MyServiceImpl implements MyService + <div id="ConfluenceContent"><p><plain-text-body>{scrollbar}</plain-text-body></p><h2 id="TapestryInversionofControlFAQ-TapestryInversionofControlContainer">Tapestry Inversion of Control Container</h2><p>Main article: <a href="ioc.html">Tapestry IoC</a></p><p> </p><parameter ac:name="style">float:right</parameter><parameter ac:name="title">Related Articles</parameter><parameter ac:name="class">aui-label</parameter><rich-text-body><parameter ac:name="showLabels">false</parameter><parameter ac:name="showSpace">false</parameter><parameter ac:name="title">Related Articles</parameter><parameter ac:name="cql">label = "ioc" and space = currentSpace()</parameter></rich-text-body><h3 id="TapestryInversionofControlFAQ-WhydoIneedtodefineaninterfaceformyservices?Whycan'tIjustusetheclassitself?">Why do I need to define an interface for my services? Why can't I just use the class itself?</h3><p>First of all: you can do exactly this, but you lose some of the functionality that Tapestry's IoC container provides.</p><p>The reason for the split is so that Tapestry can provide functionality for your service around the core service implementation. It does this by creating <em>proxies</em>: Java classes that implement the service interface. The methods of the proxy will ultimately invoke the methods of your service implementation.</p><p>One of the primary purposes for proxies is to encapsulate the service's life cycle: most services are singletons that are created <em>just in time</em>. Just in time means only as soon as you invoke a method. What's going on is that the life cycle proxy (the object that gets injected into pages, components or other service implementations) checks on each method invocation to see if the actual service exists yet. If not, it instantiates and configures it (using proper locking to ensure thread safety), then delegates the method invocation to the service.</p><p>If you bind a service class (not a service interface and class), then the service is fully instantiated the first time it is injected, rather than at that first method invocation. Further, you can't use decorations or method advice on such a service.</p><p>The final reason for the service interface / implementation split is to nudge you towards always coding to an interface, which has manifest benefits for code structure, robustness, and testability.</p><h3 id="TapestryInversionofControlFAQ-Myservicestartsathread;howdoIknowwhentheapplicationisshuttingdown,tostopthatthread?">My service starts a thread; how do I know when the application is shutting down, to stop that thread?</h3><p>This same concern applies to any long-lived resource (a thread, a database connection, a JMS queue connection) that a service may hold onto. Your code needs to know when the application has been undeployed and shutdown. This is actually quite easy, by adding some post-injection logic to your implementation class.</p><parameter ac:name="controls">true</parameter><parameter ac :name="linenumbers">true</parameter><plain-text-body>public class MyServiceImpl implements MyService { private boolean shuttingDown; @@ -156,8 +94,7 @@ }); } } -</pre> -</div></div><p>After Tapestry invokes the constructor of the service implementation, and after it performs any field injections, it invokes post injection methods. The methods must be public and return void. Parameters to a post injection method represent further injections ... in the above example, the RegistryShutdownHub is injected into the PostInjection method, since it is only used inside that one method.</p><div class="confluence-information-macro confluence-information-macro-warning"><span class="aui-icon aui-icon-small aui-iconfont-error confluence-information-macro-icon"></span><div class="confluence-information-macro-body"><p>It is <strong>not</strong> recommended that MyServiceImpl take RegistryShutdownHub as a constructor parameter and register itself as a listener inside the constructor. Doing so is an example of <a class="external-link" href="http://www.ibm.com/developerworks/java/library/j-jtp0618.html" rel="nofollow">unsafe publishing</a>, a remote but potential thr ead safety issue.</p></div></div><p>This same technique will work for any kind of resource that must be cleaned up or destroyed when the registry shuts down.</p><div class="confluence-information-macro confluence-information-macro-note"><span class="aui-icon aui-icon-small aui-iconfont-warning confluence-information-macro-icon"></span><div class="confluence-information-macro-body"><p>Be careful not to invoke methods on any service proxy objects as they will also be shutting down with the Registry. A RegistryShutdownListener should not be reliant on anything outside of itself.</p></div></div><h3 id="TapestryInversionofControlFAQ-HowdoImakemyservicestartupwiththerestoftheapplication,ratherthanlazily?">How do I make my service startup with the rest of the application, rather than lazily?</h3><p>Tapestry services are designed to be <em>lazy</em>; they are only fully realized when needed: when the first method on the service interface is invoked.</p><p>Sometimes a service does extra work that is desirable at application startup: examples may be registering message handlers with a JMS implementation, or setting up indexing. Since the service's constructor (or <a class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/PostInjection.html">@PostInjection</a> methods) are not invoked until the service is realized.</p><p>The solution is the <a class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/EagerLoad.html">@EagerLoad</a> annotation; service implementation classes marked with this annotation are loaded when the Registry is first startup, rather than lazily.</p></div> +</plain-text-body><p>After Tapestry invokes the constructor of the service implementation, and after it performs any field injections, it invokes post injection methods. The methods must be public and return void. Parameters to a post injection method represent further injections ... in the above example, the RegistryShutdownHub is injected into the PostInjection method, since it is only used inside that one method.</p><rich-text-body><p>It is <strong>not</strong> recommended that MyServiceImpl take RegistryShutdownHub as a constructor parameter and register itself as a listener inside the constructor. Doing so is an example of <a class="external-link" href="http://www.ibm.com/developerworks/java/library/j-jtp0618.html" rel="nofollow">unsafe publishing</a>, a remote but potential thread safety issue.</p></rich-text-body><p>This same technique will work for any kind of resource that must be cleaned up or destroyed when the registry shuts down.</p><rich-text-body><p>Be careful not to invoke methods on any service proxy objects as they will also be shutting down with the Registry. A RegistryShutdownListener should not be reliant on anything outside of itself.</p></rich-text-body><h3 id="TapestryInversionofControlFAQ-HowdoImakemyservicestartupwiththerestoftheapplication,ratherthanlazily?">How do I make my service startup with the rest of the application, rather than lazily?</h3><p>Tapestry services are designed to be <em>lazy</em>; they are only fully realized when needed: when the first method on the service interface is invoked.</p><p>Sometimes a service does extra work that is desirable at application startup: examples may be registering message handlers with a JMS implementation, or setting up indexing. Since the service's constructor (or <a class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/PostInjection.html">@PostInjection</a> methods) are not invoked until the service is realized.</p><p>The solutio n is the <a class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/EagerLoad.html">@EagerLoad</a> annotation; service implementation classes marked with this annotation are loaded when the Registry is first startup, rather than lazily.<plain-text-body>{scrollbar}</plain-text-body></p></div> </div> <div class="clearer"></div> Modified: websites/production/tapestry/content/templating-and-markup-faq.html ============================================================================== --- websites/production/tapestry/content/templating-and-markup-faq.html (original) +++ websites/production/tapestry/content/templating-and-markup-faq.html Tue Sep 26 19:20:27 2017 @@ -27,16 +27,6 @@ </title> <link type="text/css" rel="stylesheet" href="/resources/space.css" /> - <link href='/resources/highlighter/styles/shCoreCXF.css' rel='stylesheet' type='text/css' /> - <link href='/resources/highlighter/styles/shThemeCXF.css' rel='stylesheet' type='text/css' /> - <script src='/resources/highlighter/scripts/shCore.js' type='text/javascript'></script> - <script src='/resources/highlighter/scripts/shBrushJava.js' type='text/javascript'></script> - <script src='/resources/highlighter/scripts/shBrushXml.js' type='text/javascript'></script> - <script src='/resources/highlighter/scripts/shBrushPlain.js' type='text/javascript'></script> - <script> - SyntaxHighlighter.defaults['toolbar'] = false; - SyntaxHighlighter.all(); - </script> <link href="/styles/style.css" rel="stylesheet" type="text/css"/> @@ -77,52 +67,29 @@ </div> <div id="content"> - <div id="ConfluenceContent"><h2 id="TemplatingandMarkupFAQ-TemplatingandMarkup">Templating and Markup</h2><p>Main Article: <a href="component-templates.html">Component Templates</a></p><h3 id="TemplatingandMarkupFAQ-WhydoIgetaSAXParseExceptionwhenIuseanHTMLentity,suchas&nbsp;inmytemplate?">Why do I get a SAXParseException when I use an HTML entity, such as <code>&nbsp;</code> in my template?</h3><p>Tapestry uses a standard SAX parser to read your templates. This means that your templates must be <em>well formed</em>: open and close tags must balance, attribute values must be quoted, and entities must be declared. The easiest way to accomplish this is to add a DOCTYPE to your the top of your template:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl"> -<pre class="brush: xml; gutter: false; theme: Default" style="font-size:12px;"><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" + <div id="ConfluenceContent"><plain-text-body>{scrollbar}</plain-text-body><h2 id="TemplatingandMarkupFAQ-TemplatingandMarkup">Templating and Markup</h2><p>Main Article: <a href="component-templates.html">Component Templates</a></p><h3 id="TemplatingandMarkupFAQ-WhydoIgetaSAXParseExceptionwhenIuseanHTMLentity,suchas&nbsp;inmytemplate?">Why do I get a SAXParseException when I use an HTML entity, such as <code>&nbsp;</code> in my template?</h3><p>Tapestry uses a standard SAX parser to read your templates. This means that your templates must be <em>well formed</em>: open and close tags must balance, attribute values must be quoted, and entities must be declared. The easiest way to accomplish this is to add a DOCTYPE to your the top of your template:</p><parameter ac:name="controls">true</parameter><parameter ac:name="language">xml</parameter><plain-text-body><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> -</pre> -</div></div><p>Part of the DOCTYPE is the declaration of entities such as <code>&nbsp;</code>.</p><p>Alternately, you can simply use the numeric version: <code>&#160</code>; This is the exact same character and will render identically in the browser.</p><p>Starting in release 5.3, Tapestry introduces an XHTML doctype when no doctype is present; this means that common HTML entities will work correctly.</p><h3 id="TemplatingandMarkupFAQ-Whydosomeimagesinmypageshowupasbrokenlinks?">Why do some images in my page show up as broken links?</h3><p>You have to be careful when using relative URLs inside page templates; the base URL may not always be what you expect. For example, inside your <code>ViewUser.tml</code> file, you may have:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl"> -<pre class="brush: xml; gutter: false; theme: Default" style="font-size:12px;"> <img class="icon" src="icons/admin.png"/>${user.name} has Administrative access -</pre> -</div></div><p>This makes sense; ViewUser.tml is in the web context, as is the icons folder. The default URL for this page will be /viewuser (assuming that ViewUser class is in the  <em>root-package</em>.pages package).</p><p>However, the ViewUser page might use a page activation context to identify which user is to be displayed:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl"> -<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">public class ViewUser +</plain-text-body><p>Part of the DOCTYPE is the declaration of entities such as <code>&nbsp;</code>.</p><p>Alternately, you can simply use the numeric version: <code>&#160</code>; This is the exact same character and will render identically in the browser.</p><p>Starting in release 5.3, Tapestry introduces an XHTML doctype when no doctype is present; this means that common HTML entities will work correctly.</p><h3 id="TemplatingandMarkupFAQ-Whydosomeimagesinmypageshowupasbrokenlinks?">Why do some images in my page show up as broken links?</h3><p>You have to be careful when using relative URLs inside page templates; the base URL may not always be what you expect. For example, inside your <code>ViewUser.tml</code> file, you may have:</p><parameter ac:name="controls">true</parameter><parameter ac:name="language">xml</parameter><plain-text-body> <img class="icon" src="icons/admin.png"/>${user.name} has Administrative access +</plain-text-body><p>This makes sense; ViewUser.tml is in the web context, as is the icons folder. The default URL for this page will be /viewuser (assuming that ViewUser class is in the  <em>root-package</em>.pages package).</p><p>However, the ViewUser page might use a page activation context to identify which user is to be displayed:</p><parameter ac:name="controls">true</parameter><parameter ac:name="language">java</parameter><plain-text-body>public class ViewUser @Property @PageActivationContext private User user; . . . -</pre> -</div></div><p>With a page activation context, the URL for the page will incorporate the ID of the User object, something like <code>/viewuser/37371</code>. This is why the relative URL to the <code>admin.png</code> image is broken: the base path is relative to the page's URL, not to the page template. (In fact, the page template may not even be in the web context, it may be stored on the classpath, as component templates are.)</p><p>One solution would be to predict what the page URL will be, and adjust the path for that:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl"> -<pre class="brush: xml; gutter: false; theme: Default" style="font-size:12px;"> <img class="icon" src="../icons/admin.png"/>${user.name} has Administrative access -</pre> -</div></div><p>But this has its own problems; the page activation context may vary in length at different times, or the template in question may be a component used across many different pages, making it difficult to predict what the correct relative URL would be.</p><p>The <em>best</em> solution for this situation, one that will be sure to work in all pages and all components, is to make use of the <code>context:</code> binding prefix:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl"> -<pre class="brush: xml; gutter: false; theme: Default" style="font-size:12px;"> <img class="icon" src="${context:icons/admin.png}"/>${user.name} has Administrative access -</pre> -</div></div><p>The src attribute of the <img> tag will now be bound to a dynamically computed value: the location of the image file relative to the web application context. This is especially important for components that may be used on different pages.</p><h3 id="TemplatingandMarkupFAQ-What'sthedifferencebetweenidandt:id?">What's the difference between <code>id</code> and <code>t:id</code>?</h3><p>You might occasionally see something like the following in a template:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl"> -<pre class="brush: xml; gutter: false; theme: Default" style="font-size:12px;"><t:zone id="status" t:id="statusZone"> -</pre> -</div></div><p>Why two ids? Why are they different?</p><p>The <code>t:id</code> attribute is the Tapestry component id. This id is unique within its immediate container. This is the id you might use to inject the component into your page class:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl"> -<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;"> @InjectComponent +</plain-text-body><p>With a page activation context, the URL for the page will incorporate the ID of the User object, something like <code>/viewuser/37371</code>. This is why the relative URL to the <code>admin.png</code> image is broken: the base path is relative to the page's URL, not to the page template. (In fact, the page template may not even be in the web context, it may be stored on the classpath, as component templates are.)</p><p>One solution would be to predict what the page URL will be, and adjust the path for that:</p><parameter ac:name="controls">true</parameter><parameter ac:name="language">xml</parameter><plain-text-body> <img class="icon" src="../icons/admin.png"/>${user.name} has Administrative access +</plain-text-body><p>But this has its own problems; the page activation context may vary in length at different times, or the template in question may be a component used across many different pages, making it difficult to predict what the correct relative URL would be.</p><p>The <em>best</em> solution for this situation, one that will be sure to work in all pages and all components, is to make use of the <code>context:</code> binding prefix:</p><parameter ac:name="controls">true</parameter><parameter ac:name="language">xml</parameter><plain-text-body> <img class="icon" src="${context:icons/admin.png}"/>${user.name} has Administrative access +</plain-text-body><p>The src attribute of the <img> tag will now be bound to a dynamically computed value: the location of the image file relative to the web application context. This is especially important for components that may be used on different pages.</p><h3 id="TemplatingandMarkupFAQ-What'sthedifferencebetweenidandt:id?">What's the difference between <code>id</code> and <code>t:id</code>?</h3><p>You might occasionally see something like the following in a template:</p><parameter ac:name="controls">true</parameter><parameter ac:name="language">xml</parameter><plain-text-body><t:zone id="status" t:id="statusZone"> +</plain-text-body><p>Why two ids? Why are they different?</p><p>The <code>t:id</code> attribute is the Tapestry component id. This id is unique within its immediate container. This is the id you might use to inject the component into your page class:</p><parameter ac:name="controls">true</parameter><parameter ac:name="language">java</parameter><plain-text-body> @InjectComponent private Zone statusZone; -</pre> -</div></div><p>The other id is the client id, a unique id for the rendered element within the client-side DOM. JavaScript that needs to access the element uses this id. For example:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl"> -<pre class="brush: text; gutter: false; theme: Default" style="font-size:12px;"> $('status').hide(); -</pre> -</div></div><p>In many components, the <code>id</code> attribute is an informal parameter; a value from the template that is blindly echoed into the output document. In other cases, the component itself has an <code>id</code> attribute. Often, in the latter case, the Tapestry component id is the <em>default</em> value for the client id.</p><h3 id="TemplatingandMarkupFAQ-WhydomyimagesandstylesheetsendupwithaweirdURLslike/assets/meta/zeea17aee26bc0cae/layout/layout.css?">Why do my images and stylesheets end up with a weird URLs like <code>/assets/meta/zeea17aee26bc0cae/layout/layout.css</code>?</h3><p>Tapestry doesn't rely on the servlet container to serve up your static assets (images, stylesheets, flash movies, etc.). Instead, Tapestry processes the requests itself, streaming assets to the browser.</p><p>Asset content will be GZIP compressed (if the client supports compression, and the content is compressible). In addition, Tapestry will set a far-future expires header on the conten t. This means that the browser will not ask for the file again, greatly reducing network traffic.</p><p>The weird hex string is a <em>fingerprint</em>; it is a hash code computed from the actual content of the asset. If the asset ever changes, it will have a new fingerprint, and so will be a new path and a new (immutable) resource. This approach, combined with a far-future expires header also provided by Tapestry, ensures that clients aggressively cache assets as they navigate your site, or even between visits.</p><p><span style="color: rgb(83,145,38);font-size: 16.0px;line-height: 1.5625;">How do I add a CSS class to a Tapestry component?</span></p><p>As they say, "just do it". The majority of Tapestry components support <em>informal parameters</em>, meaning that any extra attributes in the element (in the template) will be rendered out as additional attributes. So, you can apply a CSS class or style quite easily:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl"> -<pre class="brush: xml; gutter: false; theme: Default" style="font-size:12px;"> <t:textfield t:id="username" class="big-green"/> -</pre> -</div></div><p>You can even use template expansions inside the attribute value:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl"> -<pre class="brush: xml; gutter: false; theme: Default" style="font-size:12px;"> <t:textfield t:id="username" class="${usernameClass}"/> -</pre> -</div></div><p>and</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl"> -<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;"> public String getUsernameClass() +</plain-text-body><p>The other id is the client id, a unique id for the rendered element within the client-side DOM. JavaScript that needs to access the element uses this id. For example:</p><parameter ac:name="controls">true</parameter><parameter ac:name="language">text</parameter><plain-text-body> $('status').hide(); +</plain-text-body><p>In many components, the <code>id</code> attribute is an informal parameter; a value from the template that is blindly echoed into the output document. In other cases, the component itself has an <code>id</code> attribute. Often, in the latter case, the Tapestry component id is the <em>default</em> value for the client id.</p><h3 id="TemplatingandMarkupFAQ-WhydomyimagesandstylesheetsendupwithaweirdURLslike/assets/meta/zeea17aee26bc0cae/layout/layout.css?">Why do my images and stylesheets end up with a weird URLs like <code>/assets/meta/zeea17aee26bc0cae/layout/layout.css</code>?</h3><p>Tapestry doesn't rely on the servlet container to serve up your static assets (images, stylesheets, flash movies, etc.). Instead, Tapestry processes the requests itself, streaming assets to the browser.</p><p>Asset content will be GZIP compressed (if the client supports compression, and the content is compressible). In addition, Tapestry will set a far-future expires header on the content. This means that the browser will not ask for the file again, greatly reducing network traffic.</p><p>The weird hex string is a <em>fingerprint</em>; it is a hash code computed from the actual content of the asset. If the asset ever changes, it will have a new fingerprint, and so will be a new path and a new (immutable) resource. This approach, combined with a far-future expires header also provided by Tapestry, ensures that clients aggressively cache assets as they navigate your site, or even between visits.</p><p><span style="color: rgb(83,145,38);font-size: 16.0px;line-height: 1.5625;">How do I add a CSS class to a Tapestry component?</span></p><p>As they say, "just do it". The majority of Tapestry components support <em>informal parameters</em>, meaning that any extra attributes in the element (in the template) will be rendered out as additional attributes. So, you can apply a CSS class or style quite easily:</p><parameter ac:name="controls">true</parameter><paramet er ac:name="language">xml</parameter><plain-text-body> <t:textfield t:id="username" class="big-green"/> +</plain-text-body><p>You can even use template expansions inside the attribute value:</p><parameter ac:name="controls">true</parameter><parameter ac:name="language">xml</parameter><plain-text-body> <t:textfield t:id="username" class="${usernameClass}"/> +</plain-text-body><p>and</p><parameter ac:name="controls">true</parameter><parameter ac:name="language">java</parameter><plain-text-body> public String getUsernameClass() { return isUrgent() ? "urgent" : null; } -</pre> -</div></div><p>When an informal parameter is bound to null, then the attribute is not written out at all.</p><p>You can verify which components support informal parameters by checking the component reference, or looking for the @<a class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/SupportsInformalParameters.html">SupportsInformalParameters</a> annotation in the components' source file.</p><p> </p><p> </p><p> </p><p> </p><p> </p><p> </p><p></p><p></p><p></p><p></p><p></p><p></p><div class="display-footnotes"></div> -<p></p><p></p><p></p><p></p><p></p><p> </p><p> </p><p> </p><p> </p></div> +</plain-text-body><p>When an informal parameter is bound to null, then the attribute is not written out at all.</p><p>You can verify which components support informal parameters by checking the component reference, or looking for the @<a class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/SupportsInformalParameters.html">SupportsInformalParameters</a> annotation in the components' source file.</p><plain-text-body>{scrollbar}</plain-text-body><p> </p><p> </p><p> </p><p> </p><p> </p><p> </p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p> </p><p> </p><p> </p><p> </p></div> </div> <div class="clearer"></div> Modified: websites/production/tapestry/content/test-page.html ============================================================================== --- websites/production/tapestry/content/test-page.html (original) +++ websites/production/tapestry/content/test-page.html Tue Sep 26 19:20:27 2017 @@ -27,16 +27,6 @@ </title> <link type="text/css" rel="stylesheet" href="/resources/space.css" /> - <link href='/resources/highlighter/styles/shCoreCXF.css' rel='stylesheet' type='text/css' /> - <link href='/resources/highlighter/styles/shThemeCXF.css' rel='stylesheet' type='text/css' /> - <script src='/resources/highlighter/scripts/shCore.js' type='text/javascript'></script> - <script src='/resources/highlighter/scripts/shBrushJava.js' type='text/javascript'></script> - <script src='/resources/highlighter/scripts/shBrushXml.js' type='text/javascript'></script> - <script src='/resources/highlighter/scripts/shBrushPlain.js' type='text/javascript'></script> - <script> - SyntaxHighlighter.defaults['toolbar'] = false; - SyntaxHighlighter.all(); - </script> <link href="/styles/style.css" rel="stylesheet" type="text/css"/> @@ -80,51 +70,32 @@ <div id="ConfluenceContent"><p>Test page.</p> <h2 id="TestPage-TabbedBlockTest">Tabbed Block Test</h2> -<p></p><p> -<style type="text/css"> +<p></p><p><plain-text-body> +<style type="text/css"> DIV.deck DIV.tabBar DIV.tab { position: relative; top: 1px; background: #eee; } DIV.deck DIV.tabBar DIV.tab#current { position: inherit; background: white; } DIV.deck DIV.tabBar DIV.tab a { color: black; } DIV.deck DIV.card {border: 1px solid #ccc; display: table-cell;} -</style> -</p><p></p> +</style> +</plain-text-body></p><p></p> <h3 id="TestPage-Tabstest#1–usingCompositionmacro">Tabs test #1 – using Composition macro</h3> -<script type="text/javascript">//<![CDATA[ -function debug() { } -// ]]></script><script type="text/javascript" src="/confluence/download/resources/org.randombits.confluence.composition:composition-setup/js/browser.js">//<![CDATA[ -// ]]></script><script type="text/javascript" src="/confluence/download/resources/org.randombits.confluence.composition:composition-setup/js/behaviour.js">//<![CDATA[ -// ]]></script><script type="text/javascript" src="/confluence/download/resources/org.randombits.confluence.composition:composition-setup/js/memory.js">//<![CDATA[ -// ]]></script><script type="text/javascript" src="/confluence/download/resources/org.randombits.confluence.composition:composition-setup/js/cloak.js">//<![CDATA[ -// ]]></script><script type="text/javascript">//<![CDATA[ -Cloak.closeHTML = "<img src=\'/confluence/download/resources/org.randombits.confluence.composition:toggle-cloak/img/navigate_down_10.gif\'/>"; -Cloak.openHTML = "<img src=\'/confluence/download/resources/org.randombits.confluence.composition:toggle-cloak/img/navigate_right_10.gif\'/>"; -Cloak.toggleZone = true; -Cloak.memoryDuration = 0; -Cloak.memoryPrefix = "contentId:24189280"; -Cloak.memoryPath = "/confluence/"; -// ]]></script><style type="text/css"> -.cloakToggle { /* Definition for state toggling image */ -cursor:hand; -cursor:pointer; -} -</style><script type="text/javascript" src="/confluence/download/resources/org.randombits.confluence.composition:composition-setup/js/transitions.js">//<![CDATA[ -// ]]></script><script type="text/javascript" src="/confluence/download/resources/org.randombits.confluence.composition:composition-setup/js/deck.js">//<![CDATA[ -// ]]></script><link rel="stylesheet" type="text/css" href="/confluence/styles/main-action.css?pluginCompleteKey=org.randombits.confluence.composition:composition-setup&stylesheetName=deck&spaceKey=TAPESTRY"><script type="text/javascript">//<![CDATA[ -Deck.memoryDuration = 0; -Deck.memoryPrefix = "contentId:24189280"; -Deck.memoryPath = "/confluence/"; -// ]]></script> +<plain-text-body>{composition-setup} +deck.tab.active.border=1px solid #ccc +deck.tab.inactive.border=1px solid #ccc +deck.tab.spacer=2px +deck.startHidden=false +{composition-setup}</plain-text-body> -<div class="deck" id="deck:myDeck" tablocation="top" style="display: none" loopcards="false"><div class="cards tabbed"> -<div class="card" label="Tapestry 5.4+" labelrendered="Tapestry 5.4+"> +<plain-text-body>{deck:id=myDeck}</plain-text-body> +<plain-text-body>{card:label=Tapestry 5.4+}</plain-text-body> <p>Starting with Tapestry 5.4, you can easily choose whether the foundation JavaScript framework is jQuery or Prototype.</p> -</div> -<div class="card" label="5.0-5.3" labelrendered="5.0-5.3"> +<plain-text-body>{card}</plain-text-body> +<plain-text-body>{card:label=5.0-5.3}</plain-text-body> <p>In Tapestry versions prior to 5.4 the Prototype and Scriptaculous libraries are included by default ... no extra download is required. Tapestry will automatically link into your pages the prototype.js, scriptaculous.js, and effects.js libraries, as well as the Tapestry library, tapestry.js (which largely consists of support for form input validation). Starting with Tapestry 5.3, Underscore is also included.</p> -</div> -</div></div> +<plain-text-body>{card}</plain-text-body> +<plain-text-body>{deck}</plain-text-body> <p>This works, but 1) doesn't preview very well (preview shows alternatives as side-by-side cells in a table, with no header row), and 2) requires additional processing code to be added to the SiteExporter.</p> @@ -137,7 +108,7 @@ Deck.memoryPath = "/confluence/"; <h2 id="TestPage-ChildrenTest">Children Test</h2> -<ul class="childpages-macro"><li><a href="test-page-2.html">Test Page 2</a></li></ul> +<parameter ac:name="excerpt">true</parameter> <p>foooo</p></div> </div>