1 17 18 19 20 package org.apache.lenya.cms.scheduler; 21 22 import java.io.File ; 23 import java.text.DateFormat ; 24 import java.text.SimpleDateFormat ; 25 import java.util.ArrayList ; 26 import java.util.Date ; 27 import java.util.GregorianCalendar ; 28 import java.util.List ; 29 30 import javax.servlet.http.HttpServletRequest ; 31 32 import org.apache.avalon.framework.configuration.Configuration; 33 import org.apache.avalon.framework.configuration.DefaultConfigurationBuilder; 34 import org.apache.lenya.cms.publication.Publication; 35 import org.apache.lenya.cms.publication.PublicationException; 36 import org.apache.lenya.cms.publication.PublicationFactory; 37 import org.apache.lenya.cms.scheduler.xml.TriggerHelper; 38 import org.apache.lenya.xml.NamespaceHelper; 39 import org.apache.log4j.Category; 40 import org.quartz.JobDataMap; 41 import org.quartz.JobDetail; 42 import org.quartz.Scheduler; 43 import org.quartz.SchedulerException; 44 import org.quartz.SchedulerFactory; 45 import org.quartz.Trigger; 46 import org.quartz.impl.StdSchedulerFactory; 47 import org.w3c.dom.Document ; 48 import org.w3c.dom.Element ; 49 50 public class SchedulerWrapper { 51 52 private static Category log = Category.getInstance(SchedulerWrapper.class); 53 public static final String JOB_PREFIX = "job"; 54 public static final String JOB_ID = "id"; 55 private static int jobId = 0; 56 private Scheduler scheduler = null; 57 private String servletContextPath; 58 private String schedulerConfigurationPath; 59 private SchedulerStore store = new SchedulerStore(); 60 61 67 public SchedulerWrapper(String servletContextPath, String schedulerConfigurationPath) { 68 this.servletContextPath = servletContextPath; 69 this.schedulerConfigurationPath = schedulerConfigurationPath; 70 71 SchedulerFactory factory = new StdSchedulerFactory(); 72 log.info("------- Starting up -----------------------"); 73 74 try { 75 scheduler = factory.getScheduler(); 76 77 scheduler.addSchedulerListener(new AbstractSchedulerListener()); 78 scheduler.start(); 79 } catch (SchedulerException e) { 80 log.error("Can't initialize SchedulerWrapper: ", e); 81 log.error("------- Startup failed -------------------"); 82 } 83 84 log.info("------- Startup complete ------------------"); 85 } 86 87 91 protected SchedulerStore getStore() { 92 return store; 93 } 94 95 99 private Scheduler getScheduler() { 100 return scheduler; 101 } 102 103 106 public void shutdown() { 107 log.info("------- Shutting Down ---------------------"); 108 109 try { 111 getScheduler().shutdown(); 112 } catch (SchedulerException e) { 113 log.error("------- Shutdown Failed -----------------", e); 114 } 115 116 log.info("------- Shutdown Complete -----------------"); 117 } 118 119 123 protected String getServletContextPath() { 124 return servletContextPath; 125 } 126 127 131 protected String getSchedulerConfigurationPath() { 132 return schedulerConfigurationPath; 133 } 134 135 139 protected synchronized static String getNextJobId() { 140 return "job_" + jobId++ +System.currentTimeMillis(); 141 } 142 143 152 protected void addJob(String jobGroup, Date startTime, Class jobClass, JobDataMap map) 153 throws SchedulerException, PublicationException { 154 String uniqueJobId = getNextJobId(); 155 log.debug("Job ID: [" + uniqueJobId + "]"); 156 157 JobDetail jobDetail = new JobDetail(uniqueJobId, jobGroup, jobClass); 158 jobDetail.setJobDataMap(map); 159 160 Date now = new GregorianCalendar ().getTime(); 161 if (log.isDebugEnabled()) { 162 DateFormat format = new SimpleDateFormat (); 163 log.debug("Trigger time: [" + format.format(startTime) + "]"); 164 log.debug("Current time: [" + format.format(now) + "]"); 165 } 166 167 if (startTime.after(now)) { 168 Trigger trigger = 169 TriggerHelper.createSimpleTrigger(uniqueJobId, jobGroup, startTime); 170 addJob(jobDetail, trigger); 171 log.debug("Scheduling job."); 172 } else { 173 addJob(jobDetail); 174 log.debug("Adding job without scheduling."); 175 } 176 177 log.debug("----------------------------------------------"); 178 179 store.writeSnapshot(getPublication(jobGroup), getJobWrappers(jobGroup)); 180 } 181 182 189 public void addJob(String jobGroup, Date startTime, HttpServletRequest request) 190 throws SchedulerException { 191 192 if (jobGroup == null) { 193 throw new SchedulerException("Job group must not be null!"); 194 } 195 196 try { 197 log.debug("----------------------------------------------"); 198 log.debug("Adding Job for group [" + jobGroup + "]"); 199 200 Class jobClass = TaskJob.class; 202 203 ServletJob job = ServletJobFactory.createJob(jobClass); 204 JobDataMap map = job.createJobData(request); 205 206 addJob(jobGroup, startTime, jobClass, map); 207 } catch (Exception e) { 208 log.error("Adding job failed: ", e); 209 throw new SchedulerException(e); 210 } 211 } 212 213 219 protected Publication getPublication(String jobGroup) throws PublicationException { 220 return PublicationFactory.getPublication(jobGroup, getServletContextPath()); 221 } 222 223 228 protected void addJob(JobDetail detail, Trigger trigger) { 229 try { 230 detail.setDurability(true); 231 232 Date ft = getScheduler().scheduleJob(detail, trigger); 233 log.debug("Job " + detail.getFullName() + " will run at: " + ft); 234 } catch (Exception e) { 235 log.error("Adding job failed: ", e); 236 } 237 } 238 239 243 protected void addJob(JobDetail detail) { 244 try { 245 detail.setDurability(true); 246 getScheduler().addJob(detail, true); 247 } catch (SchedulerException e) { 248 log.error("Adding job failed: ", e); 249 } 250 } 251 252 257 protected void deleteJob(String jobName, String jobGroup) { 258 try { 259 log.debug("-----------------------------------"); 260 log.debug("\n Deleting job [" + jobGroup + "/" + jobName + "]"); 261 log.debug("-----------------------------------"); 262 getScheduler().deleteJob(jobName, jobGroup); 263 getStore().writeSnapshot(getPublication(jobGroup), getJobWrappers(jobGroup)); 264 } catch (Exception e) { 265 log.error("Deleting job failed: ", e); 266 } 267 } 268 269 273 protected Configuration getSchedulerConfiguration() { 274 try { 275 DefaultConfigurationBuilder builder = new DefaultConfigurationBuilder(); 276 String path = getServletContextPath() + getSchedulerConfigurationPath(); 277 log.debug("Initializing scheduler configuration: " + path); 278 279 File configurationFile = new File (path); 280 Configuration configuration = builder.buildFromFile(configurationFile); 281 282 return configuration; 283 } catch (Exception e) { 284 log.error("Can't initialize scheduler configuration: ", e); 285 286 return null; 287 } 288 } 289 290 public static final String ELEMENT_TRIGGERS = "triggers"; 291 public static final String ELEMENT_TRIGGER = "trigger"; 292 public static final String TYPE_ATTRIBUTE = "type"; 293 public static final String CLASS_ATTRIBUTE = "class"; 294 295 300 protected Element getTriggerTypes(NamespaceHelper helper) { 301 try { 302 Configuration configuration = getSchedulerConfiguration(); 303 Configuration[] triggerConfigurations = 304 configuration.getChild(ELEMENT_TRIGGERS).getChildren(ELEMENT_TRIGGER); 305 306 Element triggersElement = helper.createElement("triggers"); 307 308 for (int i = 0; i < triggerConfigurations.length; i++) { 309 Configuration conf = triggerConfigurations[i]; 310 String type = conf.getAttribute(TYPE_ATTRIBUTE); 311 String className = conf.getAttribute(CLASS_ATTRIBUTE); 312 313 Element triggerElement = helper.createElement("trigger"); 314 triggerElement.setAttribute("name", type); 315 triggerElement.setAttribute("src", className); 316 triggersElement.appendChild(triggerElement); 317 } 318 319 return triggersElement; 320 } catch (Exception e) { 321 log.error("Can't configure trigger types: " + e); 322 323 return null; 324 } 325 } 326 327 334 protected Trigger getTrigger(String jobName, String jobGroup) throws SchedulerException { 335 log.debug("Resolving trigger for job [" + jobName + " ][ " + jobGroup + "]"); 336 String [] triggerGroups = getScheduler().getTriggerGroupNames(); 337 338 for (int groupIndex = 0; groupIndex < triggerGroups.length; groupIndex++) { 339 String [] triggerNames = getScheduler().getTriggerNames(triggerGroups[groupIndex]); 340 341 for (int nameIndex = 0; nameIndex < triggerNames.length; nameIndex++) { 342 log.debug("Trigger name: " + triggerNames[nameIndex]); 343 344 Trigger trigger = 345 getScheduler().getTrigger(triggerNames[nameIndex], triggerGroups[groupIndex]); 346 log.debug("Job group: " + trigger.getJobGroup()); 347 348 if (trigger.getJobGroup().equals(jobGroup) 349 && trigger.getJobName().equals(jobName)) { 350 return trigger; 351 } 352 } 353 } 354 355 return null; 356 } 357 358 364 public Document getSnapshot(String [] jobGroupNames) throws SchedulerException { 365 log.debug("Creating job snapshot"); 366 367 NamespaceHelper helper = SchedulerStore.getNamespaceHelper(); 368 Document document = helper.getDocument(); 369 Element root = document.getDocumentElement(); 370 371 root.appendChild(getTriggerTypes(helper)); 373 374 for (int groupIndex = 0; groupIndex < jobGroupNames.length; groupIndex++) { 375 log.debug("Creating job snapshot for group [" + jobGroupNames[groupIndex] + "]"); 376 root.appendChild(getSnapshot(helper, jobGroupNames[groupIndex])); 377 } 378 379 return document; 380 } 381 382 389 protected Element getSnapshot(NamespaceHelper helper, String group) throws SchedulerException { 390 JobWrapper[] jobs = getJobWrappers(group); 391 Element element; 392 try { 393 element = getStore().createSnapshot(helper, getPublication(group), jobs); 394 } catch (SchedulerException e) { 395 throw e; 396 } catch (PublicationException e) { 397 throw new SchedulerException(e); 398 } 399 return element; 400 } 401 402 408 protected JobWrapper[] getJobWrappers(String jobGroupName) throws SchedulerException { 409 410 List wrappers = new ArrayList (); 411 String [] jobNames = getScheduler().getJobNames(jobGroupName); 412 413 for (int nameIndex = 0; nameIndex < jobNames.length; nameIndex++) { 414 JobDetail jobDetail = getScheduler().getJobDetail(jobNames[nameIndex], jobGroupName); 415 Trigger trigger = getTrigger(jobNames[nameIndex], jobGroupName); 416 wrappers.add(new JobWrapper(jobDetail, trigger)); 417 } 418 419 return (JobWrapper[]) wrappers.toArray(new JobWrapper[wrappers.size()]); 420 } 421 422 427 public Document getSnapshot() throws SchedulerException { 428 String [] jobGroupNames = getScheduler().getJobGroupNames(); 429 return getSnapshot(jobGroupNames); 430 } 431 432 437 public void restoreJobs(String jobGroup) throws SchedulerException { 438 439 log.debug("--------------------------------------------------"); 440 log.debug("Restoring jobs for job group [" + jobGroup + "]"); 441 log.debug("--------------------------------------------------"); 442 443 try { 444 JobWrapper[] jobs = getStore().restoreJobs(getPublication(jobGroup)); 445 for (int i = 0; i < jobs.length; i++) { 446 if (jobs[i].getTrigger() != null) { 447 if (log.isDebugEnabled()) { 448 log.debug(" Trigger time in future - scheduling job."); 449 } 450 addJob(jobs[i].getJobDetail(), jobs[i].getTrigger()); 451 } else { 452 if (log.isDebugEnabled()) { 453 log.debug(" Trigger time has expired - adding job without scheduling."); 454 } 455 addJob(jobs[i].getJobDetail()); 456 } 457 } 458 } catch (Exception e) { 459 log.error("Restoring jobs failed: ", e); 460 } 461 462 } 463 464 471 public void modifyJob(String jobId, String jobGroup, Date startTime) 472 throws SchedulerException { 473 log.debug("Modifying job [" + jobId + "][" + jobGroup + "]"); 474 475 JobDetail jobDetail = getScheduler().getJobDetail(jobId, jobGroup); 476 if (jobDetail == null) { 477 throw new SchedulerException("Job not found!"); 478 } 479 480 Trigger trigger = getTrigger(jobDetail.getName(), jobGroup); 481 if (trigger == null) { 482 log.debug(" No trigger found."); 483 } else { 484 log.debug(" Trigger found. Setting new start time."); 485 jobDetail.setDurability(true); 486 if (startTime.after(new GregorianCalendar ().getTime())) { 487 log.debug(" Start time is in future - re-scheduling job."); 488 getScheduler().unscheduleJob(trigger.getName(), trigger.getGroup()); 489 trigger = TriggerHelper.createSimpleTrigger(jobId, jobGroup, startTime); 490 getScheduler().scheduleJob(trigger); 491 } else { 492 log.debug(" Start time has already expired - deleting job."); 493 getScheduler().deleteJob(jobId, jobGroup); 494 } 495 try { 496 getStore().writeSnapshot(getPublication(jobGroup), getJobWrappers(jobGroup)); 497 } catch (SchedulerException e) { 498 throw e; 499 } catch (PublicationException e) { 500 throw new SchedulerException(e); 501 } 502 } 503 } 504 505 512 public void deleteJobs(org.apache.lenya.cms.publication.Document document) 513 throws SchedulerException, PublicationException { 514 515 log.debug("Deleting jobs for document [" + document + "]"); 516 517 String jobGroup = document.getPublication().getId(); 518 JobWrapper[] jobs = getJobWrappers(jobGroup); 519 boolean changed = false; 520 for (int i = 0; i < jobs.length; i++) { 521 ServletJob job = jobs[i].getJob(); 522 String documentUrl = job.getDocumentUrl(jobs[i].getJobDetail()); 523 if (documentUrl.equals(document.getCompleteURL())) { 524 deleteJob(jobs[i].getJobDetail().getName(), jobGroup); 525 changed = true; 526 } 527 } 528 if (changed) { 529 getStore().writeSnapshot(getPublication(jobGroup), getJobWrappers(jobGroup)); 530 } 531 } 532 533 } 534 | Popular Tags |