001: /*
002: JSPWiki - a JSP-based WikiWiki clone.
003:
004: Copyright (C) 2001-2007 Janne Jalkanen (Janne.Jalkanen@iki.fi)
005:
006: This program is free software; you can redistribute it and/or modify
007: it under the terms of the GNU Lesser General Public License as published by
008: the Free Software Foundation; either version 2.1 of the License, or
009: (at your option) any later version.
010:
011: This program is distributed in the hope that it will be useful,
012: but WITHOUT ANY WARRANTY; without even the implied warranty of
013: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014: GNU Lesser General Public License for more details.
015:
016: You should have received a copy of the GNU Lesser General Public License
017: along with this program; if not, write to the Free Software
018: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
019: */
020: package com.ecyrd.jspwiki.ui;
021:
022: import com.ecyrd.jspwiki.TextUtil;
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: * @author Andrew Jaquith
028: * @since 2.4.22
029: */
030: public abstract class AbstractCommand implements Command {
031: private static final Command[] ALL_COMMANDS = new Command[] {
032: PageCommand.ATTACH, PageCommand.COMMENT,
033: PageCommand.CONFLICT, PageCommand.DELETE, PageCommand.DIFF,
034: PageCommand.EDIT, PageCommand.INFO, PageCommand.NONE,
035: PageCommand.OTHER, PageCommand.PREVIEW, PageCommand.RENAME,
036: PageCommand.RSS, PageCommand.UPLOAD, PageCommand.VIEW,
037: GroupCommand.DELETE_GROUP, GroupCommand.EDIT_GROUP,
038: GroupCommand.VIEW_GROUP, WikiCommand.CREATE_GROUP,
039: WikiCommand.ERROR, WikiCommand.FIND, WikiCommand.INSTALL,
040: WikiCommand.LOGIN, WikiCommand.LOGOUT, WikiCommand.MESSAGE,
041: WikiCommand.PREFS, WikiCommand.WORKFLOW, WikiCommand.ADMIN,
042: RedirectCommand.REDIRECT };
043:
044: private static final String HTTPS = "HTTPS://";
045:
046: private static final String HTTP = "HTTP://";
047:
048: private final String m_jsp;
049:
050: private final String m_jspFriendlyName;
051:
052: private final String m_urlPattern;
053:
054: private final String m_requestContext;
055:
056: private final String m_contentTemplate;
057:
058: private final Object m_target;
059:
060: /**
061: * Constructs a new Command with a specified wiki context, URL pattern,
062: * content template and target. The URL pattern is used to derive
063: * the JSP; if it is a "local" JSP (that is, it does not contain
064: * the <code>http://</code> or <code>https://</code> prefixes),
065: * then the JSP will be a cleansed version of the URL pattern;
066: * symbols (such as <code>%u</code>) will removed. If it the supplied
067: * URL pattern points to a non-local destination, the JSP will be set
068: * to the value supplied, unmodified.
069: * @param requestContext the request context
070: * @param urlPattern the URL pattern
071: * @param contentTemplate the content template; may be <code>null</code>
072: * @param target the target of the command, such as a WikiPage; may be
073: * <code>null</code>
074: * @throws IllegalArgumentException if the request content or URL pattern is
075: * <code>null</code>
076: */
077: protected AbstractCommand(String requestContext, String urlPattern,
078: String contentTemplate, Object target) {
079: if (requestContext == null || urlPattern == null) {
080: throw new IllegalArgumentException(
081: "Request context, URL pattern and type must not be null.");
082: }
083:
084: m_requestContext = requestContext;
085:
086: if (urlPattern.toUpperCase().startsWith(HTTP)
087: || urlPattern.toUpperCase().endsWith(HTTPS)) {
088: // For an HTTP/HTTPS url, pass it through without modification
089: m_jsp = urlPattern;
090: m_jspFriendlyName = "Special Page";
091: } else {
092: // For local JSPs, take everything to the left of ?, then
093: // delete all variable substitutions
094: String jsp = urlPattern;
095: int qPosition = urlPattern.indexOf('?');
096: if (qPosition != -1) {
097: jsp = jsp.substring(0, qPosition);
098: }
099: m_jsp = removeSubstitutions(jsp);
100:
101: // Calculate the "friendly name" for the JSP
102: if (m_jsp.toUpperCase().endsWith(".JSP")) {
103: m_jspFriendlyName = TextUtil.beautifyString(m_jsp
104: .substring(0, m_jsp.length() - 4));
105: } else {
106: m_jspFriendlyName = m_jsp;
107: }
108: }
109:
110: m_urlPattern = urlPattern;
111:
112: m_contentTemplate = contentTemplate;
113:
114: m_target = target;
115: }
116:
117: //
118: // This is just *so* much faster than doing String.replaceAll(). It would, in fact,
119: // be worth to cache this value.
120: //
121: private String removeSubstitutions(String jsp) {
122: //return jsp.replaceAll( "\u0025[a-z|A-Z]", "" );
123: StringBuffer newjsp = new StringBuffer(jsp.length());
124: for (int i = 0; i < jsp.length(); i++) {
125: char c = jsp.charAt(i);
126: if (c == '%' && i < jsp.length() - 1
127: && Character.isLetterOrDigit(jsp.charAt(i + 1))) {
128: i++;
129: continue;
130: }
131: newjsp.append(c);
132: }
133: return newjsp.toString();
134: }
135:
136: /**
137: * Returns a defensively-created array of all
138: * static Commands.
139: * @return the array of commands
140: */
141: public static final Command[] allCommands() {
142: return (Command[]) ALL_COMMANDS.clone();
143: }
144:
145: /**
146: * @see com.ecyrd.jspwiki.ui.Command#targetedCommand(Object)
147: */
148: public abstract Command targetedCommand(Object target);
149:
150: /**
151: * @see com.ecyrd.jspwiki.ui.Command#getContentTemplate()
152: */
153: public final String getContentTemplate() {
154: return m_contentTemplate;
155: }
156:
157: /**
158: * @see com.ecyrd.jspwiki.ui.Command#getJSP()
159: */
160: public final String getJSP() {
161: return m_jsp;
162: }
163:
164: /**
165: * @see com.ecyrd.jspwiki.ui.Command#getName()
166: */
167: public abstract String getName();
168:
169: /**
170: * @see com.ecyrd.jspwiki.ui.Command#getRequestContext()
171: */
172: public final String getRequestContext() {
173: return m_requestContext;
174: }
175:
176: /**
177: * @see com.ecyrd.jspwiki.ui.Command#getTarget()
178: */
179: public final Object getTarget() {
180: return m_target;
181: }
182:
183: /**
184: * @see com.ecyrd.jspwiki.ui.Command#getURLPattern()
185: */
186: public final String getURLPattern() {
187: return m_urlPattern;
188: }
189:
190: /**
191: * Returns the "friendly name" for this command's JSP, namely
192: * a beatified version of the JSP's name without the .jsp suffix.
193: * @return the friendly name
194: */
195: protected final String getJSPFriendlyName() {
196: return m_jspFriendlyName;
197: }
198:
199: /**
200: * Returns a String representation of the Command.
201: * @see java.lang.Object#toString()
202: */
203: public final String toString() {
204: return "Command"
205: + "[context="
206: + m_requestContext
207: + ","
208: + "urlPattern="
209: + m_urlPattern
210: + ","
211: + "jsp="
212: + m_jsp
213: + (m_target == null ? "" : ",target=" + m_target
214: + m_target.toString()) + "]";
215: }
216:
217: }
|