001: /*
002: * Copyright 1999,2004 The Apache Software Foundation.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.apache.catalina.ssi;
017:
018: import java.io.IOException;
019: import java.util.Collection;
020: import java.util.Date;
021: import java.util.HashSet;
022: import java.util.Iterator;
023: import java.util.Set;
024: import java.util.TimeZone;
025:
026: import org.apache.catalina.util.DateTool;
027: import org.apache.catalina.util.Strftime;
028: import org.apache.catalina.util.URLEncoder;
029:
030: /**
031: * Allows the different SSICommand implementations to share data/talk to each other
032: *
033: * @author Bip Thelin
034: * @author Amy Roh
035: * @author Dan Sandberg
036: * @version $Revision: 1.3 $, $Date: 2004/02/27 14:58:47 $
037: */
038: public class SSIMediator {
039: protected final static String DEFAULT_CONFIG_ERR_MSG = "[an error occurred while processing this directive]";
040: protected final static String DEFAULT_CONFIG_TIME_FMT = "%A, %d-%b-%Y %T %Z";
041: protected final static String DEFAULT_CONFIG_SIZE_FMT = "abbrev";
042: protected static URLEncoder urlEncoder;
043: protected String configErrMsg = DEFAULT_CONFIG_ERR_MSG;
044: protected String configTimeFmt = DEFAULT_CONFIG_TIME_FMT;
045: protected String configSizeFmt = DEFAULT_CONFIG_SIZE_FMT;
046: protected String className = getClass().getName();
047: protected SSIExternalResolver ssiExternalResolver;
048: protected Date lastModifiedDate;
049: protected int debug;
050: protected Strftime strftime;
051:
052: static {
053: //We try to encode only the same characters that apache does
054: urlEncoder = new URLEncoder();
055: urlEncoder.addSafeCharacter(',');
056: urlEncoder.addSafeCharacter(':');
057: urlEncoder.addSafeCharacter('-');
058: urlEncoder.addSafeCharacter('_');
059: urlEncoder.addSafeCharacter('.');
060: urlEncoder.addSafeCharacter('*');
061: urlEncoder.addSafeCharacter('/');
062: urlEncoder.addSafeCharacter('!');
063: urlEncoder.addSafeCharacter('~');
064: urlEncoder.addSafeCharacter('\'');
065: urlEncoder.addSafeCharacter('(');
066: urlEncoder.addSafeCharacter(')');
067: }
068:
069: public SSIMediator(SSIExternalResolver ssiExternalResolver,
070: Date lastModifiedDate, int debug) {
071: this .ssiExternalResolver = ssiExternalResolver;
072: this .lastModifiedDate = lastModifiedDate;
073: this .debug = debug;
074:
075: setConfigTimeFmt(DEFAULT_CONFIG_TIME_FMT, true);
076: }
077:
078: public void setConfigErrMsg(String configErrMsg) {
079: this .configErrMsg = configErrMsg;
080: }
081:
082: public void setConfigTimeFmt(String configTimeFmt) {
083: setConfigTimeFmt(configTimeFmt, false);
084: }
085:
086: public void setConfigTimeFmt(String configTimeFmt,
087: boolean fromConstructor) {
088: this .configTimeFmt = configTimeFmt;
089:
090: //What's the story here with DateTool.LOCALE_US?? Why??
091: this .strftime = new Strftime(configTimeFmt, DateTool.LOCALE_US);
092:
093: //Variables like DATE_LOCAL, DATE_GMT, and LAST_MODIFIED need to be updated when
094: //the timefmt changes. This is what Apache SSI does.
095: setDateVariables(fromConstructor);
096: }
097:
098: public void setConfigSizeFmt(String configSizeFmt) {
099: this .configSizeFmt = configSizeFmt;
100: }
101:
102: public String getConfigErrMsg() {
103: return configErrMsg;
104: }
105:
106: public String getConfigTimeFmt() {
107: return configTimeFmt;
108: }
109:
110: public String getConfigSizeFmt() {
111: return configSizeFmt;
112: }
113:
114: public Collection getVariableNames() {
115: Set variableNames = new HashSet();
116: //These built-in variables are supplied by the mediator ( if not over-written by the user ) and always exist
117: variableNames.add("DATE_GMT");
118: variableNames.add("DATE_LOCAL");
119: variableNames.add("LAST_MODIFIED");
120: ssiExternalResolver.addVariableNames(variableNames);
121:
122: //Remove any variables that are reserved by this class
123: Iterator iter = variableNames.iterator();
124: while (iter.hasNext()) {
125: String name = (String) iter.next();
126: if (isNameReserved(name)) {
127: iter.remove();
128: }
129: }
130: return variableNames;
131: }
132:
133: public long getFileSize(String path, boolean virtual)
134: throws IOException {
135: return ssiExternalResolver.getFileSize(path, virtual);
136: }
137:
138: public long getFileLastModified(String path, boolean virtual)
139: throws IOException {
140: return ssiExternalResolver.getFileLastModified(path, virtual);
141: }
142:
143: public String getFileText(String path, boolean virtual)
144: throws IOException {
145: return ssiExternalResolver.getFileText(path, virtual);
146: }
147:
148: protected boolean isNameReserved(String name) {
149: return name.startsWith(className + ".");
150: }
151:
152: public String getVariableValue(String variableName) {
153: return getVariableValue(variableName, "none");
154: }
155:
156: public void setVariableValue(String variableName,
157: String variableValue) {
158: if (!isNameReserved(variableName)) {
159: ssiExternalResolver.setVariableValue(variableName,
160: variableValue);
161: }
162: }
163:
164: public String getVariableValue(String variableName, String encoding) {
165: String lowerCaseVariableName = variableName.toLowerCase();
166: String variableValue = null;
167:
168: if (!isNameReserved(lowerCaseVariableName)) {
169: //Try getting it externally first, if it fails, try getting the 'built-in' value
170: variableValue = ssiExternalResolver
171: .getVariableValue(variableName);
172: if (variableValue == null) {
173: variableName = variableName.toUpperCase();
174: variableValue = (String) ssiExternalResolver
175: .getVariableValue(className + "."
176: + variableName);
177: }
178: if (variableValue != null) {
179: variableValue = encode(variableValue, encoding);
180: }
181: }
182: return variableValue;
183: }
184:
185: protected String formatDate(Date date, TimeZone timeZone) {
186: String retVal;
187:
188: if (timeZone != null) {
189: //we temporarily change strftime. Since SSIMediator is inherently single-threaded, this
190: //isn't a problem
191: TimeZone oldTimeZone = strftime.getTimeZone();
192: strftime.setTimeZone(timeZone);
193: retVal = strftime.format(date);
194: strftime.setTimeZone(oldTimeZone);
195: } else {
196: retVal = strftime.format(date);
197: }
198: return retVal;
199: }
200:
201: protected String encode(String value, String encoding) {
202: String retVal = null;
203:
204: if (encoding.equalsIgnoreCase("url")) {
205: retVal = urlEncoder.encode(value);
206: } else if (encoding.equalsIgnoreCase("none")) {
207: retVal = value;
208: } else if (encoding.equalsIgnoreCase("entity")) {
209: //Not sure how this is really different than none
210: retVal = value;
211: } else {
212: //This shouldn't be possible
213: throw new IllegalArgumentException("Unknown encoding: "
214: + encoding);
215: }
216: return retVal;
217: }
218:
219: public void log(String message) {
220: ssiExternalResolver.log(message, null);
221: }
222:
223: public void log(String message, Throwable throwable) {
224: ssiExternalResolver.log(message, throwable);
225: }
226:
227: protected void setDateVariables(boolean fromConstructor) {
228: boolean alreadySet = ssiExternalResolver
229: .getVariableValue(className + ".alreadyset") != null;
230: //skip this if we are being called from the constructor, and this has already been set
231: if (!(fromConstructor && alreadySet)) {
232: ssiExternalResolver.setVariableValue(className
233: + ".alreadyset", "true");
234:
235: Date date = new Date();
236: TimeZone timeZone = TimeZone.getTimeZone("GMT");
237: String retVal = formatDate(date, timeZone);
238:
239: //If we are setting on of the date variables, we want to remove them from the user
240: //defined list of variables, because this is what Apache does
241: setVariableValue("DATE_GMT", null);
242: ssiExternalResolver.setVariableValue(className
243: + ".DATE_GMT", retVal);
244:
245: retVal = formatDate(date, null);
246: setVariableValue("DATE_LOCAL", null);
247: ssiExternalResolver.setVariableValue(className
248: + ".DATE_LOCAL", retVal);
249:
250: retVal = formatDate(lastModifiedDate, null);
251: setVariableValue("LAST_MODIFIED", null);
252: ssiExternalResolver.setVariableValue(className
253: + ".LAST_MODIFIED", retVal);
254: }
255: }
256: }
|