You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by hl...@apache.org on 2005/01/27 23:02:24 UTC

cvs commit: jakarta-tapestry/framework/src/descriptor/META-INF tapestry.url.xml

hlship      2005/01/27 14:02:24

  Modified:    framework/src/test/org/apache/tapestry/services/impl
                        TestLinkFactory.java
               src/documentation/content/xdocs/UsersGuide common.ent
               src/documentation/content/xdocs links.ent site.xml
               examples/Workbench/src/context/WEB-INF hivemodule.xml
               framework/src/descriptor/META-INF tapestry.url.xml
  Added:       src/documentation/content/xdocs/UsersGuide friendly-urls.xml
               framework/src/test/org/apache/tapestry/engine/encoders
                        TestPageServiceEncoder.java
               framework/src/java/org/apache/tapestry/engine/encoders
                        PageServiceEncoder.java
  Removed:     framework/src/test/org/apache/tapestry/engine/encoders
                        TestServicePathEncoder.java
               framework/src/java/org/apache/tapestry/engine/encoders
                        ServicePathEncoder.java
  Log:
  Do a little renaming, and document friendly URLs in the user's guide.
  
  Revision  Changes    Path
  1.3       +3 -3      jakarta-tapestry/framework/src/test/org/apache/tapestry/services/impl/TestLinkFactory.java
  
  Index: TestLinkFactory.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/test/org/apache/tapestry/services/impl/TestLinkFactory.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- TestLinkFactory.java	5 Jan 2005 23:17:26 -0000	1.2
  +++ TestLinkFactory.java	27 Jan 2005 22:02:23 -0000	1.3
  @@ -28,7 +28,7 @@
   import org.apache.tapestry.engine.ILink;
   import org.apache.tapestry.engine.ServiceEncoder;
   import org.apache.tapestry.engine.ServiceEncoding;
  -import org.apache.tapestry.engine.encoders.ServicePathEncoder;
  +import org.apache.tapestry.engine.encoders.PageServiceEncoder;
   import org.apache.tapestry.services.ServiceConstants;
   import org.apache.tapestry.util.io.DataSqueezerImpl;
   import org.easymock.MockControl;
  @@ -142,7 +142,7 @@
   
       public void testActiveEncoder()
       {
  -        ServicePathEncoder e = new ServicePathEncoder();
  +        PageServiceEncoder e = new PageServiceEncoder();
           e.setServiceName("page");
           e.setExtension("html");
   
  @@ -174,7 +174,7 @@
   
       public void testWithServiceParameters()
       {
  -        ServicePathEncoder e = new ServicePathEncoder();
  +        PageServiceEncoder e = new PageServiceEncoder();
           e.setServiceName("external");
           e.setExtension("ext");
   
  
  
  
  1.12      +1 -0      jakarta-tapestry/src/documentation/content/xdocs/UsersGuide/common.ent
  
  Index: common.ent
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/src/documentation/content/xdocs/UsersGuide/common.ent,v
  retrieving revision 1.11
  retrieving revision 1.12
  diff -u -r1.11 -r1.12
  --- common.ent	7 Jan 2005 00:31:05 -0000	1.11
  +++ common.ent	27 Jan 2005 22:02:23 -0000	1.12
  @@ -46,6 +46,7 @@
   
   <!ENTITY binding-reference			'binding reference'>
   <!ENTITY listener-method			'listener method'>
  +<!ENTITY hivemind-descriptor		'<link href="site:hivemind">HiveMind module deployment descriptor</link>'>
   
   <!ENTITY configuration-property		'<link href="configuration.html#configuration.search-path">configuration property</link>'>
   <!ENTITY configuration.character-sets
  
  
  
  1.1                  jakarta-tapestry/src/documentation/content/xdocs/UsersGuide/friendly-urls.xml
  
  Index: friendly-urls.xml
  ===================================================================
  <?xml version="1.0" encoding="UTF-8"?>
  <!-- 
     Copyright 2005 The Apache Software Foundation
  
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at
  
         http://www.apache.org/licenses/LICENSE-2.0
  
     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     See the License for the specific language governing permissions and
     limitations under the License.
  -->
  
  <!DOCTYPE document PUBLIC "-//APACHE//DTD Documentation V1.2//EN" "./dtd/document-v12.dtd"
  [
  	<!ENTITY projectroot '../'>
  	<!ENTITY % links.ent SYSTEM "../links.ent">
    <!ENTITY % common.ent SYSTEM "common.ent">
  	%links.ent;
    %common.ent;
  ]>
  <document>
    <header>
      <title>Configuring Friendly URLs</title>
    </header>
    <body>
      
      <p>
      Earlier versions of Tapestry have had a long-standing tradition of
      <em>really ugly URLs</em>. Because the framework generates the URLs and
      is also responsible for parsing and dispatching on them in later requests, it was
      not seen as an issue.
      </p>
      
      <p>
      In fact, the ugly URLs <em>do</em> cause some problems:
      </p>
      
      <ul>
        <li>Since all requests are routed through a single  servlet
          (typically mapped to <code>/app</code>), J2EE declarative security, which is path-based,
          is defeated.</li>
       <li>A single directory may contain all the artifacts (HTML templates,  specifications, properties files) for
        all the pages in an entire application.  There isn't a sanctioned approach to organizing
        things into subdirectories.</li>
        <li>The reliance on query parameters means that common search engines will only see
          a tiny fraction of the application.</li>
      </ul>
      
      <p>
      Starting with 3.1, <em>friendly URLs</em> are integrated directly into framework (in 3.0 an
      ambitious, but more limited, patch was required). 
      </p>
      
      <p>
      Friendly URLs are divided into two aspects:
      </p>
      
      <ul>
        <li>Converting information normally stored as a query parameter into part of the URL path.</li>
        <li>Parsing the path to restore the information previously encoded.</li>
      </ul>
      
      <p>
        For example, the ugly URL <code>/app?page=news/Thread&amp;service=page</code> may be converted into
        the friendly URL <code>/news/Threads.html</code>.  In this case, the <code>page=news/Thread</code> query parameter
        becamethe <code>news/Thread</code> portion of the URL, and the <code>service=page</code> query parameter
        became the <code>.html</code> extension to the URL.
      </p>
      
    <section>
      <title>Understanding Tapestry URLs</title>
      
      <p>
        To understand how to get friendly URLs, you must understand a little about what 
        information Tapestry packs into URLs.
      </p>
      
      <p>
      Every request to a Tapestry application is mapped to an <em>engine service</em>. An engine service
      is something like a servlet, embedded within Tapestry. The <code>service</code> query parameter
      is used to select an engine service by name.  A number of services are provided with the framework, the most common
      of which are:
      </p>
      
      <dl>
        <dt>page</dt>
        <dd>Activates and renders a specific page.</dd>
        <dt>direct</dt>
        <dd>Used with the &DirectLink; and &Form; components.</dd>
        <dt>home</dt>
        <dd>Default service used when the service parameter is not specified (such as when
          first accessing the application); activates and renders the Home page.</dd>
      </dl>
      
      <p>
        Each service is responsible for creating URLs with the correct query parameters.
        By default, the URL path is always <code>/app</code> and any additional information comes out
        of the query parameters.  The most common parameters are:
      </p>
      
      <dl>
        <dt>page</dt>
        <dd>The name of a page to activate.</dd>
        <dt>service</dt>
        <dd>The service responsible for the request.</dd>
        <dt>component</dt>
        <dd>The nested component id of a component.</dd>
        <dt>sp
          
        </dt>
        <dd>
          Stores service parameters passed in the URL (used by &DirectLink;).
        </dd>
      </dl>
      
      <p>
        This a typical URL might be
        <code>/app?component=border.logout&amp;page=news/Thread&amp;service=direct</code>.  Yep, that's UGLY.
      </p>
      
    </section>
    
    <section>
      <title>Enabling Friendly URLs</title>
      
      <p>
        To use ordinary ugly URLs, Tapestry requires only a 
        <link href="configuration.html#configuration.deployment-descriptor">small amount of configuration
          in web.xml</link>.  Enabling friendly URLs requires adding more
          configuration to web.xml, and to your &hivemind-descriptor;.
      </p>
      
      <p>
        Friendly URLs are controlled by
        &ServiceEncoder;s. Getting Tapestry to output friendly URLs is a matter of
        plugging encoders into the correct pipeline ... this is all done using HiveMind.
      </p>
      
      <section>
        <title>page-service-encoder</title>
        
        <p>
          The most common type of encoder is the <code>page-service-encoder</code>, which encodes
          the <code>page</code> and <code>service</code> parameters.  In your hivemodule.xml:
        </p>
        
        <source><![CDATA[
  <contribution configuration-id="tapestry.url.ServiceEncoders">
    <page-service-encoder id="page" extension="html" service="page"/>
  </contribution>]]></source>
        
        <p>
          This contribution to the &tapestry.url.ServiceEncoders; configuration point
          creates a &ServiceEncoder; that maps the <code>.html</code> extension (on the URL path)
          to the page service. The <code>id</code> attribute must be unique for all
          contributed encoders.
        </p>
        
        <p>
          For Tapestry to recognize the URLs, you must inform the servlet container
          to send them to the Tapestry application servlet, by addining a mapping
          to web.xml:
        </p>
        <source><![CDATA[
  <servlet-mapping>
    <servlet-name>myapp</servlet-name>
    <url-pattern>*.html</url-pattern>
  </servlet-mapping>]]></source>  
        
  
  <note>
    This means that even static HTML pages that are part of your web application will be
    treated as Tapestry pages; any incoming request that ends with .html will be routed
    into the Tapestry application. Page specifications are optional, so Tapestry will treat
    the HTML pages are if they were HTML page templates.  If you want to allow ordinary static
    content, then you should use another extension such as ".page" or ".tap" (the choice
    is arbitrary).
  </note>      
        
      </section>
      
    </section>
      
    </body>
  </document>
  
  
  1.6       +4 -1      jakarta-tapestry/src/documentation/content/xdocs/links.ent
  
  Index: links.ent
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/src/documentation/content/xdocs/links.ent,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -r1.5 -r1.6
  --- links.ent	19 Dec 2004 15:31:46 -0000	1.5
  +++ links.ent	27 Jan 2005 22:02:23 -0000	1.6
  @@ -26,6 +26,7 @@
   <!-- Common Tapestry classes -->
   
   <!ENTITY apiroot "&projectroot;tapestry/apidocs/org/apache/tapestry">
  +<!ENTITY hivedoc "&projectroot;tapestry/hivedocs">
   
   <!ENTITY AbstractComponent 			'<link href="&apiroot;/AbstractComponent.html">AbstractComponent</link>'>
   <!ENTITY AbstractEngine 			'<link href="&apiroot;/engine/AbstractEngine.html">AbstractEngine</link>'>
  @@ -94,6 +95,7 @@
   <!ENTITY Pool 						'<link href="&apiroot;/util/pool/Pool.html">Pool</link>'>
   <!ENTITY RedirectFilter 			'<link href="&apiroot;/RedirectFilter.html">RedirectFilter</link>'>
   <!ENTITY RequestContext 			'<link href="&apiroot;/RequestContext.html">RequestContext</link>'>
  +<!ENTITY ServiceEncoder				'<link href="&apiroot;/engine/ServiceEncoder.html">ServiceEncoder</link>'>
   <!ENTITY SimpleEngine 				'<link href="&apiroot;/engine/SimpleEngine.html">SimpleEngine</link>'>
   <!ENTITY SpecificationParser 		'<link href="&apiroot;/parse/SpecificationParser">SpecificationParser</link>'>
   <!ENTITY StaleLinkException 		'<link href="&apiroot;/StaleLinkException.html">StaleLinkException</link>'>
  @@ -169,7 +171,8 @@
   
   <!-- HiveMind service and configuration extension points -->
   
  -<!ENTITY tapestry.services.ApplicationServices 'tapestry.services.ApplicationServices'>
  +<!ENTITY tapestry.services.ApplicationServices '<link href="&hivedoc;/service/tapestry.services.ApplicationServices.html">tapestry.services.ApplicationServices</link>'>
  +<!ENTITY tapestry.url.ServiceEncoders '<link href="&hivedoc;/config/tapestry.url.ServiceEncoders.html">tapestry.url.ServiceEncoders</link>'>
   
   <!-- Other useful stuff -->
   
  
  
  
  1.16      +1 -0      jakarta-tapestry/src/documentation/content/xdocs/site.xml
  
  Index: site.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/src/documentation/content/xdocs/site.xml,v
  retrieving revision 1.15
  retrieving revision 1.16
  diff -u -r1.15 -r1.16
  --- site.xml	7 Jan 2005 00:31:05 -0000	1.15
  +++ site.xml	27 Jan 2005 22:02:23 -0000	1.16
  @@ -42,6 +42,7 @@
         <components label="Creating Tapestry components" href="components.html"/>
         <state label="Managing server-side state" href="state.html"/>
         <hivemind label="HiveMind Integration" href="hivemind.html"/>
  +      <friend-urls label="Friendly URLs" href="friendly-urls.html"/>
         <configuration label="Configuring Tapestry" href="configuration.html"/>
         <proprties label="Tapestry Object Properties" href="properties.html"/>
         <upgrade label="Upgrading from 3.0" href="upgrade.html"/>
  
  
  
  1.1                  jakarta-tapestry/framework/src/test/org/apache/tapestry/engine/encoders/TestPageServiceEncoder.java
  
  Index: TestPageServiceEncoder.java
  ===================================================================
  // Copyright 2004, 2005 The Apache Software Foundation
  //
  // Licensed under the Apache License, Version 2.0 (the "License");
  // you may not use this file except in compliance with the License.
  // You may obtain a copy of the License at
  //
  //     http://www.apache.org/licenses/LICENSE-2.0
  //
  // Unless required by applicable law or agreed to in writing, software
  // distributed under the License is distributed on an "AS IS" BASIS,
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  // See the License for the specific language governing permissions and
  // limitations under the License.
  
  package org.apache.tapestry.engine.encoders;
  
  import org.apache.hivemind.test.HiveMindTestCase;
  import org.apache.tapestry.engine.ServiceEncoding;
  import org.apache.tapestry.services.ServiceConstants;
  import org.easymock.MockControl;
  
  /**
   * Tests for {@link org.apache.tapestry.engine.encoders.PageServiceEncoder}.
   * 
   * @author Howard M. Lewis Ship
   * @since 3.1
   */
  public class TestPageServiceEncoder extends HiveMindTestCase
  {
      public void testEncodeOtherService()
      {
          MockControl control = newControl(ServiceEncoding.class);
          ServiceEncoding e = (ServiceEncoding) control.getMock();
  
          e.getParameterValue(ServiceConstants.SERVICE);
          control.setReturnValue("foo");
  
          replayControls();
  
          PageServiceEncoder encoder = new PageServiceEncoder();
          encoder.setServiceName("page");
  
          encoder.encode(e);
  
          verifyControls();
      }
  
      public void testEncode()
      {
          MockControl control = newControl(ServiceEncoding.class);
          ServiceEncoding e = (ServiceEncoding) control.getMock();
  
          e.getParameterValue(ServiceConstants.SERVICE);
          control.setReturnValue("page");
  
          e.getParameterValue(ServiceConstants.PAGE);
          control.setReturnValue("Home");
  
          e.setServletPath("/Home.html");
          e.setParameterValue(ServiceConstants.SERVICE, null);
          e.setParameterValue(ServiceConstants.PAGE, null);
  
          replayControls();
  
          PageServiceEncoder encoder = new PageServiceEncoder();
          encoder.setServiceName("page");
          encoder.setExtension("html");
  
          encoder.encode(e);
  
          verifyControls();
      }
  
      public void testEncodeInNamespace()
      {
          MockControl control = newControl(ServiceEncoding.class);
          ServiceEncoding e = (ServiceEncoding) control.getMock();
  
          e.getParameterValue(ServiceConstants.SERVICE);
          control.setReturnValue("page");
  
          e.getParameterValue(ServiceConstants.PAGE);
          control.setReturnValue("contrib:Foo");
  
          replayControls();
  
          PageServiceEncoder encoder = new PageServiceEncoder();
          encoder.setServiceName("page");
  
          encoder.encode(e);
  
          verifyControls();
      }
  
      public void testDecodeNoExtension()
      {
          MockControl control = newControl(ServiceEncoding.class);
          ServiceEncoding e = (ServiceEncoding) control.getMock();
  
          e.getServletPath();
          control.setReturnValue("/app");
  
          replayControls();
  
          PageServiceEncoder encoder = new PageServiceEncoder();
  
          encoder.decode(e);
  
          verifyControls();
      }
  
      public void testDecodeEndsWithDot()
      {
          MockControl control = newControl(ServiceEncoding.class);
          ServiceEncoding e = (ServiceEncoding) control.getMock();
  
          e.getServletPath();
          control.setReturnValue("/ends.with.dot.");
  
          replayControls();
  
          PageServiceEncoder encoder = new PageServiceEncoder();
  
          encoder.decode(e);
  
          verifyControls();
      }
  
      public void testDecodeWrongExtension()
      {
          MockControl control = newControl(ServiceEncoding.class);
          ServiceEncoding e = (ServiceEncoding) control.getMock();
  
          e.getServletPath();
          control.setReturnValue("/Home.direct");
  
          replayControls();
  
          PageServiceEncoder encoder = new PageServiceEncoder();
  
          encoder.decode(e);
  
          verifyControls();
      }
  
      public void testDecodeSuccess()
      {
          MockControl control = newControl(ServiceEncoding.class);
          ServiceEncoding e = (ServiceEncoding) control.getMock();
  
          e.getServletPath();
          control.setReturnValue("/Home.html");
  
          e.setParameterValue(ServiceConstants.SERVICE, "page");
          e.setParameterValue(ServiceConstants.PAGE, "Home");
  
          replayControls();
  
          PageServiceEncoder encoder = new PageServiceEncoder();
          encoder.setExtension("html");
          encoder.setServiceName("page");
  
          encoder.decode(e);
  
          verifyControls();
      }
  }
  
  
  1.1                  jakarta-tapestry/framework/src/java/org/apache/tapestry/engine/encoders/PageServiceEncoder.java
  
  Index: PageServiceEncoder.java
  ===================================================================
  // Copyright 2004, 2005 The Apache Software Foundation
  //
  // Licensed under the Apache License, Version 2.0 (the "License");
  // you may not use this file except in compliance with the License.
  // You may obtain a copy of the License at
  //
  //     http://www.apache.org/licenses/LICENSE-2.0
  //
  // Unless required by applicable law or agreed to in writing, software
  // distributed under the License is distributed on an "AS IS" BASIS,
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  // See the License for the specific language governing permissions and
  // limitations under the License.
  
  package org.apache.tapestry.engine.encoders;
  
  import org.apache.tapestry.INamespace;
  import org.apache.tapestry.engine.ServiceEncoder;
  import org.apache.tapestry.engine.ServiceEncoding;
  import org.apache.tapestry.services.ServiceConstants;
  
  /**
   * The canonical implementation of {@link org.apache.tapestry.engine.ServiceEncoder}, it
   * recognizes a service and a page. The page name becomes the servlet path, prefixed with "/" and
   * suffixed with a dot and a particular extension. In this way, "/app?service=page&amp;page=Home"
   * becomes simply "Home.html".
   * 
   * @author Howard M. Lewis Ship
   * @since 3.1
   */
  public class PageServiceEncoder implements ServiceEncoder
  {
      private String _extension;
  
      private String _serviceName;
  
      public void encode(ServiceEncoding encoding)
      {
          String service = encoding.getParameterValue(ServiceConstants.SERVICE);
  
          if (!service.equals(_serviceName))
              return;
  
          String pageName = encoding.getParameterValue(ServiceConstants.PAGE);
  
          // Only handle pages in the application namespace (not from a library).
  
          if (pageName.indexOf(INamespace.SEPARATOR) >= 0)
              return;
  
          StringBuffer buffer = new StringBuffer("/");
          buffer.append(pageName);
          buffer.append('.');
          buffer.append(_extension);
  
          encoding.setServletPath(buffer.toString());
  
          encoding.setParameterValue(ServiceConstants.SERVICE, null);
          encoding.setParameterValue(ServiceConstants.PAGE, null);
      }
  
      public void decode(ServiceEncoding encoding)
      {
          String servletPath = encoding.getServletPath();
  
          int dotx = servletPath.lastIndexOf('.');
          if (dotx < 0)
              return;
  
          String extension = servletPath.substring(dotx + 1);
  
          if (!extension.equals(_extension))
              return;
  
          // Skip the slash and the dot.
  
          String page = servletPath.substring(1, dotx);
  
          encoding.setParameterValue(ServiceConstants.SERVICE, _serviceName);
          encoding.setParameterValue(ServiceConstants.PAGE, page);
      }
  
      public void setExtension(String extension)
      {
          _extension = extension;
      }
  
      public void setServiceName(String serviceName)
      {
          _serviceName = serviceName;
      }
  }
  
  
  1.5       +2 -2      jakarta-tapestry/examples/Workbench/src/context/WEB-INF/hivemodule.xml
  
  Index: hivemodule.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/examples/Workbench/src/context/WEB-INF/hivemodule.xml,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- hivemodule.xml	6 Jan 2005 02:17:24 -0000	1.4
  +++ hivemodule.xml	27 Jan 2005 22:02:23 -0000	1.5
  @@ -23,8 +23,8 @@
     </contribution>
     
     <contribution configuration-id="tapestry.url.ServiceEncoders">
  -    <path-encoder id="direct" extension="direct" service="direct"/>
  -    <path-encoder id="page" extension="page" service="page"/>
  +    <page-service-encoder id="direct" extension="direct" service="direct"/>
  +    <page-service-encoder id="page" extension="page" service="page"/>
     </contribution>
     
     <service-point id="Chart" interface="org.apache.tapestry.engine.IEngineService">
  
  
  
  1.5       +2 -2      jakarta-tapestry/framework/src/descriptor/META-INF/tapestry.url.xml
  
  Index: tapestry.url.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/descriptor/META-INF/tapestry.url.xml,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- tapestry.url.xml	6 Jan 2005 02:17:26 -0000	1.4
  +++ tapestry.url.xml	27 Jan 2005 22:02:23 -0000	1.5
  @@ -67,7 +67,7 @@
         </element>
         
         
  -      <element name="path-encoder">
  +      <element name="page-service-encoder">
           
           An encoder that identifies the service as a pathname extension, and encodes the page as the
           servlet path.
  @@ -95,7 +95,7 @@
             <read-attribute attribute="after" property="after"/>
             <invoke-parent method="addElement"/>
             
  -          <create-object class="org.apache.tapestry.engine.encoders.ServicePathEncoder"/>
  +          <create-object class="org.apache.tapestry.engine.encoders.PageServiceEncoder"/>
             <read-attribute attribute="extension" property="extension"/>
             <read-attribute attribute="service" property="serviceName"/>
             <invoke-parent method="setEncoder"/>          
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: tapestry-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: tapestry-dev-help@jakarta.apache.org