View Javadoc

1   package com.atlassian.scheduler.core.status;
2   
3   import com.atlassian.scheduler.JobRunner;
4   import com.atlassian.scheduler.SchedulerService;
5   import com.atlassian.scheduler.config.JobId;
6   import com.atlassian.scheduler.config.JobRunnerKey;
7   import com.atlassian.scheduler.config.RunMode;
8   import com.atlassian.scheduler.config.Schedule;
9   import com.atlassian.scheduler.core.AbstractSchedulerService;
10  import com.atlassian.scheduler.status.JobDetails;
11  import com.atlassian.util.concurrent.LazyReference;
12  
13  import javax.annotation.Nonnull;
14  import javax.annotation.Nullable;
15  import java.io.Serializable;
16  import java.util.Date;
17  import java.util.Map;
18  
19  import static com.atlassian.util.concurrent.Assertions.notNull;
20  
21  /**
22   * A job details implementation that waits until the first request to one of
23   * the methods that needs to know the state of the parameters map before trying
24   * to deserialize it.  {@link SchedulerService} implementations are encouraged
25   * to prefer this implementation when returning multiple {@link JobDetails}
26   * objects, as the deserialization is unnecessary if the caller is not going to
27   * use those values.
28   *
29   * @since v1.0
30   */
31  public class LazyJobDetails extends AbstractJobDetails {
32      private final LazyReference<AbstractJobDetails> delegateRef;
33  
34      /**
35       * Creates a lazy job details representation.
36       * <p>
37       * <strong>WARNING</strong>: For efficiency reasons, {@code byte[] parameters} is <em>not</em> copied.
38       * </p>
39       *
40       * @param jobId        the job's ID
41       * @param jobRunnerKey the job runner's key
42       * @param runMode      the running mode of the job
43       * @param schedule     the job's schedule
44       * @param nextRunTime  the next run time for the job, if known
45       * @param parameters   the parameters map in serialized form.  For efficiency reasons, this constructor
46       *                     uses the original array directly without making a safe copy.
47       */
48      public LazyJobDetails(final AbstractSchedulerService schedulerService, final JobId jobId,
49                            final JobRunnerKey jobRunnerKey, final RunMode runMode, final Schedule schedule,
50                            @Nullable final Date nextRunTime, @Nullable final byte[] parameters) {
51          super(jobId, jobRunnerKey, runMode, schedule, nextRunTime, parameters);
52          notNull("schedulerService", schedulerService);
53  
54          this.delegateRef = new LazyReference<AbstractJobDetails>() {
55              @Nonnull
56              @Override
57              protected AbstractJobDetails create() throws Exception {
58                  Throwable cause = null;
59                  try {
60                      final JobRunner jobRunner = schedulerService.getJobRunner(jobRunnerKey);
61                      if (jobRunner != null) {
62                          final ClassLoader classLoader = jobRunner.getClass().getClassLoader();
63                          final Map<String, Serializable> parametersMap = schedulerService
64                                  .getParameterMapSerializer()
65                                  .deserializeParameters(classLoader, parameters);
66                          return new SimpleJobDetails(jobId, jobRunnerKey, runMode, schedule, nextRunTime, parameters,
67                                  parametersMap);
68                      }
69                  } catch (Exception ex) {
70                      cause = ex;
71                  } catch (LinkageError err) {
72                      cause = err;
73                  }
74                  return new UnusableJobDetails(jobId, jobRunnerKey, runMode, schedule, nextRunTime, parameters, cause);
75              }
76          };
77      }
78  
79      @Nonnull
80      @Override
81      public Map<String, Serializable> getParameters() {
82          return getDelegate().getParameters();
83      }
84  
85      @Override
86      public boolean isRunnable() {
87          return getDelegate().isRunnable();
88      }
89  
90      @Override
91      protected void appendToStringDetails(StringBuilder sb) {
92          if (delegateRef.isInitialized()) {
93              final AbstractJobDetails delegate = getDelegate();
94              sb.append(",delegate=").append(delegate.getClass().getSimpleName());
95              delegate.appendToStringDetails(sb);
96          } else {
97              sb.append(",delegate=(unresolved)");
98          }
99      }
100 
101     // Hides the misleading @Nullable taint from LazyReference.get()
102     private AbstractJobDetails getDelegate() {
103         return delegateRef.get();
104     }
105 
106 }