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     */
019    package org.apache.wiki.ui;
020    
021    import org.apache.wiki.util.TextUtil;
022    
023    
024    /**
025     * Abstract, immutable Command implementation class. All of the fields in this
026     * class are <code>final</code>. This class is thread-safe.
027     * @since 2.4.22
028     */
029    public abstract class AbstractCommand implements Command
030    {
031        private static final Command[] ALL_COMMANDS = new Command[] {
032            PageCommand.ATTACH,
033            PageCommand.COMMENT,
034            PageCommand.CONFLICT,
035            PageCommand.DELETE,
036            PageCommand.DIFF,
037            PageCommand.EDIT,
038            PageCommand.INFO,
039            PageCommand.NONE,
040            PageCommand.OTHER,
041            PageCommand.PREVIEW,
042            PageCommand.RENAME,
043            PageCommand.RSS,
044            PageCommand.UPLOAD,
045            PageCommand.VIEW,
046            GroupCommand.DELETE_GROUP,
047            GroupCommand.EDIT_GROUP,
048            GroupCommand.VIEW_GROUP,
049            WikiCommand.CREATE_GROUP,
050            WikiCommand.ERROR,
051            WikiCommand.FIND,
052            WikiCommand.INSTALL,
053            WikiCommand.LOGIN,
054            WikiCommand.LOGOUT,
055            WikiCommand.MESSAGE,
056            WikiCommand.PREFS,
057            WikiCommand.WORKFLOW,
058            WikiCommand.ADMIN,
059            RedirectCommand.REDIRECT
060        };
061    
062        private static final String    HTTPS = "HTTPS://";
063    
064        private static final String    HTTP = "HTTP://";
065    
066        private final String           m_jsp;
067    
068        private final String           m_jspFriendlyName;
069    
070        private final String           m_urlPattern;
071    
072        private final String           m_requestContext;
073    
074        private final String           m_contentTemplate;
075    
076        private final Object           m_target;
077    
078        /**
079         * Constructs a new Command with a specified wiki context, URL pattern,
080         * content template and target. The URL pattern is used to derive
081         * the JSP; if it is a "local" JSP (that is, it does not contain
082         * the <code>http://</code> or <code>https://</code> prefixes),
083         * then the JSP will be a cleansed version of the URL pattern;
084         * symbols (such as <code>%u</code>) will removed. If it the supplied
085         * URL pattern points to a non-local destination, the JSP will be set
086         * to the value supplied, unmodified.
087         * @param requestContext the request context
088         * @param urlPattern the URL pattern
089         * @param contentTemplate the content template; may be <code>null</code>
090         * @param target the target of the command, such as a WikiPage; may be
091         *            <code>null</code>
092         * @throws IllegalArgumentException if the request content or URL pattern is
093         *             <code>null</code>
094         */
095        protected AbstractCommand( String requestContext, String urlPattern, String contentTemplate, Object target )
096        {
097            if ( requestContext == null || urlPattern == null )
098            {
099                throw new IllegalArgumentException( "Request context, URL pattern and type must not be null." );
100            }
101    
102            m_requestContext = requestContext;
103    
104            if ( urlPattern.toUpperCase().startsWith( HTTP ) ||
105                 urlPattern.toUpperCase().endsWith( HTTPS ) )
106            {
107                // For an HTTP/HTTPS url, pass it through without modification
108                m_jsp = urlPattern;
109                m_jspFriendlyName = "Special Page";
110            }
111            else
112            {
113                // For local JSPs, take everything to the left of ?, then
114                // delete all variable substitutions
115                String jsp = urlPattern;
116                int qPosition = urlPattern.indexOf( '?' );
117                if ( qPosition != -1 )
118                {
119                    jsp = jsp.substring( 0, qPosition );
120                }
121                m_jsp = removeSubstitutions(jsp);
122    
123                // Calculate the "friendly name" for the JSP
124                if ( m_jsp.toUpperCase().endsWith( ".JSP" ) )
125                {
126                    m_jspFriendlyName = TextUtil.beautifyString( m_jsp.substring( 0, m_jsp.length() - 4 ) );
127                }
128                else
129                {
130                    m_jspFriendlyName = m_jsp;
131                }
132            }
133    
134            m_urlPattern = urlPattern;
135    
136            m_contentTemplate = contentTemplate;
137    
138            m_target = target;
139        }
140    
141        //
142        //  This is just *so* much faster than doing String.replaceAll().  It would, in fact,
143        //  be worth to cache this value.
144        //
145        private String removeSubstitutions(String jsp)
146        {
147            //return jsp.replaceAll( "\u0025[a-z|A-Z]", "" );
148            StringBuffer newjsp = new StringBuffer( jsp.length() );
149            for( int i = 0; i < jsp.length(); i++ )
150            {
151                char c = jsp.charAt(i);
152                if( c == '%' && i < jsp.length()-1 && Character.isLetterOrDigit( jsp.charAt(i+1) ) )
153                {
154                    i++;
155                    continue;
156                }
157                newjsp.append( c );
158            }
159            return newjsp.toString();
160        }
161    
162        /**
163         * Returns a defensively-created array of all
164         * static Commands.
165         * @return the array of commands
166         */
167        public static final Command[] allCommands()
168        {
169            return ALL_COMMANDS.clone();
170        }
171    
172        /**
173         * @see org.apache.wiki.ui.Command#targetedCommand(Object)
174         */
175        public abstract Command targetedCommand( Object target );
176    
177        /**
178         * @see org.apache.wiki.ui.Command#getContentTemplate()
179         */
180        public final String getContentTemplate()
181        {
182            return m_contentTemplate;
183        }
184    
185        /**
186         * @see org.apache.wiki.ui.Command#getJSP()
187         */
188        public final String getJSP()
189        {
190            return m_jsp;
191        }
192    
193        /**
194         * @see org.apache.wiki.ui.Command#getName()
195         */
196        public abstract String getName();
197    
198        /**
199         * @see org.apache.wiki.ui.Command#getRequestContext()
200         */
201        public final String getRequestContext()
202        {
203            return m_requestContext;
204        }
205    
206        /**
207         * @see org.apache.wiki.ui.Command#getTarget()
208         */
209        public final Object getTarget()
210        {
211            return m_target;
212        }
213    
214        /**
215         * @see org.apache.wiki.ui.Command#getURLPattern()
216         */
217        public final String getURLPattern()
218        {
219            return m_urlPattern;
220        }
221    
222        /**
223         * Returns the "friendly name" for this command's JSP, namely
224         * a beatified version of the JSP's name without the .jsp suffix.
225         * @return the friendly name
226         */
227        protected final String getJSPFriendlyName()
228        {
229            return m_jspFriendlyName;
230        }
231    
232        /**
233         * Returns a String representation of the Command.
234         * @see java.lang.Object#toString()
235         */
236        public final String toString()
237        {
238            return "Command" +
239                   "[context=" + m_requestContext + "," +
240                   "urlPattern=" + m_urlPattern + "," +
241                   "jsp=" +  m_jsp +
242                   ( m_target == null ? "" : ",target=" + m_target + m_target.toString() ) +
243                   "]";
244        }
245    
246    }