Home » quartz-1.6.0 » org » quartz » [javadoc | source]

    1   
    2   /* 
    3    * Copyright 2004-2005 OpenSymphony 
    4    * 
    5    * Licensed under the Apache License, Version 2.0 (the "License"); you may not 
    6    * use this file except in compliance with the License. You may obtain a copy 
    7    * of the License at 
    8    * 
    9    *   http://www.apache.org/licenses/LICENSE-2.0 
   10    *   
   11    * Unless required by applicable law or agreed to in writing, software 
   12    * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 
   13    * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 
   14    * License for the specific language governing permissions and limitations 
   15    * under the License.
   16    * 
   17    */
   18   
   19   /*
   20    * Previously Copyright (c) 2001-2004 James House
   21    */
   22   package org.quartz;
   23   
   24   import java.util.HashSet;
   25   import java.util.Set;
   26   
   27   import org.apache.commons.collections.SetUtils;
   28   import org.quartz.utils.Key;
   29   
   30   /**
   31    * <p>
   32    * Conveys the detail properties of a given <code>Job</code> instance.
   33    * </p>
   34    * 
   35    * <p>
   36    * Quartz does not store an actual instance of a <code>Job</code> class, but
   37    * instead allows you to define an instance of one, through the use of a <code>JobDetail</code>.
   38    * </p>
   39    * 
   40    * <p>
   41    * <code>Job</code>s have a name and group associated with them, which
   42    * should uniquely identify them within a single <code>{@link Scheduler}</code>.
   43    * </p>
   44    * 
   45    * <p>
   46    * <code>Trigger</code>s are the 'mechanism' by which <code>Job</code>s
   47    * are scheduled. Many <code>Trigger</code>s can point to the same <code>Job</code>,
   48    * but a single <code>Trigger</code> can only point to one <code>Job</code>.
   49    * </p>
   50    * 
   51    * @see Job
   52    * @see StatefulJob
   53    * @see JobDataMap
   54    * @see Trigger
   55    * 
   56    * @author James House
   57    * @author Sharada Jambula
   58    */
   59   public class JobDetail implements Cloneable, java.io.Serializable {
   60   
   61       /*
   62        * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   63        * 
   64        * Data members.
   65        * 
   66        * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   67        */
   68   
   69       private String name;
   70   
   71       private String group = Scheduler.DEFAULT_GROUP;
   72   
   73       private String description;
   74   
   75       private Class jobClass;
   76   
   77       private JobDataMap jobDataMap;
   78   
   79       private boolean volatility = false;
   80   
   81       private boolean durability = false;
   82   
   83       private boolean shouldRecover = false;
   84   
   85       private Set jobListeners = SetUtils.orderedSet(new HashSet());
   86   
   87       private transient Key key = null;
   88   
   89       /*
   90       * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   91       *
   92       * Constructors.
   93       *
   94       * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   95       */
   96   
   97       /**
   98        * <p>
   99        * Create a <code>JobDetail</code> with no specified name or group, and
  100        * the default settings of all the other properties.
  101        * </p>
  102        * 
  103        * <p>
  104        * Note that the {@link #setName(String)},{@link #setGroup(String)}and
  105        * {@link #setJobClass(Class)}methods must be called before the job can be
  106        * placed into a {@link Scheduler}
  107        * </p>
  108        */
  109       public JobDetail() {
  110           // do nothing...
  111       }
  112   
  113       /**
  114        * <p>
  115        * Create a <code>JobDetail</code> with the given name, and group, and
  116        * the default settings of all the other properties.
  117        * </p>
  118        * 
  119        * @param group if <code>null</code>, Scheduler.DEFAULT_GROUP will be used.
  120        * 
  121        * @exception IllegalArgumentException
  122        *              if nameis null or empty, or the group is an empty string.
  123        */
  124       public JobDetail(String name, String group, Class jobClass) {
  125           setName(name);
  126           setGroup(group);
  127           setJobClass(jobClass);
  128       }
  129   
  130       /**
  131        * <p>
  132        * Create a <code>JobDetail</code> with the given name, and group, and
  133        * the given settings of all the other properties.
  134        * </p>
  135        * 
  136        * @param group if <code>null</code>, Scheduler.DEFAULT_GROUP will be used.
  137        * 
  138        * @exception IllegalArgumentException
  139        *              if nameis null or empty, or the group is an empty string.
  140        */
  141       public JobDetail(String name, String group, Class jobClass,
  142                        boolean volatility, boolean durability, boolean recover) {
  143           setName(name);
  144           setGroup(group);
  145           setJobClass(jobClass);
  146           setVolatility(volatility);
  147           setDurability(durability);
  148           setRequestsRecovery(recover);
  149       }
  150   
  151       /*
  152        * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  153        * 
  154        * Interface.
  155        * 
  156        * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  157        */
  158   
  159       /**
  160        * <p>
  161        * Get the name of this <code>Job</code>.
  162        * </p>
  163        */
  164       public String getName() {
  165           return name;
  166       }
  167   
  168       /**
  169        * <p>
  170        * Set the name of this <code>Job</code>.
  171        * </p>
  172        * 
  173        * @exception IllegalArgumentException
  174        *              if name is null or empty.
  175        */
  176       public void setName(String name) {
  177           if (name == null || name.trim().length() == 0) {
  178               throw new IllegalArgumentException("Job name cannot be empty.");
  179           }
  180   
  181           this.name = name;
  182       }
  183   
  184       /**
  185        * <p>
  186        * Get the group of this <code>Job</code>.
  187        * </p>
  188        */
  189       public String getGroup() {
  190           return group;
  191       }
  192   
  193       /**
  194        * <p>
  195        * Set the group of this <code>Job</code>.
  196        * </p>
  197        * 
  198        * @param group if <code>null</code>, Scheduler.DEFAULT_GROUP will be used.
  199        * 
  200        * @exception IllegalArgumentException
  201        *              if the group is an empty string.
  202        */
  203       public void setGroup(String group) {
  204           if (group != null && group.trim().length() == 0) {
  205               throw new IllegalArgumentException(
  206                       "Group name cannot be empty.");
  207           }
  208   
  209           if (group == null) {
  210               group = Scheduler.DEFAULT_GROUP;
  211           }
  212   
  213           this.group = group;
  214       }
  215   
  216       /**
  217        * <p>
  218        * Returns the 'full name' of the <code>JobDetail</code> in the format
  219        * "group.name".
  220        * </p>
  221        */
  222       public String getFullName() {
  223           return group + "." + name;
  224       }
  225   
  226       public Key getKey() {
  227           if(key == null) {
  228               key = new Key(getName(), getGroup());
  229           }
  230   
  231           return key;
  232       }
  233   
  234       /**
  235        * <p>
  236        * Return the description given to the <code>Job</code> instance by its
  237        * creator (if any).
  238        * </p>
  239        * 
  240        * @return null if no description was set.
  241        */
  242       public String getDescription() {
  243           return description;
  244       }
  245   
  246       /**
  247        * <p>
  248        * Set a description for the <code>Job</code> instance - may be useful
  249        * for remembering/displaying the purpose of the job, though the
  250        * description has no meaning to Quartz.
  251        * </p>
  252        */
  253       public void setDescription(String description) {
  254           this.description = description;
  255       }
  256   
  257       /**
  258        * <p>
  259        * Get the instance of <code>Job</code> that will be executed.
  260        * </p>
  261        */
  262       public Class getJobClass() {
  263           return jobClass;
  264       }
  265   
  266       /**
  267        * <p>
  268        * Set the instance of <code>Job</code> that will be executed.
  269        * </p>
  270        * 
  271        * @exception IllegalArgumentException
  272        *              if jobClass is null or the class is not a <code>Job</code>.
  273        */
  274       public void setJobClass(Class jobClass) {
  275           if (jobClass == null) {
  276               throw new IllegalArgumentException("Job class cannot be null.");
  277           }
  278   
  279           if (!Job.class.isAssignableFrom(jobClass)) {
  280               throw new IllegalArgumentException(
  281                       "Job class must implement the Job interface.");
  282           }
  283   
  284           this.jobClass = jobClass;
  285       }
  286   
  287       /**
  288        * <p>
  289        * Get the <code>JobDataMap</code> that is associated with the <code>Job</code>.
  290        * </p>
  291        */
  292       public JobDataMap getJobDataMap() {
  293           if (jobDataMap == null) {
  294               jobDataMap = new JobDataMap();
  295           }
  296           return jobDataMap;
  297       }
  298   
  299       /**
  300        * <p>
  301        * Set the <code>JobDataMap</code> to be associated with the <code>Job</code>.
  302        * </p>
  303        */
  304       public void setJobDataMap(JobDataMap jobDataMap) {
  305           this.jobDataMap = jobDataMap;
  306       }
  307   
  308       /**
  309        * <p>
  310        * Validates whether the properties of the <code>JobDetail</code> are
  311        * valid for submission into a <code>Scheduler</code>.
  312        * 
  313        * @throws IllegalStateException
  314        *           if a required property (such as Name, Group, Class) is not
  315        *           set.
  316        */
  317       public void validate() throws SchedulerException {
  318           if (name == null) {
  319               throw new SchedulerException("Job's name cannot be null",
  320                       SchedulerException.ERR_CLIENT_ERROR);
  321           }
  322   
  323           if (group == null) {
  324               throw new SchedulerException("Job's group cannot be null",
  325                       SchedulerException.ERR_CLIENT_ERROR);
  326           }
  327   
  328           if (jobClass == null) {
  329               throw new SchedulerException("Job's class cannot be null",
  330                       SchedulerException.ERR_CLIENT_ERROR);
  331           }
  332       }
  333   
  334       /**
  335        * <p>
  336        * Set whether or not the <code>Job</code> should be persisted in the
  337        * <code>{@link org.quartz.spi.JobStore}</code> for re-use after program
  338        * restarts.
  339        * </p>
  340        * 
  341        * <p>
  342        * If not explicitly set, the default value is <code>false</code>.
  343        * </p>
  344        */
  345       public void setVolatility(boolean volatility) {
  346           this.volatility = volatility;
  347       }
  348   
  349       /**
  350        * <p>
  351        * Set whether or not the <code>Job</code> should remain stored after it
  352        * is orphaned (no <code>{@link Trigger}s</code> point to it).
  353        * </p>
  354        * 
  355        * <p>
  356        * If not explicitly set, the default value is <code>false</code>.
  357        * </p>
  358        */
  359       public void setDurability(boolean durability) {
  360           this.durability = durability;
  361       }
  362   
  363       /**
  364        * <p>
  365        * Set whether or not the the <code>Scheduler</code> should re-execute
  366        * the <code>Job</code> if a 'recovery' or 'fail-over' situation is
  367        * encountered.
  368        * </p>
  369        * 
  370        * <p>
  371        * If not explicitly set, the default value is <code>false</code>.
  372        * </p>
  373        * 
  374        * @see JobExecutionContext#isRecovering()
  375        */
  376       public void setRequestsRecovery(boolean shouldRecover) {
  377           this.shouldRecover = shouldRecover;
  378       }
  379   
  380       /**
  381        * <p>
  382        * Whether or not the <code>Job</code> should not be persisted in the
  383        * <code>{@link org.quartz.spi.JobStore}</code> for re-use after program
  384        * restarts.
  385        * </p>
  386        * 
  387        * <p>
  388        * If not explicitly set, the default value is <code>false</code>.
  389        * </p>
  390        * 
  391        * @return <code>true</code> if the <code>Job</code> should be garbage
  392        *         collected along with the <code>{@link Scheduler}</code>.
  393        */
  394       public boolean isVolatile() {
  395           return volatility;
  396       }
  397   
  398       /**
  399        * <p>
  400        * Whether or not the <code>Job</code> should remain stored after it is
  401        * orphaned (no <code>{@link Trigger}s</code> point to it).
  402        * </p>
  403        * 
  404        * <p>
  405        * If not explicitly set, the default value is <code>false</code>.
  406        * </p>
  407        * 
  408        * @return <code>true</code> if the Job should remain persisted after
  409        *         being orphaned.
  410        */
  411       public boolean isDurable() {
  412           return durability;
  413       }
  414   
  415       /**
  416        * <p>
  417        * Whether or not the <code>Job</code> implements the interface <code>{@link StatefulJob}</code>.
  418        * </p>
  419        */
  420       public boolean isStateful() {
  421           if (jobClass == null) {
  422               return false;
  423           }
  424   
  425           return (StatefulJob.class.isAssignableFrom(jobClass));
  426       }
  427   
  428       /**
  429        * <p>
  430        * Instructs the <code>Scheduler</code> whether or not the <code>Job</code>
  431        * should be re-executed if a 'recovery' or 'fail-over' situation is
  432        * encountered.
  433        * </p>
  434        * 
  435        * <p>
  436        * If not explicitly set, the default value is <code>false</code>.
  437        * </p>
  438        * 
  439        * @see JobExecutionContext#isRecovering()
  440        */
  441       public boolean requestsRecovery() {
  442           return shouldRecover;
  443       }
  444   
  445       /**
  446        * <p>
  447        * Add the specified name of a <code>{@link JobListener}</code> to the
  448        * end of the <code>Job</code>'s list of listeners.
  449        * </p>
  450        */
  451       public void addJobListener(String name) {
  452           if (jobListeners.add(name) == false) {
  453               throw new IllegalArgumentException(
  454                   "Job listener '" + name + "' is already registered for job detail: " + getFullName());
  455           }
  456       }
  457   
  458       /**
  459        * <p>
  460        * Remove the specified name of a <code>{@link JobListener}</code> from
  461        * the <code>Job</code>'s list of listeners.
  462        * </p>
  463        * 
  464        * @return true if the given name was found in the list, and removed
  465        */
  466       public boolean removeJobListener(String name) {
  467           return jobListeners.remove(name);
  468       }
  469   
  470       /**
  471        * <p>
  472        * Returns an array of <code>String</code> s containing the names of all
  473        * <code>{@link JobListener}</code>s assigned to the <code>Job</code>,
  474        * in the order in which they should be notified.
  475        * </p>
  476        */
  477       public String[] getJobListenerNames() {
  478           return (String[])jobListeners.toArray(new String[jobListeners.size()]);
  479       }
  480   
  481       /**
  482        * <p>
  483        * Return a simple string representation of this object.
  484        * </p>
  485        */
  486       public String toString() {
  487           return "JobDetail '" + getFullName() + "':  jobClass: '"
  488                   + ((getJobClass() == null) ? null : getJobClass().getName())
  489                   + " isStateful: " + isStateful() + " isVolatile: "
  490                   + isVolatile() + " isDurable: " + isDurable()
  491                   + " requestsRecovers: " + requestsRecovery();
  492       }
  493   
  494       public Object clone() {
  495           JobDetail copy;
  496           try {
  497               copy = (JobDetail) super.clone();
  498               copy.jobListeners = SetUtils.orderedSet(new HashSet(jobListeners));
  499               if (jobDataMap != null) {
  500                   copy.jobDataMap = (JobDataMap) jobDataMap.clone();
  501               }
  502           } catch (CloneNotSupportedException ex) {
  503               throw new IncompatibleClassChangeError("Not Cloneable.");
  504           }
  505   
  506           return copy;
  507       }
  508   }

Home » quartz-1.6.0 » org » quartz » [javadoc | source]