1 /**
2 * Copyright 2005-2008 the original author or authors.
3 *
4 * Licensed under the Gnu General Pubic License, Version 2.0 (the
5 * "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.opensource.org/licenses/gpl-license.php
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 * See the Gnu General Public License for more details.
14 */
15 package org.figure8.join.control.action;
16
17 import org.figure8.join.control.JoinAction;
18 import org.figure8.join.control.form.QuartzCronForm;
19 import org.figure8.join.core.Configurable;
20 import org.figure8.join.core.ContainerContextHandler;
21 import org.figure8.join.core.DuplicateEntityException;
22 import org.figure8.join.core.setup.BootstrapUtil;
23 import org.figure8.join.core.setup.BootstrapManager;
24 import org.figure8.join.services.scheduling.QuartzCronInfo;
25 import org.figure8.join.services.scheduling.QuartzCronManager;
26 import org.figure8.join.services.scheduling.QuartzCronParameterInfo;
27 import org.figure8.join.services.security.InvalidLoginException;
28 import org.figure8.join.services.remoting.CronService;
29 import org.figure8.join.services.remoting.services.BeansHelper;
30 import org.figure8.join.services.remoting.beans.RemoteQuartzCronInfo;
31 import org.figure8.join.businessobjects.security.User;
32 import org.figure8.join.util.ScriptLogAccessorProxy;
33 import org.figure8.join.util.LogUtil;
34
35 import org.apache.commons.logging.Log;
36 import org.apache.commons.beanutils.PropertyUtils;
37 import org.apache.struts.action.ActionForm;
38 import org.apache.struts.action.ActionForward;
39 import org.apache.struts.action.ActionMapping;
40
41 import com.caucho.hessian.client.HessianProxyFactory;
42
43 import javax.servlet.http.HttpSession;
44 import javax.servlet.http.HttpServletRequest;
45 import javax.servlet.http.HttpServletResponse;
46
47 import java.io.IOException;
48 import java.io.InputStream;
49 import java.io.ByteArrayInputStream;
50 import java.util.List;
51 import java.util.Iterator;
52 import java.util.Properties;
53 import java.util.Enumeration;
54 import java.rmi.RemoteException;
55 /**
56 * Struts action used for managing crons within Join application.
57 * @author <a href="mailto:jerome.evrard@gmail.com">Jerome Evrard</a>
58 * @author <a href="mailto:laurent.broudoux@free.fr">Laurent Broudoux</a>
59 * @version $Revision: 1.6 $
60 *
61 * @struts.action path="/quartzCron" name="quartzCronForm"
62 * scope="request" parameter="op" validate="true"
63 * input="/pages/mainpage.jsp?body=/jsp/quartzcrons.jsp"
64 * @struts.action-forward name="Crons" path="/jsp/quartzcrons.jsp"
65 * @struts.action-forward name="Details" path="/jsp/quartzcrondetails.jsp"
66 * @struts.action-forward name="CronHelp" path="/jsp/cronexpressionhelp.jsp"
67 * @struts.action-forward name="Parameters" path="/jsp/configurableparameters.jsp"
68 */
69 public class QuartzCronActions extends JoinAction{
70
71
72
73 /** Get a commons logger. */
74 private static final Log log = LogUtil.getLog(QuartzCronActions.class);
75
76 /** <code>SAVE_OP</code>: Action name to load a cron */
77 public static final String LOAD_OP = "load";
78 /** <code>SAVE_OP</code>: Action name to save a new cron */
79 public static final String SAVE_OP = "save";
80 /** Operation code for saving the configurable parameters of Quartz job */
81 public static final String SAVE_PARAM_OP = "saveParameters";
82 /** Operation code for retrieving the details and script log infos of a Quartz cron */
83 public static final String DETAILS_OP = "details";
84 /** Operation code for getting help about cron expression syntax */
85 public static final String CRON_HELP_OP = "cronHelp";
86
87 /**
88 * The session scope attribute under which the cron object
89 * currently selected by our logged-in User is stored.
90 */
91 public static final String QUARTZ_CRON_KEY = "quartzCron";
92 /**
93 * The session scope attribute under which the retrieved crons
94 * list is stored.
95 */
96 public static final String QUARTZ_CRONS_KEY = "quartzCrons";
97 /**
98 * The request scope attribute under which is stored the cron that
99 * has raised a DuplicateEntityException during save of another one.
100 */
101 public static final String DUPLICATE_QUARTZ_CRON_KEY = "duplicate";
102
103
104
105
106 /** <code>quartzcronManager</code>: The cron manager */
107 private QuartzCronManager cronManager;
108 /** <code>service</code>: Service to get a remote acces */
109 private CronService service;
110
111
112
113
114 /** Creates a new instance of QuartzCronActions. */
115 public QuartzCronActions(){
116 }
117
118
119
120
121 /** @param quartzCronManager The cronManager to set.*/
122 public void setQuartzCronManager(QuartzCronManager quartzCronManager){
123 this.cronManager = quartzCronManager;
124 }
125
126
127
128
129 /**
130 * @param operation String representing the operation to invoke on Action
131 * @param mapping Mapping between forwards name and path for this action
132 * @param form The form object containing request parameters
133 * @param request The servlet container request wrapper
134 * @param response The servlet container response wrapper
135 * @return A forward to the next view to render and display
136 * @throws Exception such as InfraStructureExceptions ...
137 */
138 public ActionForward doExecute(String operation, ActionMapping mapping, ActionForm form,
139 HttpServletRequest request, HttpServletResponse response) throws Exception{
140
141 log.debug("doExecute() called for '" + operation + "' operation");
142
143
144 initializeManagerOrService();
145
146 if (form instanceof QuartzCronForm){
147
148
149 updateQuartzCronsInRequest(request);
150
151 if (LOAD_OP.equals(operation)){
152 return loadQuartzCron(mapping, (QuartzCronForm)form, request, response);
153 }
154 else if (SAVE_OP.equals(operation)){
155 return saveQuartzCron(mapping, (QuartzCronForm)form, request, response);
156 }
157 else if (SAVE_PARAM_OP.equals(operation)){
158 return saveQuartzCronParameters(mapping, (QuartzCronForm)form, request, response);
159 }
160 else if (DETAILS_OP.equals(operation)){
161 return getQuartzCronDetails(mapping, (QuartzCronForm)form, request, response);
162 }
163 else if (CRON_HELP_OP.equalsIgnoreCase(operation)){
164 return mapping.findForward("CronHelp");
165 }
166 else{
167
168 request.getSession().removeAttribute(QUARTZ_CRON_KEY);
169 removeObsoleteForm(mapping, request);
170 return mapping.findForward("Crons");
171 }
172 }
173
174 return null;
175 }
176
177
178
179
180 /**
181 * Load a specified cron info from datastore and fill form with it.
182 * @return A forward to the next view to render and display
183 */
184 protected ActionForward loadQuartzCron(ActionMapping mapping, QuartzCronForm form,
185 HttpServletRequest request, HttpServletResponse response) throws Exception{
186 HttpSession session = request.getSession();
187
188 if (cronManager != null){
189
190 QuartzCronInfo cron = cronManager.getQuartzCron(form.getName());
191 session.setAttribute(QUARTZ_CRON_KEY, cron);
192
193 PropertyUtils.copyProperties(form, cron);
194
195 Iterator itUser = cron.getJobParameterInfos().iterator();
196 String strParams = "";
197 while (itUser.hasNext()){
198 QuartzCronParameterInfo param = (QuartzCronParameterInfo)itUser.next();
199 if (!param.isJobParameter())
200 strParams = strParams + param.getName() + "=" + param.getValue() +"\n";
201 }
202 form.setUserProperties(strParams);
203 }
204 else if (service != null){
205
206 String token = loginToRemoteService(request);
207 RemoteQuartzCronInfo remoteCron = service.getQuartzCronInfo(token, form.getName());
208 logoutFromRemoteService(token);
209
210 QuartzCronInfo cron = BeansHelper.getLocalObject(remoteCron);
211 session.setAttribute(QUARTZ_CRON_KEY, cron);
212
213 PropertyUtils.copyProperties(form, remoteCron);
214 }
215
216 return mapping.findForward("Crons");
217 }
218
219 /**
220 * Load a specified cron info from datastore and fill form with it.
221 * @return A forward to the next view to render and display
222 */
223 protected ActionForward saveQuartzCron(ActionMapping mapping, QuartzCronForm form,
224 HttpServletRequest request, HttpServletResponse response) throws Exception{
225
226 HttpSession session = request.getSession();
227 QuartzCronInfo cron = (QuartzCronInfo)session.getAttribute(QUARTZ_CRON_KEY);
228
229
230 if (cron == null){
231 log.info("Creation of a new QuartzCronInfo with name: " + form.getName());
232 cron = new QuartzCronInfo(form.getName(), form.getCronExpression(), "", form.getJobClass());
233 }
234 else{
235 log.info("Update of existing QuartzCronInfo having name: " + form.getName());
236 PropertyUtils.copyProperties(cron, form);
237 }
238
239
240 Iterator cronParams = cron.getJobParameterInfos().iterator();
241 while (cronParams != null && cronParams.hasNext()){
242 QuartzCronParameterInfo paramInfo = (QuartzCronParameterInfo)cronParams.next();
243 if (!paramInfo.isJobParameter())
244 cronParams.remove();
245 }
246
247 createUserQuartzCronParameterInfos(cron, form);
248
249
250 try{
251 if (cronManager != null){
252 log.debug("Saving QuartzCronInfo '" + form.getName() + "' using local manager");
253
254 cronManager.saveQuartzCronInfo(cron);
255 }
256 else if (service != null){
257 log.debug("Saving QuartzCronInfo '" + form.getName() + "' using remote service");
258
259 String token = loginToRemoteService(request);
260 service.saveCron(token, BeansHelper.getRemoteObject(cron));
261 logoutFromRemoteService(token);
262 }
263 }
264 catch (DuplicateEntityException dee){
265
266 request.setAttribute(DUPLICATE_QUARTZ_CRON_KEY, dee.getOriginalEntity());
267 return mapping.findForward("Crons");
268 }
269
270
271 if (Configurable.class.isAssignableFrom(cron.checkJobClass())){
272 session.setAttribute(QUARTZ_CRON_KEY, cron);
273
274 request.setAttribute(OP_PARAMETER, SAVE_PARAM_OP);
275 request.setAttribute("configurableId", cron.getName());
276 session.setAttribute("configurable", cron.checkJobClass().newInstance());
277 request.setAttribute("action", "quartzCron");
278
279
280 List parameters = cron.getJobParameterInfos();
281 for (int i=0; i < parameters.size(); i++){
282 QuartzCronParameterInfo param = (QuartzCronParameterInfo)parameters.get(i);
283 if (param.isJobParameter())
284 form.addParameter(param);
285 }
286
287 return mapping.findForward("Parameters");
288 }
289
290
291 session.removeAttribute(QUARTZ_CRON_KEY);
292 removeObsoleteForm(mapping, request);
293 return mapping.findForward("Crons");
294 }
295
296 /**
297 * Save a cron parameters into datastore. The cron is an already existing one.
298 * @return A forward to the next view to render and display
299 */
300 protected ActionForward saveQuartzCronParameters(ActionMapping mapping, QuartzCronForm form,
301 HttpServletRequest request, HttpServletResponse response)
302 throws Exception{
303
304 HttpSession session = request.getSession();
305 QuartzCronInfo cron = (QuartzCronInfo)session.getAttribute(QUARTZ_CRON_KEY);
306
307 if (cron != null){
308 log.info("Adding QuartzCronParameterInfo to quartz cron: " + cron.getName());
309
310 Iterator cronParams = cron.getJobParameterInfos().iterator();
311 while (cronParams != null && cronParams.hasNext()){
312 QuartzCronParameterInfo paramInfo = (QuartzCronParameterInfo)cronParams.next();
313 if (paramInfo.isJobParameter())
314 cronParams.remove();
315 }
316
317
318 Iterator parameters = form.getParameters().keySet().iterator();
319 while (parameters != null && parameters.hasNext()){
320
321 String name = (String)parameters.next();
322 String value = (String)form.getMappedParameter(name);
323 if (log.isDebugEnabled())
324 log.debug("Adding a cron parameter: " + name + "=" + value);
325
326 QuartzCronParameterInfo paramInfo = new QuartzCronParameterInfo(name, value, true);
327 cron.addJobParameterInfo(paramInfo);
328 }
329
330 if (cronManager != null){
331 log.debug("Saving quartz cron '" + form.getName() + "' parameters using local manager");
332
333 cronManager.saveQuartzCronInfo(cron);
334 }
335 else if (service != null){
336 log.debug("Saving quartz cron '" + form.getName() + "' parameters using remote service");
337
338 String token = loginToRemoteService(request);
339 service.saveCron(token, BeansHelper.getRemoteObject(cron));
340 logoutFromRemoteService(token);
341 }
342 }
343
344 session.removeAttribute(QUARTZ_CRON_KEY);
345 removeObsoleteForm(mapping, request);
346 return mapping.findForward("Crons");
347 }
348
349 /**
350 * Get all the details of a registered quartz cron from datastore. This includes getting its execution logs infos.
351 * @return A forward to the next view to render and display
352 */
353 protected ActionForward getQuartzCronDetails(ActionMapping mapping, QuartzCronForm form,
354 HttpServletRequest request, HttpServletResponse response)
355 throws Exception{
356 if (cronManager != null){
357
358 QuartzCronInfo info = cronManager.getQuartzCron(form.getName());
359 request.setAttribute(QUARTZ_CRON_KEY, info);
360 }
361 else if (service != null){
362
363 String token = loginToRemoteService(request);
364 RemoteQuartzCronInfo info = service.getQuartzCronInfo(token, form.getName());
365 logoutFromRemoteService(token);
366 request.setAttribute(QUARTZ_CRON_KEY, info);
367 }
368
369 ScriptLogAccessorProxy proxy = ScriptLogAccessorProxy.getInstance();
370 List logInfos = proxy.getScriptLogInfos(form.getName(), "QuartzAdapter");
371 request.setAttribute("scriptLogInfos", logInfos);
372
373
374 return mapping.findForward("Details");
375 }
376
377 /**
378 * Update the crons definitions collection within request.
379 * @param request The servlet container request wrapper
380 * @throws Exception if consumers cannot be refreshed
381 */
382 protected void updateQuartzCronsInRequest(HttpServletRequest request) throws Exception{
383 if (cronManager != null){
384
385 request.setAttribute(QUARTZ_CRONS_KEY, cronManager.getQuartzCronInfos());
386 }
387 else if (service != null){
388
389 String token = loginToRemoteService(request);
390 request.setAttribute(QUARTZ_CRONS_KEY, service.getQuartzCronInfo(token));
391 logoutFromRemoteService(token);
392 }
393 }
394
395 /**
396 * Initialize the local consumer manager or the remote service depending
397 * on the application setup and the application side we are on.
398 * @throws Exception if manager cannot be found or remote service is not available
399 */
400 protected void initializeManagerOrService() throws Exception{
401 if (cronManager == null && service == null){
402 BootstrapManager bootstrapManager = BootstrapUtil.getBootstrapManager();
403
404 if (bootstrapManager.isDissociatedSetup() && bootstrapManager.isSynchronousSide()){
405 String url = bootstrapManager.getOtherSideUrl() + "/remoting/hessian/CronService";
406 log.info("Connecting to remote CronService using url: " + url);
407 HessianProxyFactory proxyFactory = new HessianProxyFactory();
408 service = (CronService)proxyFactory.create(CronService.class, url);
409 }
410 else{
411
412 log.info("Looking up local QuartzCronManager using 'quartzCronManager' component");
413 ContainerContextHandler handler = ContainerContextHandler.getInstance();
414 cronManager = (QuartzCronManager)handler.getComponent("quartzCronManager");
415 }
416 }
417 }
418
419
420
421
422 /**
423 * Create the user parameters of the current edited cron from formular.
424 * @param cron The cron to create parameters for
425 * @param form The current edited formular.
426 */
427 private void createUserQuartzCronParameterInfos(QuartzCronInfo cron, QuartzCronForm form){
428
429 Properties properties = new Properties();
430 try{
431 InputStream is = new ByteArrayInputStream(form.getUserProperties().getBytes());
432 properties.load(is);
433 }
434 catch (IOException ioe){
435 ioe.printStackTrace();
436 }
437 Enumeration enumUserProps = properties.keys();
438 while (enumUserProps.hasMoreElements()){
439
440 String name = (String)enumUserProps.nextElement();
441 String value = properties.getProperty(name);
442 QuartzCronParameterInfo parameter = new QuartzCronParameterInfo(name, value, false);
443 cron.addJobParameterInfo(parameter);
444 }
445 }
446
447 /** Login for using the remote service. */
448 private String loginToRemoteService(HttpServletRequest request) throws InvalidLoginException, RemoteException{
449
450 User user = getUserContainer(request).getView().getUser();
451 String pwd = getUserContainer(request).getView().getClearPassword();
452
453 String token = service.login(user.getLogin(), pwd);
454 return token;
455 }
456
457 /** Logout from the remote service. */
458 private void logoutFromRemoteService(String token) throws RemoteException{
459 service.logout(token);
460 }
461 }