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 ) {} // This is fine
116        }
117
118        if( editor != null ) {
119            final String[] editorlist = getEditorList();
120            editor = editor.trim();
121            for( final String s : editorlist ) {
122                if( s.equalsIgnoreCase( editor ) ) {
123                    return s;
124                }
125            }
126        }
127
128        return EDITOR_PLAIN;
129    }
130
131    /** {@inheritDoc} */
132    @Override
133    public String[] getEditorList() {
134        final String[] editors = new String[ m_editors.size() ];
135        final Set< String > keys = m_editors.keySet();
136
137        return keys.toArray( editors );
138    }
139
140    /** {@inheritDoc} */
141    @Override
142    public String getEditorPath( final Context context ) {
143        final String editor = getEditorName( context );
144        final WikiEditorInfo ed = m_editors.get( editor );
145        final String path;
146        if( ed != null ) {
147            path = ed.getPath();
148        } else {
149            path = "editors/"+editor+".jsp";
150        }
151
152        return path;
153    }
154
155    /**  Contains info about an editor. */
156    private static final class WikiEditorInfo extends WikiModuleInfo {
157        private String m_path;
158
159        static WikiEditorInfo newInstance( final String name, final Element el ) {
160            if( name == null || name.isEmpty() ) {
161                return null;
162            }
163            final WikiEditorInfo info = new WikiEditorInfo( name );
164            info.initializeFromXML( el );
165            return info;
166        }
167
168        /** {@inheritDoc} */
169        @Override
170        protected void initializeFromXML( final Element el ) {
171            super.initializeFromXML( el );
172            m_path = el.getChildText("path");
173        }
174
175        private WikiEditorInfo( final String name ) {
176            super( name );
177        }
178
179        public String getPath() {
180            return m_path;
181        }
182    }
183
184    /** {@inheritDoc} */
185    @Override
186    public Collection< WikiModuleInfo > modules() {
187        return modules( m_editors.values().iterator() );
188    }
189
190    /** {@inheritDoc} */
191    @Override
192    public WikiEditorInfo getModuleInfo( final String moduleName ) {
193        return m_editors.get( moduleName );
194    }
195
196}