1 package de.webman.util.scheduler ; 2 3 import de.webman.util.registry.Manager; 4 import de.webman.util.registry.RegistryException; 5 import de.webman.util.log4j.WebmanCategory; 6 import org.apache.log4j.Category; 7 import java.io.File ; 8 import java.io.IOException ; 9 import java.io.BufferedInputStream ; 10 import java.io.FileInputStream ; 11 import java.util.List ; 12 import java.util.Iterator ; 13 import java.util.Map ; 14 import java.util.HashMap ; 15 import java.util.ArrayList ; 16 import org.w3c.dom.Node ; 17 import org.w3c.dom.Document ; 18 import org.w3c.dom.Element ; 19 import org.xml.sax.SAXException ; 20 import org.xml.sax.InputSource ; 21 import javax.xml.parsers.DocumentBuilderFactory ; 22 import javax.xml.parsers.DocumentBuilder ; 23 import javax.xml.parsers.ParserConfigurationException ; 24 import java.text.SimpleDateFormat ; 25 import java.text.ParseException ; 26 import java.util.GregorianCalendar ; 27 import java.util.Calendar ; 28 import java.util.Date ; 29 30 31 73 public class SchedulerMgr 74 implements Manager 75 { 76 77 80 private static Category cat = Category.getInstance(SchedulerMgr.class); 81 82 85 public static final int MILLISECONDS_PER_SEC = 1000; 86 89 public static final int MILLISECONDS_PER_MIN = 1000 * 60; 90 93 public static final int MILLISECONDS_PER_HOUR = 1000 * 60 * 60; 94 97 public static final int MILLISECONDS_PER_DAY = 1000 * 60 * 60 * 24; 98 99 102 private static SimpleDateFormat date_format; 103 104 107 private static SimpleDateFormat time_format; 108 109 110 111 114 115 static { 116 date_format = new SimpleDateFormat ("dd.MM.yyyy"); 117 date_format.setLenient(false); 118 119 time_format = new SimpleDateFormat ("HH:mm:ss"); 120 time_format.setLenient(false); 121 } 122 123 128 SchedulerMgr(String basedir) 129 throws RegistryException 130 { 131 cat.info("setup scheduler system"); 132 133 try { 134 File syncfile = new File (basedir, "WEB-INF/classes/scheduler.xml"); 135 readXMLStream(new BufferedInputStream (new FileInputStream (syncfile))); 136 137 startThread(); 139 140 cat.info("scheduler system started successfully"); 141 } 142 catch (SchedulerException se) { 143 throw new RegistryException(se); 144 } 145 catch (IOException ioe) { 146 cat.info ("no 'scheduler.xml' found. No schedulers started"); 147 } 148 } 149 150 151 155 158 166 private void readXMLStream(BufferedInputStream in) 167 throws IOException , RegistryException, SchedulerException 168 { 169 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); 170 factory.setNamespaceAware(false); 171 factory.setValidating(false); 172 173 Document doc = null; 174 try { 175 DocumentBuilder builder = factory.newDocumentBuilder(); 176 doc = builder.parse(new InputSource (in)); 177 } 178 catch (ParserConfigurationException pce) { 179 throw new RegistryException(pce); 180 } 181 catch (SAXException se) { 182 throw new RegistryException(se); 183 } 184 185 Node c0 = doc.getDocumentElement(); 186 if (!("scheduler".equals(c0.getNodeName()))) 187 throw new RegistryException("bad root element '" + c0.getNodeName() + "'"); 188 189 for (Node c1 = c0.getFirstChild(); c1 != null; c1 = c1.getNextSibling()) { 190 if (c1.getNodeType() == Node.ELEMENT_NODE) { 191 if ("service".equals(c1.getNodeName())) { 192 Element ce = (Element )c1; 193 HashMap prms = null; 194 195 196 for (Node c2 = c1.getFirstChild(); c2 != null; c2 = c2.getNextSibling()) { 197 if (c2.getNodeType() == Node.ELEMENT_NODE) { 198 if ("param".equals(c2.getNodeName())) { 199 Element c2e = (Element )c2; 200 201 String key = c2e.getAttribute("key"); 202 String value = c2e.getAttribute("value"); 203 204 if (prms == null) 205 prms = new HashMap (); 206 207 prms.put(key, value); 208 } 209 else 210 throw new RegistryException("unknown element: '" + c2.getNodeName() + "'"); 211 } 212 } 213 214 setupSchedulerService(ce, prms); 215 } 216 else 217 throw new RegistryException("unknown element: '" + c1.getNodeName() + "'"); 218 } 219 } 220 } 221 222 226 private String getTextData(Node cntx) { 227 cntx.normalize(); 228 229 for (Node n = cntx.getFirstChild(); n != null; n = n.getNextSibling()) { 230 if (n.getNodeType() == Node.TEXT_NODE) { 231 return n.getNodeValue(); 232 } 233 else if (n.getNodeType() == Node.CDATA_SECTION_NODE) { 234 return n.getNodeValue(); 235 } 236 } 237 return null; 238 } 239 240 241 247 private boolean setupSchedulerService(Element ce, Map params) 248 throws RegistryException, SchedulerException 249 { 250 SchedulerServiceFactory sfact = null; 251 Date start_at = null; 252 Date stop_at = null; 253 long frequency = 0; 254 long delay = 0; 255 boolean start_once = false; 256 SchedulerService service_impl = null; 257 258 String id = ce.getAttribute("id").trim(); 259 String freq_s = ce.getAttribute("frequency").trim(); 260 String freq_unit_s = ce.getAttribute("freq-unit").trim(); 261 String delay_s = ce.getAttribute("delay").trim(); 262 String delay_unit = ce.getAttribute("delay-unit").trim(); 263 String start_date_s = ce.getAttribute("start-date").trim(); 264 String start_time_s = ce.getAttribute("start-time").trim(); 265 String stop_date_s = ce.getAttribute("stop-date").trim(); 266 String stop_time_s = ce.getAttribute("stop-time").trim(); 267 String fact_s = ce.getAttribute("factory-class").trim(); 268 269 270 271 try { 272 Class fact = Class.forName(fact_s.trim()); 273 sfact = (SchedulerServiceFactory)fact.newInstance(); 274 } 275 catch (Exception e) { 276 cat.error("Can't load scheduler service: '" + fact_s + "' (" + e + ")"); 277 return false; 278 } 279 280 281 start_at = parsePointOfTime(start_date_s, start_time_s, new Date ()); 282 if (start_at == null) 283 return false; 284 285 286 stop_at = parsePointOfTime(stop_date_s, stop_time_s, null); 287 288 289 start_once = "ONCE".equals(freq_s.toUpperCase()); 290 if (!start_once) { 291 try { 292 frequency = parseTimeWithUnit(freq_s, freq_unit_s); 293 } 294 catch (NumberFormatException nfe) { 295 cat.error("Bad frequency setting: '" + freq_s + " " + freq_unit_s + 296 "' for scheduler service '" + id + "' (" + nfe + ")"); 297 return false; 298 } 299 300 if (frequency <= 0) { 301 cat.error("bad or no time setting for scheduler service '" + id + "'"); 302 return false; 303 } 304 305 try { 306 delay = parseTimeWithUnit(delay_s, delay_unit); 307 } 308 catch (NumberFormatException nfe) { 309 cat.error("Bad delay setting: '" + delay_s + " " + delay_unit + 310 "' for scheduler service '" + id + "' (" + nfe + ")"); 311 return false; 312 } 313 } 314 315 316 if (params != null) { 317 for (Iterator it = params.keySet().iterator(); it.hasNext(); ) { 318 String key = (String )it.next(); 319 sfact.setProperty(key, params.get(key)); 320 } 321 } 322 323 324 if (start_once) 325 registerOneTimeService(id, start_at, sfact); 326 else 327 registerFrequentService(id, start_at, stop_at, frequency, delay, sfact); 328 329 return true; 330 } 331 332 333 342 private Date parsePointOfTime(String at_date, String at_time, Date def) 343 { 344 Date start_at_date = null; 345 Date start_at_time = null; 346 347 348 if (at_date != null && at_date.length() > 0) { 349 try { 350 start_at_date = date_format.parse(at_date); 351 } 352 catch (ParseException pe) { 353 cat.error("bad date setting: '" + pe + "'"); 354 return null; 355 } 356 } 357 358 if (at_time != null && at_time.length() > 0) { 359 try { 360 start_at_time = time_format.parse(at_time); 361 } 362 catch (ParseException pe) { 363 cat.error("bad time setting: '" + pe + "'"); 364 return null; 365 } 366 } 367 368 if (start_at_date != null && start_at_time != null) { 369 Calendar dcal = Calendar.getInstance(); 370 Calendar tcal = Calendar.getInstance(); 371 dcal.setTime(start_at_date); 372 tcal.setTime(start_at_time); 373 374 return new GregorianCalendar (dcal.get(Calendar.YEAR), 375 dcal.get(Calendar.MONTH), 376 dcal.get(Calendar.DAY_OF_MONTH), 377 tcal.get(Calendar.HOUR_OF_DAY), 378 tcal.get(Calendar.MINUTE), 379 tcal.get(Calendar.SECOND)).getTime(); 380 } 381 else if (start_at_date != null) { 382 return start_at_date; 383 } 384 else if (start_at_time != null) { 385 Calendar dcal = Calendar.getInstance(); Calendar tcal = Calendar.getInstance(); 387 tcal.setTime(start_at_time); 388 return new GregorianCalendar (dcal.get(Calendar.YEAR), 389 dcal.get(Calendar.MONTH), 390 dcal.get(Calendar.DAY_OF_MONTH), 391 tcal.get(Calendar.HOUR_OF_DAY), 392 tcal.get(Calendar.MINUTE), 393 tcal.get(Calendar.SECOND)).getTime(); 394 } 395 396 return def; 397 } 398 399 400 410 private long parseTimeWithUnit(String tmstr, String unit) 411 throws NumberFormatException 412 { 413 long tm = Long.parseLong(tmstr); 414 415 if (unit != null && unit.length() > 0) { 416 if ("SECONDS".equals(unit.toUpperCase())) 417 tm *= MILLISECONDS_PER_SEC; 418 else if ("MINUTES".equals(unit.toUpperCase())) 419 tm *= MILLISECONDS_PER_MIN; 420 else if ("HOURS".equals(unit.toUpperCase())) 421 tm *= MILLISECONDS_PER_HOUR; 422 else if ("DAYS".equals(unit.toUpperCase())) 423 tm *= MILLISECONDS_PER_DAY; 424 else 425 throw new NumberFormatException ("unknown time unit: '" + unit + "'"); 426 } 427 else 428 tm *= MILLISECONDS_PER_MIN; 429 430 return tm; 431 } 432 433 434 435 438 441 private final static long DEFAULT_CHECK_TIME = 10 * 1000; 443 446 private final static long MIN_CHECK_TIME = 1000; 448 451 private ArrayList schedulers = new ArrayList (); 452 453 456 private Iterator checker = null; 457 458 461 private SchedulerThread thread = null; 462 463 466 private long sleepTime = DEFAULT_CHECK_TIME; 467 468 471 private void startThread() { 472 if (thread == null && schedulers.size() > 0) { 473 thread = new SchedulerThread(this); 474 Thread t = new Thread (thread); 475 476 477 t.setDaemon(true); 478 t.start(); 479 } 480 } 481 482 485 void checkNext() { 486 cat.info("check next"); 487 synchronized(schedulers) { 488 if (checker == null || !checker.hasNext()) { 489 checker = schedulers.iterator(); 490 if (!checker.hasNext()) { 491 thread.stop(); 492 thread = null; 493 sleepTime = DEFAULT_CHECK_TIME; 494 } 495 } 496 497 ServiceEntry srve = (ServiceEntry)checker.next(); 498 Date now = new Date (); 499 if (srve.isDue(now)) 500 srve.executeNewService(); 501 502 if (srve.isOutdated(now)) { 503 cat.debug ("remove outdated service + '" + srve.id + "'"); 504 checker.remove(); 505 } 506 } 507 } 508 509 512 long getSleepTime() { 513 return sleepTime; 514 } 515 516 517 523 private void addService(ServiceEntry se, long _hint) { 524 synchronized(schedulers) { 525 cat.info("register scheduler service '" + se.id + "' (" + 526 se.factory.getClass().getName() + ") hint at: " + _hint); 527 schedulers.add(se); 528 529 531 if (_hint < sleepTime) { 532 if (_hint > 0) 533 sleepTime = _hint + MIN_CHECK_TIME; 534 else 535 sleepTime = MIN_CHECK_TIME; 536 } 537 if (thread == null) 538 startThread(); 539 540 541 checker = null; 542 } 543 } 544 545 546 557 public void registerFrequentService(String _id, 558 Date _start_at, Date _stop_at, 559 long _frequency, long _delay, 560 SchedulerServiceFactory _sfact) 561 { 562 addService(new FrequentService(_id, _start_at, _stop_at, _frequency, _delay, _sfact), 563 _frequency); 564 } 565 566 573 public void registerOneTimeService(String _id, 574 Date _start_at, 575 SchedulerServiceFactory _sfact) 576 { 577 Calendar cal = Calendar.getInstance(); 578 cal.setTime(_start_at); 579 long check_time = System.currentTimeMillis() - cal.getTime().getTime(); 580 581 addService(new OneTimeService(_id, _start_at, _sfact), check_time); 582 } 583 } 584 585 | Popular Tags |