001: /*
002: JSPWiki - a JSP-based WikiWiki clone.
003:
004: Copyright (C) 2001-2002 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 java.net.URL;
023: import java.util.*;
024:
025: import javax.servlet.jsp.PageContext;
026:
027: import org.apache.log4j.Logger;
028: import org.jdom.Document;
029: import org.jdom.Element;
030: import org.jdom.JDOMException;
031: import org.jdom.input.SAXBuilder;
032: import org.jdom.xpath.XPath;
033:
034: import com.ecyrd.jspwiki.NoSuchVariableException;
035: import com.ecyrd.jspwiki.WikiContext;
036: import com.ecyrd.jspwiki.WikiEngine;
037: import com.ecyrd.jspwiki.modules.ModuleManager;
038: import com.ecyrd.jspwiki.modules.WikiModuleInfo;
039: import com.ecyrd.jspwiki.plugin.PluginManager;
040: import com.ecyrd.jspwiki.preferences.Preferences;
041:
042: /**
043: * Defines an editor manager. An editor can be added by adding a
044: * suitable JSP file under templates/default/editors
045: * If you want your editor to include any scripts or something, you
046: * can simply request it by adding the following in your
047: * ini/jspwiki_module.xml:
048: *
049: * <pre>
050: * <modules>
051: * <editor name="myeditor">
052: * <author>Janne Jalkanen</author>
053: * <script>foo.js</script>
054: * <stylesheet>foo.css</stylesheet>
055: * <path>editors/myeditor.jsp</path>
056: * </editor>
057: * </modules>
058: * </pre>
059: *
060: * @author jalkanen
061: * @author Christoph Sauer
062: * @author Chuck Smith
063: * @author Dirk Frederickx
064: * @since 2.4
065: */
066: public class EditorManager extends ModuleManager {
067: /** The property name for setting the editor. Current value is "jspwiki.editor" */
068: /* not used anymore -- replaced by defaultpref.template.editor */
069: public static final String PROP_EDITORTYPE = "jspwiki.editor";
070:
071: /** Parameter for changing editors at run-time */
072: public static final String PARA_EDITOR = "editor";
073:
074: /** Known name for the plain wikimarkup editor. */
075: public static final String EDITOR_PLAIN = "plain";
076:
077: /** Known name for the preview editor component. */
078: public static final String EDITOR_PREVIEW = "preview";
079:
080: /** Known attribute name for storing the user edited text inside a HTTP parameter. */
081: public static final String REQ_EDITEDTEXT = "_editedtext";
082:
083: /** Known attribute name for storing the user edited text inside a session or a page context */
084: public static final String ATTR_EDITEDTEXT = REQ_EDITEDTEXT;
085:
086: private Map m_editors;
087:
088: private static Logger log = Logger.getLogger(EditorManager.class);
089:
090: public EditorManager(WikiEngine engine) {
091: super (engine);
092: }
093:
094: /**
095: * Initializes the EditorManager. It also registers any editors it can find.
096: *
097: * @param props Properties for setup.
098: */
099: public void initialize(Properties props) {
100: registerEditors();
101: }
102:
103: /**
104: * This method goes through the jspwiki_module.xml files and hunts for editors.
105: * Any editors found are put in the registry.
106: *
107: */
108: private void registerEditors() {
109: log.info("Registering editor modules");
110:
111: m_editors = new HashMap();
112: SAXBuilder builder = new SAXBuilder();
113:
114: try {
115: //
116: // Register all editors which have created a resource containing its properties.
117: //
118: // Get all resources of all modules
119: //
120:
121: Enumeration resources = getClass().getClassLoader()
122: .getResources(PLUGIN_RESOURCE_LOCATION);
123:
124: while (resources.hasMoreElements()) {
125: URL resource = (URL) resources.nextElement();
126:
127: try {
128: log.debug("Processing XML: " + resource);
129:
130: Document doc = builder.build(resource);
131:
132: List plugins = XPath.selectNodes(doc,
133: "/modules/editor");
134:
135: for (Iterator i = plugins.iterator(); i.hasNext();) {
136: Element pluginEl = (Element) i.next();
137:
138: String name = pluginEl
139: .getAttributeValue("name");
140:
141: WikiEditorInfo info = WikiEditorInfo
142: .newInstance(name, pluginEl);
143:
144: if (checkCompatibility(info)) {
145: m_editors.put(name, info);
146:
147: log.debug("Registered editor " + name);
148: } else {
149: log
150: .info("Editor '"
151: + name
152: + "' not compatible with this version of JSPWiki.");
153: }
154: }
155: } catch (java.io.IOException e) {
156: log.error("Couldn't load "
157: + PluginManager.PLUGIN_RESOURCE_LOCATION
158: + " resources: " + resource, e);
159: } catch (JDOMException e) {
160: log.error("Error parsing XML for plugin: "
161: + PluginManager.PLUGIN_RESOURCE_LOCATION);
162: }
163: }
164: } catch (java.io.IOException e) {
165: log.error("Couldn't load all " + PLUGIN_RESOURCE_LOCATION
166: + " resources", e);
167: }
168: }
169:
170: /**
171: * Returns an editor for the current context. The editor names are matched in
172: * a case insensitive manner. At the moment, the only place that this method
173: * looks in is the property file, but in the future this will also look at
174: * user preferences.
175: * <p>
176: * Determines the editor to use by the following order of conditions:
177: * 1. Editor set in User Preferences
178: * 2. Default Editor set in jspwiki.properties
179: * <p>
180: * For the PREVIEW context, this method returns the "preview" editor.
181: *
182: * @param context The context that is chosen.
183: * @return The name of the chosen editor. If no match could be found, will
184: * revert to the default "plain" editor.
185: */
186: public String getEditorName(WikiContext context) {
187: if (context.getRequestContext().equals(WikiContext.PREVIEW))
188: return EDITOR_PREVIEW;
189:
190: String editor = null;
191:
192: // User has set an editor in preferences
193: editor = Preferences.getPreference(context, PARA_EDITOR);
194:
195: /* FIXME: actual default 'editor' property is read by the Preferences class */
196: if (editor == null) {
197: // or use the default editor in jspwiki.properties
198: try {
199: editor = m_engine.getVariableManager().getValue(
200: context, PROP_EDITORTYPE);
201: } catch (NoSuchVariableException e) {
202: } // This is fine
203: }
204:
205: if (editor != null) {
206: String[] editorlist = getEditorList();
207:
208: editor = editor.trim();
209:
210: for (int i = 0; i < editorlist.length; i++) {
211: if (editorlist[i].equalsIgnoreCase(editor)) {
212: return editorlist[i];
213: }
214: }
215: }
216:
217: return EDITOR_PLAIN;
218: }
219:
220: /**
221: * Returns a list of editors as Strings of editor names.
222: *
223: * @return the list of available editors
224: */
225: public String[] getEditorList() {
226: String[] editors = new String[m_editors.size()];
227:
228: Set keys = m_editors.keySet();
229:
230: return (String[]) keys.toArray(editors);
231: }
232:
233: /**
234: * Convenience method for getting the path to the editor JSP file.
235: *
236: * @param context
237: * @return e.g. "editors/plain.jsp"
238: */
239: public String getEditorPath(WikiContext context) {
240: String path = null;
241:
242: String editor = getEditorName(context);
243:
244: WikiEditorInfo ed = (WikiEditorInfo) m_editors.get(editor);
245:
246: if (ed != null) {
247: path = ed.getPath();
248: } else {
249: path = "editors/" + editor + ".jsp";
250: }
251:
252: return path;
253: }
254:
255: /**
256: * Convenience function which examines the current context and attempts to figure
257: * out whether the edited text is in the HTTP request parameters or somewhere in
258: * the session.
259: *
260: * @param ctx the JSP page context
261: * @return the edited text, if present in the session page context or as a parameter
262: */
263: public static String getEditedText(PageContext ctx) {
264: String usertext = ctx.getRequest().getParameter(REQ_EDITEDTEXT);
265:
266: if (usertext == null) {
267: usertext = (String) ctx.findAttribute(ATTR_EDITEDTEXT);
268: }
269:
270: return usertext;
271: }
272:
273: /**
274: * Contains info about an editor.
275: *
276: * @author jalkanen
277: *
278: */
279: private static final class WikiEditorInfo extends WikiModuleInfo {
280: private String m_path;
281:
282: protected static WikiEditorInfo newInstance(String name,
283: Element el) {
284: if (name == null || name.length() == 0)
285: return null;
286: WikiEditorInfo info = new WikiEditorInfo(name);
287:
288: info.initializeFromXML(el);
289: return info;
290: }
291:
292: protected void initializeFromXML(Element el) {
293: super .initializeFromXML(el);
294: m_path = el.getChildText("path");
295: }
296:
297: private WikiEditorInfo(String name) {
298: super (name);
299: }
300:
301: public String getPath() {
302: return m_path;
303: }
304: }
305:
306: public Collection modules() {
307: ArrayList ls = new ArrayList();
308:
309: ls.addAll(m_editors.values());
310:
311: return ls;
312: }
313:
314: }
|