001: // Copyright 2006, 2007 The Apache Software Foundation
002: //
003: // Licensed under the Apache License, Version 2.0 (the "License");
004: // you may not use this file except in compliance with the License.
005: // You may obtain a copy of the License at
006: //
007: // http://www.apache.org/licenses/LICENSE-2.0
008: //
009: // Unless required by applicable law or agreed to in writing, software
010: // distributed under the License is distributed on an "AS IS" BASIS,
011: // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012: // See the License for the specific language governing permissions and
013: // limitations under the License.
014:
015: package org.apache.tapestry.internal.services;
016:
017: import java.io.IOException;
018:
019: import org.apache.tapestry.internal.TapestryInternalUtils;
020: import org.apache.tapestry.services.ActionResponseGenerator;
021: import org.apache.tapestry.services.ComponentClassResolver;
022: import org.apache.tapestry.services.Dispatcher;
023: import org.apache.tapestry.services.PageRenderRequestHandler;
024: import org.apache.tapestry.services.Request;
025: import org.apache.tapestry.services.Response;
026:
027: /**
028: * Dispatches incoming requests for render requests. Render requests consist of either just a
029: * logical page name (case insensitive) or a logical page name plus additional context. Because of
030: * this structure, it take a little bit of work to identify the split point between the page name
031: * and the context.
032: */
033: public class PageRenderDispatcher implements Dispatcher {
034: private final ComponentClassResolver _componentClassResolver;
035:
036: private final PageRenderRequestHandler _handler;
037:
038: public PageRenderDispatcher(
039: ComponentClassResolver componentClassResolver,
040: PageRenderRequestHandler handler) {
041: _componentClassResolver = componentClassResolver;
042: _handler = handler;
043: }
044:
045: public boolean dispatch(Request request, final Response response)
046: throws IOException {
047: // Rememeber that the path starts with a leading slash that is not part of the logical page
048: // name.
049:
050: String path = request.getPath();
051:
052: // TAPESTRY-1343: This can happen in Tomcat (but not in Jetty) for URL such as
053: // http://.../context (with no trailing slash).
054: if (path.equals(""))
055: return false;
056:
057: int searchStart = 1;
058:
059: while (true) {
060: int nextslashx = path.indexOf('/', searchStart);
061:
062: boolean atEnd = nextslashx < 0;
063:
064: String pageName = atEnd ? path.substring(1) : path
065: .substring(1, nextslashx);
066:
067: if (_componentClassResolver.isPageName(pageName)) {
068: String[] context = atEnd ? new String[0]
069: : convertActivationContext(path
070: .substring(nextslashx + 1));
071:
072: ActionResponseGenerator responseGenerator = _handler
073: .handle(pageName, context);
074:
075: if (responseGenerator != null)
076: responseGenerator.sendClientResponse(response);
077:
078: return true;
079: }
080:
081: if (atEnd)
082: return false;
083:
084: // Advance to the next slash within the path.
085:
086: searchStart = nextslashx + 1;
087: }
088: }
089:
090: /**
091: * Converts the "extra path", the portion after the page name (and after the slash seperating
092: * the page name from the activation context) into an array of strings. LinkFactory and friends
093: * URL encode each value, so we URL decode the value (we assume that page names are "URL safe").
094: *
095: * @param extraPath
096: * @return
097: */
098: private String[] convertActivationContext(String extraPath) {
099: if (extraPath.length() == 0)
100: return new String[0];
101:
102: String[] context = extraPath.split("/");
103:
104: for (int i = 0; i < context.length; i++) {
105: context[i] = TapestryInternalUtils.urlDecode(context[i]);
106: }
107:
108: return context;
109: }
110: }
|