001/*
002 *  Copyright 2014 Anyware Services
003 *
004 *  Licensed under the Apache License, Version 2.0 (the "License");
005 *  you may not use this file except in compliance with the License.
006 *  You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 *  Unless required by applicable law or agreed to in writing, software
011 *  distributed under the License is distributed on an "AS IS" BASIS,
012 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *  See the License for the specific language governing permissions and
014 *  limitations under the License.
015 */
016package org.ametys.cms.script;
017
018import java.io.File;
019import java.io.IOException;
020import java.io.InputStream;
021import java.util.ArrayList;
022import java.util.Collections;
023import java.util.List;
024import java.util.Map;
025
026import org.apache.avalon.framework.component.Component;
027import org.apache.avalon.framework.configuration.Configuration;
028import org.apache.avalon.framework.configuration.ConfigurationException;
029import org.apache.avalon.framework.configuration.DefaultConfiguration;
030import org.apache.avalon.framework.configuration.DefaultConfigurationBuilder;
031import org.apache.avalon.framework.context.ContextException;
032import org.apache.avalon.framework.context.Contextualizable;
033import org.apache.avalon.framework.logger.AbstractLogEnabled;
034import org.apache.avalon.framework.service.ServiceException;
035import org.apache.avalon.framework.service.ServiceManager;
036import org.apache.avalon.framework.service.Serviceable;
037import org.apache.cocoon.Constants;
038import org.apache.cocoon.environment.Context;
039import org.apache.commons.lang.StringUtils;
040import org.apache.excalibur.source.Source;
041import org.apache.excalibur.source.SourceResolver;
042import org.xml.sax.SAXException;
043
044import org.ametys.core.ui.Callable;
045import org.ametys.core.util.I18nUtils;
046import org.ametys.runtime.i18n.I18nizableText;
047
048/**
049 * Script manager.
050 * Can be used to retrieves global script functions and help text defined in various configuration files
051 */
052public class ScriptManager extends AbstractLogEnabled implements Component, Contextualizable, Serviceable
053{
054    /** The Avalon role */
055    public static final String ROLE = ScriptManager.class.getName();
056    
057    /** The list of script configuration */
058    protected static List<Configuration> _scriptConfigurations;
059    
060    /** Cocoon context */
061    protected Context _context;
062    
063    /** i18n utils */
064    protected I18nUtils _i18nUtils;
065    
066    /** Source resolver */
067    private SourceResolver _sourceResolver;
068    
069    @Override
070    public void contextualize(org.apache.avalon.framework.context.Context context) throws ContextException
071    {
072        _context = (Context) context.get(Constants.CONTEXT_ENVIRONMENT_CONTEXT);
073    }
074    
075    public void service(ServiceManager manager) throws ServiceException
076    {
077        _i18nUtils = (I18nUtils) manager.lookup(I18nUtils.ROLE);
078        _sourceResolver = (SourceResolver) manager.lookup(SourceResolver.ROLE);
079    }
080    
081    /**
082     * Initialize the static script files if needed.
083     * Returns list of configurations for these files.
084     * @return list of configurations
085     * @throws ConfigurationException If the configuration is wrong 
086     * @throws SAXException If an error occurred
087     * @throws IOException If an error occurred
088     */
089    protected List<Configuration> _getScriptConfigurations() throws ConfigurationException, SAXException, IOException
090    {
091        if (_scriptConfigurations == null)
092        {
093            _scriptConfigurations = new ArrayList<>(2);
094            
095            Source pluginScriptsSource = _sourceResolver.resolveURI("plugin:cms://script/scripts.xml");
096            
097            try (InputStream is = pluginScriptsSource.getInputStream())
098            {
099                Configuration pluginScriptsCfg = new DefaultConfigurationBuilder().build(is);
100                _scriptConfigurations.add(pluginScriptsCfg);
101            }
102            
103            File webInfScriptsFile = new File(_context.getRealPath("/WEB-INF/param/scripts.xml"));
104            Configuration webInfScriptsCfg = webInfScriptsFile.exists() ? (DefaultConfiguration) new DefaultConfigurationBuilder().buildFromFile(webInfScriptsFile) : new DefaultConfiguration("scripts");
105            _scriptConfigurations.add(webInfScriptsCfg);
106        }
107        
108        return _scriptConfigurations;
109    }
110    
111    /**
112     * Retrieves the configured scripts
113     * @return a String containing all the configured scripts
114     * @throws IOException If an error occurred
115     * @throws SAXException If an error occurred 
116     * @throws ConfigurationException If the configuration is wrong
117     */
118    public String getGlobalScripts() throws ConfigurationException, SAXException, IOException
119    {
120        List<Configuration> scriptConfigurations = _getScriptConfigurations();
121        StringBuilder sb = new StringBuilder();
122        
123        for (Configuration scriptCfg : scriptConfigurations)
124        {
125            sb.append(scriptCfg.getChild("script").getValue(StringUtils.EMPTY));
126        }
127        
128        return sb.toString();
129    }
130    
131    /**
132     * Retrieves and concatenates the script descriptions
133     * @return a String containing the concatenated description
134     * @throws IOException If an error occurred
135     * @throws SAXException If an error occurred
136     * @throws ConfigurationException If the configuration is wrong
137     */
138    @Callable
139    public Map<String, Object> getScriptHtmlDescription() throws ConfigurationException, SAXException, IOException
140    {
141        List<Configuration> scriptConfigurations = _getScriptConfigurations();
142        StringBuilder sb = new StringBuilder();
143        
144        // Base description
145        sb.append(_i18nUtils.translate(new I18nizableText("plugin.cms", "UITOOL_SCRIPT_SEARCH_HELP_BASE_DESCRIPTION"))).append("<br/><br/>");
146        
147        // Description from files
148        for (Configuration scriptCfg : scriptConfigurations)
149        {
150            I18nizableText i18nDesc = _parseI18nizableText(scriptCfg, "cms", "description");
151            String desc = _i18nUtils.translate(i18nDesc);
152            
153            if (StringUtils.isNotEmpty(desc))
154            {
155                sb.append(desc).append("<br/><br/>");
156            }
157        }
158        
159        return Collections.singletonMap("description", (Object) sb.toString());
160    }
161    
162    /**
163     * Parses an i18n text.
164     * @param config the configuration to use.
165     * @param pluginName the current plugin name.
166     * @param name the child name.
167     * @return the i18n text.
168     */
169    protected I18nizableText _parseI18nizableText(Configuration config, String pluginName, String name)
170    {
171        return I18nizableText.parseI18nizableText(config.getChild(name), "plugin." + pluginName, "");
172    }
173}