Source Code Cross Referenced for RAMJobStore.java in  » Project-Management » quartz » org » quartz » simpl » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Project Management » quartz » org.quartz.simpl 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /* 
0002:         * Copyright 2004-2005 OpenSymphony 
0003:         * 
0004:         * Licensed under the Apache License, Version 2.0 (the "License"); you may not 
0005:         * use this file except in compliance with the License. You may obtain a copy 
0006:         * of the License at 
0007:         * 
0008:         *   http://www.apache.org/licenses/LICENSE-2.0 
0009:         *   
0010:         * Unless required by applicable law or agreed to in writing, software 
0011:         * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 
0012:         * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 
0013:         * License for the specific language governing permissions and limitations 
0014:         * under the License.
0015:         * 
0016:         */
0017:
0018:        /*
0019:         * Previously Copyright (c) 2001-2004 James House
0020:         */
0021:        package org.quartz.simpl;
0022:
0023:        import java.util.ArrayList;
0024:        import java.util.Comparator;
0025:        import java.util.Date;
0026:        import java.util.HashMap;
0027:        import java.util.HashSet;
0028:        import java.util.Iterator;
0029:        import java.util.Set;
0030:        import java.util.TreeSet;
0031:
0032:        import org.apache.commons.logging.Log;
0033:        import org.apache.commons.logging.LogFactory;
0034:        import org.quartz.Calendar;
0035:        import org.quartz.JobDataMap;
0036:        import org.quartz.JobDetail;
0037:        import org.quartz.JobPersistenceException;
0038:        import org.quartz.ObjectAlreadyExistsException;
0039:        import org.quartz.SchedulerException;
0040:        import org.quartz.Trigger;
0041:        import org.quartz.core.SchedulingContext;
0042:        import org.quartz.spi.ClassLoadHelper;
0043:        import org.quartz.spi.JobStore;
0044:        import org.quartz.spi.SchedulerSignaler;
0045:        import org.quartz.spi.TriggerFiredBundle;
0046:
0047:        /**
0048:         * <p>
0049:         * This class implements a <code>{@link org.quartz.spi.JobStore}</code> that
0050:         * utilizes RAM as its storage device.
0051:         * </p>
0052:         * 
0053:         * <p>
0054:         * As you should know, the ramification of this is that access is extrememly
0055:         * fast, but the data is completely volatile - therefore this <code>JobStore</code>
0056:         * should not be used if true persistence between program shutdowns is
0057:         * required.
0058:         * </p>
0059:         * 
0060:         * @author James House
0061:         * @author Sharada Jambula
0062:         * @author Eric Mueller
0063:         */
0064:        public class RAMJobStore implements  JobStore {
0065:
0066:            /*
0067:             * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0068:             * 
0069:             * Data members.
0070:             * 
0071:             * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0072:             */
0073:
0074:            protected HashMap jobsByFQN = new HashMap(1000);
0075:
0076:            protected HashMap triggersByFQN = new HashMap(1000);
0077:
0078:            protected HashMap jobsByGroup = new HashMap(25);
0079:
0080:            protected HashMap triggersByGroup = new HashMap(25);
0081:
0082:            protected TreeSet timeTriggers = new TreeSet(
0083:                    new TriggerComparator());
0084:
0085:            protected HashMap calendarsByName = new HashMap(25);
0086:
0087:            protected ArrayList triggers = new ArrayList(1000);
0088:
0089:            protected final Object jobLock = new Object();
0090:
0091:            protected final Object triggerLock = new Object();
0092:
0093:            protected HashSet pausedTriggerGroups = new HashSet();
0094:
0095:            protected HashSet blockedJobs = new HashSet();
0096:
0097:            protected long misfireThreshold = 5000l;
0098:
0099:            protected SchedulerSignaler signaler;
0100:
0101:            private final Log log = LogFactory.getLog(getClass());
0102:
0103:            /*
0104:             * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0105:             * 
0106:             * Constructors.
0107:             * 
0108:             * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0109:             */
0110:
0111:            /**
0112:             * <p>
0113:             * Create a new <code>RAMJobStore</code>.
0114:             * </p>
0115:             */
0116:            public RAMJobStore() {
0117:            }
0118:
0119:            /*
0120:             * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0121:             * 
0122:             * Interface.
0123:             * 
0124:             * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0125:             */
0126:
0127:            protected Log getLog() {
0128:                return log;
0129:            }
0130:
0131:            /**
0132:             * <p>
0133:             * Called by the QuartzScheduler before the <code>JobStore</code> is
0134:             * used, in order to give the it a chance to initialize.
0135:             * </p>
0136:             */
0137:            public void initialize(ClassLoadHelper loadHelper,
0138:                    SchedulerSignaler signaler) {
0139:
0140:                this .signaler = signaler;
0141:
0142:                getLog().info("RAMJobStore initialized.");
0143:            }
0144:
0145:            public void schedulerStarted() throws SchedulerException {
0146:                // nothing to do
0147:            }
0148:
0149:            public long getMisfireThreshold() {
0150:                return misfireThreshold;
0151:            }
0152:
0153:            /**
0154:             * The number of milliseconds by which a trigger must have missed its
0155:             * next-fire-time, in order for it to be considered "misfired" and thus
0156:             * have its misfire instruction applied.
0157:             * 
0158:             * @param misfireThreshold
0159:             */
0160:            public void setMisfireThreshold(long misfireThreshold) {
0161:                if (misfireThreshold < 1) {
0162:                    throw new IllegalArgumentException(
0163:                            "Misfirethreashold must be larger than 0");
0164:                }
0165:                this .misfireThreshold = misfireThreshold;
0166:            }
0167:
0168:            /**
0169:             * <p>
0170:             * Called by the QuartzScheduler to inform the <code>JobStore</code> that
0171:             * it should free up all of it's resources because the scheduler is
0172:             * shutting down.
0173:             * </p>
0174:             */
0175:            public void shutdown() {
0176:            }
0177:
0178:            public boolean supportsPersistence() {
0179:                return false;
0180:            }
0181:
0182:            /**
0183:             * <p>
0184:             * Store the given <code>{@link org.quartz.JobDetail}</code> and <code>{@link org.quartz.Trigger}</code>.
0185:             * </p>
0186:             * 
0187:             * @param newJob
0188:             *          The <code>JobDetail</code> to be stored.
0189:             * @param newTrigger
0190:             *          The <code>Trigger</code> to be stored.
0191:             * @throws ObjectAlreadyExistsException
0192:             *           if a <code>Job</code> with the same name/group already
0193:             *           exists.
0194:             */
0195:            public void storeJobAndTrigger(SchedulingContext ctxt,
0196:                    JobDetail newJob, Trigger newTrigger)
0197:                    throws JobPersistenceException {
0198:                storeJob(ctxt, newJob, false);
0199:                storeTrigger(ctxt, newTrigger, false);
0200:            }
0201:
0202:            /**
0203:             * <p>
0204:             * Store the given <code>{@link org.quartz.Job}</code>.
0205:             * </p>
0206:             * 
0207:             * @param newJob
0208:             *          The <code>Job</code> to be stored.
0209:             * @param replaceExisting
0210:             *          If <code>true</code>, any <code>Job</code> existing in the
0211:             *          <code>JobStore</code> with the same name & group should be
0212:             *          over-written.
0213:             * @throws ObjectAlreadyExistsException
0214:             *           if a <code>Job</code> with the same name/group already
0215:             *           exists, and replaceExisting is set to false.
0216:             */
0217:            public void storeJob(SchedulingContext ctxt, JobDetail newJob,
0218:                    boolean replaceExisting)
0219:                    throws ObjectAlreadyExistsException {
0220:                JobWrapper jw = new JobWrapper((JobDetail) newJob.clone());
0221:
0222:                boolean repl = false;
0223:
0224:                if (jobsByFQN.get(jw.key) != null) {
0225:                    if (!replaceExisting) {
0226:                        throw new ObjectAlreadyExistsException(newJob);
0227:                    }
0228:                    repl = true;
0229:                }
0230:
0231:                synchronized (jobLock) {
0232:                    if (!repl) {
0233:                        // get job group
0234:                        HashMap grpMap = (HashMap) jobsByGroup.get(newJob
0235:                                .getGroup());
0236:                        if (grpMap == null) {
0237:                            grpMap = new HashMap(100);
0238:                            jobsByGroup.put(newJob.getGroup(), grpMap);
0239:                        }
0240:                        // add to jobs by group
0241:                        grpMap.put(newJob.getName(), jw);
0242:                        // add to jobs by FQN map
0243:                        jobsByFQN.put(jw.key, jw);
0244:                    } else {
0245:                        // update job detail
0246:                        JobWrapper orig = (JobWrapper) jobsByFQN.get(jw.key);
0247:                        orig.jobDetail = jw.jobDetail; // already cloned
0248:                    }
0249:                }
0250:            }
0251:
0252:            /**
0253:             * <p>
0254:             * Remove (delete) the <code>{@link org.quartz.Job}</code> with the given
0255:             * name, and any <code>{@link org.quartz.Trigger}</code> s that reference
0256:             * it.
0257:             * </p>
0258:             *
0259:             * @param jobName
0260:             *          The name of the <code>Job</code> to be removed.
0261:             * @param groupName
0262:             *          The group name of the <code>Job</code> to be removed.
0263:             * @return <code>true</code> if a <code>Job</code> with the given name &
0264:             *         group was found and removed from the store.
0265:             */
0266:            public boolean removeJob(SchedulingContext ctxt, String jobName,
0267:                    String groupName) {
0268:                String key = JobWrapper.getJobNameKey(jobName, groupName);
0269:
0270:                boolean found = false;
0271:
0272:                Trigger[] trigger = getTriggersForJob(ctxt, jobName, groupName);
0273:                for (int i = 0; i < trigger.length; i++) {
0274:                    Trigger trig = trigger[i];
0275:                    this .removeTrigger(ctxt, trig.getName(), trig.getGroup());
0276:                    found = true;
0277:                }
0278:                synchronized (jobLock) {
0279:                    found = (jobsByFQN.remove(key) != null) | found;
0280:                    if (found) {
0281:
0282:                        HashMap grpMap = (HashMap) jobsByGroup.get(groupName);
0283:                        if (grpMap != null) {
0284:                            grpMap.remove(jobName);
0285:                            if (grpMap.size() == 0) {
0286:                                jobsByGroup.remove(groupName);
0287:                            }
0288:                        }
0289:                    }
0290:                }
0291:
0292:                return found;
0293:            }
0294:
0295:            /**
0296:             * <p>
0297:             * Store the given <code>{@link org.quartz.Trigger}</code>.
0298:             * </p>
0299:             *
0300:             * @param newTrigger
0301:             *          The <code>Trigger</code> to be stored.
0302:             * @param replaceExisting
0303:             *          If <code>true</code>, any <code>Trigger</code> existing in
0304:             *          the <code>JobStore</code> with the same name & group should
0305:             *          be over-written.
0306:             * @throws ObjectAlreadyExistsException
0307:             *           if a <code>Trigger</code> with the same name/group already
0308:             *           exists, and replaceExisting is set to false.
0309:             *
0310:             * @see #pauseTriggerGroup(SchedulingContext, String)
0311:             */
0312:            public void storeTrigger(SchedulingContext ctxt,
0313:                    Trigger newTrigger, boolean replaceExisting)
0314:                    throws JobPersistenceException {
0315:                TriggerWrapper tw = new TriggerWrapper((Trigger) newTrigger
0316:                        .clone());
0317:
0318:                if (triggersByFQN.get(tw.key) != null) {
0319:                    if (!replaceExisting) {
0320:                        throw new ObjectAlreadyExistsException(newTrigger);
0321:                    }
0322:
0323:                    removeTrigger(ctxt, newTrigger.getName(), newTrigger
0324:                            .getGroup());
0325:                }
0326:
0327:                if (retrieveJob(ctxt, newTrigger.getJobName(), newTrigger
0328:                        .getJobGroup()) == null) {
0329:                    throw new JobPersistenceException("The job ("
0330:                            + newTrigger.getFullJobName()
0331:                            + ") referenced by the trigger does not exist.");
0332:                }
0333:
0334:                synchronized (triggerLock) {
0335:                    // add to triggers array
0336:                    triggers.add(tw);
0337:                    // add to triggers by group
0338:                    HashMap grpMap = (HashMap) triggersByGroup.get(newTrigger
0339:                            .getGroup());
0340:                    if (grpMap == null) {
0341:                        grpMap = new HashMap(100);
0342:                        triggersByGroup.put(newTrigger.getGroup(), grpMap);
0343:                    }
0344:                    grpMap.put(newTrigger.getName(), tw);
0345:                    // add to triggers by FQN map
0346:                    triggersByFQN.put(tw.key, tw);
0347:
0348:                    synchronized (pausedTriggerGroups) {
0349:                        if (pausedTriggerGroups.contains(newTrigger.getGroup())) {
0350:                            tw.state = TriggerWrapper.STATE_PAUSED;
0351:                            if (blockedJobs.contains(tw.jobKey)) {
0352:                                tw.state = TriggerWrapper.STATE_PAUSED_BLOCKED;
0353:                            }
0354:                        } else if (blockedJobs.contains(tw.jobKey)) {
0355:                            tw.state = TriggerWrapper.STATE_BLOCKED;
0356:                        } else {
0357:                            timeTriggers.add(tw);
0358:                        }
0359:                    }
0360:                }
0361:            }
0362:
0363:            /**
0364:             * <p>
0365:             * Remove (delete) the <code>{@link org.quartz.Trigger}</code> with the
0366:             * given name.
0367:             * </p>
0368:             *
0369:             * @param triggerName
0370:             *          The name of the <code>Trigger</code> to be removed.
0371:             * @param groupName
0372:             *          The group name of the <code>Trigger</code> to be removed.
0373:             * @return <code>true</code> if a <code>Trigger</code> with the given
0374:             *         name & group was found and removed from the store.
0375:             */
0376:            public boolean removeTrigger(SchedulingContext ctxt,
0377:                    String triggerName, String groupName) {
0378:                String key = TriggerWrapper.getTriggerNameKey(triggerName,
0379:                        groupName);
0380:
0381:                boolean found = false;
0382:
0383:                synchronized (triggerLock) {
0384:                    // remove from triggers by FQN map
0385:                    found = (triggersByFQN.remove(key) == null) ? false : true;
0386:                    if (found) {
0387:                        TriggerWrapper tw = null;
0388:                        // remove from triggers by group
0389:                        HashMap grpMap = (HashMap) triggersByGroup
0390:                                .get(groupName);
0391:                        if (grpMap != null) {
0392:                            grpMap.remove(triggerName);
0393:                            if (grpMap.size() == 0) {
0394:                                triggersByGroup.remove(groupName);
0395:                            }
0396:                        }
0397:                        // remove from triggers array
0398:                        Iterator tgs = triggers.iterator();
0399:                        while (tgs.hasNext()) {
0400:                            tw = (TriggerWrapper) tgs.next();
0401:                            if (key.equals(tw.key)) {
0402:                                tgs.remove();
0403:                                break;
0404:                            }
0405:                        }
0406:                        timeTriggers.remove(tw);
0407:
0408:                        JobWrapper jw = (JobWrapper) jobsByFQN.get(JobWrapper
0409:                                .getJobNameKey(tw.trigger.getJobName(),
0410:                                        tw.trigger.getJobGroup()));
0411:                        Trigger[] trigs = getTriggersForJob(ctxt, tw.trigger
0412:                                .getJobName(), tw.trigger.getJobGroup());
0413:                        if ((trigs == null || trigs.length == 0)
0414:                                && !jw.jobDetail.isDurable()) {
0415:                            removeJob(ctxt, tw.trigger.getJobName(), tw.trigger
0416:                                    .getJobGroup());
0417:                        }
0418:                    }
0419:                }
0420:
0421:                return found;
0422:            }
0423:
0424:            /**
0425:             * @see org.quartz.spi.JobStore#replaceTrigger(org.quartz.core.SchedulingContext, java.lang.String, java.lang.String, org.quartz.Trigger)
0426:             */
0427:            public boolean replaceTrigger(SchedulingContext ctxt,
0428:                    String triggerName, String groupName, Trigger newTrigger)
0429:                    throws JobPersistenceException {
0430:                String key = TriggerWrapper.getTriggerNameKey(triggerName,
0431:                        groupName);
0432:
0433:                boolean found = false;
0434:
0435:                synchronized (triggerLock) {
0436:                    // remove from triggers by FQN map
0437:                    TriggerWrapper tw = (TriggerWrapper) triggersByFQN
0438:                            .remove(key);
0439:                    found = (tw == null) ? false : true;
0440:
0441:                    if (found) {
0442:
0443:                        if (!tw.getTrigger().getJobName().equals(
0444:                                newTrigger.getJobName())
0445:                                || !tw.getTrigger().getJobGroup().equals(
0446:                                        newTrigger.getJobGroup())) {
0447:                            throw new JobPersistenceException(
0448:                                    "New trigger is not related to the same job as the old trigger.");
0449:                        }
0450:
0451:                        tw = null;
0452:                        // remove from triggers by group
0453:                        HashMap grpMap = (HashMap) triggersByGroup
0454:                                .get(groupName);
0455:                        if (grpMap != null) {
0456:                            grpMap.remove(triggerName);
0457:                            if (grpMap.size() == 0) {
0458:                                triggersByGroup.remove(groupName);
0459:                            }
0460:                        }
0461:                        // remove from triggers array
0462:                        Iterator tgs = triggers.iterator();
0463:                        while (tgs.hasNext()) {
0464:                            tw = (TriggerWrapper) tgs.next();
0465:                            if (key.equals(tw.key)) {
0466:                                tgs.remove();
0467:                                break;
0468:                            }
0469:                        }
0470:                        timeTriggers.remove(tw);
0471:
0472:                        try {
0473:                            storeTrigger(ctxt, newTrigger, false);
0474:                        } catch (JobPersistenceException jpe) {
0475:                            storeTrigger(ctxt, tw.getTrigger(), false); // put previous trigger back...
0476:                            throw jpe;
0477:                        }
0478:                    }
0479:                }
0480:
0481:                return found;
0482:            }
0483:
0484:            /**
0485:             * <p>
0486:             * Retrieve the <code>{@link org.quartz.JobDetail}</code> for the given
0487:             * <code>{@link org.quartz.Job}</code>.
0488:             * </p>
0489:             *
0490:             * @param jobName
0491:             *          The name of the <code>Job</code> to be retrieved.
0492:             * @param groupName
0493:             *          The group name of the <code>Job</code> to be retrieved.
0494:             * @return The desired <code>Job</code>, or null if there is no match.
0495:             */
0496:            public JobDetail retrieveJob(SchedulingContext ctxt,
0497:                    String jobName, String groupName) {
0498:                JobWrapper jw = (JobWrapper) jobsByFQN.get(JobWrapper
0499:                        .getJobNameKey(jobName, groupName));
0500:
0501:                return (jw != null) ? (JobDetail) jw.jobDetail.clone() : null;
0502:            }
0503:
0504:            /**
0505:             * <p>
0506:             * Retrieve the given <code>{@link org.quartz.Trigger}</code>.
0507:             * </p>
0508:             *
0509:             * @param triggerName
0510:             *          The name of the <code>Trigger</code> to be retrieved.
0511:             * @param groupName
0512:             *          The group name of the <code>Trigger</code> to be retrieved.
0513:             * @return The desired <code>Trigger</code>, or null if there is no
0514:             *         match.
0515:             */
0516:            public Trigger retrieveTrigger(SchedulingContext ctxt,
0517:                    String triggerName, String groupName) {
0518:                TriggerWrapper tw = (TriggerWrapper) triggersByFQN
0519:                        .get(TriggerWrapper.getTriggerNameKey(triggerName,
0520:                                groupName));
0521:
0522:                return (tw != null) ? (Trigger) tw.getTrigger().clone() : null;
0523:            }
0524:
0525:            /**
0526:             * <p>
0527:             * Get the current state of the identified <code>{@link Trigger}</code>.
0528:             * </p>
0529:             *
0530:             * @see Trigger#STATE_NORMAL
0531:             * @see Trigger#STATE_PAUSED
0532:             * @see Trigger#STATE_COMPLETE
0533:             * @see Trigger#STATE_ERROR
0534:             * @see Trigger#STATE_BLOCKED
0535:             * @see Trigger#STATE_NONE
0536:             */
0537:            public int getTriggerState(SchedulingContext ctxt,
0538:                    String triggerName, String groupName)
0539:                    throws JobPersistenceException {
0540:                TriggerWrapper tw = (TriggerWrapper) triggersByFQN
0541:                        .get(TriggerWrapper.getTriggerNameKey(triggerName,
0542:                                groupName));
0543:                if (tw == null) {
0544:                    return Trigger.STATE_NONE;
0545:                }
0546:
0547:                if (tw.state == TriggerWrapper.STATE_COMPLETE) {
0548:                    return Trigger.STATE_COMPLETE;
0549:                }
0550:
0551:                if (tw.state == TriggerWrapper.STATE_PAUSED) {
0552:                    return Trigger.STATE_PAUSED;
0553:                }
0554:
0555:                if (tw.state == TriggerWrapper.STATE_PAUSED_BLOCKED) {
0556:                    return Trigger.STATE_PAUSED;
0557:                }
0558:
0559:                if (tw.state == TriggerWrapper.STATE_BLOCKED) {
0560:                    return Trigger.STATE_BLOCKED;
0561:                }
0562:
0563:                if (tw.state == TriggerWrapper.STATE_ERROR) {
0564:                    return Trigger.STATE_ERROR;
0565:                }
0566:
0567:                return Trigger.STATE_NORMAL;
0568:            }
0569:
0570:            /**
0571:             * <p>
0572:             * Store the given <code>{@link org.quartz.Calendar}</code>.
0573:             * </p>
0574:             *
0575:             * @param calendar
0576:             *          The <code>Calendar</code> to be stored.
0577:             * @param replaceExisting
0578:             *          If <code>true</code>, any <code>Calendar</code> existing
0579:             *          in the <code>JobStore</code> with the same name & group
0580:             *          should be over-written.
0581:             * @param updateTriggers
0582:             *          If <code>true</code>, any <code>Trigger</code>s existing
0583:             *          in the <code>JobStore</code> that reference an existing
0584:             *          Calendar with the same name with have their next fire time
0585:             *          re-computed with the new <code>Calendar</code>.
0586:             * @throws ObjectAlreadyExistsException
0587:             *           if a <code>Calendar</code> with the same name already
0588:             *           exists, and replaceExisting is set to false.
0589:             */
0590:            public void storeCalendar(SchedulingContext ctxt, String name,
0591:                    Calendar calendar, boolean replaceExisting,
0592:                    boolean updateTriggers) throws ObjectAlreadyExistsException {
0593:                Object obj = calendarsByName.get(name);
0594:
0595:                if (obj != null && replaceExisting == false) {
0596:                    throw new ObjectAlreadyExistsException(
0597:                            "Calendar with name '" + name + "' already exists.");
0598:                } else if (obj != null) {
0599:                    calendarsByName.remove(name);
0600:                }
0601:
0602:                calendarsByName.put(name, calendar);
0603:
0604:                if (obj != null && updateTriggers) {
0605:                    synchronized (triggerLock) {
0606:                        Iterator trigs = getTriggerWrappersForCalendar(name)
0607:                                .iterator();
0608:                        while (trigs.hasNext()) {
0609:                            TriggerWrapper tw = (TriggerWrapper) trigs.next();
0610:                            Trigger trig = tw.getTrigger();
0611:                            boolean removed = timeTriggers.remove(tw);
0612:
0613:                            trig.updateWithNewCalendar(calendar,
0614:                                    getMisfireThreshold());
0615:
0616:                            if (removed) {
0617:                                timeTriggers.add(tw);
0618:                            }
0619:                        }
0620:                    }
0621:                }
0622:            }
0623:
0624:            /**
0625:             * <p>
0626:             * Remove (delete) the <code>{@link org.quartz.Calendar}</code> with the
0627:             * given name.
0628:             * </p>
0629:             *
0630:             * <p>
0631:             * If removal of the <code>Calendar</code> would result in
0632:             * <code.Trigger</code>s pointing to non-existent calendars, then a
0633:             * <code>JobPersistenceException</code> will be thrown.</p>
0634:             *       *
0635:             * @param calName The name of the <code>Calendar</code> to be removed.
0636:             * @return <code>true</code> if a <code>Calendar</code> with the given name
0637:             * was found and removed from the store.
0638:             */
0639:            public boolean removeCalendar(SchedulingContext ctxt, String calName)
0640:                    throws JobPersistenceException {
0641:                int numRefs = 0;
0642:
0643:                synchronized (triggerLock) {
0644:                    Iterator itr = triggers.iterator();
0645:                    while (itr.hasNext()) {
0646:                        Trigger trigg = ((TriggerWrapper) itr.next()).trigger;
0647:                        if (trigg.getCalendarName() != null
0648:                                && trigg.getCalendarName().equals(calName)) {
0649:                            numRefs++;
0650:                        }
0651:                    }
0652:                }
0653:
0654:                if (numRefs > 0) {
0655:                    throw new JobPersistenceException(
0656:                            "Calender cannot be removed if it referenced by a Trigger!");
0657:                }
0658:
0659:                return (calendarsByName.remove(calName) != null);
0660:            }
0661:
0662:            /**
0663:             * <p>
0664:             * Retrieve the given <code>{@link org.quartz.Trigger}</code>.
0665:             * </p>
0666:             *
0667:             * @param calName
0668:             *          The name of the <code>Calendar</code> to be retrieved.
0669:             * @return The desired <code>Calendar</code>, or null if there is no
0670:             *         match.
0671:             */
0672:            public Calendar retrieveCalendar(SchedulingContext ctxt,
0673:                    String calName) {
0674:                return (Calendar) calendarsByName.get(calName);
0675:            }
0676:
0677:            /**
0678:             * <p>
0679:             * Get the number of <code>{@link org.quartz.JobDetail}</code> s that are
0680:             * stored in the <code>JobsStore</code>.
0681:             * </p>
0682:             */
0683:            public int getNumberOfJobs(SchedulingContext ctxt) {
0684:                return jobsByFQN.size();
0685:            }
0686:
0687:            /**
0688:             * <p>
0689:             * Get the number of <code>{@link org.quartz.Trigger}</code> s that are
0690:             * stored in the <code>JobsStore</code>.
0691:             * </p>
0692:             */
0693:            public int getNumberOfTriggers(SchedulingContext ctxt) {
0694:                return triggers.size();
0695:            }
0696:
0697:            /**
0698:             * <p>
0699:             * Get the number of <code>{@link org.quartz.Calendar}</code> s that are
0700:             * stored in the <code>JobsStore</code>.
0701:             * </p>
0702:             */
0703:            public int getNumberOfCalendars(SchedulingContext ctxt) {
0704:                return calendarsByName.size();
0705:            }
0706:
0707:            /**
0708:             * <p>
0709:             * Get the names of all of the <code>{@link org.quartz.Job}</code> s that
0710:             * have the given group name.
0711:             * </p>
0712:             */
0713:            public String[] getJobNames(SchedulingContext ctxt, String groupName) {
0714:                String[] outList = null;
0715:                HashMap grpMap = (HashMap) jobsByGroup.get(groupName);
0716:                if (grpMap != null) {
0717:                    synchronized (jobLock) {
0718:                        outList = new String[grpMap.size()];
0719:                        int outListPos = 0;
0720:
0721:                        for (Iterator valueIter = grpMap.values().iterator(); valueIter
0722:                                .hasNext();) {
0723:                            JobWrapper jw = (JobWrapper) valueIter.next();
0724:
0725:                            if (jw != null) {
0726:                                outList[outListPos++] = jw.jobDetail.getName();
0727:                            }
0728:                        }
0729:                    }
0730:                } else {
0731:                    outList = new String[0];
0732:                }
0733:
0734:                return outList;
0735:            }
0736:
0737:            /**
0738:             * <p>
0739:             * Get the names of all of the <code>{@link org.quartz.Calendar}</code> s
0740:             * in the <code>JobStore</code>.
0741:             * </p>
0742:             *
0743:             * <p>
0744:             * If there are no Calendars in the given group name, the result should be
0745:             * a zero-length array (not <code>null</code>).
0746:             * </p>
0747:             */
0748:            public String[] getCalendarNames(SchedulingContext ctxt) {
0749:                Set names = calendarsByName.keySet();
0750:                return (String[]) names.toArray(new String[names.size()]);
0751:            }
0752:
0753:            /**
0754:             * <p>
0755:             * Get the names of all of the <code>{@link org.quartz.Trigger}</code> s
0756:             * that have the given group name.
0757:             * </p>
0758:             */
0759:            public String[] getTriggerNames(SchedulingContext ctxt,
0760:                    String groupName) {
0761:                String[] outList = null;
0762:                HashMap grpMap = (HashMap) triggersByGroup.get(groupName);
0763:                if (grpMap != null) {
0764:                    synchronized (triggerLock) {
0765:                        outList = new String[grpMap.size()];
0766:                        int outListPos = 0;
0767:
0768:                        for (Iterator valueIter = grpMap.values().iterator(); valueIter
0769:                                .hasNext();) {
0770:                            TriggerWrapper tw = (TriggerWrapper) valueIter
0771:                                    .next();
0772:
0773:                            if (tw != null) {
0774:                                outList[outListPos++] = tw.trigger.getName();
0775:                            }
0776:                        }
0777:                    }
0778:                } else {
0779:                    outList = new String[0];
0780:                }
0781:
0782:                return outList;
0783:            }
0784:
0785:            /**
0786:             * <p>
0787:             * Get the names of all of the <code>{@link org.quartz.Job}</code>
0788:             * groups.
0789:             * </p>
0790:             */
0791:            public String[] getJobGroupNames(SchedulingContext ctxt) {
0792:                String[] outList = null;
0793:
0794:                synchronized (jobLock) {
0795:                    outList = new String[jobsByGroup.size()];
0796:                    int outListPos = 0;
0797:                    Iterator keys = jobsByGroup.keySet().iterator();
0798:                    while (keys.hasNext()) {
0799:                        outList[outListPos++] = (String) keys.next();
0800:                    }
0801:                }
0802:
0803:                return outList;
0804:            }
0805:
0806:            /**
0807:             * <p>
0808:             * Get the names of all of the <code>{@link org.quartz.Trigger}</code>
0809:             * groups.
0810:             * </p>
0811:             */
0812:            public String[] getTriggerGroupNames(SchedulingContext ctxt) {
0813:                String[] outList = null;
0814:
0815:                synchronized (triggerLock) {
0816:                    outList = new String[triggersByGroup.size()];
0817:                    int outListPos = 0;
0818:                    Iterator keys = triggersByGroup.keySet().iterator();
0819:                    while (keys.hasNext()) {
0820:                        outList[outListPos++] = (String) keys.next();
0821:                    }
0822:                }
0823:
0824:                return outList;
0825:            }
0826:
0827:            /**
0828:             * <p>
0829:             * Get all of the Triggers that are associated to the given Job.
0830:             * </p>
0831:             *
0832:             * <p>
0833:             * If there are no matches, a zero-length array should be returned.
0834:             * </p>
0835:             */
0836:            public Trigger[] getTriggersForJob(SchedulingContext ctxt,
0837:                    String jobName, String groupName) {
0838:                ArrayList trigList = new ArrayList();
0839:
0840:                String jobKey = JobWrapper.getJobNameKey(jobName, groupName);
0841:                synchronized (triggerLock) {
0842:                    for (int i = 0; i < triggers.size(); i++) {
0843:                        TriggerWrapper tw = (TriggerWrapper) triggers.get(i);
0844:                        if (tw.jobKey.equals(jobKey)) {
0845:                            trigList.add(tw.trigger.clone());
0846:                        }
0847:                    }
0848:                }
0849:
0850:                return (Trigger[]) trigList
0851:                        .toArray(new Trigger[trigList.size()]);
0852:            }
0853:
0854:            protected ArrayList getTriggerWrappersForJob(String jobName,
0855:                    String groupName) {
0856:                ArrayList trigList = new ArrayList();
0857:
0858:                String jobKey = JobWrapper.getJobNameKey(jobName, groupName);
0859:                synchronized (triggerLock) {
0860:                    for (int i = 0; i < triggers.size(); i++) {
0861:                        TriggerWrapper tw = (TriggerWrapper) triggers.get(i);
0862:                        if (tw.jobKey.equals(jobKey)) {
0863:                            trigList.add(tw);
0864:                        }
0865:                    }
0866:                }
0867:
0868:                return trigList;
0869:            }
0870:
0871:            protected ArrayList getTriggerWrappersForCalendar(String calName) {
0872:                ArrayList trigList = new ArrayList();
0873:
0874:                synchronized (triggerLock) {
0875:                    for (int i = 0; i < triggers.size(); i++) {
0876:                        TriggerWrapper tw = (TriggerWrapper) triggers.get(i);
0877:                        String tcalName = tw.getTrigger().getCalendarName();
0878:                        if (tcalName != null && tcalName.equals(calName)) {
0879:                            trigList.add(tw);
0880:                        }
0881:                    }
0882:                }
0883:
0884:                return trigList;
0885:            }
0886:
0887:            /**
0888:             * <p>
0889:             * Pause the <code>{@link Trigger}</code> with the given name.
0890:             * </p>
0891:             *
0892:             */
0893:            public void pauseTrigger(SchedulingContext ctxt,
0894:                    String triggerName, String groupName) {
0895:
0896:                TriggerWrapper tw = (TriggerWrapper) triggersByFQN
0897:                        .get(TriggerWrapper.getTriggerNameKey(triggerName,
0898:                                groupName));
0899:
0900:                // does the trigger exist?
0901:                if (tw == null || tw.trigger == null) {
0902:                    return;
0903:                }
0904:
0905:                // if the trigger is "complete" pausing it does not make sense...
0906:                if (tw.state == TriggerWrapper.STATE_COMPLETE) {
0907:                    return;
0908:                }
0909:
0910:                synchronized (triggerLock) {
0911:                    if (tw.state == TriggerWrapper.STATE_BLOCKED) {
0912:                        tw.state = TriggerWrapper.STATE_PAUSED_BLOCKED;
0913:                    } else {
0914:                        tw.state = TriggerWrapper.STATE_PAUSED;
0915:                    }
0916:
0917:                    timeTriggers.remove(tw);
0918:                }
0919:            }
0920:
0921:            /**
0922:             * <p>
0923:             * Pause all of the <code>{@link Trigger}s</code> in the given group.
0924:             * </p>
0925:             *
0926:             * <p>
0927:             * The JobStore should "remember" that the group is paused, and impose the
0928:             * pause on any new triggers that are added to the group while the group is
0929:             * paused.
0930:             * </p>
0931:             *
0932:             */
0933:            public void pauseTriggerGroup(SchedulingContext ctxt,
0934:                    String groupName) {
0935:
0936:                synchronized (pausedTriggerGroups) {
0937:                    if (pausedTriggerGroups.contains(groupName)) {
0938:                        return;
0939:                    }
0940:
0941:                    pausedTriggerGroups.add(groupName);
0942:                    String[] names = getTriggerNames(ctxt, groupName);
0943:
0944:                    for (int i = 0; i < names.length; i++) {
0945:                        pauseTrigger(ctxt, names[i], groupName);
0946:                    }
0947:                }
0948:            }
0949:
0950:            /**
0951:             * <p>
0952:             * Pause the <code>{@link org.quartz.JobDetail}</code> with the given
0953:             * name - by pausing all of its current <code>Trigger</code>s.
0954:             * </p>
0955:             *
0956:             */
0957:            public void pauseJob(SchedulingContext ctxt, String jobName,
0958:                    String groupName) {
0959:                synchronized (pausedTriggerGroups) {
0960:                    Trigger[] triggers = getTriggersForJob(ctxt, jobName,
0961:                            groupName);
0962:                    for (int j = 0; j < triggers.length; j++) {
0963:                        pauseTrigger(ctxt, triggers[j].getName(), triggers[j]
0964:                                .getGroup());
0965:                    }
0966:                }
0967:            }
0968:
0969:            /**
0970:             * <p>
0971:             * Pause all of the <code>{@link org.quartz.JobDetail}s</code> in the
0972:             * given group - by pausing all of their <code>Trigger</code>s.
0973:             * </p>
0974:             *
0975:             *
0976:             * <p>
0977:             * The JobStore should "remember" that the group is paused, and impose the
0978:             * pause on any new jobs that are added to the group while the group is
0979:             * paused.
0980:             * </p>
0981:             */
0982:            public void pauseJobGroup(SchedulingContext ctxt, String groupName) {
0983:                synchronized (pausedTriggerGroups) {
0984:                    String[] jobNames = getJobNames(ctxt, groupName);
0985:
0986:                    for (int i = 0; i < jobNames.length; i++) {
0987:                        Trigger[] triggers = getTriggersForJob(ctxt,
0988:                                jobNames[i], groupName);
0989:                        for (int j = 0; j < triggers.length; j++) {
0990:                            pauseTrigger(ctxt, triggers[j].getName(),
0991:                                    triggers[j].getGroup());
0992:                        }
0993:                    }
0994:                }
0995:            }
0996:
0997:            /**
0998:             * <p>
0999:             * Resume (un-pause) the <code>{@link Trigger}</code> with the given
1000:             * name.
1001:             * </p>
1002:             *
1003:             * <p>
1004:             * If the <code>Trigger</code> missed one or more fire-times, then the
1005:             * <code>Trigger</code>'s misfire instruction will be applied.
1006:             * </p>
1007:             *
1008:             */
1009:            public void resumeTrigger(SchedulingContext ctxt,
1010:                    String triggerName, String groupName) {
1011:
1012:                TriggerWrapper tw = (TriggerWrapper) triggersByFQN
1013:                        .get(TriggerWrapper.getTriggerNameKey(triggerName,
1014:                                groupName));
1015:
1016:                Trigger trig = tw.getTrigger();
1017:
1018:                // does the trigger exist?
1019:                if (tw == null || tw.trigger == null) {
1020:                    return;
1021:                }
1022:                // if the trigger is not paused resuming it does not make sense...
1023:                if (tw.state != TriggerWrapper.STATE_PAUSED
1024:                        && tw.state != TriggerWrapper.STATE_PAUSED_BLOCKED) {
1025:                    return;
1026:                }
1027:
1028:                synchronized (triggerLock) {
1029:                    if (blockedJobs.contains(JobWrapper.getJobNameKey(trig
1030:                            .getJobName(), trig.getJobGroup()))) {
1031:                        tw.state = TriggerWrapper.STATE_BLOCKED;
1032:                    } else {
1033:                        tw.state = TriggerWrapper.STATE_WAITING;
1034:                    }
1035:
1036:                    applyMisfire(tw);
1037:
1038:                    if (tw.state == TriggerWrapper.STATE_WAITING) {
1039:                        timeTriggers.add(tw);
1040:                    }
1041:                }
1042:            }
1043:
1044:            /**
1045:             * <p>
1046:             * Resume (un-pause) all of the <code>{@link Trigger}s</code> in the
1047:             * given group.
1048:             * </p>
1049:             *
1050:             * <p>
1051:             * If any <code>Trigger</code> missed one or more fire-times, then the
1052:             * <code>Trigger</code>'s misfire instruction will be applied.
1053:             * </p>
1054:             *
1055:             */
1056:            public void resumeTriggerGroup(SchedulingContext ctxt,
1057:                    String groupName) {
1058:
1059:                synchronized (pausedTriggerGroups) {
1060:                    String[] names = getTriggerNames(ctxt, groupName);
1061:
1062:                    for (int i = 0; i < names.length; i++) {
1063:                        resumeTrigger(ctxt, names[i], groupName);
1064:                    }
1065:                    pausedTriggerGroups.remove(groupName);
1066:                }
1067:            }
1068:
1069:            /**
1070:             * <p>
1071:             * Resume (un-pause) the <code>{@link org.quartz.JobDetail}</code> with
1072:             * the given name.
1073:             * </p>
1074:             *
1075:             * <p>
1076:             * If any of the <code>Job</code>'s<code>Trigger</code> s missed one
1077:             * or more fire-times, then the <code>Trigger</code>'s misfire
1078:             * instruction will be applied.
1079:             * </p>
1080:             *
1081:             */
1082:            public void resumeJob(SchedulingContext ctxt, String jobName,
1083:                    String groupName) {
1084:
1085:                synchronized (pausedTriggerGroups) {
1086:                    Trigger[] triggers = getTriggersForJob(ctxt, jobName,
1087:                            groupName);
1088:                    for (int j = 0; j < triggers.length; j++) {
1089:                        resumeTrigger(ctxt, triggers[j].getName(), triggers[j]
1090:                                .getGroup());
1091:                    }
1092:                }
1093:            }
1094:
1095:            /**
1096:             * <p>
1097:             * Resume (un-pause) all of the <code>{@link org.quartz.JobDetail}s</code>
1098:             * in the given group.
1099:             * </p>
1100:             *
1101:             * <p>
1102:             * If any of the <code>Job</code> s had <code>Trigger</code> s that
1103:             * missed one or more fire-times, then the <code>Trigger</code>'s
1104:             * misfire instruction will be applied.
1105:             * </p>
1106:             *
1107:             */
1108:            public void resumeJobGroup(SchedulingContext ctxt, String groupName) {
1109:                synchronized (pausedTriggerGroups) {
1110:                    String[] jobNames = getJobNames(ctxt, groupName);
1111:
1112:                    for (int i = 0; i < jobNames.length; i++) {
1113:                        Trigger[] triggers = getTriggersForJob(ctxt,
1114:                                jobNames[i], groupName);
1115:                        for (int j = 0; j < triggers.length; j++) {
1116:                            resumeTrigger(ctxt, triggers[j].getName(),
1117:                                    triggers[j].getGroup());
1118:                        }
1119:                    }
1120:                }
1121:            }
1122:
1123:            /**
1124:             * <p>
1125:             * Pause all triggers - equivalent of calling <code>pauseTriggerGroup(group)</code>
1126:             * on every group.
1127:             * </p>
1128:             *
1129:             * <p>
1130:             * When <code>resumeAll()</code> is called (to un-pause), trigger misfire
1131:             * instructions WILL be applied.
1132:             * </p>
1133:             *
1134:             * @see #resumeAll(SchedulingContext)
1135:             * @see #pauseTriggerGroup(SchedulingContext, String)
1136:             */
1137:            public void pauseAll(SchedulingContext ctxt) {
1138:
1139:                synchronized (pausedTriggerGroups) {
1140:                    String[] names = getTriggerGroupNames(ctxt);
1141:
1142:                    for (int i = 0; i < names.length; i++) {
1143:                        pauseTriggerGroup(ctxt, names[i]);
1144:                    }
1145:                }
1146:            }
1147:
1148:            /**
1149:             * <p>
1150:             * Resume (un-pause) all triggers - equivalent of calling <code>resumeTriggerGroup(group)</code>
1151:             * on every group.
1152:             * </p>
1153:             *
1154:             * <p>
1155:             * If any <code>Trigger</code> missed one or more fire-times, then the
1156:             * <code>Trigger</code>'s misfire instruction will be applied.
1157:             * </p>
1158:             *
1159:             * @see #pauseAll(SchedulingContext)
1160:             */
1161:            public void resumeAll(SchedulingContext ctxt) {
1162:
1163:                synchronized (pausedTriggerGroups) {
1164:                    String[] names = getTriggerGroupNames(ctxt);
1165:
1166:                    for (int i = 0; i < names.length; i++) {
1167:                        resumeTriggerGroup(ctxt, names[i]);
1168:                    }
1169:                }
1170:            }
1171:
1172:            protected boolean applyMisfire(TriggerWrapper tw) {
1173:
1174:                long misfireTime = System.currentTimeMillis();
1175:                if (getMisfireThreshold() > 0) {
1176:                    misfireTime -= getMisfireThreshold();
1177:                }
1178:
1179:                java.util.Date tnft = tw.trigger.getNextFireTime();
1180:                if (tnft.getTime() > misfireTime) {
1181:                    return false;
1182:                }
1183:
1184:                Calendar cal = null;
1185:                if (tw.trigger.getCalendarName() != null) {
1186:                    cal = retrieveCalendar(null, tw.trigger.getCalendarName());
1187:                }
1188:
1189:                signaler.notifyTriggerListenersMisfired((Trigger) tw.trigger
1190:                        .clone());
1191:
1192:                tw.trigger.updateAfterMisfire(cal);
1193:
1194:                if (tw.trigger.getNextFireTime() == null) {
1195:                    tw.state = TriggerWrapper.STATE_COMPLETE;
1196:                    synchronized (triggerLock) {
1197:                        timeTriggers.remove(tw);
1198:                    }
1199:                } else if (tnft.equals(tw.trigger.getNextFireTime())) {
1200:                    return false;
1201:                }
1202:
1203:                return true;
1204:            }
1205:
1206:            private static long ftrCtr = System.currentTimeMillis();
1207:
1208:            protected synchronized String getFiredTriggerRecordId() {
1209:                return String.valueOf(ftrCtr++);
1210:            }
1211:
1212:            /**
1213:             * <p>
1214:             * Get a handle to the next trigger to be fired, and mark it as 'reserved'
1215:             * by the calling scheduler.
1216:             * </p>
1217:             *
1218:             * @see #releaseAcquiredTrigger(SchedulingContext, Trigger)
1219:             */
1220:            public Trigger acquireNextTrigger(SchedulingContext ctxt,
1221:                    long noLaterThan) {
1222:                TriggerWrapper tw = null;
1223:
1224:                synchronized (triggerLock) {
1225:
1226:                    while (tw == null) {
1227:                        try {
1228:                            tw = (TriggerWrapper) timeTriggers.first();
1229:                        } catch (java.util.NoSuchElementException nsee) {
1230:                            return null;
1231:                        }
1232:
1233:                        if (tw == null) {
1234:                            return null;
1235:                        }
1236:
1237:                        if (tw.trigger.getNextFireTime() == null) {
1238:                            timeTriggers.remove(tw);
1239:                            tw = null;
1240:                            continue;
1241:                        }
1242:
1243:                        timeTriggers.remove(tw);
1244:
1245:                        if (applyMisfire(tw)) {
1246:                            if (tw.trigger.getNextFireTime() != null) {
1247:                                timeTriggers.add(tw);
1248:                            }
1249:                            tw = null;
1250:                            continue;
1251:                        }
1252:
1253:                        if (tw.trigger.getNextFireTime().getTime() > noLaterThan) {
1254:                            timeTriggers.add(tw);
1255:                            return null;
1256:                        }
1257:
1258:                        tw.state = TriggerWrapper.STATE_ACQUIRED;
1259:
1260:                        tw.trigger.setFireInstanceId(getFiredTriggerRecordId());
1261:                        Trigger trig = (Trigger) tw.trigger.clone();
1262:                        return trig;
1263:                    }
1264:                }
1265:
1266:                return null;
1267:            }
1268:
1269:            /**
1270:             * <p>
1271:             * Inform the <code>JobStore</code> that the scheduler no longer plans to
1272:             * fire the given <code>Trigger</code>, that it had previously acquired
1273:             * (reserved).
1274:             * </p>
1275:             */
1276:            public void releaseAcquiredTrigger(SchedulingContext ctxt,
1277:                    Trigger trigger) {
1278:                synchronized (triggerLock) {
1279:                    TriggerWrapper tw = (TriggerWrapper) triggersByFQN
1280:                            .get(TriggerWrapper.getTriggerNameKey(trigger));
1281:                    if (tw != null && tw.state == TriggerWrapper.STATE_ACQUIRED) {
1282:                        tw.state = TriggerWrapper.STATE_WAITING;
1283:                        timeTriggers.add(tw);
1284:                    }
1285:                }
1286:            }
1287:
1288:            /**
1289:             * <p>
1290:             * Inform the <code>JobStore</code> that the scheduler is now firing the
1291:             * given <code>Trigger</code> (executing its associated <code>Job</code>),
1292:             * that it had previously acquired (reserved).
1293:             * </p>
1294:             */
1295:            public TriggerFiredBundle triggerFired(SchedulingContext ctxt,
1296:                    Trigger trigger) {
1297:
1298:                synchronized (triggerLock) {
1299:                    TriggerWrapper tw = (TriggerWrapper) triggersByFQN
1300:                            .get(TriggerWrapper.getTriggerNameKey(trigger));
1301:                    // was the trigger deleted since being acquired?
1302:                    if (tw == null || tw.trigger == null) {
1303:                        return null;
1304:                    }
1305:                    // was the trigger completed since being acquired?
1306:                    if (tw.state == TriggerWrapper.STATE_COMPLETE) {
1307:                        return null;
1308:                    }
1309:                    // was the trigger paused since being acquired?
1310:                    if (tw.state == TriggerWrapper.STATE_PAUSED) {
1311:                        return null;
1312:                    }
1313:                    // was the trigger blocked since being acquired?
1314:                    if (tw.state == TriggerWrapper.STATE_BLOCKED) {
1315:                        return null;
1316:                    }
1317:                    // was the trigger paused and blocked since being acquired?
1318:                    if (tw.state == TriggerWrapper.STATE_PAUSED_BLOCKED) {
1319:                        return null;
1320:                    }
1321:
1322:                    Calendar cal = null;
1323:                    if (tw.trigger.getCalendarName() != null) {
1324:                        cal = retrieveCalendar(ctxt, tw.trigger
1325:                                .getCalendarName());
1326:                    }
1327:                    Date prevFireTime = trigger.getPreviousFireTime();
1328:                    // call triggered on our copy, and the scheduler's copy
1329:                    tw.trigger.triggered(cal);
1330:                    trigger.triggered(cal);
1331:                    //tw.state = TriggerWrapper.STATE_EXECUTING;
1332:                    tw.state = TriggerWrapper.STATE_WAITING;
1333:
1334:                    TriggerFiredBundle bndle = new TriggerFiredBundle(
1335:                            retrieveJob(ctxt, trigger.getJobName(), trigger
1336:                                    .getJobGroup()), trigger, cal, false,
1337:                            new Date(), trigger.getPreviousFireTime(),
1338:                            prevFireTime, trigger.getNextFireTime());
1339:
1340:                    JobDetail job = bndle.getJobDetail();
1341:
1342:                    if (job.isStateful()) {
1343:                        ArrayList trigs = getTriggerWrappersForJob(job
1344:                                .getName(), job.getGroup());
1345:                        Iterator itr = trigs.iterator();
1346:                        while (itr.hasNext()) {
1347:                            TriggerWrapper ttw = (TriggerWrapper) itr.next();
1348:                            if (ttw.state == TriggerWrapper.STATE_WAITING) {
1349:                                ttw.state = TriggerWrapper.STATE_BLOCKED;
1350:                            }
1351:                            if (ttw.state == TriggerWrapper.STATE_PAUSED) {
1352:                                ttw.state = TriggerWrapper.STATE_PAUSED_BLOCKED;
1353:                            }
1354:                            timeTriggers.remove(ttw);
1355:                        }
1356:                        blockedJobs.add(JobWrapper.getJobNameKey(job));
1357:                    } else if (tw.trigger.getNextFireTime() != null) {
1358:                        synchronized (triggerLock) {
1359:                            timeTriggers.add(tw);
1360:                        }
1361:                    }
1362:
1363:                    return bndle;
1364:                }
1365:            }
1366:
1367:            /**
1368:             * <p>
1369:             * Inform the <code>JobStore</code> that the scheduler has completed the
1370:             * firing of the given <code>Trigger</code> (and the execution its
1371:             * associated <code>Job</code>), and that the <code>{@link org.quartz.JobDataMap}</code>
1372:             * in the given <code>JobDetail</code> should be updated if the <code>Job</code>
1373:             * is stateful.
1374:             * </p>
1375:             */
1376:            public void triggeredJobComplete(SchedulingContext ctxt,
1377:                    Trigger trigger, JobDetail jobDetail, int triggerInstCode) {
1378:
1379:                synchronized (triggerLock) {
1380:
1381:                    String jobKey = JobWrapper.getJobNameKey(jobDetail
1382:                            .getName(), jobDetail.getGroup());
1383:                    JobWrapper jw = (JobWrapper) jobsByFQN.get(jobKey);
1384:                    TriggerWrapper tw = (TriggerWrapper) triggersByFQN
1385:                            .get(TriggerWrapper.getTriggerNameKey(trigger));
1386:
1387:                    // It's possible that the job is null if:
1388:                    //   1- it was deleted during execution
1389:                    //   2- RAMJobStore is being used only for volatile jobs / triggers
1390:                    //      from the JDBC job store
1391:                    if (jw != null) {
1392:                        JobDetail jd = jw.jobDetail;
1393:
1394:                        if (jd.isStateful()) {
1395:                            JobDataMap newData = jobDetail.getJobDataMap();
1396:                            if (newData != null) {
1397:                                newData = (JobDataMap) newData.clone();
1398:                                newData.clearDirtyFlag();
1399:                            }
1400:                            jd.setJobDataMap(newData);
1401:                            blockedJobs.remove(JobWrapper.getJobNameKey(jd));
1402:                            ArrayList trigs = getTriggerWrappersForJob(jd
1403:                                    .getName(), jd.getGroup());
1404:                            Iterator itr = trigs.iterator();
1405:                            while (itr.hasNext()) {
1406:                                TriggerWrapper ttw = (TriggerWrapper) itr
1407:                                        .next();
1408:                                if (ttw.state == TriggerWrapper.STATE_BLOCKED) {
1409:                                    ttw.state = TriggerWrapper.STATE_WAITING;
1410:                                    timeTriggers.add(ttw);
1411:                                }
1412:                                if (ttw.state == TriggerWrapper.STATE_PAUSED_BLOCKED) {
1413:                                    ttw.state = TriggerWrapper.STATE_PAUSED;
1414:                                }
1415:                            }
1416:                        }
1417:                    } else { // even if it was deleted, there may be cleanup to do
1418:                        blockedJobs.remove(JobWrapper.getJobNameKey(jobDetail));
1419:                    }
1420:
1421:                    // check for trigger deleted during execution...
1422:                    if (tw != null) {
1423:                        if (triggerInstCode == Trigger.INSTRUCTION_DELETE_TRIGGER) {
1424:
1425:                            if (trigger.getNextFireTime() == null) {
1426:                                // double check for possible reschedule within job 
1427:                                // execution, which would cancel the need to delete...
1428:                                if (tw.getTrigger().getNextFireTime() == null) {
1429:                                    removeTrigger(ctxt, trigger.getName(),
1430:                                            trigger.getGroup());
1431:                                }
1432:                            } else {
1433:                                removeTrigger(ctxt, trigger.getName(), trigger
1434:                                        .getGroup());
1435:                            }
1436:                        } else if (triggerInstCode == Trigger.INSTRUCTION_SET_TRIGGER_COMPLETE) {
1437:                            tw.state = TriggerWrapper.STATE_COMPLETE;
1438:                            timeTriggers.remove(tw);
1439:                        } else if (triggerInstCode == Trigger.INSTRUCTION_SET_TRIGGER_ERROR) {
1440:                            getLog().info(
1441:                                    "Trigger " + trigger.getFullName()
1442:                                            + " set to ERROR state.");
1443:                            tw.state = TriggerWrapper.STATE_ERROR;
1444:                        } else if (triggerInstCode == Trigger.INSTRUCTION_SET_ALL_JOB_TRIGGERS_ERROR) {
1445:                            getLog().info(
1446:                                    "All triggers of Job "
1447:                                            + trigger.getFullJobName()
1448:                                            + " set to ERROR state.");
1449:                            setAllTriggersOfJobToState(trigger.getJobName(),
1450:                                    trigger.getJobGroup(),
1451:                                    TriggerWrapper.STATE_ERROR);
1452:                        } else if (triggerInstCode == Trigger.INSTRUCTION_SET_ALL_JOB_TRIGGERS_COMPLETE) {
1453:                            setAllTriggersOfJobToState(trigger.getJobName(),
1454:                                    trigger.getJobGroup(),
1455:                                    TriggerWrapper.STATE_COMPLETE);
1456:                        }
1457:                    }
1458:                }
1459:            }
1460:
1461:            protected void setAllTriggersOfJobToState(String jobName,
1462:                    String jobGroup, int state) {
1463:                ArrayList tws = getTriggerWrappersForJob(jobName, jobGroup);
1464:                Iterator itr = tws.iterator();
1465:                while (itr.hasNext()) {
1466:                    TriggerWrapper tw = (TriggerWrapper) itr.next();
1467:                    tw.state = state;
1468:                    if (state != TriggerWrapper.STATE_WAITING) {
1469:                        timeTriggers.remove(tw);
1470:                    }
1471:                }
1472:            }
1473:
1474:            protected String peekTriggers() {
1475:
1476:                StringBuffer str = new StringBuffer();
1477:                TriggerWrapper tw = null;
1478:                synchronized (triggerLock) {
1479:                    for (Iterator valueIter = triggersByFQN.values().iterator(); valueIter
1480:                            .hasNext();) {
1481:                        tw = (TriggerWrapper) valueIter.next();
1482:                        str.append(tw.trigger.getName());
1483:                        str.append("/");
1484:                    }
1485:                }
1486:                str.append(" | ");
1487:
1488:                synchronized (triggerLock) {
1489:                    Iterator itr = timeTriggers.iterator();
1490:                    while (itr.hasNext()) {
1491:                        tw = (TriggerWrapper) itr.next();
1492:                        str.append(tw.trigger.getName());
1493:                        str.append("->");
1494:                    }
1495:                }
1496:
1497:                return str.toString();
1498:            }
1499:
1500:            /** 
1501:             * @see org.quartz.spi.JobStore#getPausedTriggerGroups(org.quartz.core.SchedulingContext)
1502:             */
1503:            public Set getPausedTriggerGroups(SchedulingContext ctxt)
1504:                    throws JobPersistenceException {
1505:                HashSet set = new HashSet();
1506:
1507:                set.addAll(pausedTriggerGroups);
1508:
1509:                return set;
1510:            }
1511:
1512:        }
1513:
1514:        /*******************************************************************************
1515:         * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1516:         * 
1517:         * Helper Classes. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1518:         */
1519:
1520:        class TriggerComparator implements  Comparator {
1521:
1522:            public int compare(Object obj1, Object obj2) {
1523:                TriggerWrapper trig1 = (TriggerWrapper) obj1;
1524:                TriggerWrapper trig2 = (TriggerWrapper) obj2;
1525:
1526:                int comp = trig1.trigger.compareTo(trig2.trigger);
1527:                if (comp != 0) {
1528:                    return comp;
1529:                }
1530:
1531:                comp = trig2.trigger.getPriority()
1532:                        - trig1.trigger.getPriority();
1533:                if (comp != 0) {
1534:                    return comp;
1535:                }
1536:
1537:                return trig1.trigger.getFullName().compareTo(
1538:                        trig2.trigger.getFullName());
1539:            }
1540:
1541:            public boolean equals(Object obj) {
1542:                return (obj instanceof  TriggerComparator);
1543:            }
1544:        }
1545:
1546:        class JobWrapper {
1547:
1548:            public String key;
1549:
1550:            public JobDetail jobDetail;
1551:
1552:            JobWrapper(JobDetail jobDetail) {
1553:                this .jobDetail = jobDetail;
1554:                key = getJobNameKey(jobDetail);
1555:            }
1556:
1557:            JobWrapper(JobDetail jobDetail, String key) {
1558:                this .jobDetail = jobDetail;
1559:                this .key = key;
1560:            }
1561:
1562:            static String getJobNameKey(JobDetail jobDetail) {
1563:                return jobDetail.getGroup() + "_$x$x$_" + jobDetail.getName();
1564:            }
1565:
1566:            static String getJobNameKey(String jobName, String groupName) {
1567:                return groupName + "_$x$x$_" + jobName;
1568:            }
1569:
1570:            public boolean equals(Object obj) {
1571:                if (obj instanceof  JobWrapper) {
1572:                    JobWrapper jw = (JobWrapper) obj;
1573:                    if (jw.key.equals(this .key)) {
1574:                        return true;
1575:                    }
1576:                }
1577:
1578:                return false;
1579:            }
1580:
1581:            public int hashCode() {
1582:                return key.hashCode();
1583:            }
1584:
1585:        }
1586:
1587:        class TriggerWrapper {
1588:
1589:            public String key;
1590:
1591:            public String jobKey;
1592:
1593:            public Trigger trigger;
1594:
1595:            public int state = STATE_WAITING;
1596:
1597:            public static final int STATE_WAITING = 0;
1598:
1599:            public static final int STATE_ACQUIRED = 1;
1600:
1601:            public static final int STATE_EXECUTING = 2;
1602:
1603:            public static final int STATE_COMPLETE = 3;
1604:
1605:            public static final int STATE_PAUSED = 4;
1606:
1607:            public static final int STATE_BLOCKED = 5;
1608:
1609:            public static final int STATE_PAUSED_BLOCKED = 6;
1610:
1611:            public static final int STATE_ERROR = 7;
1612:
1613:            TriggerWrapper(Trigger trigger) {
1614:                this .trigger = trigger;
1615:                key = getTriggerNameKey(trigger);
1616:                this .jobKey = JobWrapper.getJobNameKey(trigger.getJobName(),
1617:                        trigger.getJobGroup());
1618:            }
1619:
1620:            static String getTriggerNameKey(Trigger trigger) {
1621:                return trigger.getGroup() + "_$x$x$_" + trigger.getName();
1622:            }
1623:
1624:            static String getTriggerNameKey(String triggerName, String groupName) {
1625:                return groupName + "_$x$x$_" + triggerName;
1626:            }
1627:
1628:            public boolean equals(Object obj) {
1629:                if (obj instanceof  TriggerWrapper) {
1630:                    TriggerWrapper tw = (TriggerWrapper) obj;
1631:                    if (tw.key.equals(this .key)) {
1632:                        return true;
1633:                    }
1634:                }
1635:
1636:                return false;
1637:            }
1638:
1639:            public int hashCode() {
1640:                return key.hashCode();
1641:            }
1642:
1643:            public Trigger getTrigger() {
1644:                return this.trigger;
1645:            }
1646:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.