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