tapestry-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From conflue...@apache.org
Subject [CONF] Apache Tapestry > Component Libraries
Date Sun, 03 Jul 2011 11:39:00 GMT
<html>
<head>
    <base href="https://cwiki.apache.org/confluence">
            <link rel="stylesheet" href="/confluence/s/2042/9/12/_/styles/combined.css?spaceKey=TAPESTRY&amp;forWysiwyg=true"
type="text/css">
    </head>
<body style="background: white;" bgcolor="white" class="email-body">
<div id="pageContent">
<div id="notificationFormat">
<div class="wiki-content">
<div class="email">
    <h2><a href="https://cwiki.apache.org/confluence/display/TAPESTRY/Component+Libraries">Component
Libraries</a></h2>
    <h4>Page <b>edited</b> by             <a href="https://cwiki.apache.org/confluence/display/~bobharner">Bob
Harner</a>
    </h4>
        <div id="versionComment">
        <b>Comment:</b>
        More smoothly integrated the paragraphs on 5.2's automatic asset version mapping<br
/>
    </div>
        <br/>
                         <h4>Changes (4)</h4>
                                 
    
<div id="page-diffs">
                    <table class="diff" cellpadding="0" cellspacing="0">
    
            <tr><td class="diff-snipped" >...<br></td></tr>
            <tr><td class="diff-unchanged" >The image file here would exposed
to the web browser via the URL /happyapp/assets/org/example/happylib/components/happy.jpg
(this assumes that the application was deployed as happyapp.war). <br> <br></td></tr>
            <tr><td class="diff-changed-lines" >Tapestry uses a far-future expiration
date for classpath assets; this allows browsers to aggressively cache the file, but <span
class="diff-added-words"style="background-color: #dfd;">in Tapestry 5.1 and earlier</span>
this causes a problem <span class="diff-deleted-words"style="color:#999;background-color:#fdd;text-decoration:line-through;">should</span>
<span class="diff-added-words"style="background-color: #dfd;">when</span> a later
version of the library <span class="diff-changed-words">change<span class="diff-added-chars"style="background-color:
#dfd;">s</span></span> the file. This is discussed in detail in [Yahoo&#39;s
Performance Best Practices|http://developer.yahoo.com/performance/rules.html#expires]. <br></td></tr>
            <tr><td class="diff-unchanged" > <br></td></tr>
            <tr><td class="diff-changed-lines" >To handle this <span class="diff-changed-words">problem<span
class="diff-added-chars"style="background-color: #dfd;"> in Tapestry 5.1 and earlier</span>,</span>
you should map your library assets to a versioned folder. This can be accomplished using another
contribution from the HappyModule, this time to the ClasspathAssetAliasManager service whose
configuration maps a virtual folder underneath /assets to a package: <br></td></tr>
            <tr><td class="diff-unchanged" > <br>{code} <br></td></tr>
            <tr><td class="diff-snipped" >...<br></td></tr>
            <tr><td class="diff-unchanged" >With this in place, and the library
and applications rebuilt and redeployed, the URL for happy.jpg becomes /happyapp/assets/happylib/1.0/components/happy.jpg.
This is shorter, but also incorporates a version number (&quot;1.0&quot;) that can
be changed in a later release. <br> <br></td></tr>
            <tr><td class="diff-added-lines" style="background-color: #dfd;">{since:since=5.2}
<br>In version 5.2 and later, Tapestry automatically creates a mapping for assets inside
your JAR. In the above example, the icon image will be exposed as {{/assets/}}{_}application
version{_}{{/happy/components/happy.jpg}} (the application version number is incorporated
into the URL). The &quot;happy&quot; portion is a virtual folder that maps to the
library&#39;s root package (as folder {{org/example/happylib}} on the Java classpath).
The application version is a configurable value. <br>{since} <br> <br></td></tr>
            <tr><td class="diff-unchanged" >h2. Conclusion <br> <br>That&#39;s
it\! Autoloading plus the virtual folders for components and for assets takes care of all
the issues related to components. Just build your JARs, setup the JAR Manifest, and drop them
into your applications. <br></td></tr>
            <tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">
<br>{since:since=5.2}{since} <br> <br>h2. A note about Assets <br>
<br>Tapestry automatically creates a mapping for assets inside your JAR. In the above
example, the icon image will be exposed as {{/assets/}}{_}application version{_}{{/happy/components/happy.jpg}}
(the application version number is incorporated into the URL). The &quot;happy&quot;
portion is a virtual folder that maps to the library&#39;s root package (as folder {{org/example/happylib}}
on the Java classpath). <br> <br>The application version is a configurable value.
<br> <br>In Tapestry 5.1 and earlier, it was necessary to explicitly create a
mapping, via a contribution to the ClasspathAssetAliasManager service, to expose library assets.
This is no longer necessary in Tapestry 5.2. <br></td></tr>
    
            </table>
    </div>                            <h4>Full Content</h4>
                    <div class="notificationGreySide">
        <style type='text/css'>/*<![CDATA[*/
table.ScrollbarTable  {border: none;padding: 3px;width: 100%;padding: 3px;margin: 0px;background-color:
#f0f0f0}
table.ScrollbarTable td.ScrollbarPrevIcon {text-align: center;width: 16px;border: none;}
table.ScrollbarTable td.ScrollbarPrevName {text-align: left;border: none;}
table.ScrollbarTable td.ScrollbarParent {text-align: center;border: none;}
table.ScrollbarTable td.ScrollbarNextName {text-align: right;border: none;}
table.ScrollbarTable td.ScrollbarNextIcon {text-align: center;width: 16px;border: none;}

/*]]>*/</style><div class="Scrollbar"><table class='ScrollbarTable'><tr><td
class='ScrollbarPrevIcon'><a href="/confluence/display/TAPESTRY/Supporting+Informal+Parameters"><img
border='0' align='middle' src='/confluence/images/icons/back_16.gif' width='16' height='16'></a></td><td
width='33%' class='ScrollbarPrevName'><a href="/confluence/display/TAPESTRY/Supporting+Informal+Parameters">Supporting
Informal Parameters</a>&nbsp;</td><td width='33%' class='ScrollbarParent'><sup><a
href="/confluence/display/TAPESTRY/Cookbook"><img border='0' align='middle' src='/confluence/images/icons/up_16.gif'
width='8' height='8'></a></sup><a href="/confluence/display/TAPESTRY/Cookbook">Cookbook</a></td><td
width='33%' class='ScrollbarNextName'>&nbsp;<a href="/confluence/display/TAPESTRY/Switching+Cases">Switching
Cases</a></td><td class='ScrollbarNextIcon'><a href="/confluence/display/TAPESTRY/Switching+Cases"><img
border='0' align='middle' src='/confluence/images/icons/forwd_16.gif' width='16' height='16'></a></td></tr></table></div>


<h1><a name="ComponentLibraries-CreatingComponentLibraries"></a>Creating
Component Libraries</h1>

<p>Nearly every Tapestry application includes a least a couple of custom components,
specific to the application. What's exciting about Tapestry is how easy it is to package components
for reuse across many applications ... and the fact that applications using a component library
need no special configuration.</p>

<p>A Tapestry component library consists of components (and optionally mixins, pages
and component base classes). In addition, a component library will have a module that can
define new services (needed by the components) or configure other services present in Tapestry.
Finally, components can be packaged with <em>assets</em>: resources such as images,
stylesheets and JavaScript libraries that need to be provided to the client web browser.</p>

<p>We're going to create a somewhat insipid component that displays a large happy face
icon.</p>

<p>Tapestry doesn't mandate that you use any build system, but we'll assume for the
moment that you are using Maven 2. In that case, you'll have a pom.xml file something like
the following:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeHeader panelHeader"
style="border-bottom-width: 1px;"><b>pom.xml</b></div><div class="codeContent
panelContent">
<pre class="code-xml">
<span class="code-tag">&lt;project&gt;</span>
  <span class="code-tag">&lt;modelVersion&gt;</span>4.0.0<span class="code-tag">&lt;/modelVersion&gt;</span>
  <span class="code-tag">&lt;groupId&gt;</span>org.example<span class="code-tag">&lt;/groupId&gt;</span>
  <span class="code-tag">&lt;artifactId&gt;</span>happylib<span class="code-tag">&lt;/artifactId&gt;</span>
  <span class="code-tag">&lt;version&gt;</span>1.0-SNAPSHOT<span class="code-tag">&lt;/version&gt;</span>
  <span class="code-tag">&lt;packaging&gt;</span>jar<span class="code-tag">&lt;/packaging&gt;</span>
  <span class="code-tag">&lt;name&gt;</span>happylib Tapestry 5 Library<span
class="code-tag">&lt;/name&gt;</span>

  <span class="code-tag">&lt;dependencies&gt;</span>
    <span class="code-tag">&lt;dependency&gt;</span>
      <span class="code-tag">&lt;groupId&gt;</span>org.apache.tapestry<span
class="code-tag">&lt;/groupId&gt;</span>
      <span class="code-tag">&lt;artifactId&gt;</span>tapestry-core<span
class="code-tag">&lt;/artifactId&gt;</span>
      <span class="code-tag">&lt;version&gt;</span>${tapestry-release-version}<span
class="code-tag">&lt;/version&gt;</span>
    <span class="code-tag">&lt;/dependency&gt;</span>

    <span class="code-tag">&lt;dependency&gt;</span>
      <span class="code-tag">&lt;groupId&gt;</span>org.testng<span
class="code-tag">&lt;/groupId&gt;</span>
      <span class="code-tag">&lt;artifactId&gt;</span>testng<span class="code-tag">&lt;/artifactId&gt;</span>
      <span class="code-tag">&lt;version&gt;</span>5.1<span class="code-tag">&lt;/version&gt;</span>
      <span class="code-tag">&lt;classifier&gt;</span>jdk15<span class="code-tag">&lt;/classifier&gt;</span>
      <span class="code-tag">&lt;scope&gt;</span>test<span class="code-tag">&lt;/scope&gt;</span>
    <span class="code-tag">&lt;/dependency&gt;</span>
  <span class="code-tag">&lt;/dependencies&gt;</span>

  <span class="code-tag">&lt;build&gt;</span>
    <span class="code-tag">&lt;plugins&gt;</span>
      <span class="code-tag">&lt;plugin&gt;</span>
        <span class="code-tag">&lt;groupId&gt;</span>org.apache.maven.plugins<span
class="code-tag">&lt;/groupId&gt;</span>
        <span class="code-tag">&lt;artifactId&gt;</span>maven-compiler-plugin<span
class="code-tag">&lt;/artifactId&gt;</span>
        <span class="code-tag">&lt;configuration&gt;</span>
          <span class="code-tag">&lt;source&gt;</span>1.5<span class="code-tag">&lt;/source&gt;</span>
          <span class="code-tag">&lt;target&gt;</span>1.5<span class="code-tag">&lt;/target&gt;</span>
          <span class="code-tag">&lt;optimize&gt;</span>true<span class="code-tag">&lt;/optimize&gt;</span>
        <span class="code-tag">&lt;/configuration&gt;</span>
      <span class="code-tag">&lt;/plugin&gt;</span>

      <span class="code-tag">&lt;plugin&gt;</span>
           <span class="code-tag">&lt;groupId&gt;</span>org.apache.maven.plugins<span
class="code-tag">&lt;/groupId&gt;</span>
           <span class="code-tag">&lt;artifactId&gt;</span>maven-jar-plugin<span
class="code-tag">&lt;/artifactId&gt;</span>
           <span class="code-tag">&lt;configuration&gt;</span>
           <span class="code-tag">&lt;archive&gt;</span>
             <span class="code-tag">&lt;manifestEntries&gt;</span>
               <span class="code-tag">&lt;Tapestry-Module-Classes&gt;</span>org.example.happylib.services.HappyModule<span
class="code-tag">&lt;/Tapestry-Module-Classes&gt;</span>
             <span class="code-tag">&lt;/manifestEntries&gt;</span>
           <span class="code-tag">&lt;/archive&gt;</span>
           <span class="code-tag">&lt;/configuration&gt;</span>
       <span class="code-tag">&lt;/plugin&gt;</span>

    <span class="code-tag">&lt;/plugins&gt;</span>
  <span class="code-tag">&lt;/build&gt;</span>

  <span class="code-tag">&lt;repositories&gt;</span>
    <span class="code-tag">&lt;repository&gt;</span>
      <span class="code-tag">&lt;id&gt;</span>codehaus.snapshots<span
class="code-tag">&lt;/id&gt;</span>
      <span class="code-tag">&lt;url&gt;</span>http://snapshots.repository.codehaus.org<span
class="code-tag">&lt;/url&gt;</span>
    <span class="code-tag">&lt;/repository&gt;</span>
    <span class="code-tag">&lt;repository&gt;</span>
      <span class="code-tag">&lt;id&gt;</span>OpenQA_Release<span class="code-tag">&lt;/id&gt;</span>
      <span class="code-tag">&lt;name&gt;</span>OpenQA Release Repository<span
class="code-tag">&lt;/name&gt;</span>
      <span class="code-tag">&lt;url&gt;</span>http://archiva.openqa.org/repository/releases/<span
class="code-tag">&lt;/url&gt;</span>
    <span class="code-tag">&lt;/repository&gt;</span>
  <span class="code-tag">&lt;/repositories&gt;</span>

  <span class="code-tag">&lt;properties&gt;</span>
    <span class="code-tag">&lt;tapestry-release-version&gt;</span>5.2.0<span
class="code-tag">&lt;/tapestry-release-version&gt;</span>
  <span class="code-tag">&lt;/properties&gt;</span>
<span class="code-tag">&lt;/project&gt;</span>
</pre>
</div></div>

<p>You will need to modify the Tapestry release version number ("5.2.0" in the listing
above) to reflect the current version of Tapestry when you create your component library.</p>

<p>We'll go into more detail about the relevant portions of this POM in the later sections.</p>

<h2><a name="ComponentLibraries-Step1%3AChooseabasepackagename"></a>Step
1: Choose a base package name</h2>

<p>Just as with Tapestry applications, Tapestry component libraries should have a <em>unique</em>
base package name. In this example, we'll use <tt>org.examples.happylib</tt>.</p>

<p>As with an application, we'll follow the conventions: we'll place the module for
this library inside the services package, and place pages and components under their respective
packages.</p>

<h2><a name="ComponentLibraries-Step2%3ACreateyourpagesand%2Forcomponents"></a>Step
2: Create your pages and/or components</h2>

<p>Our component is very simple:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeHeader panelHeader"
style="border-bottom-width: 1px;"><b>HappyIcon.java</b></div><div
class="codeContent panelContent">
<pre class="code-java">
<span class="code-keyword">package</span> org.example.happylib.components;

<span class="code-keyword">import</span> org.apache.tapestry5.Asset;
<span class="code-keyword">import</span> org.apache.tapestry5.MarkupWriter;
<span class="code-keyword">import</span> org.apache.tapestry5.annotations.Path;
<span class="code-keyword">import</span> org.apache.tapestry5.ioc.annotations.Inject;

<span class="code-keyword">public</span> class HappyIcon
{
    @Inject
    @Path(<span class="code-quote">"happy.jpg"</span>)
    <span class="code-keyword">private</span> Asset happyIcon;

    <span class="code-object">boolean</span> beginRender(MarkupWriter writer)
    {
        writer.element(<span class="code-quote">"img"</span>, <span class="code-quote">"src"</span>,
happyIcon);
        writer.end();

        <span class="code-keyword">return</span> <span class="code-keyword">false</span>;
    }
}
</pre>
</div></div>

<p>HappyIcon appears inside the components sub-package. The happyIcon field is injected
with the the Asset for the file <tt>happy.jpg</tt>. The path specified with the
@Path annotation is relative to the <tt>HappyIcon.class</tt> file; it should be
stored in the project under <tt>src/main/resources/org/example/happylib/components</tt>.</p>

<p>Tapestry ensures that the <tt>happy.jpg</tt> asset can be accessed from
the client web browser; the src attribute of the &lt;img&gt; tag will be a URL that
directly accesses the image file ... there's no need to unpackage the <tt>happy.jpg</tt>
file. This works for any asset file stored under the library's root package.</p>

<p>This component renders out an <tt>&lt;img&gt;</tt> tag for the
icon.</p>

<p>Often, a component library will have many different components, or even pages.</p>

<h2><a name="ComponentLibraries-Step3%3AChooseavirtualfoldername"></a>Step
3: Choose a virtual folder name</h2>

<p>In Tapestry, components that have been packaged in a library are referenced using
a virtual folder name. It's effectively as if the application had a new root-level folder
containing the components.</p>

<p>In our example, we'll use "happy" as the folder name. That means the application
will include the HappyIcon component in the template as:</p>

<ul>
	<li><tt>&lt;t:happy.happyicon/&gt;</tt> or <tt>&lt;t:happy.icon/&gt;</tt></li>
	<li><tt>&lt;img t:type="happy.happyicon"/&gt;</tt> or <tt>&lt;img
t:type="happy/icon/"&gt;</tt></li>
</ul>


<p>Why "icon" vs. "happyicon"? Tapestry notices that the folder name, "happy" is a prefix
or suffix of the class name ("HappyIcon") and creates an alias that strips off the prefix
(or suffix). To Tapestry, they are completely identical: two different aliases for the same
component class name.</p>

<p>The above naming is somewhat clumsy, and can be improved by introducing an additional
namespace into the template:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-xml">
&lt;html <span class="code-keyword">xmlns:t</span>=<span class="code-quote">"http://tapestry.apache.org/schema/tapestry_5_1_0.xsd"</span>
  <span class="code-keyword">xmlns:h</span>=<span class="code-quote">"tapestry-library:happy"</span>&gt;

  ...

  <span class="code-tag">&lt;h:icon/&gt;</span>

  ...
<span class="code-tag">&lt;/html&gt;</span>
</pre>
</div></div>

<p>The special namespace mapping for sets up namespace prefix "h:" to mean the same
as "happy/". It then becomes possible to reference components within the happy virtual folder
directly.</p>

<h2><a name="ComponentLibraries-Step4%3AConfigurethevirtualfolder"></a>Step
4: Configure the virtual folder</h2>

<p>Tapestry needs to know where to search for your component class. This is accomplished
in your library's IoC module class, by making a <em>contribution</em> to the ComponentClassResolver
service configuration.</p>

<p>At application startup, Tapestry will read the library module along with all other
modules and configure the ComponentClassResolver service using information in the module:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeHeader panelHeader"
style="border-bottom-width: 1px;"><b>HappyModule.java</b></div><div
class="codeContent panelContent">
<pre class="code-java">
<span class="code-keyword">package</span> org.example.happylib.services;

<span class="code-keyword">import</span> org.apache.tapestry5.ioc.Configuration;
<span class="code-keyword">import</span> org.apache.tapestry5.services.LibraryMapping;

<span class="code-keyword">public</span> class HappyModule
{
    <span class="code-keyword">public</span> <span class="code-keyword">static</span>
void contributeComponentClassResolver(Configuration&lt;LibraryMapping&gt; configuration)
    {
        configuration.add(<span class="code-keyword">new</span> LibraryMapping(<span
class="code-quote">"happy"</span>, <span class="code-quote">"org.example.happylib"</span>));
    }
}
</pre>
</div></div>

<p>The ComponentClassResolver service is responsible for mapping libraries to packages;
it takes as a contribution a collection of these LibraryMapping objects. Every module may
make its own contribution to the ComponentClassResolver service, mapping its own package ("org.example.happylib")
to its own folder ("happy").</p>

<p>This module class is also where you would define new services that can be accessed
by your components (or other parts of the application).</p>

<div class='panelMacro'><table class='noteMacro'><colgroup><col width='24'><col></colgroup><tr><td
valign='top'><img src="/confluence/images/icons/emoticons/warning.gif" width="16" height="16"
align="absmiddle" alt="" border="0"></td><td>It is possible to add a mapping
for "core", the core library for Tapestry components; all the built-in Tapestry components
(TextField, BeanEditForm, Grid, etc.) are actually in the core library. When Tapestry doesn't
find a component in your application, it next searches inside the "core" library. Contributing
an additional package as "core" simply extends the number of packages searched for core components
(it doesn't replace Tapestry's default package, org.apache.tapestry5.corelib). Adding to "core"
is sometimes reasonable, if you ensure that there is virtually no chance of a naming conflict
(via different modules contributing packages to core with conflicting class names).</td></tr></table></div>

<h2><a name="ComponentLibraries-Step5%3AConfigurethemoduletoautoload"></a>Step
5: Configure the module to autoload</h2>

<p>For Tapestry to load your module at application startup, it is necessary to put an
entry in the JAR manifest. This is taken care of in the pom.xml above:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeHeader panelHeader"
style="border-bottom-width: 1px;"><b>pom.xml (partial)</b></div><div
class="codeContent panelContent">
<pre class="code-xml">
      <span class="code-tag">&lt;plugin&gt;</span>
           <span class="code-tag">&lt;groupId&gt;</span>org.apache.maven.plugins<span
class="code-tag">&lt;/groupId&gt;</span>
           <span class="code-tag">&lt;artifactId&gt;</span>maven-jar-plugin<span
class="code-tag">&lt;/artifactId&gt;</span>
           <span class="code-tag">&lt;configuration&gt;</span>
           <span class="code-tag">&lt;archive&gt;</span>
             <span class="code-tag">&lt;manifestEntries&gt;</span>
             <span class="code-tag">&lt;Tapestry-Module-Classes&gt;</span>org.example.happylib.services.HappyModule<span
class="code-tag">&lt;/Tapestry-Module-Classes&gt;</span>
             <span class="code-tag">&lt;/manifestEntries&gt;</span>
           <span class="code-tag">&lt;/archive&gt;</span>
           <span class="code-tag">&lt;/configuration&gt;</span>
       <span class="code-tag">&lt;/plugin&gt;</span>
</pre>
</div></div>

<h2><a name="ComponentLibraries-Step6%3AExtendingClientAccess"></a>Step
6: Extending Client Access</h2>

<p>As of Tapestry 5.2, a new step is needed: extending access for the assets. This is
accomplished in your library's module class, HappyModule:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
<span class="code-keyword">public</span> <span class="code-keyword">static</span>
void contributeRegexAuthorizer(Configuration&lt;<span class="code-object">String</span>&gt;
configuration)
{
    configuration.add(<span class="code-quote">"^org/example/happylib/.*\\.jpg$"</span>);
}
</pre>
</div></div>

<p>This contribution uses a regular expression to identify that any resource on the
classpath under the org/example/happylib folder with a jpg extension is allowed. If you had
a mix of different image types, you could replace jpg with (jpg&#124;gif&#124;png).</p>

<h2><a name="ComponentLibraries-Step7%3AVersioningAssets"></a>Step 7: Versioning
Assets</h2>

<p>Classpath assets, those packaged in JAR files (such as the happy.jpg asset) are retrieved
by the client web browser using a URL that reflects the package name. Tapestry users a special
virtual folder, /assets, under the context folder for this purpose.</p>

<p>The image file here would exposed to the web browser via the URL /happyapp/assets/org/example/happylib/components/happy.jpg
(this assumes that the application was deployed as happyapp.war).</p>

<p>Tapestry uses a far-future expiration date for classpath assets; this allows browsers
to aggressively cache the file, but in Tapestry 5.1 and earlier this causes a problem when
a later version of the library changes the file. This is discussed in detail in <a href="http://developer.yahoo.com/performance/rules.html#expires"
class="external-link" rel="nofollow">Yahoo's Performance Best Practices</a>.</p>

<p>To handle this problem in Tapestry 5.1 and earlier, you should map your library assets
to a versioned folder. This can be accomplished using another contribution from the HappyModule,
this time to the ClasspathAssetAliasManager service whose configuration maps a virtual folder
underneath /assets to a package:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
<span class="code-keyword">public</span> <span class="code-keyword">static</span>
void contributeClasspathAssetAliasManager(MappedConfiguration&lt;<span class="code-object">String</span>,
<span class="code-object">String</span>&gt; configuration)
{
    configuration.add(<span class="code-quote">"happylib/1.0"</span>, <span
class="code-quote">"org/example/happylib"</span>);
}
</pre>
</div></div>

<p>With this in place, and the library and applications rebuilt and redeployed, the
URL for happy.jpg becomes /happyapp/assets/happylib/1.0/components/happy.jpg. This is shorter,
but also incorporates a version number ("1.0") that can be changed in a later release.</p>



<div class='panelMacro'><table class='infoMacro'><colgroup><col width='24'><col></colgroup><tr><td
valign='top'><img src="/confluence/images/icons/emoticons/information.gif" width="16"
height="16" align="absmiddle" alt="" border="0"></td><td><b>Added in
5.2</b><br /></td></tr></table></div>
<div style="border-right: 20px solid #D8E4F1;border-left: 20px solid #D8E4F1;">
<p>In version 5.2 and later, Tapestry automatically creates a mapping for assets inside
your JAR. In the above example, the icon image will be exposed as <tt>/assets/</tt><em>application
version</em><tt>/happy/components/happy.jpg</tt> (the application version
number is incorporated into the URL). The "happy" portion is a virtual folder that maps to
the library's root package (as folder <tt>org/example/happylib</tt> on the Java
classpath). The application version is a configurable value.</p>
</div>

<h2><a name="ComponentLibraries-Conclusion"></a>Conclusion</h2>

<p>That's it&#33; Autoloading plus the virtual folders for components and for assets
takes care of all the issues related to components. Just build your JARs, setup the JAR Manifest,
and drop them into your applications.</p>

    </div>
        <div id="commentsSection" class="wiki-content pageSection">
        <div style="float: right;">
            <a href="https://cwiki.apache.org/confluence/users/viewnotifications.action"
class="grey">Change Notification Preferences</a>
        </div>
        <a href="https://cwiki.apache.org/confluence/display/TAPESTRY/Component+Libraries">View
Online</a>
        |
        <a href="https://cwiki.apache.org/confluence/pages/diffpagesbyversion.action?pageId=21266608&revisedVersion=11&originalVersion=10">View
Changes</a>
            </div>
</div>
</div>
</div>
</div>
</body>
</html>

Mime
View raw message