public static Trigger convertTriggerFromNativeObject(org.quartz.Trigger quartzTrigger) {
    Trigger spagobiTrigger;

    spagobiTrigger = new Trigger();
    spagobiTrigger.setName(quartzTrigger.getName());
    spagobiTrigger.setGroupName(quartzTrigger.getGroup());
    spagobiTrigger.setDescription(quartzTrigger.getDescription());

    // spagobiTrigger.setCalendarName( quartzTrigger.getCalendarName() );
    Assert.assertTrue(
        quartzTrigger.getCalendarName() == null,
        "quartz trigger calendar name is not null: " + quartzTrigger.getCalendarName());

    spagobiTrigger.setStartTime(quartzTrigger.getStartTime());
    spagobiTrigger.setEndTime(quartzTrigger.getEndTime());

    // triggers that run immediately have a generated name that starts with schedule_uuid_ (see
    // TriggerXMLDeserializer)
    // It would be better anyway to relay on a specific property to recognize if a trigger is
    // thinked to run immediately
    spagobiTrigger.setRunImmediately(spagobiTrigger.getName().startsWith("schedule_uuid_"));

    if (quartzTrigger instanceof org.quartz.CronTrigger) {
      org.quartz.CronTrigger quartzCronTrigger = (org.quartz.CronTrigger) quartzTrigger;
      // dirty trick
      String expression = (String) quartzCronTrigger.getJobDataMap().get(SPAGOBI_CRON_EXPRESSION);
      if (expression != null) {
        quartzCronTrigger.getJobDataMap().remove(SPAGOBI_CRON_EXPRESSION);
      } else {
        // for back compatibility
        expression =
            (String) quartzCronTrigger.getJobDataMap().get(SPAGOBI_CRON_EXPRESSION_DEPRECATED);
        quartzCronTrigger.getJobDataMap().remove(SPAGOBI_CRON_EXPRESSION_DEPRECATED);
      }
      spagobiTrigger.setCronExpression(new CronExpression(expression));
    }

    Job job = new Job();
    job.setName(quartzTrigger.getJobName());
    job.setGroupName(quartzTrigger.getJobGroup());
    job.setVolatile(quartzTrigger.isVolatile());
    Map<String, String> parameters =
        convertParametersFromNativeObject(quartzTrigger.getJobDataMap());
    job.addParameters(parameters);

    spagobiTrigger.setJob(job);

    return spagobiTrigger;
  }
  public static Job convertJobFromNativeObject(org.quartz.JobDetail quartzJob) {
    Job spagobiJob;

    spagobiJob = new Job();
    spagobiJob.setName(quartzJob.getName());
    spagobiJob.setGroupName(quartzJob.getGroup());
    spagobiJob.setDescription(quartzJob.getDescription());
    spagobiJob.setJobClass(quartzJob.getJobClass());
    spagobiJob.setDurable(quartzJob.isDurable());
    spagobiJob.setRequestsRecovery(quartzJob.requestsRecovery());
    spagobiJob.setVolatile(quartzJob.isVolatile());

    Map<String, String> parameters = convertParametersFromNativeObject(quartzJob.getJobDataMap());
    spagobiJob.addParameters(parameters);

    return spagobiJob;
  }
  public static org.quartz.JobDetail convertJobToNativeObject(Job spagobiJob) {
    org.quartz.JobDetail quartzJob;

    quartzJob = new org.quartz.JobDetail();
    quartzJob.setName(spagobiJob.getName());
    quartzJob.setGroup(spagobiJob.getGroupName());
    quartzJob.setDescription(spagobiJob.getDescription());
    quartzJob.setJobClass(spagobiJob.getJobClass());
    quartzJob.setDurability(spagobiJob.isDurable());
    quartzJob.setRequestsRecovery(spagobiJob.isRequestsRecovery());
    quartzJob.setVolatility(spagobiJob.isVolatile());

    JobDataMap parameters = convertParametersToNativeObject(spagobiJob.getParameters());
    quartzJob.setJobDataMap(parameters);

    return quartzJob;
  }
  public Object serialize(Object o, Locale locale) throws SerializationException {
    StringBuffer result = null;

    if (!(o instanceof Job)) {
      throw new SerializationException(
          "JobXMLSerializer is unable to serialize object of type: " + o.getClass().getName());
    }

    try {
      Job job = (Job) o;
      result = new StringBuffer();

      String jobName = job.getName();
      String jobGroupName = job.getGroupName();
      String jobDescription = job.getDescription();
      String jobClassName = job.getJobClass().getName();
      String jobDurability = job.isDurable() ? "true" : "false";
      String jobRequestRecovery = job.isRequestsRecovery() ? "true" : "false";
      String jobVolatility = job.isVolatile() ? "true" : "false";
      Map<String, String> parameters = job.getParameters();

      boolean isForServiceConsumer =
          "service".equalsIgnoreCase(properties.getProperty(PROPERTY_CONSUMER));

      String rootTag = "ROW";
      if (isForServiceConsumer) rootTag = "JOB_DETAIL";

      result.append("<" + rootTag + " ");
      result.append(" " + JOB_NAME + "=\"" + (jobName != null ? jobName : "") + "\"");
      result.append(" " + JOB_GROUP + "=\"" + (jobGroupName != null ? jobGroupName : "") + "\"");
      result.append(
          " " + JOB_DESCRIPTION + "=\"" + (jobDescription != null ? jobDescription : "") + "\"");
      result.append(" " + JOB_CLASS + "=\"" + (jobClassName != null ? jobClassName : "") + "\"");
      result.append(" " + JOB_DURABILITY + "=\"" + jobDurability + "\"");
      result.append(" " + JOB_REQUEST_RECOVERY + "=\"" + jobRequestRecovery + "\"");
      result.append(" " + USE_VOLATILITY + "=\"" + jobVolatility + "\"");
      if (isForServiceConsumer) {
        result.append(">");
        result.append("<JOB_PARAMETERS>");

        Set<String> keys = parameters.keySet();
        for (String key : keys) {
          result.append("<JOB_PARAMETER ");

          String value = parameters.get(key);
          if (value == null) {
            logger.warn("Job parameter [" + key + "] has no value");
            continue;
          }
          result.append(" name=\"" + key + "\"");
          result.append(" value=\"" + value + "\"");
          result.append(" />");
        }

        result.append("</JOB_PARAMETERS>");
        result.append("</JOB_DETAIL>");
      } else {
        result.append(" />");
      }

    } catch (Throwable t) {
      throw new SerializationException("An error occurred while serializing object: " + o, t);
    } finally {

    }

    return result.toString();
  }