/**
   * Returns an instance of the configured job class.
   *
   * <p>If any error occurs during class invocaion, the error is written to the OpenCms log and
   * <code>null</code> is returned.
   *
   * <p>
   *
   * @return an instance of the configured job class, or null if an error occurred
   */
  public synchronized I_CmsScheduledJob getJobInstance() {

    if (m_jobInstance != null) {

      if (LOG.isDebugEnabled()) {
        LOG.debug(
            Messages.get()
                .getBundle()
                .key(Messages.LOG_REUSING_INSTANCE_1, m_jobInstance.getClass().getName()));
      }

      // job instance already initialized
      return m_jobInstance;
    }

    I_CmsScheduledJob job = null;

    try {
      // create an instance of the OpenCms job class
      job = (I_CmsScheduledJob) Class.forName(getClassName()).newInstance();
    } catch (ClassNotFoundException e) {
      LOG.error(Messages.get().getBundle().key(Messages.LOG_CLASS_NOT_FOUND_1, getClassName()), e);
    } catch (IllegalAccessException e) {
      LOG.error(Messages.get().getBundle().key(Messages.LOG_ILLEGAL_ACCESS_0), e);
    } catch (InstantiationException e) {
      LOG.error(Messages.get().getBundle().key(Messages.LOG_INSTANCE_GENERATION_0), e);
    } catch (ClassCastException e) {
      LOG.error(Messages.get().getBundle().key(Messages.LOG_BAD_INTERFACE_0), e);
    }

    if (m_reuseInstance) {
      // job instance must be re-used
      m_jobInstance = job;
    }

    if (LOG.isDebugEnabled()) {
      LOG.debug(Messages.get().getBundle().key(Messages.LOG_JOB_CREATED_1, getClassName()));
    }

    // this should not flood the log files: if class name is wrong or jar files missing this will
    // most likely persist until restart.
    if (job == null) {
      setActive(false);
    }
    return job;
  }
  /**
   * Constructor for creating a new job with all required parameters.
   *
   * <p>
   *
   * @param id the id of the job of <code>null</code> if a new id should be automatically generated
   * @param jobName the display name of the job
   * @param className the class name of the job, must be an instance of <code>
   *     {@link I_CmsScheduledJob}</code>
   * @param context the OpenCms user context information to use when executing the job
   * @param cronExpression the cron expression for scheduling the job
   * @param reuseInstance indicates if the job class should be re-used
   * @param active indicates if the job should be active in the scheduler
   * @param parameters the job parameters
   */
  public CmsScheduledJobInfo(
      String id,
      String jobName,
      String className,
      CmsContextInfo context,
      String cronExpression,
      boolean reuseInstance,
      boolean active,
      SortedMap<String, String> parameters) {

    m_frozen = false;
    setId(id);
    if (CmsStringUtil.isNotEmpty(jobName)) {
      // job name is optional, if not present class name will be used
      setJobName(jobName);
    }
    setClassName(className);
    setContextInfo(context);
    setCronExpression(cronExpression);
    setReuseInstance(reuseInstance);
    setActive(active);
    setParameters(parameters);
  }