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    public abstract Command targetedCommand( final Object target );
106
107    /**
108     * @see org.apache.wiki.api.core.Command#getContentTemplate()
109     */
110    public final String getContentTemplate() {
111        return m_contentTemplate;
112    }
113
114    /**
115     * @see org.apache.wiki.api.core.Command#getJSP()
116     */
117    public final String getJSP() {
118        return m_jsp;
119    }
120
121    /**
122     * @see org.apache.wiki.api.core.Command#getName()
123     */
124    public abstract String getName();
125
126    /**
127     * @see org.apache.wiki.api.core.Command#getRequestContext()
128     */
129    public final String getRequestContext() {
130        return m_requestContext;
131    }
132
133    /**
134     * @see org.apache.wiki.api.core.Command#getTarget()
135     */
136    public final Object getTarget() {
137        return m_target;
138    }
139
140    /**
141     * @see org.apache.wiki.api.core.Command#getURLPattern()
142     */
143    public final String getURLPattern() {
144        return m_urlPattern;
145    }
146
147    /**
148     * Returns the "friendly name" for this command's JSP, namely a beatified version of the JSP's name without the .jsp suffix.
149     *
150     * @return the friendly name
151     */
152    protected final String getJSPFriendlyName() {
153        return m_jspFriendlyName;
154    }
155
156    /**
157     * Returns a String representation of the Command.
158     *
159     * @see java.lang.Object#toString()
160     */
161    public final String toString() {
162        return "Command" +
163               "[context=" + m_requestContext + "," +
164               "urlPattern=" + m_urlPattern + "," +
165               "jsp=" +  m_jsp +
166               ( m_target == null ? "" : ",target=" + m_target + m_target ) +
167               "]";
168    }
169
170}