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 */
019package org.apache.wiki.ui;
020
021import org.apache.log4j.Logger;
022import org.apache.wiki.api.core.Context;
023import org.apache.wiki.api.core.ContextEnum;
024import org.apache.wiki.api.core.Engine;
025import org.apache.wiki.api.exceptions.NoSuchVariableException;
026import org.apache.wiki.modules.BaseModuleManager;
027import org.apache.wiki.modules.WikiModuleInfo;
028import org.apache.wiki.preferences.Preferences;
029import org.apache.wiki.util.XmlUtil;
030import org.apache.wiki.variables.VariableManager;
031import org.jdom2.Element;
032
033import java.util.Collection;
034import java.util.HashMap;
035import java.util.List;
036import java.util.Map;
037import java.util.Properties;
038import java.util.Set;
039
040
041/**
042 *  Defines an editor manager.  An editor can be added by adding a suitable JSP file under templates/default/editors
043 *  If you want your editor to include any scripts or something, you can simply request it by adding the following in your
044 *  {@code ini/jspwiki_module.xml}:
045 *
046 *  <pre>
047 *  &lt;modules>
048 *   &lt;editor name="myeditor">
049 *       &lt;author>Janne Jalkanen&lt;/author>
050 *       &lt;script>foo.js&lt;/script>
051 *       &lt;stylesheet>foo.css&lt;/stylesheet>
052 *       &lt;path>editors/myeditor.jsp&lt;/path>
053 *   &lt;/editor>
054 *  &lt;/modules>
055 *  </pre>
056 *
057 *  @since 2.4
058 */
059public class DefaultEditorManager extends BaseModuleManager implements EditorManager {
060
061    private Map< String, WikiEditorInfo > m_editors;
062
063    private static final Logger log = Logger.getLogger( DefaultEditorManager.class );
064
065    public DefaultEditorManager( final Engine engine ) {
066        super( engine );
067    }
068
069    /**
070     * {@inheritDoc}
071     *
072     * Initializes the EditorManager.  It also registers any editors it can find.
073     */
074    @Override
075    public void initialize( final Engine engine, final Properties props ) {
076        registerEditors();
077    }
078
079    /** This method goes through the jspwiki_module.xml files and hunts for editors. Any editors found are put in the registry. */
080    private void registerEditors() {
081        log.info( "Registering editor modules" );
082        m_editors = new HashMap<>();
083
084        // Register all editors which have created a resource containing its properties. Get all resources of all modules
085        final List< Element > editors = XmlUtil.parse( PLUGIN_RESOURCE_LOCATION, "/modules/editor" );
086        for( final Element pluginEl : editors ) {
087            final String name = pluginEl.getAttributeValue( "name" );
088            final WikiEditorInfo info = WikiEditorInfo.newInstance( name, pluginEl );
089
090            if( checkCompatibility( info ) ) {
091                m_editors.put( name, info );
092                log.debug( "Registered editor " + name );
093            } else {
094                log.info( "Editor '" + name + "' not compatible with this version of JSPWiki." );
095            }
096        }
097    }
098
099    /** {@inheritDoc} */
100    @Override
101    public String getEditorName( final Context context ) {
102        if( context.getRequestContext().equals( ContextEnum.PAGE_PREVIEW.getRequestContext() ) ) {
103            return EDITOR_PREVIEW;
104        }
105
106        // User has set an editor in preferences
107        String editor = Preferences.getPreference( context, PARA_EDITOR );
108
109        /* FIXME: actual default 'editor' property is read by the Preferences class */
110        if( editor == null ) {
111            // or use the default editor in jspwiki.properties
112            try {
113                editor = m_engine.getManager( VariableManager.class ).getValue( context, PROP_EDITORTYPE );
114            } catch( final NoSuchVariableException e ) {} // This is fine
115        }
116
117        if( editor != null ) {
118            final String[] editorlist = getEditorList();
119            editor = editor.trim();
120            for( final String s : editorlist ) {
121                if( s.equalsIgnoreCase( editor ) ) {
122                    return s;
123                }
124            }
125        }
126
127        return EDITOR_PLAIN;
128    }
129
130    /** {@inheritDoc} */
131    @Override
132    public String[] getEditorList() {
133        final String[] editors = new String[ m_editors.size() ];
134        final Set< String > keys = m_editors.keySet();
135
136        return keys.toArray( editors );
137    }
138
139    /** {@inheritDoc} */
140    @Override
141    public String getEditorPath( final Context context ) {
142        final String editor = getEditorName( context );
143        final WikiEditorInfo ed = m_editors.get( editor );
144        final String path;
145        if( ed != null ) {
146            path = ed.getPath();
147        } else {
148            path = "editors/"+editor+".jsp";
149        }
150
151        return path;
152    }
153
154    /**  Contains info about an editor. */
155    private static final class WikiEditorInfo extends WikiModuleInfo {
156        private String m_path;
157
158        protected static WikiEditorInfo newInstance( final String name, final Element el ) {
159            if( name == null || name.length() == 0 ) {
160                return null;
161            }
162            final WikiEditorInfo info = new WikiEditorInfo( name );
163            info.initializeFromXML( el );
164            return info;
165        }
166
167        /** {@inheritDoc} */
168        @Override
169        protected void initializeFromXML( final Element el ) {
170            super.initializeFromXML( el );
171            m_path = el.getChildText("path");
172        }
173
174        private WikiEditorInfo( final String name ) {
175            super( name );
176        }
177
178        public String getPath() {
179            return m_path;
180        }
181    }
182
183    /** {@inheritDoc} */
184    @Override
185    public Collection< WikiModuleInfo > modules() {
186        return modules( m_editors.values().iterator() );
187    }
188
189    /** {@inheritDoc} */
190    @Override
191    public WikiEditorInfo getModuleInfo( final String moduleName ) {
192        return m_editors.get( moduleName );
193    }
194
195}