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.HashMap; 019import java.util.List; 020import java.util.Map; 021 022import org.apache.avalon.framework.component.Component; 023import org.apache.avalon.framework.configuration.Configurable; 024import org.apache.avalon.framework.configuration.Configuration; 025import org.apache.avalon.framework.configuration.ConfigurationException; 026import org.apache.avalon.framework.service.ServiceException; 027import org.apache.avalon.framework.service.ServiceManager; 028import org.apache.avalon.framework.service.Serviceable; 029import org.apache.commons.lang3.StringUtils; 030 031import org.ametys.core.schedule.Runnable; 032import org.ametys.core.schedule.RunnableExtensionPoint; 033import org.ametys.core.schedule.Schedulable; 034import org.ametys.core.schedule.SchedulableExtensionPoint; 035import org.ametys.core.user.UserIdentity; 036import org.ametys.core.user.population.UserPopulationDAO; 037import org.ametys.runtime.i18n.I18nizableText; 038import org.ametys.runtime.model.ElementDefinition; 039import org.ametys.runtime.model.ModelHelper; 040import org.ametys.runtime.plugin.component.PluginAware; 041 042/** 043 * Static implementation of {@link Runnable} which is configurable 044 */ 045public class StaticRunnable implements Runnable, Component, Configurable, PluginAware, Serviceable 046{ 047 /** The extension point for {@link Schedulable}s */ 048 protected SchedulableExtensionPoint _schedulableEP; 049 /** The name of the plugin that declared this component */ 050 protected String _pluginName; 051 /** The name of the feature that declared this component */ 052 protected String _featureName; 053 /** The id of this extension */ 054 protected String _id; 055 /** The label */ 056 protected I18nizableText _label; 057 /** The description */ 058 protected I18nizableText _description; 059 /** The fire process */ 060 protected FireProcess _fireProcess; 061 /** The CRON expression for scheduling the job */ 062 protected String _cronExpression; 063 /** The id of the {@link Schedulable} to execute */ 064 protected String _schedulableId; 065 /** Can the runnable be removed */ 066 protected boolean _removable; 067 /** Can the runnable be edited */ 068 protected boolean _modifiable; 069 /** Can the runnable be deactivated */ 070 protected boolean _deactivatable; 071 /** The misfire policy. Default to MisfirePolicy#DO_NOTHING */ 072 protected MisfirePolicy _misfirePolicy; 073 /** The parameter values */ 074 protected Map<String, Object> _parameterValues; 075 076 @Override 077 public void service(ServiceManager manager) throws ServiceException 078 { 079 _schedulableEP = (SchedulableExtensionPoint) manager.lookup(SchedulableExtensionPoint.ROLE); 080 } 081 082 @Override 083 public void setPluginInfo(String pluginName, String featureName, String id) 084 { 085 _pluginName = pluginName; 086 _featureName = featureName; 087 _id = id; 088 } 089 090 @Override 091 public void configure(Configuration configuration) throws ConfigurationException 092 { 093 _label = I18nizableText.parseI18nizableText(configuration.getChild("label"), "plugin." + _pluginName); 094 _description = I18nizableText.parseI18nizableText(configuration.getChild("description"), "plugin." + _pluginName); 095 _fireProcess = FireProcess.valueOf(configuration.getChild("fire-process").getValue("cron").toUpperCase()); 096 _cronExpression = configuration.getChild("cron").getValue("0 0 2 * * ? *"); 097 _schedulableId = configuration.getChild("schedulableId").getValue(); 098 if (!_schedulableEP.hasExtension(_schedulableId)) 099 { 100 String message = String.format("The extension '%s' of point '%s' declared in the feature '%s' in the plugin '%s' references the Schedulable extension '%s' but it seems to not exist.", 101 _id, RunnableExtensionPoint.class.getName(), _featureName, _pluginName, _schedulableId); 102 throw new ConfigurationException(message, configuration); 103 } 104 105 _removable = configuration.getChild("removable").getValueAsBoolean(false); 106 _modifiable = configuration.getChild("modifiable").getValueAsBoolean(false); 107 _deactivatable = configuration.getChild("deactivatable").getValueAsBoolean(false); 108 _misfirePolicy = MisfirePolicy.valueOf(configuration.getChild("misfire-policy").getValue("do_nothing").toUpperCase()); 109 _configureParameterValues(configuration.getChild("parameters")); 110 } 111 112 @Override 113 public String getId() 114 { 115 return _id; 116 } 117 118 @Override 119 public I18nizableText getLabel() 120 { 121 return _label; 122 } 123 124 @Override 125 public I18nizableText getDescription() 126 { 127 return _description; 128 } 129 130 @Override 131 public FireProcess getFireProcess() 132 { 133 return _fireProcess; 134 } 135 136 @Override 137 public String getCronExpression() 138 { 139 return _cronExpression; 140 } 141 142 @Override 143 public String getSchedulableId() 144 { 145 return _schedulableId; 146 } 147 148 @Override 149 public boolean isRemovable() 150 { 151 return _removable; 152 } 153 154 @Override 155 public boolean isModifiable() 156 { 157 return _modifiable; 158 } 159 160 @Override 161 public boolean isDeactivatable() 162 { 163 return _deactivatable; 164 } 165 166 @Override 167 public MisfirePolicy getMisfirePolicy() 168 { 169 return _misfirePolicy; 170 } 171 172 @Override 173 public boolean isVolatile() 174 { 175 // A configurable runnable is read every time the server restart, so it must be volatile 176 return true; 177 } 178 179 @Override 180 public Map<String, Object> getParameterValues() 181 { 182 return _parameterValues; 183 } 184 185 /** 186 * Configure the values of the parameters 187 * @param paramConfigs the configurations of the parameter values 188 * @throws ConfigurationException if an error occurs 189 */ 190 protected void _configureParameterValues(Configuration paramConfigs) throws ConfigurationException 191 { 192 _parameterValues = new HashMap<>(); 193 194 Schedulable schedulable = _schedulableEP.getExtension(_schedulableId); 195 Map<String, ElementDefinition> declaredParameters = schedulable.getParameters(); 196 197 for (String paramId : declaredParameters.keySet()) 198 { 199 ElementDefinition definition = declaredParameters.get(paramId); 200 Object typedValue = null; 201 202 Configuration paramConf = paramConfigs.getChild(paramId, false); 203 if (paramConf != null) 204 { 205 String valueAsString = paramConf.getValue(StringUtils.EMPTY); 206 typedValue = definition.getType().castValue(valueAsString); 207 } 208 209 List<I18nizableText> errors = ModelHelper.validateValue(definition, typedValue); 210 if (errors.isEmpty()) 211 { 212 _parameterValues.put(paramId, typedValue); 213 } 214 else 215 { 216 StringBuilder message = new StringBuilder("The parameter '").append(paramId).append("' is not valid for the Runnable of id '").append(_id).append("':"); 217 for (I18nizableText error : errors) 218 { 219 message.append("\n* " + error.toString()); 220 } 221 222 throw new ConfigurationException(message.toString(), paramConfigs); 223 } 224 } 225 } 226 227 @Override 228 public UserIdentity getUserIdentity() 229 { 230 return UserPopulationDAO.SYSTEM_USER_IDENTITY; 231 } 232}