1 package com.atlassian.scheduler.config;
2
3 import com.atlassian.annotations.PublicApi;
4 import com.atlassian.scheduler.JobRunner;
5 import com.atlassian.scheduler.SchedulerService;
6 import com.atlassian.scheduler.status.JobDetails;
7 import com.google.common.collect.ImmutableMap;
8
9 import javax.annotation.Nonnull;
10 import javax.annotation.Nullable;
11 import javax.annotation.concurrent.Immutable;
12 import java.io.Serializable;
13 import java.util.Date;
14 import java.util.Map;
15
16 import static com.atlassian.scheduler.config.RunMode.RUN_ONCE_PER_CLUSTER;
17 import static com.atlassian.scheduler.util.Safe.copy;
18 import static com.atlassian.util.concurrent.Assertions.notNull;
19
20 /**
21 * Configuration options available when scheduling a job to be run. This is similar to
22 * {@link JobDetails}, but provides only the information that is relevant to configuring
23 * the job or for the job to reference when it is actually running.
24 *
25 * @see JobDetails
26 */
27 @Immutable
28 @PublicApi
29 public final class JobConfig {
30 static final Map<String, Serializable> NO_PARAMETERS = ImmutableMap.of();
31
32 /**
33 * Creates a new job configuration for the specified job runner key.
34 * <p>
35 * By default, the job configuration will assume:
36 * </p>
37 * <ul>
38 * <li><code>{@link #withRunMode(RunMode) withRunMode}({@link RunMode#RUN_ONCE_PER_CLUSTER})</code></li>
39 * <li><code>{@link #withSchedule(Schedule) withSchedule}({@link Schedule#runOnce(Date) Schedule.runOnce}(new Date()))</code></li>
40 * <li><code>{@link #withParameters(Map) withParameters}(null)</code></li>
41 * </ul>
42 * <p>
43 * Any of which may be overridden by calling the appropriate method. Note that chaining the
44 * methods is recommended, as these methods return an altered copy rather than modifiying the
45 * original {@code JobConfig} in place. For example, use:
46 * </p>
47 * <pre><code>
48 * JobConfig config = JobConfig.forJobRunnerKey("myJobToDoImportantThings")
49 * .withSchedule(Schedule.forInterval(Date, long))
50 * .withRunMode(RunMode.RUN_LOCALLY);
51 * </code></pre>
52 *
53 * @param jobRunnerKey the unique identifier used to
54 * {@link SchedulerService#registerJobRunner(JobRunnerKey, JobRunner) register}
55 * the {@link JobRunner}
56 * @return a job configuration for the specified job runner key that will use the default settings
57 */
58 public static JobConfig forJobRunnerKey(JobRunnerKey jobRunnerKey) {
59 notNull("jobRunnerKey", jobRunnerKey);
60 return new JobConfig(jobRunnerKey, RUN_ONCE_PER_CLUSTER, Schedule.runOnce(null), NO_PARAMETERS);
61 }
62
63
64 private final JobRunnerKey jobRunnerKey;
65 private final RunMode runMode;
66 private final Schedule schedule;
67 private final Map<String, Serializable> parameters;
68
69 private JobConfig(JobRunnerKey jobRunnerKey, @Nullable RunMode runMode, @Nullable Schedule schedule,
70 Map<String, Serializable> parameters) {
71 this.jobRunnerKey = jobRunnerKey;
72 this.runMode = (runMode != null) ? runMode : RUN_ONCE_PER_CLUSTER;
73 this.schedule = (schedule != null) ? schedule : Schedule.runOnce(null);
74
75 // handled by withParameters and would be redundant elsewhere
76 //noinspection AssignmentToCollectionOrArrayFieldFromParameter
77 this.parameters = parameters;
78 }
79
80
81 @Nonnull
82 public JobRunnerKey getJobRunnerKey() {
83 return jobRunnerKey;
84 }
85
86 @Nonnull
87 public RunMode getRunMode() {
88 return runMode;
89 }
90
91 @Nonnull
92 public Schedule getSchedule() {
93 return schedule;
94 }
95
96 @Nonnull
97 public Map<String, Serializable> getParameters() {
98 return parameters;
99 }
100
101
102 /**
103 * Returns a copy of this job config that will use the specified run mode
104 * instead of what it currently uses.
105 *
106 * @param runMode the new run mode; may be {@code null}, in which case the default
107 * {@link RunMode#RUN_ONCE_PER_CLUSTER} is used
108 * @return the new job configuration; the original is left unchanged
109 */
110 public JobConfig withRunMode(RunMode runMode) {
111 return new JobConfig(jobRunnerKey, runMode, schedule, parameters);
112 }
113
114 /**
115 * Returns a copy of this job config that will use the specified schedule
116 * instead of what it currently uses.
117 *
118 * @param schedule the new schedule; may be {@code null}, in which case the default
119 * {@link Schedule#runOnce(Date) runOnce(new Date())} is used
120 * @return the new job configuration; the original is left unchanged
121 */
122 public JobConfig withSchedule(Schedule schedule) {
123 return new JobConfig(jobRunnerKey, runMode, schedule, parameters);
124 }
125
126 /**
127 * Returns a copy of this job config that will use the specified parameters
128 * instead of what it currently uses.
129 * <p>
130 * <strong>WARNING</strong>: The parameters map must be serializable, so all of its
131 * contents must be as well. Using objects that are not serializable, even as data
132 * members of objects that are themselves serializable, will usually fail. Developers
133 * are encouraged to limit the information stored here to a few simple keys for
134 * accessing the runtime data that is needed instead of storing large objects,
135 * injectable components, etc. in the {@code parameters} map.
136 * </p>
137 * <p>
138 * <strong>WARNING</strong>: The scheduler service assumes that the objects within the
139 * {@code parameters} map are immutable. Modifying objects after they have been added
140 * to the parameters map may have unpredictable results.
141 * </p>
142 *
143 * @param parameters the new parameters; may be {@code null}, in which case the
144 * {@link JobRunner} is provided with an empty map at run time. The map
145 * should contain only immutable, serializable data
146 * @return the new job configuration; the original is left unchanged
147 */
148 public JobConfig withParameters(@Nullable Map<String, Serializable> parameters) {
149 return new JobConfig(jobRunnerKey, runMode, schedule, copy(parameters));
150 }
151
152
153 @Override
154 public boolean equals(@Nullable final Object o) {
155 if (this == o) {
156 return true;
157 }
158 if (o == null || getClass() != o.getClass()) {
159 return false;
160 }
161
162 final JobConfig other = (JobConfig) o;
163 return jobRunnerKey.equals(other.jobRunnerKey) &&
164 runMode == other.runMode &&
165 schedule.equals(other.schedule) &&
166 parameters.equals(other.parameters);
167 }
168
169 @Override
170 public int hashCode() {
171 int result = jobRunnerKey.hashCode();
172 result = 31 * result + runMode.hashCode();
173 result = 31 * result + schedule.hashCode();
174 result = 31 * result + parameters.hashCode();
175 return result;
176 }
177
178 @Override
179 public String toString() {
180 return "JobConfig[jobRunnerKey=" + jobRunnerKey +
181 ",runMode=" + runMode +
182 ",schedule=" + schedule +
183 ",parameters=" + parameters +
184 ']';
185 }
186 }