KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > catalina > ssi > SSIProcessor


1 /*
2  * Copyright 1999,2004 The Apache Software Foundation. Licensed under the
3  * Apache License, Version 2.0 (the "License"); you may not use this file
4  * except in compliance with the License. You may obtain a copy of the License
5  * at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable
6  * law or agreed to in writing, software distributed under the License is
7  * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
8  * KIND, either express or implied. See the License for the specific language
9  * governing permissions and limitations under the License.
10  */

11 package org.apache.catalina.ssi;
12
13
14 import java.io.IOException JavaDoc;
15 import java.io.PrintWriter JavaDoc;
16 import java.io.Reader JavaDoc;
17 import java.io.StringWriter JavaDoc;
18 import java.util.HashMap JavaDoc;
19 import java.util.StringTokenizer JavaDoc;
20 import org.apache.catalina.util.IOTools;
21 /**
22  * The entry point to SSI processing. This class does the actual parsing,
23  * delegating to the SSIMediator, SSICommand, and SSIExternalResolver as
24  * necessary[
25  *
26  * @author Dan Sandberg
27  * @author David Becker
28  * @version $Revision: 467222 $, $Date: 2006-10-24 05:17:11 +0200 (mar., 24 oct. 2006) $
29  */

30 public class SSIProcessor {
31     /** The start pattern */
32     protected final static String JavaDoc COMMAND_START = "<!--#";
33     /** The end pattern */
34     protected final static String JavaDoc COMMAND_END = "-->";
35     protected final static int BUFFER_SIZE = 4096;
36     protected SSIExternalResolver ssiExternalResolver;
37     protected HashMap JavaDoc commands = new HashMap JavaDoc();
38     protected int debug;
39
40
41     public SSIProcessor(SSIExternalResolver ssiExternalResolver, int debug) {
42         this.ssiExternalResolver = ssiExternalResolver;
43         this.debug = debug;
44         addBuiltinCommands();
45     }
46
47
48     protected void addBuiltinCommands() {
49         addCommand("config", new SSIConfig());
50         addCommand("echo", new SSIEcho());
51         addCommand("exec", new SSIExec());
52         addCommand("include", new SSIInclude());
53         addCommand("flastmod", new SSIFlastmod());
54         addCommand("fsize", new SSIFsize());
55         addCommand("printenv", new SSIPrintenv());
56         addCommand("set", new SSISet());
57         SSIConditional ssiConditional = new SSIConditional();
58         addCommand("if", ssiConditional);
59         addCommand("elif", ssiConditional);
60         addCommand("endif", ssiConditional);
61         addCommand("else", ssiConditional);
62     }
63
64
65     public void addCommand(String JavaDoc name, SSICommand command) {
66         commands.put(name, command);
67     }
68
69
70     /**
71      * Process a file with server-side commands, reading from reader and
72      * writing the processed version to writer. NOTE: We really should be doing
73      * this in a streaming way rather than converting it to an array first.
74      *
75      * @param reader
76      * the reader to read the file containing SSIs from
77      * @param writer
78      * the writer to write the file with the SSIs processed.
79      * @return the most current modified date resulting from any SSI commands
80      * @throws IOException
81      * when things go horribly awry. Should be unlikely since the
82      * SSICommand usually catches 'normal' IOExceptions.
83      */

84     public long process(Reader JavaDoc reader, long lastModifiedDate,
85             PrintWriter JavaDoc writer) throws IOException JavaDoc {
86         SSIMediator ssiMediator = new SSIMediator(ssiExternalResolver,
87                 lastModifiedDate, debug);
88         StringWriter JavaDoc stringWriter = new StringWriter JavaDoc();
89         IOTools.flow(reader, stringWriter);
90         String JavaDoc fileContents = stringWriter.toString();
91         stringWriter = null;
92         int index = 0;
93         boolean inside = false;
94         StringBuffer JavaDoc command = new StringBuffer JavaDoc();
95         try {
96             while (index < fileContents.length()) {
97                 char c = fileContents.charAt(index);
98                 if (!inside) {
99                     if (c == COMMAND_START.charAt(0)
100                             && charCmp(fileContents, index, COMMAND_START)) {
101                         inside = true;
102                         index += COMMAND_START.length();
103                         command.setLength(0); //clear the command string
104
} else {
105                         if (!ssiMediator.getConditionalState().processConditionalCommandsOnly) {
106                             writer.write(c);
107                         }
108                         index++;
109                     }
110                 } else {
111                     if (c == COMMAND_END.charAt(0)
112                             && charCmp(fileContents, index, COMMAND_END)) {
113                         inside = false;
114                         index += COMMAND_END.length();
115                         String JavaDoc strCmd = parseCmd(command);
116                         if (debug > 0) {
117                             ssiExternalResolver.log(
118                                     "SSIProcessor.process -- processing command: "
119                                             + strCmd, null);
120                         }
121                         String JavaDoc[] paramNames = parseParamNames(command, strCmd
122                                 .length());
123                         String JavaDoc[] paramValues = parseParamValues(command,
124                                 strCmd.length(), paramNames.length);
125                         //We need to fetch this value each time, since it may
126
// change
127
// during the loop
128
String JavaDoc configErrMsg = ssiMediator.getConfigErrMsg();
129                         SSICommand ssiCommand = (SSICommand)commands
130                                 .get(strCmd.toLowerCase());
131                         String JavaDoc errorMessage = null;
132                         if (ssiCommand == null) {
133                             errorMessage = "Unknown command: " + strCmd;
134                         } else if (paramValues == null) {
135                             errorMessage = "Error parsing directive parameters.";
136                         } else if (paramNames.length != paramValues.length) {
137                             errorMessage = "Parameter names count does not match parameter values count on command: "
138                                     + strCmd;
139                         } else {
140                             // don't process the command if we are processing
141
// conditional
142
// commands only and the
143
// command is not conditional
144
if (!ssiMediator.getConditionalState().processConditionalCommandsOnly
145                                     || ssiCommand instanceof SSIConditional) {
146                                 long lmd = ssiCommand.process(ssiMediator, strCmd,
147                                                paramNames, paramValues, writer);
148                                 if (lmd > lastModifiedDate) {
149                                     lastModifiedDate = lmd;
150                                 }
151                             }
152                         }
153                         if (errorMessage != null) {
154                             ssiExternalResolver.log(errorMessage, null);
155                             writer.write(configErrMsg);
156                         }
157                     } else {
158                         command.append(c);
159                         index++;
160                     }
161                 }
162             }
163         } catch (SSIStopProcessingException e) {
164             //If we are here, then we have already stopped processing, so all
165
// is good
166
}
167         return lastModifiedDate;
168     }
169
170
171     /**
172      * Parse a StringBuffer and take out the param type token. Called from
173      * <code>requestHandler</code>
174      *
175      * @param cmd
176      * a value of type 'StringBuffer'
177      * @return a value of type 'String[]'
178      */

179     protected String JavaDoc[] parseParamNames(StringBuffer JavaDoc cmd, int start) {
180         int bIdx = start;
181         int i = 0;
182         int quotes = 0;
183         boolean inside = false;
184         StringBuffer JavaDoc retBuf = new StringBuffer JavaDoc();
185         while (bIdx < cmd.length()) {
186             if (!inside) {
187                 while (bIdx < cmd.length() && isSpace(cmd.charAt(bIdx)))
188                     bIdx++;
189                 if (bIdx >= cmd.length()) break;
190                 inside = !inside;
191             } else {
192                 while (bIdx < cmd.length() && cmd.charAt(bIdx) != '=') {
193                     retBuf.append(cmd.charAt(bIdx));
194                     bIdx++;
195                 }
196                 retBuf.append('=');
197                 inside = !inside;
198                 quotes = 0;
199                 boolean escaped = false;
200                 for (; bIdx < cmd.length() && quotes != 2; bIdx++) {
201                     char c = cmd.charAt(bIdx);
202                     // Need to skip escaped characters
203
if (c == '\\' && !escaped) {
204                         escaped = true;
205                         bIdx++;
206                         continue;
207                     }
208                     escaped = false;
209                     if (c == '"') quotes++;
210                 }
211             }
212         }
213         StringTokenizer JavaDoc str = new StringTokenizer JavaDoc(retBuf.toString(), "=");
214         String JavaDoc[] retString = new String JavaDoc[str.countTokens()];
215         while (str.hasMoreTokens()) {
216             retString[i++] = str.nextToken().trim();
217         }
218         return retString;
219     }
220
221
222     /**
223      * Parse a StringBuffer and take out the param token. Called from
224      * <code>requestHandler</code>
225      *
226      * @param cmd
227      * a value of type 'StringBuffer'
228      * @return a value of type 'String[]'
229      */

230     protected String JavaDoc[] parseParamValues(StringBuffer JavaDoc cmd, int start, int count) {
231         int valIndex = 0;
232         boolean inside = false;
233         String JavaDoc[] vals = new String JavaDoc[count];
234         StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
235         char endQuote = 0;
236         for (int bIdx = start; bIdx < cmd.length(); bIdx++) {
237             if (!inside) {
238                 while (bIdx < cmd.length() && !isQuote(cmd.charAt(bIdx)))
239                     bIdx++;
240                 if (bIdx >= cmd.length()) break;
241                 inside = !inside;
242                 endQuote = cmd.charAt(bIdx);
243             } else {
244                 boolean escaped = false;
245                 for (; bIdx < cmd.length(); bIdx++) {
246                     char c = cmd.charAt(bIdx);
247                     // Check for escapes
248
if (c == '\\' && !escaped) {
249                         escaped = true;
250                         continue;
251                     }
252                     // If we reach the other " then stop
253
if (c == endQuote && !escaped) break;
254                     // Since parsing of attributes and var
255
// substitution is done in separate places,
256
// we need to leave escape in the string
257
if (c == '$' && escaped) sb.append('\\');
258                     escaped = false;
259                     sb.append(c);
260                 }
261                 // If we hit the end without seeing a quote
262
// the signal an error
263
if (bIdx == cmd.length()) return null;
264                 vals[valIndex++] = sb.toString();
265                 sb.delete(0, sb.length()); // clear the buffer
266
inside = !inside;
267             }
268         }
269         return vals;
270     }
271
272
273     /**
274      * Parse a StringBuffer and take out the command token. Called from
275      * <code>requestHandler</code>
276      *
277      * @param cmd
278      * a value of type 'StringBuffer'
279      * @return a value of type 'String', or null if there is none
280      */

281     private String JavaDoc parseCmd(StringBuffer JavaDoc cmd) {
282         int firstLetter = -1;
283         int lastLetter = -1;
284         for (int i = 0; i < cmd.length(); i++) {
285             char c = cmd.charAt(i);
286             if (Character.isLetter(c)) {
287                 if (firstLetter == -1) {
288                     firstLetter = i;
289                 }
290                 lastLetter = i;
291             } else if (isSpace(c)) {
292                 if (lastLetter > -1) {
293                     break;
294                 }
295             } else {
296                 break;
297             }
298         }
299         String JavaDoc command = null;
300         if (firstLetter != -1) {
301             command = cmd.substring(firstLetter, lastLetter + 1);
302         }
303         return command;
304     }
305
306
307     protected boolean charCmp(String JavaDoc buf, int index, String JavaDoc command) {
308         return buf.regionMatches(index, command, 0, command.length());
309     }
310
311
312     protected boolean isSpace(char c) {
313         return c == ' ' || c == '\n' || c == '\t' || c == '\r';
314     }
315     
316     protected boolean isQuote(char c) {
317         return c == '\'' || c == '\"' || c == '`';
318     }
319 }
Popular Tags