001: /*
002: * Copyright 2004, 2005, 2006 Odysseus Software GmbH
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package de.odysseus.calyxo.control.impl;
017:
018: import java.io.IOException;
019: import java.io.UnsupportedEncodingException;
020: import java.net.URLEncoder;
021: import java.util.Iterator;
022:
023: import javax.servlet.RequestDispatcher;
024: import javax.servlet.ServletException;
025: import javax.servlet.http.HttpServletRequest;
026: import javax.servlet.http.HttpServletResponse;
027:
028: import org.apache.commons.logging.Log;
029: import org.apache.commons.logging.LogFactory;
030:
031: import de.odysseus.calyxo.base.ModuleContext;
032: import de.odysseus.calyxo.base.ModuleSupport;
033:
034: import de.odysseus.calyxo.control.Dispatcher;
035: import de.odysseus.calyxo.control.conf.DispatchConfig;
036: import de.odysseus.calyxo.control.conf.ParamConfig;
037: import de.odysseus.calyxo.control.conf.ParamsConfig;
038:
039: /**
040: * Dispatcher class.
041: * The dispatcher is responsible to perform a forward, include or redirect
042: * according to a dispatch config. Each module has its own dispatcher and
043: * dispatches to actions in its module or to resource paths.
044: * <p/>
045: * This class may be subclassed to modify dispatching behaviour.
046: *
047: * @author Christoph Beck
048: */
049: public class DefaultDispatcher implements Dispatcher {
050: protected static final Log log = LogFactory
051: .getLog(DefaultDispatcher.class);
052:
053: private ModuleContext context;
054: private ModuleSupport support;
055:
056: public DefaultDispatcher(ModuleContext context) {
057: this .context = context;
058: this .support = ModuleSupport.getInstance(context
059: .getServletContext());
060: }
061:
062: /**
063: * Dispatch request.
064: * </p>
065: * If the dispatch element specifies an action, dispatch to that action.
066: * Otherwise, the dispatch element must specify a path. If that path starts
067: * with a "/", treat it as a context-relative path and dispatch accordingly.
068: * If the path doesn't start with a "/" leave it unchanged.
069: * </p>
070: * If the redirection flag is set, dispatch by redirection.
071: * Otherwise, dispatch by forward or include, depending on if the
072: * response has already been committed.
073: *
074: * @param request the request we process
075: * @param response the response we process
076: * @param dispatch the dispatch target
077: * @throws IOException passed through
078: * @throws ServletException passed through
079: */
080: public void dispatch(HttpServletRequest request,
081: HttpServletResponse response, DispatchConfig dispatch)
082: throws IOException, ServletException {
083: String path = null;
084: if (dispatch.getAction() != null) {
085: ModuleContext module = context;
086: if (dispatch.getModule() != null) { // switch module
087: module = support.getModuleContext(dispatch.getModule());
088: if (module == null) {
089: throw new ServletException("Unknown module in '"
090: + dispatch.toInlineString() + "'");
091: }
092: }
093: path = module.getPath(dispatch.getAction());
094: } else /* if (dispatch.getPath() != null) */{
095: path = dispatch.getPath();
096: }
097: path = addParams(path, dispatch, "UTF-8");
098: dispatch(request, response, path, dispatch.isRedirect());
099: }
100:
101: /**
102: * Append the dispatch parameters as URL parameters to the
103: * specified path.
104: * @param path uri
105: * @param config parameters
106: * @param encoding encoding to be used, e.g. <code>"UTF-8"</code>
107: * @return uri with query string according to the dispatch parameters.
108: * @throws UnsupportedEncodingException
109: */
110: protected String addParams(String path, ParamsConfig config,
111: String encoding) throws UnsupportedEncodingException {
112: // append query parameters
113: Iterator params = config.getParamConfigs();
114: if (params.hasNext()) {
115: StringBuffer buf = new StringBuffer(path);
116: // save anchor (if any)
117: String anchor = null;
118: int hash = path.indexOf('#');
119: if (hash > 0) {
120: anchor = path.substring(hash);
121: buf.setLength(hash);
122: }
123: buf.append(path.indexOf('?') > 0 ? '&' : '?');
124: do {
125: ParamConfig param = (ParamConfig) params.next();
126: buf
127: .append(URLEncoder.encode(param.getName(),
128: encoding));
129: buf.append('=');
130: buf.append(URLEncoder
131: .encode(param.getValue(), encoding));
132: if (params.hasNext()) {
133: buf.append('&');
134: } else {
135: break;
136: }
137: } while (true);
138: // restore anchor (if any)
139: if (anchor != null) {
140: buf.append(anchor);
141: }
142: return buf.toString();
143: }
144: return path;
145: }
146:
147: /**
148: * Dispatch to specified uri.
149: * If the redirection flag is set, send a redirect to the specified uri.
150: * Otherwise, use a request dispatcher to dispatch to specified uri:
151: * Use include, if the response is already committed, forward else.
152: * In case of redirection, the path is prepended with the request context
153: * path, if it starts with a slash (<code>'/'</code>).
154: * @param request the request we process
155: * @param response the response we process
156: * @param uri context-relative path (may be an absolute URL if redirection
157: * is used).
158: * @param redirect use redirection flag
159: * @throws IOException passed through
160: * @throws ServletException passed through
161: */
162: protected void dispatch(HttpServletRequest request,
163: HttpServletResponse response, String uri, boolean redirect)
164: throws IOException, ServletException {
165: if (redirect) {
166: if (uri.startsWith("/")) {
167: uri = request.getContextPath() + uri;
168: }
169: response.sendRedirect(response.encodeRedirectURL(uri));
170: } else {
171: RequestDispatcher dispatcher = request
172: .getRequestDispatcher(uri);
173: if (response.isCommitted()) {
174: if (log.isDebugEnabled())
175: log.debug("include " + uri);
176: dispatcher.include(request, response);
177: } else {
178: if (log.isDebugEnabled())
179: log.debug("forward " + uri);
180: dispatcher.forward(request, response);
181: }
182: }
183: }
184: }
|