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}