    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.ui;
    020
    021import org.apache.wiki.api.core.Command;
    022import org.apache.wiki.util.TextUtil;
    023
    024
    025/**
    026 * Abstract, immutable Command implementation class. All of the fields in this class are <code>final</code>. This class is thread-safe.
    027 *
    028 * @since 2.4.22
    029 */
    030public abstract class AbstractCommand implements Command {
    031
    032    private static final String HTTPS = "HTTPS://";
    033    private static final String HTTP = "HTTP://";
    034
    035    private final String m_jsp;
    036    private final String m_jspFriendlyName;
    037    private final String m_urlPattern;
    038    private final String m_requestContext;
    039    private final String m_contentTemplate;
    040    private final Object m_target;
    041
    042    /**
    043     * Constructs a new Command with a specified wiki context, URL pattern, content template and target. The URL pattern is used to derive
    044     * the JSP; if it is a "local" JSP (that is, it does not contain the <code>http://</code> or <code>https://</code> prefixes),
    045     * then the JSP will be a cleansed version of the URL pattern; symbols (such as <code>%u</code>) will be removed. If the supplied
    046     * URL pattern points to a non-local destination, the JSP will be set to the value supplied, unmodified.
    047     *
    048     * @param requestContext the request context
    049     * @param urlPattern the URL pattern
    050     * @param contentTemplate the content template; may be <code>null</code>
    051     * @param target the target of the command, such as a WikiPage; may be <code>null</code>
    052     * @throws IllegalArgumentException if the request content or URL pattern is <code>null</code>
    053     */
    054    protected AbstractCommand( final String requestContext, final String urlPattern, final String contentTemplate, final Object target ) {
    055        if( requestContext == null || urlPattern == null ) {
    056            throw new IllegalArgumentException( "Request context, URL pattern and type must not be null." );
    057        }
    058
    059        m_requestContext = requestContext;
    060        if ( urlPattern.toUpperCase().startsWith( HTTP ) || urlPattern.toUpperCase().startsWith( HTTPS ) ) {
    061            // For an HTTP/HTTPS url, pass it through without modification
    062            m_jsp = urlPattern;
    063            m_jspFriendlyName = "Special Page";
    064        } else {
    065            // For local JSPs, take everything to the left of ?, then delete all variable substitutions
    066            String jsp = urlPattern;
    067            final int qPosition = urlPattern.indexOf( '?' );
    068            if ( qPosition != -1 ) {
    069                jsp = jsp.substring( 0, qPosition );
    070            }
    071            m_jsp = removeSubstitutions(jsp);
    072
    073            // Calculate the "friendly name" for the JSP
    074            if ( m_jsp.toUpperCase().endsWith( ".JSP" ) ) {
    075                m_jspFriendlyName = TextUtil.beautifyString( m_jsp.substring( 0, m_jsp.length() - 4 ) );
    076            } else {
    077                m_jspFriendlyName = m_jsp;
    078            }
    079        }
    080        m_urlPattern = urlPattern;
    081        m_contentTemplate = contentTemplate;
    082        m_target = target;
    083    }
    084
    085    //
    086    //  This is just *so* much faster than doing String.replaceAll().  It would, in fact, be worth to cache this value.
    087    //
    088    private String removeSubstitutions( final String jsp ) {
    089        //return jsp.replaceAll( "\u0025[a-z|A-Z]", "" );
    090        final StringBuilder newjsp = new StringBuilder( jsp.length() );
    091        for( int i = 0; i < jsp.length(); i++ ) {
    092            final char c = jsp.charAt(i);
    093            if( c == '%' && i < jsp.length() - 1 && Character.isLetterOrDigit( jsp.charAt( i + 1 ) ) ) {
    094                i++;
    095                continue;
    096            }
    097            newjsp.append( c );
    098        }
    099        return newjsp.toString();
    100    }
    101
    102    /**
    103     * @see org.apache.wiki.api.core.Command#targetedCommand(Object)
    104     */
    105    @Override
    106    public abstract Command targetedCommand(final Object target );
    107
    108    /**
    109     * @see org.apache.wiki.api.core.Command#getContentTemplate()
    110     */
    111    @Override
    112    public final String getContentTemplate() {
    113        return m_contentTemplate;
    114    }
    115
    116    /**
    117     * @see org.apache.wiki.api.core.Command#getJSP()
    118     */
    119    @Override
    120    public final String getJSP() {
    121        return m_jsp;
    122    }
    123
    124    /**
    125     * @see org.apache.wiki.api.core.Command#getName()
    126     */
    127    @Override
    128    public abstract String getName();
    129
    130    /**
    131     * @see org.apache.wiki.api.core.Command#getRequestContext()
    132     */
    133    @Override
    134    public final String getRequestContext() {
    135        return m_requestContext;
    136    }
    137
    138    /**
    139     * @see org.apache.wiki.api.core.Command#getTarget()
    140     */
    141    @Override
    142    public final Object getTarget() {
    143        return m_target;
    144    }
    145
    146    /**
    147     * @see org.apache.wiki.api.core.Command#getURLPattern()
    148     */
    149    @Override
    150    public final String getURLPattern() {
    151        return m_urlPattern;
    152    }
    153
    154    /**
    155     * Returns the "friendly name" for this command's JSP, namely a beatified version of the JSP's name without the .jsp suffix.
    156     *
    157     * @return the friendly name
    158     */
    159    protected final String getJSPFriendlyName() {
    160        return m_jspFriendlyName;
    161    }
    162
    163    /**
    164     * Returns a String representation of the Command.
    165     *
    166     * @see java.lang.Object#toString()
    167     */
    168    public final String toString() {
    169        return "Command" +
    170               "[context=" + m_requestContext + "," +
    171               "urlPattern=" + m_urlPattern + "," +
    172               "jsp=" +  m_jsp +
    173               ( m_target == null ? "" : ",target=" + m_target + m_target ) +
    174               "]";
    175    }
    176
    177}