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.api.core.Command;
023import org.apache.wiki.api.core.ContextEnum;
024import org.apache.wiki.api.core.Engine;
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/**
034 *  Implements the default URL constructor using links directly to the 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 Engine m_engine;
042
043    /** Contains the absolute path of the JSPWiki Web application without the actual servlet (which is the m_urlPrefix). */
044    protected String m_pathPrefix = "";
045
046    /**
047     *
048     * {@inheritDoc}
049     */
050    @Override
051    public void initialize( final Engine engine, final Properties properties ) {
052        m_engine = engine;
053        m_pathPrefix = engine.getBaseURL() + "/";
054    }
055
056    /**
057     *  Does replacement of some particular variables.  The variables are:
058     *
059     *  <ul>
060     *  <li> "%u" - inserts either the base URL (when absolute is required), or the base path (which is an absolute path without the host name).
061     *  <li> "%U" - always inserts the base URL
062     *  <li> "%p" - always inserts the base path
063     *  <li> "%n" - inserts the page name
064     *  </ul>
065     *
066     * @param baseptrn  The pattern to use
067     * @param name The page name
068     * @return A replacement.
069     */
070    protected final String doReplacement( String baseptrn, final String name ) {
071        final String baseurl = m_pathPrefix;
072
073        baseptrn = TextUtil.replaceString( baseptrn, "%u", baseurl );
074        baseptrn = TextUtil.replaceString( baseptrn, "%U", m_engine.getBaseURL() );
075        baseptrn = TextUtil.replaceString( baseptrn, "%n", encodeURI(name) );
076        baseptrn = TextUtil.replaceString( baseptrn, "%p", m_pathPrefix );
077
078        return baseptrn;
079    }
080
081    /**
082     *  URLEncoder returns pluses, when we want to have the percent encoding.  See http://issues.apache.org/bugzilla/show_bug.cgi?id=39278
083     *  for more info.
084     *
085     *  We also convert any %2F's back to slashes to make nicer-looking URLs.
086     */
087    private String encodeURI( String uri ) {
088        uri = m_engine.encodeName(uri);
089        uri = StringUtils.replace( uri, "+", "%20" );
090        uri = StringUtils.replace( uri, "%2F", "/" );
091
092        return uri;
093    }
094
095    /**
096     * Returns the URL pattern for a supplied wiki request context.
097     * @param context the wiki context
098     * @param name the wiki page
099     * @return A pattern for replacement.
100     * @throws IllegalArgumentException if the context cannot be found
101     */
102    public static String getURLPattern( final String context, final String name ) throws IllegalArgumentException {
103        if( context.equals( ContextEnum.PAGE_VIEW.getRequestContext() ) && name == null) {
104            // FIXME
105            return "%uWiki.jsp";
106        }
107
108        // Find the action matching our pattern (could throw exception)
109        final Command command = CommandResolver.findCommand( context );
110
111        return command.getURLPattern();
112    }
113
114    /**
115     *  Constructs the actual URL based on the context.
116     */
117    private String makeURL( final String context, final String name ) {
118        return doReplacement( getURLPattern( context, name ), name );
119    }
120
121    /**
122     *  Constructs the URL with a bunch of parameters.
123     *  @param parameters If null or empty, no parameters are added.
124     *
125     *  {@inheritDoc}
126     */
127    @Override
128    public String makeURL( final String context, final String name, String parameters ) {
129        if( parameters != null && !parameters.isEmpty() ) {
130            if( context.equals( ContextEnum.PAGE_ATTACH.getRequestContext() ) ) {
131                parameters = "?" + parameters;
132            } else if( context.equals( ContextEnum.PAGE_NONE.getRequestContext() ) ) {
133                parameters = name.indexOf( '?' ) != -1 ? "&amp;" : "?" + parameters;
134            } else {
135                parameters = "&amp;" + parameters;
136            }
137        } else {
138            parameters = "";
139        }
140        return makeURL( context, name ) + parameters;
141    }
142
143    /**
144     *  Should parse the "page" parameter from the actual request.
145     *
146     *  {@inheritDoc}
147     */
148    @Override
149    public String parsePage( final String context, final HttpServletRequest request, final Charset encoding ) {
150        String pagereq = request.getParameter( "page" );
151        if( context.equals( ContextEnum.PAGE_ATTACH.getRequestContext() ) ) {
152            pagereq = URLConstructor.parsePageFromURL( request, encoding );
153        }
154
155        return pagereq;
156    }
157
158    /**
159     *  This method is not needed for the DefaultURLConstructor.
160     *
161     * @param request The HTTP Request that was used to end up in this page.
162     * @return "Wiki.jsp", "PageInfo.jsp", etc.  Just return the name, JSPWiki will figure out the page.
163     */
164    @Override
165    public String getForwardPage( final HttpServletRequest request ) {
166        return "Wiki.jsp";
167    }
168
169}