001/*
002 *  Copyright 2016 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.plugins.core.impl.schedule;
017
018import java.util.LinkedHashMap;
019import java.util.Map;
020
021import org.apache.avalon.framework.component.Component;
022import org.apache.avalon.framework.configuration.Configurable;
023import org.apache.avalon.framework.configuration.Configuration;
024import org.apache.avalon.framework.configuration.ConfigurationException;
025import org.apache.avalon.framework.context.Context;
026import org.apache.avalon.framework.context.ContextException;
027import org.apache.avalon.framework.context.Contextualizable;
028import org.apache.avalon.framework.service.ServiceException;
029import org.apache.avalon.framework.service.ServiceManager;
030import org.apache.avalon.framework.service.Serviceable;
031import org.quartz.JobExecutionContext;
032
033import org.ametys.core.schedule.Schedulable;
034import org.ametys.runtime.i18n.I18nizableText;
035import org.ametys.runtime.parameter.AbstractParameterParser;
036import org.ametys.runtime.parameter.Enumerator;
037import org.ametys.runtime.parameter.Parameter;
038import org.ametys.runtime.parameter.ParameterHelper;
039import org.ametys.runtime.parameter.ParameterHelper.ParameterType;
040import org.ametys.runtime.parameter.Validator;
041import org.ametys.runtime.plugin.component.AbstractLogEnabled;
042import org.ametys.runtime.plugin.component.PluginAware;
043import org.ametys.runtime.plugin.component.ThreadSafeComponentManager;
044
045/**
046 * Default static implementation of {@link Schedulable}
047 * For implementing the {@link Schedulable} interface (while being {@link Configurable}), extends this class and implements the {@link #execute(org.quartz.JobExecutionContext)} method
048 * <br>
049 * For instance:
050 * <pre>
051 * public class SayHelloSchedulable extends AbstractStaticSchedulable
052 * {
053 *     public static final String FIRSTNAME_KEY = "firstName";
054 *     
055 *     private static final String __JOBDATAMAP_FIRSTNAME_KEY = Scheduler.PARAM_VALUES_PREFIX + FIRSTNAME_KEY;
056 *     
057 *     public void execute(JobExecutionContext context) throws Exception
058 *     {
059 *         JobKey jobKey = context.getJobDetail().getKey();
060 *         JobDataMap jobDataMap = context.getJobDetail().getJobDataMap();
061 *         String name = jobDataMap.getString(__JOBDATAMAP_FIRSTNAME_KEY);
062 *         System.out.println("[" + jobKey + "] " + new Date() + " - Hello  " + name + "!");
063 *     }
064 * }
065 * </pre>
066 */
067public abstract class AbstractStaticSchedulable extends AbstractLogEnabled implements Schedulable, Component, Configurable, PluginAware, Serviceable, Contextualizable
068{
069    /** The name of the plugin that has declared this component */
070    protected String _pluginName;
071    /** The id of this extension */
072    protected String _id;
073    /** The service manager */
074    protected ServiceManager _smanager;
075    /** The context */
076    protected Context _context;
077    /** The label */
078    protected I18nizableText _label;
079    /** The description */
080    protected I18nizableText _description;
081    /** The icon glyph */
082    protected String _iconGlyph;
083    /** The small icon */
084    protected String _iconSmall;
085    /** The medium icon */
086    protected String _iconMedium;
087    /** The large icon */
088    protected String _iconLarge;
089    /** True if the schedulable is private */
090    protected boolean _private;
091    /** True if two runnables of this schedulable can be executed concurrently */
092    protected boolean _acceptConcurrentExecution;
093    /** The parameters */
094    protected Map<String, Parameter<ParameterType>> _parameters;
095    
096    @Override
097    public void setPluginInfo(String pluginName, String featureName, String id)
098    {
099        _pluginName = pluginName;
100        _id = id;
101    }
102    
103    @Override
104    public void contextualize(Context context) throws ContextException
105    {
106        _context = context;
107    }
108    
109    @Override
110    public void service(ServiceManager manager) throws ServiceException
111    {
112        _smanager = manager;
113    }
114    
115    @Override
116    public void configure(Configuration configuration) throws ConfigurationException
117    {
118        _label = I18nizableText.parseI18nizableText(configuration.getChild("label"), "plugin." + _pluginName);
119        _description = I18nizableText.parseI18nizableText(configuration.getChild("description"), "plugin." + _pluginName);
120        _iconGlyph = configuration.getChild("icon-glyph").getValue("");
121        _iconSmall = configuration.getChild("icon-small").getValue("");
122        _iconMedium = configuration.getChild("icon-medium").getValue("");
123        _iconLarge = configuration.getChild("icon-large").getValue("");
124        _private = configuration.getChild("private").getValueAsBoolean(false);
125        _acceptConcurrentExecution = configuration.getChild("acceptConcurrentExecution").getValueAsBoolean(true);
126        _configureParameters(configuration.getChild("parameters"));
127    }
128    
129    private void _configureParameters(Configuration paramConfigs) throws ConfigurationException
130    {
131        _parameters = new LinkedHashMap<>();
132        
133        ThreadSafeComponentManager<Validator> validatorManager = new ThreadSafeComponentManager<>();
134        validatorManager.setLogger(getLogger());
135        validatorManager.contextualize(_context);
136        validatorManager.service(_smanager);
137        
138        ThreadSafeComponentManager<Enumerator> enumeratorManager = new ThreadSafeComponentManager<>();
139        enumeratorManager.setLogger(getLogger());
140        enumeratorManager.contextualize(_context);
141        enumeratorManager.service(_smanager);
142        
143        SchedulableParameterParser paramParser = new SchedulableParameterParser(enumeratorManager, validatorManager);
144        for (Configuration paramConf : paramConfigs.getChildren("param"))
145        {
146            Parameter<ParameterType> parameter = paramParser.parseParameter(_smanager, _pluginName, paramConf);
147            String id = parameter.getId();
148            
149            if (_parameters.containsKey(id))
150            {
151                throw new ConfigurationException("The parameter '" + id + "' is already declared. IDs must be unique.", paramConf);
152            }
153            
154            _parameters.put(id, parameter);
155        }
156        
157        try
158        {
159            paramParser.lookupComponents();
160        }
161        catch (Exception e)
162        {
163            throw new ConfigurationException("Unable to lookup parameter local components", paramConfigs, e);
164        }
165    }
166    
167    @Override
168    public abstract void execute(JobExecutionContext context) throws Exception;
169    
170    @Override
171    public String getId()
172    {
173        return _id;
174    }
175
176    @Override
177    public I18nizableText getLabel()
178    {
179        return _label;
180    }
181
182    @Override
183    public I18nizableText getDescription()
184    {
185        return _description;
186    }
187
188    @Override
189    public String getIconGlyph()
190    {
191        return _iconGlyph;
192    }
193
194    @Override
195    public String getIconSmall()
196    {
197        return _iconSmall;
198    }
199
200    @Override
201    public String getIconMedium()
202    {
203        return _iconMedium;
204    }
205
206    @Override
207    public String getIconLarge()
208    {
209        return _iconLarge;
210    }
211    
212    @Override
213    public boolean isPrivate()
214    {
215        return _private;
216    }
217    
218    @Override
219    public boolean acceptConcurrentExecution()
220    {
221        return _acceptConcurrentExecution;
222    }
223
224    @Override
225    public Map<String, Parameter<ParameterType>> getParameters()
226    {
227        return _parameters;
228    }
229    
230    /**
231     * Class for parsing parameters of a {@link Schedulable}
232     */
233    public class SchedulableParameterParser extends AbstractParameterParser<Parameter<ParameterType>, ParameterType>
234    {
235        /**
236         * Constructor
237         * @param enumeratorManager The manager for enumeration
238         * @param validatorManager The manager for validation
239         */
240        public SchedulableParameterParser(ThreadSafeComponentManager<Enumerator> enumeratorManager, ThreadSafeComponentManager<Validator> validatorManager)
241        {
242            super(enumeratorManager, validatorManager);
243        }
244        
245        @Override
246        protected Parameter<ParameterType> _createParameter(Configuration parameterConfig) throws ConfigurationException
247        {
248            return new Parameter<>();
249        }
250        
251        @Override
252        protected String _parseId(Configuration parameterConfig) throws ConfigurationException
253        {
254            return parameterConfig.getAttribute("id");
255        }
256        
257        @Override
258        protected ParameterType _parseType(Configuration parameterConfig) throws ConfigurationException
259        {
260            try
261            {
262                return ParameterType.valueOf(parameterConfig.getAttribute("type").toUpperCase());
263            }
264            catch (IllegalArgumentException e)
265            {
266                throw new ConfigurationException("Invalid parameter type", parameterConfig, e);
267            }
268        }
269        
270        @Override
271        protected Object _parseDefaultValue(Configuration parameterConfig, Parameter<ParameterType> parameter) throws ConfigurationException
272        {
273            String defaultValue = parameterConfig.getChild("default-value").getValue(null);
274            return ParameterHelper.castValue(defaultValue, parameter.getType());
275        }
276        
277        @Override
278        protected void _additionalParsing(ServiceManager manager, String pluginName, Configuration parameterConfig, String parameterId, Parameter<ParameterType> parameter)
279                throws ConfigurationException
280        {
281            super._additionalParsing(manager, pluginName, parameterConfig, parameterId, parameter);
282            parameter.setId(parameterId);
283        }
284    }
285}