001/*
002    Licensed to the Apache Software Foundation (ASF) under one
003    or more contributor license agreements.  See the NOTICE file
004    distributed with this work for additional information
005    regarding copyright ownership.  The ASF licenses this file
006    to you under the Apache License, Version 2.0 (the
007    "License"); you may not use this file except in compliance
008    with the License.  You may obtain a copy of the License at
009
010       http://www.apache.org/licenses/LICENSE-2.0
011
012    Unless required by applicable law or agreed to in writing,
013    software distributed under the License is distributed on an
014    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015    KIND, either express or implied.  See the License for the
016    specific language governing permissions and limitations
017    under the License.
018 */
019package org.apache.wiki.url;
020
021import org.apache.commons.lang3.StringUtils;
022import org.apache.wiki.WikiContext;
023import org.apache.wiki.WikiEngine;
024import org.apache.wiki.ui.Command;
025import org.apache.wiki.ui.CommandResolver;
026import org.apache.wiki.util.TextUtil;
027
028import javax.servlet.http.HttpServletRequest;
029import java.nio.charset.Charset;
030import java.util.Properties;
031
032/**
033 *  Implements the default URL constructor using links directly to the
034 *  JSP pages.  This is what JSPWiki by default is using.  For example,
035 *  WikiContext.VIEW points at "Wiki.jsp", etc.
036 *
037 *  @since 2.2
038 */
039public class DefaultURLConstructor implements URLConstructor {
040
041    protected WikiEngine m_engine;
042
043    /**
044     *  Contains the absolute path of the JSPWiki Web application without the
045     *  actual servlet (which is the m_urlPrefix).
046     */
047    protected String m_pathPrefix = "";
048
049    /**
050     *
051     * {@inheritDoc}
052     */
053    public void initialize( final WikiEngine engine, final Properties properties ) {
054        m_engine = engine;
055        m_pathPrefix = engine.getBaseURL() + "/";
056    }
057
058    /**
059     *  Does replacement of some particular variables.  The variables are:
060     *
061     *  <ul>
062     *  <li> "%u" - inserts either the base URL (when absolute is required), or the base path
063     *       (which is an absolute path without the host name).
064     *  <li> "%U" - always inserts the base URL
065     *  <li> "%p" - always inserts the base path
066     *  <li> "%n" - inserts the page name
067     *  </ul>
068     *
069     * @param baseptrn  The pattern to use
070     * @param name The page name
071     * @param absolute If true, %u is always the entire base URL, otherwise it depends on
072     *                 the setting in jspwiki.properties.
073     * @return A replacement.
074     */
075    protected final String doReplacement( String baseptrn, final String name, final boolean absolute ) {
076        String baseurl = m_pathPrefix;
077
078        if( absolute ) {
079            baseurl = m_engine.getBaseURL() + "/";
080        }
081
082        baseptrn = TextUtil.replaceString( baseptrn, "%u", baseurl );
083        baseptrn = TextUtil.replaceString( baseptrn, "%U", m_engine.getBaseURL() );
084        baseptrn = TextUtil.replaceString( baseptrn, "%n", encodeURI(name) );
085        baseptrn = TextUtil.replaceString( baseptrn, "%p", m_pathPrefix );
086
087        return baseptrn;
088    }
089
090    /**
091     *  URLEncoder returns pluses, when we want to have the percent
092     *  encoding.  See http://issues.apache.org/bugzilla/show_bug.cgi?id=39278
093     *  for more info.
094     *
095     *  We also convert any %2F's back to slashes to make nicer-looking URLs.
096     */
097    private String encodeURI( String uri ) {
098        uri = m_engine.encodeName(uri);
099        uri = StringUtils.replace( uri, "+", "%20" );
100        uri = StringUtils.replace( uri, "%2F", "/" );
101
102        return uri;
103    }
104
105    /**
106     * Returns the URL pattern for a supplied wiki request context.
107     * @param context the wiki context
108     * @param name the wiki page
109     * @return A pattern for replacement.
110     * @throws IllegalArgumentException if the context cannot be found
111     */
112    public static String getURLPattern( final String context, final String name ) throws IllegalArgumentException {
113        if( context.equals(WikiContext.VIEW) && name == null) {
114            // FIXME
115            return "%uWiki.jsp";
116        }
117
118        // Find the action matching our pattern (could throw exception)
119        final Command command = CommandResolver.findCommand( context );
120
121        return command.getURLPattern();
122    }
123
124    /**
125     *  Constructs the actual URL based on the context.
126     */
127    private String makeURL( final String context, final String name, final boolean absolute ) {
128        return doReplacement( getURLPattern(context,name), name, absolute );
129    }
130
131    /**
132     *  Constructs the URL with a bunch of parameters.
133     *  @param parameters If null or empty, no parameters are added.
134     *
135     *  {@inheritDoc}
136     */
137    public String makeURL( final String context, final String name, final boolean absolute, String parameters ) {
138        if( parameters != null && parameters.length() > 0 ) {
139            if( context.equals(WikiContext.ATTACH) ) {
140                parameters = "?"+parameters;
141            } else if( context.equals(WikiContext.NONE) ) {
142                parameters = (name.indexOf('?') != -1 ) ? "&amp;" : "?" + parameters;
143            } else {
144                parameters = "&amp;"+parameters;
145            }
146        } else {
147            parameters = "";
148        }
149        return makeURL( context, name, absolute ) + parameters;
150    }
151
152    /**
153     *  Should parse the "page" parameter from the actual
154     *  request.
155     *
156     *  {@inheritDoc}
157     */
158    public String parsePage( final String context, final HttpServletRequest request, final Charset encoding ) {
159        String pagereq = request.getParameter( "page" );
160        if( context.equals(WikiContext.ATTACH) ) {
161            pagereq = parsePageFromURL( request, encoding );
162        }
163
164        return pagereq;
165    }
166
167    /**
168     *  Takes the name of the page from the request URI.
169     *  The initial slash is also removed.  If there is no page,
170     *  returns null.
171     *
172     *  @param request The request to parse
173     *  @param encoding The encoding to use
174     *
175     *  @return a parsed page name, or null, if it cannot be found
176     */
177    public static String parsePageFromURL( final HttpServletRequest request, final Charset encoding ) {
178        final String name = request.getPathInfo();
179        if( name == null || name.length() <= 1 ) {
180            return null;
181        } else if( name.charAt(0) == '/' ) {
182            return name.substring(1);
183        }
184
185        //
186        //  This is required, because by default all URLs are handled as Latin1, even if they are really UTF-8.
187        //
188        // name = TextUtil.urlDecode( name, encoding );
189
190        return name;
191    }
192
193
194    /**
195     *  This method is not needed for the DefaultURLConstructor.
196     *
197     * @param request The HTTP Request that was used to end up in this page.
198     * @return "Wiki.jsp", "PageInfo.jsp", etc.  Just return the name, JSPWiki will figure out the page.
199     */
200    public String getForwardPage( final HttpServletRequest request ) {
201        return "Wiki.jsp";
202    }
203
204}