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&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&page=news/Thread&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&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