001: /*
002: JSPWiki - a JSP-based WikiWiki clone.
003:
004: Copyright (C) 2001 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;
021:
022: import java.security.Principal;
023: import java.util.Date;
024: import java.util.Iterator;
025: import java.util.List;
026: import java.util.Properties;
027:
028: import javax.servlet.http.HttpServletRequest;
029: import javax.servlet.http.HttpSession;
030:
031: import com.ecyrd.jspwiki.filters.PageFilter;
032: import com.ecyrd.jspwiki.modules.InternalModule;
033:
034: /**
035: * Manages variables. Variables are case-insensitive. A list of all
036: * available variables is on a Wiki page called "WikiVariables".
037: *
038: * @author Janne Jalkanen
039: * @since 1.9.20.
040: */
041: public class VariableManager {
042: //private static Logger log = Logger.getLogger( VariableManager.class );
043:
044: // FIXME: These are probably obsolete.
045: public static final String VAR_ERROR = "error";
046: public static final String VAR_MSG = "msg";
047:
048: /**
049: * Contains a list of those properties that shall never be shown.
050: * Put names here in lower case.
051: */
052:
053: static final String[] THE_BIG_NO_NO_LIST = { "jspwiki.auth.masterpassword" };
054:
055: /**
056: * Creates a VariableManager object using the property list given.
057: * @param props The properties.
058: */
059: public VariableManager(Properties props) {
060: }
061:
062: /**
063: * Returns true if the link is really command to insert
064: * a variable.
065: * <P>
066: * Currently we just check if the link starts with "{$".
067: *
068: * @param link The link text
069: * @return true, if this represents a variable link.
070: */
071: public static boolean isVariableLink(String link) {
072: return link.startsWith("{$");
073: }
074:
075: /**
076: * Parses the link and finds a value. This is essentially used
077: * once {@link #isVariableLink(String)} has found that the link text
078: * actually contains a variable. For example, you could pass in
079: * "{$username}" and get back "JanneJalkanen".
080: *
081: * @param context The WikiContext
082: * @param link The link text containing the variable name.
083: * @return The variable value.
084: * @throws IllegalArgumentException If the format is not valid (does not
085: * start with "{$", is zero length, etc.)
086: * @throws NoSuchVariableException If a variable is not known.
087: */
088: public String parseAndGetValue(WikiContext context, String link)
089: throws IllegalArgumentException, NoSuchVariableException {
090: if (!link.startsWith("{$"))
091: throw new IllegalArgumentException(
092: "Link does not start with {$");
093:
094: if (!link.endsWith("}"))
095: throw new IllegalArgumentException(
096: "Link does not end with }");
097:
098: String varName = link.substring(2, link.length() - 1);
099:
100: return getValue(context, varName.trim());
101: }
102:
103: /**
104: * This method does in-place expansion of any variables. However,
105: * the expansion is not done twice, that is, a variable containing text $variable
106: * will not be expanded.
107: * <P>
108: * The variables should be in the same format ({$variablename} as in the web
109: * pages.
110: *
111: * @param context The WikiContext of the current page.
112: * @param source The source string.
113: * @return The source string with variables expanded.
114: */
115: // FIXME: somewhat slow.
116: public String expandVariables(WikiContext context, String source) {
117: StringBuffer result = new StringBuffer();
118:
119: for (int i = 0; i < source.length(); i++) {
120: if (source.charAt(i) == '{') {
121: if (i < source.length() - 2
122: && source.charAt(i + 1) == '$') {
123: int end = source.indexOf('}', i);
124:
125: if (end != -1) {
126: String varname = source.substring(i + 2, end);
127: String value;
128:
129: try {
130: value = getValue(context, varname);
131: } catch (NoSuchVariableException e) {
132: value = e.getMessage();
133: } catch (IllegalArgumentException e) {
134: value = e.getMessage();
135: }
136:
137: result.append(value);
138: i = end;
139: continue;
140: }
141: } else {
142: result.append('{');
143: }
144: } else {
145: result.append(source.charAt(i));
146: }
147: }
148:
149: return result.toString();
150: }
151:
152: /**
153: * Returns the value of a named variable. See {@link #getValue(WikiContext, String)}.
154: * The only difference is that this method does not throw an exception, but it
155: * returns the given default value instead.
156: *
157: * @param context WikiContext
158: * @param varName The name of the variable
159: * @param defValue A default value.
160: * @return The variable value, or if not found, the default value.
161: */
162: public String getValue(WikiContext context, String varName,
163: String defValue) {
164: try {
165: return getValue(context, varName);
166: } catch (NoSuchVariableException e) {
167: return defValue;
168: }
169: }
170:
171: /**
172: * Returns a value of the named variable. The resolving order is
173: * <ol>
174: * <li>Known "constant" name, such as "pagename", etc. This is so
175: * that pages could not override certain constants.
176: * <li>WikiContext local variable. This allows a programmer to
177: * set a parameter which cannot be overridden by user.
178: * <li>HTTP Session
179: * <li>HTTP Request parameters
180: * <li>WikiPage variable. As set by the user with the SET directive.
181: * <li>jspwiki.properties
182: * </ol>
183: *
184: * Use this method only whenever you really need to have a parameter that
185: * can be overridden by anyone using the wiki.
186: *
187: * @param context The WikiContext
188: * @param varName Name of the variable.
189: *
190: * @return The variable value.
191: *
192: * @throws IllegalArgumentException If the name is somehow broken.
193: * @throws NoSuchVariableException If a variable is not known.
194: */
195: // FIXME: Currently a bit complicated. Perhaps should use reflection
196: // or something to make an easy way of doing stuff.
197: public String getValue(WikiContext context, String varName)
198: throws IllegalArgumentException, NoSuchVariableException {
199: if (varName == null)
200: throw new IllegalArgumentException("Null variable name.");
201:
202: if (varName.length() == 0)
203: throw new IllegalArgumentException(
204: "Zero length variable name.");
205:
206: // Faster than doing equalsIgnoreCase()
207: String name = varName.toLowerCase();
208:
209: for (int i = 0; i < THE_BIG_NO_NO_LIST.length; i++) {
210: if (name.equals(THE_BIG_NO_NO_LIST[i]))
211: return ""; // FIXME: Should this be something different?
212: }
213:
214: if (name.equals("pagename")) {
215: return context.getPage().getName();
216: } else if (name.equals("applicationname")) {
217: return context.getEngine().getApplicationName();
218: } else if (name.equals("jspwikiversion")) {
219: return Release.getVersionString();
220: } else if (name.equals("encoding")) {
221: return context.getEngine().getContentEncoding();
222: } else if (name.equals("totalpages")) {
223: return Integer.toString(context.getEngine().getPageCount());
224: } else if (name.equals("pageprovider")) {
225: return context.getEngine().getCurrentProvider();
226: } else if (name.equals("pageproviderdescription")) {
227: return context.getEngine().getCurrentProviderInfo();
228: } else if (name.equals("attachmentprovider")) {
229: WikiProvider p = context.getEngine().getAttachmentManager()
230: .getCurrentProvider();
231: return (p != null) ? p.getClass().getName() : "-";
232: } else if (name.equals("attachmentproviderdescription")) {
233: WikiProvider p = context.getEngine().getAttachmentManager()
234: .getCurrentProvider();
235:
236: return (p != null) ? p.getProviderInfo() : "-";
237: } else if (name.equals("interwikilinks")) {
238: StringBuffer res = new StringBuffer();
239:
240: for (Iterator i = context.getEngine()
241: .getAllInterWikiLinks().iterator(); i.hasNext();) {
242: if (res.length() > 0)
243: res.append(", ");
244: String link = (String) i.next();
245: res.append(link);
246: res.append(" --> ");
247: res.append(context.getEngine().getInterWikiURL(link));
248: }
249: return res.toString();
250: } else if (name.equals("inlinedimages")) {
251: StringBuffer res = new StringBuffer();
252:
253: for (Iterator i = context.getEngine()
254: .getAllInlinedImagePatterns().iterator(); i
255: .hasNext();) {
256: if (res.length() > 0)
257: res.append(", ");
258:
259: String ptrn = (String) i.next();
260: res.append(ptrn);
261: }
262:
263: return res.toString();
264: } else if (name.equals("pluginpath")) {
265: String s = context.getEngine().getPluginSearchPath();
266:
267: return (s == null) ? "-" : s;
268: } else if (name.equals("baseurl")) {
269: return context.getEngine().getBaseURL();
270: } else if (name.equals("uptime")) {
271: Date now = new Date();
272: long secondsRunning = (now.getTime() - context.getEngine()
273: .getStartTime().getTime()) / 1000L;
274:
275: long seconds = secondsRunning % 60;
276: long minutes = (secondsRunning /= 60) % 60;
277: long hours = (secondsRunning /= 60) % 24;
278: long days = secondsRunning /= 24;
279:
280: return days + "d, " + hours + "h " + minutes + "m "
281: + seconds + "s";
282: } else if (name.equals("loginstatus")) {
283: WikiSession session = context.getWikiSession();
284: return session.getStatus();
285: } else if (name.equals("username")) {
286: Principal wup = context.getCurrentUser();
287:
288: return wup != null ? wup.getName() : "not logged in";
289: } else if (name.equals("requestcontext")) {
290: return context.getRequestContext();
291: } else if (name.equals("pagefilters")) {
292: List filters = context.getEngine().getFilterManager()
293: .getFilterList();
294: StringBuffer sb = new StringBuffer();
295:
296: for (Iterator i = filters.iterator(); i.hasNext();) {
297: PageFilter pf = (PageFilter) i.next();
298: String f = pf.getClass().getName();
299:
300: if (pf instanceof InternalModule)
301: continue;
302:
303: if (sb.length() > 0)
304: sb.append(", ");
305: sb.append(f);
306: }
307:
308: return sb.toString();
309: } else {
310: //
311: // Check if such a context variable exists,
312: // returning its string representation.
313: //
314: if ((context.getVariable(varName)) != null) {
315: return context.getVariable(varName).toString();
316: }
317:
318: //
319: // Well, I guess it wasn't a final straw. We also allow
320: // variables from the session and the request (in this order).
321: //
322:
323: HttpServletRequest req = context.getHttpRequest();
324: if (req != null && req.getSession() != null) {
325: HttpSession session = req.getSession();
326:
327: try {
328: String s;
329:
330: if ((s = (String) session.getAttribute(varName)) != null)
331: return s;
332:
333: if ((s = context.getHttpParameter(varName)) != null)
334: return s;
335: } catch (ClassCastException e) {
336: }
337: }
338:
339: // And the final straw: see if the current page has named metadata.
340:
341: WikiPage pg = context.getPage();
342: if (pg != null) {
343: Object metadata = pg.getAttribute(varName);
344: if (metadata != null)
345: return metadata.toString();
346: }
347:
348: // And the final straw part 2: see if the "real" current page has
349: // named metadata. This allows a parent page to control a inserted
350: // page through defining variables
351: WikiPage rpg = context.getRealPage();
352: if (rpg != null) {
353: Object metadata = rpg.getAttribute(varName);
354: if (metadata != null)
355: return metadata.toString();
356: }
357:
358: // Next-to-final straw: attempt to fetch using property name
359: // We don't allow fetching any other properties than those starting
360: // with "jspwiki.". I know my own code, but I can't vouch for bugs
361: // in other people's code... :-)
362:
363: if (varName.startsWith("jspwiki.")) {
364: Properties props = context.getEngine()
365: .getWikiProperties();
366:
367: String s = props.getProperty(varName);
368: if (s != null) {
369: return s;
370: }
371: }
372:
373: //
374: // Final defaults for some known quantities.
375: //
376:
377: if (varName.equals(VAR_ERROR) || varName.equals(VAR_MSG))
378: return "";
379:
380: throw new NoSuchVariableException("No variable " + varName
381: + " defined.");
382: }
383: }
384: }
|