001: /*
002: JSPWiki - a JSP-based WikiWiki clone.
003:
004: Copyright (C) 2001-2005 Janne Jalkanen (Janne.Jalkanen@iki.fi)
005:
006: This program is free software; you can redistribute it and/or modify
007: it under the terms of the GNU Lesser General Public License as published by
008: the Free Software Foundation; either version 2.1 of the License, or
009: (at your option) any later version.
010:
011: This program is distributed in the hope that it will be useful,
012: but WITHOUT ANY WARRANTY; without even the implied warranty of
013: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014: GNU Lesser General Public License for more details.
015:
016: You should have received a copy of the GNU Lesser General Public License
017: along with this program; if not, write to the Free Software
018: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
019: */
020: package com.ecyrd.jspwiki.url;
021:
022: import java.io.UnsupportedEncodingException;
023: import java.net.MalformedURLException;
024: import java.net.URL;
025: import java.util.Properties;
026:
027: import javax.servlet.http.HttpServletRequest;
028:
029: import org.apache.commons.lang.StringUtils;
030:
031: import com.ecyrd.jspwiki.TextUtil;
032: import com.ecyrd.jspwiki.WikiContext;
033: import com.ecyrd.jspwiki.WikiEngine;
034: import com.ecyrd.jspwiki.ui.Command;
035: import com.ecyrd.jspwiki.ui.CommandResolver;
036:
037: /**
038: * Implements the default URL constructor using links directly to the
039: * JSP pages. This is what JSPWiki by default is using. For example,
040: * WikiContext.VIEW points at "Wiki.jsp", etc.
041: *
042: * @author Janne Jalkanen
043: * @since 2.2
044: */
045: public class DefaultURLConstructor implements URLConstructor {
046: protected WikiEngine m_engine;
047:
048: /** Are URL styles relative or absolute? */
049: protected boolean m_useRelativeURLStyle = true;
050:
051: /**
052: * Contains the absolute path of the JSPWiki Web application without the
053: * actual servlet (which is the m_urlPrefix).
054: */
055: protected String m_pathPrefix = "";
056:
057: /**
058: *
059: * {@inheritDoc}
060: */
061: public void initialize(WikiEngine engine, Properties properties) {
062: m_engine = engine;
063:
064: m_useRelativeURLStyle = "relative".equals(properties
065: .getProperty(WikiEngine.PROP_REFSTYLE, "relative"));
066:
067: String baseurl = engine.getBaseURL();
068:
069: if (baseurl != null && baseurl.length() > 0) {
070: try {
071: URL url = new URL(baseurl);
072:
073: String path = url.getPath();
074:
075: m_pathPrefix = path;
076: } catch (MalformedURLException e) {
077: m_pathPrefix = "/JSPWiki"; // Just a guess.
078: }
079: }
080: }
081:
082: /**
083: * Does replacement of some particular variables. The variables are:
084: *
085: * <ul>
086: * <li> "%u" - inserts either the base URL (when absolute is required), or the base path
087: * (which is an absolute path without the host name).
088: * <li> "%U" - always inserts the base URL
089: * <li> "%p" - always inserts the base path
090: * <li> "%n" - inserts the page name
091: * </ul>
092: *
093: * @param baseptrn The pattern to use
094: * @param name The page name
095: * @param absolute If true, %u is always the entire base URL, otherwise it depends on
096: * the setting in jspwiki.properties.
097: * @return A replacement.
098: */
099: protected final String doReplacement(String baseptrn, String name,
100: boolean absolute) {
101: String baseurl = m_pathPrefix;
102:
103: if (absolute)
104: baseurl = m_engine.getBaseURL();
105:
106: baseptrn = TextUtil.replaceString(baseptrn, "%u", baseurl);
107: baseptrn = TextUtil.replaceString(baseptrn, "%U", m_engine
108: .getBaseURL());
109: baseptrn = TextUtil.replaceString(baseptrn, "%n",
110: encodeURI(name));
111: baseptrn = TextUtil.replaceString(baseptrn, "%p", m_pathPrefix);
112:
113: return baseptrn;
114: }
115:
116: /**
117: * URLEncoder returns pluses, when we want to have the percent
118: * encoding. See http://issues.apache.org/bugzilla/show_bug.cgi?id=39278
119: * for more info.
120: *
121: * We also convert any %2F's back to slashes to make nicer-looking URLs.
122: */
123: private final String encodeURI(String uri) {
124: uri = m_engine.encodeName(uri);
125:
126: uri = StringUtils.replace(uri, "+", "%20");
127: uri = StringUtils.replace(uri, "%2F", "/");
128:
129: return uri;
130: }
131:
132: /**
133: * Returns the URL pattern for a supplied wiki request context.
134: * @param context the wiki context
135: * @param name the wiki page
136: * @return A pattern for replacement.
137: * @throws IllegalArgumentException if the context cannot be found
138: */
139: public static String getURLPattern(String context, String name)
140: throws IllegalArgumentException {
141: if (context.equals(WikiContext.VIEW)) {
142: if (name == null)
143: return "%uWiki.jsp"; // FIXME
144: }
145:
146: // Find the action matching our pattern (could throw exception)
147: Command command = CommandResolver.findCommand(context);
148:
149: return command.getURLPattern();
150: }
151:
152: /**
153: * Constructs the actual URL based on the context.
154: */
155: private String makeURL(String context, String name, boolean absolute) {
156: return doReplacement(getURLPattern(context, name), name,
157: absolute);
158: }
159:
160: /**
161: * Constructs the URL with a bunch of parameters.
162: * @param parameters If null or empty, no parameters are added.
163: *
164: * {@inheritDoc}
165: */
166: public String makeURL(String context, String name,
167: boolean absolute, String parameters) {
168: if (parameters != null && parameters.length() > 0) {
169: if (context.equals(WikiContext.ATTACH)) {
170: parameters = "?" + parameters;
171: } else if (context.equals(WikiContext.NONE)) {
172: parameters = (name.indexOf('?') != -1) ? "&" : "?"
173: + parameters;
174: } else {
175: parameters = "&" + parameters;
176: }
177: } else {
178: parameters = "";
179: }
180: return makeURL(context, name, absolute) + parameters;
181: }
182:
183: /**
184: * Should parse the "page" parameter from the actual
185: * request.
186: *
187: * {@inheritDoc}
188: */
189: public String parsePage(String context, HttpServletRequest request,
190: String encoding) throws UnsupportedEncodingException {
191: request.setCharacterEncoding(encoding);
192: String pagereq = request.getParameter("page");
193:
194: if (context.equals(WikiContext.ATTACH)) {
195: pagereq = parsePageFromURL(request, encoding);
196: }
197:
198: return pagereq;
199: }
200:
201: /**
202: * There's a bug in Tomcat until 5.5.16 at least: The "+" sign is not
203: * properly decoded by the servlet container, and therefore request.getPathInfo()
204: * will return faulty results for paths which contains + signs to signify spaces.
205: * <p>
206: * This method provides a workaround by simply parsing the getRequestURI(), which
207: * is returned from the servlet container undedecoded.
208: * <p>
209: * Please see <a href="http://issues.apache.org/bugzilla/show_bug.cgi?id=39278">Tomcat Bug 39278</a>
210: * for more information.
211: *
212: * @param request A HTTP servlet request
213: * @param encoding The used encoding
214: * @return a String, decoded by JSPWiki, specifying extra path information that comes
215: * after the servlet path but before the query string in the request URL;
216: * or null if the URL does not have any extra path information
217: * @throws UnsupportedEncodingException
218: */
219: /*
220: private static String getPathInfo( HttpServletRequest request, String encoding )
221: throws UnsupportedEncodingException
222: {
223: String c = request.getContextPath(); // Undecoded
224: String s = request.getServletPath(); // Decoded
225: String u = request.getRequestURI(); // Undecoded
226:
227: c = URLDecoder.decode( c, encoding );
228: u = URLDecoder.decode( u, encoding );
229:
230: String pi = u.substring( s.length()+c.length() );
231:
232: if( pi.length() == 0 ) pi = null;
233:
234: return pi;
235: }
236: */
237: /**
238: * Takes the name of the page from the request URI.
239: * The initial slash is also removed. If there is no page,
240: * returns null.
241: *
242: * @param request The request to parse
243: * @param encoding The encoding to use
244: *
245: * @return a parsed page name, or null, if it cannot be found
246: *
247: * @throws UnsupportedEncodingException If the encoding is not recognized.
248: */
249: public static String parsePageFromURL(HttpServletRequest request,
250: String encoding) throws UnsupportedEncodingException {
251: String name = request.getPathInfo();
252:
253: if (name == null || name.length() <= 1) {
254: return null;
255: } else if (name.charAt(0) == '/') {
256: name = name.substring(1);
257: }
258:
259: //
260: // This is required, because by default all URLs are handled
261: // as Latin1, even if they are really UTF-8.
262: //
263:
264: // name = TextUtil.urlDecode( name, encoding );
265:
266: return name;
267: }
268:
269: /**
270: * This method is not needed for the DefaultURLConstructor.
271: *
272: * @return {@inheritDoc}
273: * @param {@inheritDoc}
274: */
275: public String getForwardPage(HttpServletRequest request) {
276: return request.getPathInfo();
277: }
278: }
|