1 /* 2 * Copyright 2004-2005 OpenSymphony 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 * use this file except in compliance with the License. You may obtain a copy 6 * of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 * License for the specific language governing permissions and limitations 14 * under the License. 15 * 16 */ 17 18 /* 19 * Previously Copyright (c) 2001-2004 James House 20 */ 21 package org.quartz.impl; 22 23 import org.apache.commons.logging.Log; 24 import org.apache.commons.logging.LogFactory; 25 import org.quartz.Scheduler; 26 import org.quartz.SchedulerException; 27 import org.quartz.SchedulerFactory; 28 import org.quartz.core.JobRunShellFactory; 29 import org.quartz.core.QuartzScheduler; 30 import org.quartz.core.QuartzSchedulerResources; 31 import org.quartz.core.SchedulingContext; 32 import org.quartz.simpl.CascadingClassLoadHelper; 33 import org.quartz.simpl.RAMJobStore; 34 import org.quartz.simpl.SimpleThreadPool; 35 import org.quartz.spi.ClassLoadHelper; 36 import org.quartz.spi.JobStore; 37 import org.quartz.spi.SchedulerPlugin; 38 import org.quartz.spi.ThreadPool; 39 40 import java.util.Collection; 41 import java.util.Iterator; 42 import java.util.Map; 43 44 /** 45 * <p> 46 * A singleton implementation of <code>{@link org.quartz.SchedulerFactory}</code>. 47 * </p> 48 * 49 * <p> 50 * Here are some examples of using this class: 51 * </p> 52 * <p> 53 * To create a scheduler that does not write anything to the database (is not 54 * persistent), you can call <code>createVolatileScheduler</code>: 55 * 56 * <pre> 57 * DirectSchedulerFactory.getInstance().createVolatileScheduler(10); // 10 threads * // don't forget to start the scheduler: DirectSchedulerFactory.getInstance().getScheduler().start(); 58 * </pre> 59 * 60 * 61 * <p> 62 * Several create methods are provided for convenience. All create methods 63 * eventually end up calling the create method with all the parameters: 64 * </p> 65 * 66 * <pre> 67 * public void createScheduler(String schedulerName, String schedulerInstanceId, ThreadPool threadPool, JobStore jobStore, String rmiRegistryHost, int rmiRegistryPort) 68 * </pre> 69 * 70 * 71 * <p> 72 * Here is an example of using this method: 73 * </p> 74 * * 75 * * <pre>// create the thread pool SimpleThreadPool threadPool = new SimpleThreadPool(maxThreads, Thread.NORM_PRIORITY); threadPool.initialize(); * // create the job store JobStore jobStore = new RAMJobStore(); jobStore.initialize(); 76 * 77 * DirectSchedulerFactory.getInstance().createScheduler("My Quartz Scheduler", "My Instance", threadPool, jobStore, "localhost", 1099); * // don't forget to start the scheduler: DirectSchedulerFactory.getInstance().getScheduler("My Quartz Scheduler", "My Instance").start(); 78 * </pre> 79 * 80 * 81 * <p> 82 * You can also use a JDBCJobStore instead of the RAMJobStore: 83 * </p> 84 * 85 * <pre> 86 * DBConnectionManager.getInstance().addConnectionProvider("someDatasource", new JNDIConnectionProvider("someDatasourceJNDIName")); 87 * 88 * JDBCJobStore jdbcJobStore = new JDBCJobStore(); jdbcJobStore.setDataSource("someDatasource"); jdbcJobStore.setPostgresStyleBlobs(true); jdbcJobStore.setTablePrefix("QRTZ_"); jdbcJobStore.setInstanceId("My Instance"); jdbcJobStore.initialize(); 89 * </pre> 90 * 91 * @author Mohammad Rezaei 92 * @author James House 93 * 94 * @see JobStore 95 * @see ThreadPool 96 */ 97 public class DirectSchedulerFactory implements SchedulerFactory { 98 99 /* 100 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 101 * 102 * Constants. 103 * 104 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 105 */ 106 public static final String DEFAULT_INSTANCE_ID = "SIMPLE_NON_CLUSTERED"; 107 108 public static final String DEFAULT_SCHEDULER_NAME = "SimpleQuartzScheduler"; 109 110 /* 111 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 112 * 113 * Data members. 114 * 115 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 116 */ 117 118 private boolean initialized = false; 119 120 private static DirectSchedulerFactory instance = new DirectSchedulerFactory(); 121 122 private final Log log = LogFactory.getLog(getClass()); 123 124 /* 125 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 126 * 127 * Constructors. 128 * 129 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 130 */ 131 132 protected Log getLog() { 133 return log; 134 } 135 136 /** 137 * Constructor 138 */ 139 protected DirectSchedulerFactory() { 140 } 141 142 /* 143 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 144 * 145 * Interface. 146 * 147 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 148 */ 149 150 public static DirectSchedulerFactory getInstance() { 151 return instance; 152 } 153 154 /** 155 * Creates an in memory job store (<code>{@link RAMJobStore}</code>) 156 * The thread priority is set to Thread.NORM_PRIORITY 157 * 158 * @param maxThreads 159 * The number of threads in the thread pool 160 * @throws SchedulerException 161 * if initialization failed. 162 */ 163 public void createVolatileScheduler(int maxThreads) 164 throws SchedulerException { 165 SimpleThreadPool threadPool = new SimpleThreadPool(maxThreads, 166 Thread.NORM_PRIORITY); 167 threadPool.initialize(); 168 JobStore jobStore = new RAMJobStore(); 169 this.createScheduler(threadPool, jobStore); 170 171 } 172 173 /** 174 * @deprecated see correctly spelled method. 175 * @see #createVolatileScheduler(int) 176 */ 177 public void createVolatileSchduler(int maxThreads) 178 throws SchedulerException { 179 createVolatileScheduler(maxThreads); 180 } 181 182 /** 183 * Creates a proxy to a remote scheduler. This scheduler can be retrieved 184 * via {@link DirectSchedulerFactory#getScheduler()} 185 * 186 * @param rmiHost 187 * The hostname for remote scheduler 188 * @param rmiPort 189 * Port for the remote scheduler. The default RMI port is 1099. 190 * @throws SchedulerException 191 * if the remote scheduler could not be reached. 192 */ 193 public void createRemoteScheduler(String rmiHost, int rmiPort) 194 throws SchedulerException { 195 createRemoteScheduler(DEFAULT_SCHEDULER_NAME, DEFAULT_INSTANCE_ID, 196 rmiHost, rmiPort); 197 initialized = true; 198 } 199 200 /** 201 * Same as 202 * {@link DirectSchedulerFactory#createRemoteScheduler(String rmiHost, int rmiPort)}, 203 * with the addition of specifying the scheduler name and instance ID. This 204 * scheduler can only be retrieved via 205 * {@link DirectSchedulerFactory#getScheduler(String)} 206 * 207 * @param schedulerName 208 * The name for the scheduler. 209 * @param schedulerInstanceId 210 * The instance ID for the scheduler. 211 * @param rmiHost 212 * The hostname for remote scheduler 213 * @param rmiPort 214 * Port for the remote scheduler. The default RMI port is 1099. 215 * @throws SchedulerException 216 * if the remote scheduler could not be reached. 217 */ 218 public void createRemoteScheduler(String schedulerName, 219 String schedulerInstanceId, String rmiHost, int rmiPort) 220 throws SchedulerException { 221 createRemoteScheduler(schedulerName, 222 schedulerInstanceId, null, rmiHost, rmiPort); 223 } 224 225 /** 226 * Same as 227 * {@link DirectSchedulerFactory#createRemoteScheduler(String rmiHost, int rmiPort)}, 228 * with the addition of specifying the scheduler name, instance ID, and rmi 229 * bind name. This scheduler can only be retrieved via 230 * {@link DirectSchedulerFactory#getScheduler(String)} 231 * 232 * @param schedulerName 233 * The name for the scheduler. 234 * @param schedulerInstanceId 235 * The instance ID for the scheduler. 236 * @param rmiBindName 237 * The name of the remote scheduler in the RMI repository. If null 238 * defaults to the generated unique identifier. 239 * @param rmiHost 240 * The hostname for remote scheduler 241 * @param rmiPort 242 * Port for the remote scheduler. The default RMI port is 1099. 243 * @throws SchedulerException 244 * if the remote scheduler could not be reached. 245 */ 246 public void createRemoteScheduler(String schedulerName, 247 String schedulerInstanceId, String rmiBindName, String rmiHost, int rmiPort) 248 throws SchedulerException { 249 SchedulingContext schedCtxt = new SchedulingContext(); 250 schedCtxt.setInstanceId(schedulerInstanceId); 251 252 String uid = (rmiBindName != null) ? rmiBindName : 253 QuartzSchedulerResources.getUniqueIdentifier( 254 schedulerName, schedulerInstanceId); 255 256 RemoteScheduler remoteScheduler = new RemoteScheduler(schedCtxt, uid, 257 rmiHost, rmiPort); 258 259 SchedulerRepository schedRep = SchedulerRepository.getInstance(); 260 schedRep.bind(remoteScheduler); 261 } 262 263 /** 264 * Creates a scheduler using the specified thread pool and job store. This 265 * scheduler can be retrieved via 266 * {@link DirectSchedulerFactory#getScheduler()} 267 * 268 * @param threadPool 269 * The thread pool for executing jobs 270 * @param jobStore 271 * The type of job store 272 * @throws SchedulerException 273 * if initialization failed 274 */ 275 public void createScheduler(ThreadPool threadPool, JobStore jobStore) 276 throws SchedulerException { 277 createScheduler(DEFAULT_SCHEDULER_NAME, DEFAULT_INSTANCE_ID, 278 threadPool, jobStore); 279 initialized = true; 280 } 281 282 /** 283 * Same as 284 * {@link DirectSchedulerFactory#createScheduler(ThreadPool threadPool, JobStore jobStore)}, 285 * with the addition of specifying the scheduler name and instance ID. This 286 * scheduler can only be retrieved via 287 * {@link DirectSchedulerFactory#getScheduler(String)} 288 * 289 * @param schedulerName 290 * The name for the scheduler. 291 * @param schedulerInstanceId 292 * The instance ID for the scheduler. 293 * @param threadPool 294 * The thread pool for executing jobs 295 * @param jobStore 296 * The type of job store 297 * @throws SchedulerException 298 * if initialization failed 299 */ 300 public void createScheduler(String schedulerName, 301 String schedulerInstanceId, ThreadPool threadPool, JobStore jobStore) 302 throws SchedulerException { 303 createScheduler(schedulerName, schedulerInstanceId, threadPool, 304 jobStore, null, 0, -1, -1); 305 } 306 307 /** 308 * Creates a scheduler using the specified thread pool and job store and 309 * binds it to RMI. 310 * 311 * @param schedulerName 312 * The name for the scheduler. 313 * @param schedulerInstanceId 314 * The instance ID for the scheduler. 315 * @param threadPool 316 * The thread pool for executing jobs 317 * @param jobStore 318 * The type of job store 319 * @param rmiRegistryHost 320 * The hostname to register this scheduler with for RMI. Can use 321 * "null" if no RMI is required. 322 * @param rmiRegistryPort 323 * The port for RMI. Typically 1099. 324 * @param idleWaitTime 325 * The idle wait time in milliseconds. You can specify "-1" for 326 * the default value, which is currently 30000 ms. 327 * @throws SchedulerException 328 * if initialization failed 329 */ 330 public void createScheduler(String schedulerName, 331 String schedulerInstanceId, ThreadPool threadPool, 332 JobStore jobStore, String rmiRegistryHost, int rmiRegistryPort, 333 long idleWaitTime, long dbFailureRetryInterval) 334 throws SchedulerException { 335 createScheduler(schedulerName, 336 schedulerInstanceId, threadPool, 337 jobStore, null, // plugins 338 rmiRegistryHost, rmiRegistryPort, 339 idleWaitTime, dbFailureRetryInterval); 340 } 341 342 /** 343 * Creates a scheduler using the specified thread pool, job store, and 344 * plugins, and binds it to RMI. 345 * 346 * @param schedulerName 347 * The name for the scheduler. 348 * @param schedulerInstanceId 349 * The instance ID for the scheduler. 350 * @param threadPool 351 * The thread pool for executing jobs 352 * @param jobStore 353 * The type of job store 354 * @param schedulerPluginMap 355 * Map from a <code>String</code> plugin names to 356 * <code>{@link org.quartz.spi.SchedulerPlugin}</code>s. Can use 357 * "null" if no plugins are required. 358 * @param rmiRegistryHost 359 * The hostname to register this scheduler with for RMI. Can use 360 * "null" if no RMI is required. 361 * @param rmiRegistryPort 362 * The port for RMI. Typically 1099. 363 * @param idleWaitTime 364 * The idle wait time in milliseconds. You can specify "-1" for 365 * the default value, which is currently 30000 ms. 366 * @throws SchedulerException 367 * if initialization failed 368 */ 369 public void createScheduler(String schedulerName, 370 String schedulerInstanceId, ThreadPool threadPool, 371 JobStore jobStore, Map schedulerPluginMap, 372 String rmiRegistryHost, int rmiRegistryPort, 373 long idleWaitTime, long dbFailureRetryInterval) 374 throws SchedulerException { 375 // Currently only one run-shell factory is available... 376 JobRunShellFactory jrsf = new StdJobRunShellFactory(); 377 378 // Fire everything up 379 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 380 SchedulingContext schedCtxt = new SchedulingContext(); 381 schedCtxt.setInstanceId(schedulerInstanceId); 382 383 QuartzSchedulerResources qrs = new QuartzSchedulerResources(); 384 385 qrs.setName(schedulerName); 386 qrs.setInstanceId(schedulerInstanceId); 387 qrs.setJobRunShellFactory(jrsf); 388 qrs.setThreadPool(threadPool); 389 qrs.setJobStore(jobStore); 390 qrs.setRMIRegistryHost(rmiRegistryHost); 391 qrs.setRMIRegistryPort(rmiRegistryPort); 392 393 // add plugins 394 if (schedulerPluginMap != null) { 395 for (Iterator pluginIter = schedulerPluginMap.values().iterator(); pluginIter.hasNext();) { 396 qrs.addSchedulerPlugin((SchedulerPlugin)pluginIter.next()); 397 } 398 } 399 400 QuartzScheduler qs = new QuartzScheduler(qrs, schedCtxt, idleWaitTime, 401 dbFailureRetryInterval); 402 403 ClassLoadHelper cch = new CascadingClassLoadHelper(); 404 cch.initialize(); 405 406 jobStore.initialize(cch, qs.getSchedulerSignaler()); 407 408 Scheduler scheduler = new StdScheduler(qs, schedCtxt); 409 410 // Initialize plugins now that we have a Scheduler instance. 411 if (schedulerPluginMap != null) { 412 for (Iterator pluginEntryIter = schedulerPluginMap.entrySet().iterator(); pluginEntryIter.hasNext();) { 413 Map.Entry pluginEntry = (Map.Entry)pluginEntryIter.next(); 414 415 ((SchedulerPlugin)pluginEntry.getValue()).initialize( 416 (String)pluginEntry.getKey(), scheduler); 417 } 418 } 419 420 jrsf.initialize(scheduler, schedCtxt); 421 422 getLog().info("Quartz scheduler '" + scheduler.getSchedulerName()); 423 424 getLog().info("Quartz scheduler version: " + qs.getVersion()); 425 426 SchedulerRepository schedRep = SchedulerRepository.getInstance(); 427 428 qs.addNoGCObject(schedRep); // prevents the repository from being 429 // garbage collected 430 431 schedRep.bind(scheduler); 432 } 433 434 /* 435 * public void registerSchedulerForRmi(String schedulerName, String 436 * schedulerId, String registryHost, int registryPort) throws 437 * SchedulerException, RemoteException { QuartzScheduler scheduler = 438 * (QuartzScheduler) this.getScheduler(); scheduler.bind(registryHost, 439 * registryPort); } 440 */ 441 442 /** 443 * <p> 444 * Returns a handle to the Scheduler produced by this factory. 445 * </p> 446 * 447 * <p> 448 * you must call createRemoteScheduler or createScheduler methods before 449 * calling getScheduler() 450 * </p> 451 */ 452 public Scheduler getScheduler() throws SchedulerException { 453 if (!initialized) { 454 throw new SchedulerException( 455 "you must call createRemoteScheduler or createScheduler methods before calling getScheduler()"); 456 } 457 458 return getScheduler(DEFAULT_SCHEDULER_NAME); 459 } 460 461 /** 462 * <p> 463 * Returns a handle to the Scheduler with the given name, if it exists. 464 * </p> 465 */ 466 public Scheduler getScheduler(String schedName) throws SchedulerException { 467 SchedulerRepository schedRep = SchedulerRepository.getInstance(); 468 469 return schedRep.lookup(schedName); 470 } 471 472 /** 473 * <p> 474 * Returns a handle to all known Schedulers (made by any 475 * StdSchedulerFactory instance.). 476 * </p> 477 */ 478 public Collection getAllSchedulers() throws SchedulerException { 479 return SchedulerRepository.getInstance().lookupAll(); 480 } 481 482 }