001    /* 
002        Licensed to the Apache Software Foundation (ASF) under one
003        or more contributor license agreements.  See the NOTICE file
004        distributed with this work for additional information
005        regarding copyright ownership.  The ASF licenses this file
006        to you under the Apache License, Version 2.0 (the
007        "License"); you may not use this file except in compliance
008        with the License.  You may obtain a copy of the License at
009    
010           http://www.apache.org/licenses/LICENSE-2.0
011    
012        Unless required by applicable law or agreed to in writing,
013        software distributed under the License is distributed on an
014        "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015        KIND, either express or implied.  See the License for the
016        specific language governing permissions and limitations
017        under the License.  
018     */
019    package org.apache.wiki.ui;
020    
021    import java.util.ArrayList;
022    import java.util.Collection;
023    import java.util.HashMap;
024    import java.util.Iterator;
025    import java.util.List;
026    import java.util.Map;
027    import java.util.Properties;
028    import java.util.Set;
029    
030    import javax.servlet.jsp.PageContext;
031    
032    import org.apache.log4j.Logger;
033    import org.apache.wiki.WikiContext;
034    import org.apache.wiki.WikiEngine;
035    import org.apache.wiki.api.exceptions.NoSuchVariableException;
036    import org.apache.wiki.modules.ModuleManager;
037    import org.apache.wiki.modules.WikiModuleInfo;
038    import org.apache.wiki.preferences.Preferences;
039    import org.apache.wiki.util.XmlUtil;
040    import org.jdom2.Element;
041    
042    
043    /**
044     *  Defines an editor manager.  An editor can be added by adding a
045     *  suitable JSP file under templates/default/editors
046     *  If you want your editor to include any scripts or something, you
047     *  can simply request it by adding the following in your
048     *  ini/jspwiki_module.xml:
049     *
050     *  <pre>
051     *  <modules>
052     *   <editor name="myeditor">
053     *       <author>Janne Jalkanen</author>
054     *       <script>foo.js</script>
055     *       <stylesheet>foo.css</stylesheet>
056     *       <path>editors/myeditor.jsp</path>
057     *   </editor>
058     *  </modules>
059     *  </pre>
060     *
061     *  @since 2.4
062     */
063    public class EditorManager extends ModuleManager {
064    
065        /** The property name for setting the editor.  Current value is "jspwiki.editor" */
066        /* not used anymore -- replaced by defaultpref.template.editor */
067        public static final String       PROP_EDITORTYPE = "jspwiki.editor";
068    
069        /** Parameter for changing editors at run-time */
070        public static final String       PARA_EDITOR     = "editor";
071    
072        /** Known name for the plain wikimarkup editor. */
073        public static final String       EDITOR_PLAIN    = "plain";
074    
075        /** Known name for the preview editor component. */
076        public static final String       EDITOR_PREVIEW  = "preview";
077    
078        /** Known attribute name for storing the user edited text inside a HTTP parameter. */
079        public static final String       REQ_EDITEDTEXT  = "_editedtext";
080    
081        /** Known attribute name for storing the user edited text inside a session or a page context */
082        public static final String       ATTR_EDITEDTEXT = REQ_EDITEDTEXT;
083    
084        private             Map<String, WikiEditorInfo>  m_editors;
085    
086        private static      Logger       log             = Logger.getLogger( EditorManager.class );
087    
088        public EditorManager( WikiEngine engine )
089        {
090            super(engine);
091        }
092    
093        /**
094         *  Initializes the EditorManager.  It also registers any editors it can find.
095         *
096         *  @param props  Properties for setup.
097         */
098        public void initialize( Properties props )
099        {
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            m_editors = new HashMap<String, WikiEditorInfo>();
111    
112            //
113            // Register all editors which have created a resource containing its properties.
114            //
115            // Get all resources of all modules
116            //
117            List< Element > editors = XmlUtil.parse( PLUGIN_RESOURCE_LOCATION, "/modules/editor" );
118    
119            for( Iterator< Element > i = editors.iterator(); i.hasNext(); ) {
120                Element pluginEl = i.next();
121                String name = pluginEl.getAttributeValue( "name" );
122                WikiEditorInfo info = WikiEditorInfo.newInstance( name, pluginEl );
123    
124                if( checkCompatibility(info) ) {
125                    m_editors.put( name, info );
126                    log.debug( "Registered editor " + name );
127                } else {
128                    log.info( "Editor '" + name + "' not compatible with this version of JSPWiki." );
129                }
130            }
131        }
132    
133        /**
134         *  Returns an editor for the current context.  The editor names are matched in
135         *  a case insensitive manner.  At the moment, the only place that this method
136         *  looks in is the property file, but in the future this will also look at
137         *  user preferences.
138         *  <p>
139         *  Determines the editor to use by the following order of conditions:
140         *  1. Editor set in User Preferences
141         *  2. Default Editor set in jspwiki.properties
142         *  <p>
143         *  For the PREVIEW context, this method returns the "preview" editor.
144         *
145         * @param context The context that is chosen.
146         * @return The name of the chosen editor.  If no match could be found, will
147         *         revert to the default "plain" editor.
148         */
149        public String getEditorName( WikiContext context )
150        {
151            if( context.getRequestContext().equals(WikiContext.PREVIEW) )
152                return EDITOR_PREVIEW;
153    
154            String editor = null;
155    
156            // User has set an editor in preferences
157            editor = Preferences.getPreference( context, PARA_EDITOR );
158    
159            /* FIXME: actual default 'editor' property is read by the Preferences class */
160            if (editor == null)
161            {
162                // or use the default editor in jspwiki.properties
163                try
164                {
165                    editor = m_engine.getVariableManager().getValue( context, PROP_EDITORTYPE );
166                }
167                catch( NoSuchVariableException e ) {} // This is fine
168            }
169    
170            if (editor != null)
171            {
172                String[] editorlist = getEditorList();
173    
174                editor = editor.trim();
175    
176                for( int i = 0; i < editorlist.length; i++ )
177                {
178                    if( editorlist[i].equalsIgnoreCase(editor))
179                    {
180                        return editorlist[i];
181                    }
182                }
183            }
184    
185            return EDITOR_PLAIN;
186        }
187    
188        /**
189         *  Returns a list of editors as Strings of editor names.
190         *
191         *  @return the list of available editors
192         */
193        public String[] getEditorList()
194        {
195            String[] editors = new String[m_editors.size()];
196    
197            Set<String> keys = m_editors.keySet();
198    
199            return keys.toArray( editors );
200        }
201    
202        /**
203         *  Convenience method for getting the path to the editor JSP file.
204         *
205         *  @param context
206         *  @return e.g. "editors/plain.jsp"
207         */
208        public String getEditorPath( WikiContext context )
209        {
210            String path = null;
211    
212            String editor = getEditorName( context );
213    
214            WikiEditorInfo ed = m_editors.get( editor );
215    
216            if( ed != null )
217            {
218                path = ed.getPath();
219            }
220            else
221            {
222                path = "editors/"+editor+".jsp";
223            }
224    
225            return path;
226        }
227    
228        /**
229         *  Convenience function which examines the current context and attempts to figure
230         *  out whether the edited text is in the HTTP request parameters or somewhere in
231         *  the session.
232         *
233         *  @param ctx the JSP page context
234         *  @return the edited text, if present in the session page context or as a parameter
235         */
236        public static String getEditedText( PageContext ctx )
237        {
238            String usertext = ctx.getRequest().getParameter( REQ_EDITEDTEXT );
239    
240            if( usertext == null )
241            {
242                usertext = (String)ctx.findAttribute( ATTR_EDITEDTEXT );
243            }
244    
245            return usertext;
246        }
247    
248        /**
249         *  Contains info about an editor.
250         *
251         */
252        private static final class WikiEditorInfo
253            extends WikiModuleInfo
254        {
255            private String m_path;
256    
257            protected static WikiEditorInfo newInstance( String name, Element el )
258            {
259                if( name == null || name.length() == 0 ) return null;
260                WikiEditorInfo info = new WikiEditorInfo( name );
261    
262                info.initializeFromXML( el );
263                return info;
264            }
265    
266            protected void initializeFromXML( Element el )
267            {
268                super.initializeFromXML( el );
269                m_path = el.getChildText("path");
270            }
271    
272            private WikiEditorInfo( String name )
273            {
274                super(name);
275            }
276    
277            public String getPath()
278            {
279                return m_path;
280            }
281        }
282    
283        public Collection modules()
284        {
285            ArrayList<WikiModuleInfo> ls = new ArrayList<WikiModuleInfo>();
286    
287            ls.addAll( m_editors.values() );
288    
289            return ls;
290        }
291    
292    }