1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.opencastproject.job.jpa;
22
23 import static org.opencastproject.job.api.Job.FailureReason.NONE;
24
25 import org.opencastproject.job.api.Job;
26 import org.opencastproject.job.api.Job.FailureReason;
27 import org.opencastproject.job.api.Job.Status;
28 import org.opencastproject.job.api.JobImpl;
29 import org.opencastproject.security.api.Organization;
30 import org.opencastproject.security.api.User;
31 import org.opencastproject.serviceregistry.impl.jpa.ServiceRegistrationJpaImpl;
32
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
35
36 import java.net.URI;
37 import java.util.Date;
38 import java.util.List;
39
40 import javax.persistence.Access;
41 import javax.persistence.AccessType;
42 import javax.persistence.Basic;
43 import javax.persistence.CascadeType;
44 import javax.persistence.CollectionTable;
45 import javax.persistence.Column;
46 import javax.persistence.ElementCollection;
47 import javax.persistence.Entity;
48 import javax.persistence.FetchType;
49 import javax.persistence.GeneratedValue;
50 import javax.persistence.Id;
51 import javax.persistence.Index;
52 import javax.persistence.JoinColumn;
53 import javax.persistence.Lob;
54 import javax.persistence.ManyToOne;
55 import javax.persistence.NamedQueries;
56 import javax.persistence.NamedQuery;
57 import javax.persistence.OneToMany;
58 import javax.persistence.OneToOne;
59 import javax.persistence.OrderColumn;
60 import javax.persistence.PostLoad;
61 import javax.persistence.Table;
62 import javax.persistence.Temporal;
63 import javax.persistence.TemporalType;
64 import javax.persistence.Transient;
65 import javax.persistence.Version;
66
67
68
69
70 @Entity(name = "Job")
71 @Access(AccessType.FIELD)
72 @Table(name = "oc_job", indexes = {
73 @Index(name = "IX_oc_job_parent", columnList = ("parent")),
74 @Index(name = "IX_oc_job_root", columnList = ("root")),
75 @Index(name = "IX_oc_job_creator_service", columnList = ("creator_service")),
76 @Index(name = "IX_oc_job_processor_service", columnList = ("processor_service")),
77 @Index(name = "IX_oc_job_status", columnList = ("status")),
78 @Index(name = "IX_oc_job_date_created", columnList = ("date_created")),
79 @Index(name = "IX_oc_job_date_completed", columnList = ("date_completed")),
80 @Index(name = "IX_oc_job_dispatchable", columnList = ("dispatchable")),
81 @Index(name = "IX_oc_job_operation", columnList = ("operation")) })
82 @NamedQueries({
83 @NamedQuery(name = "Job", query = "SELECT j FROM Job j "
84 + "where j.status = :status and j.creatorServiceRegistration.serviceType = :serviceType "
85 + "order by j.dateCreated"),
86 @NamedQuery(name = "Job.type", query = "SELECT j FROM Job j "
87 + "where j.creatorServiceRegistration.serviceType = :serviceType order by j.dateCreated"),
88 @NamedQuery(name = "Job.status", query = "SELECT j FROM Job j "
89 + "where j.status = :status order by j.dateCreated"),
90 @NamedQuery(name = "Job.statuses", query = "SELECT j FROM Job j "
91 + "where j.status in :statuses order by j.dateCreated"),
92 @NamedQuery(name = "Job.countByOrganizationAndHost",
93 query = "SELECT j.organization, j.processorServiceRegistration.hostRegistration.baseUrl, count(j) FROM Job j "
94 + "WHERE j.status in :statuses "
95 + "GROUP BY j.organization, j.processorServiceRegistration.hostRegistration.baseUrl"),
96 @NamedQuery(name = "Job.countTypeByOrganization",
97 query = "SELECT j.organization, count(j) FROM Job j "
98 + "WHERE j.operation = :operation and j.status in :statuses "
99 + "GROUP BY j.organization"),
100 @NamedQuery(name = "Job.all", query = "SELECT j FROM Job j order by j.dateCreated"),
101 @NamedQuery(name = "Job.dispatchable.status", query = "SELECT j FROM Job j where j.dispatchable = true and "
102 + "j.status in :statuses order by j.dateCreated"),
103 @NamedQuery(name = "Job.dispatchable.status.idfilter", query = "SELECT j.id FROM Job j "
104 + "WHERE j.dispatchable = true AND j.status IN :statuses AND j.id IN :jobids ORDER BY j.dateCreated"),
105 @NamedQuery(name = "Job.undispatchable.status", query = "SELECT j FROM Job j where j.dispatchable = false and "
106 + "j.status in :statuses order by j.dateCreated"),
107 @NamedQuery(name = "Job.payload", query = "SELECT j.payload FROM Job j where j.operation = :operation "
108 + "order by j.dateCreated"),
109 @NamedQuery(name = "Job.processinghost.status", query = "SELECT j FROM Job j "
110 + "where j.status in :statuses and j.processorServiceRegistration is not null and "
111 + "j.processorServiceRegistration.serviceType = :serviceType and "
112 + "j.processorServiceRegistration.hostRegistration.baseUrl = :host order by j.dateCreated"),
113 @NamedQuery(name = "Job.root.children", query = "SELECT j FROM Job j "
114 + "WHERE j.rootJob.id = :id ORDER BY j.dateCreated"),
115 @NamedQuery(name = "Job.children", query = "SELECT j FROM Job j "
116 + "WHERE j.parentJob.id = :id ORDER BY j.dateCreated"),
117 @NamedQuery(name = "Job.withoutParent", query = "SELECT j FROM Job j WHERE j.parentJob IS NULL"),
118 @NamedQuery(name = "Job.avgOperation", query = "SELECT j.operation, AVG(j.runTime), AVG(j.queueTime) "
119 + "FROM Job j GROUP BY j.operation"),
120
121
122 @NamedQuery(name = "Job.count", query = "SELECT COUNT(j) FROM Job j "
123 + "where j.status = :status and j.creatorServiceRegistration.serviceType = :serviceType"),
124 @NamedQuery(name = "Job.count.all", query = "SELECT COUNT(j) FROM Job j"),
125 @NamedQuery(name = "Job.count.nullType", query = "SELECT COUNT(j) FROM Job j where j.status = :status"),
126 @NamedQuery(name = "Job.count.nullStatus", query = "SELECT COUNT(j) FROM Job j "
127 + "where j.creatorServiceRegistration.serviceType = :serviceType"),
128 @NamedQuery(name = "Job.countByHost", query = "SELECT COUNT(j) FROM Job j "
129 + "where j.status = :status and j.processorServiceRegistration is not null and "
130 + "j.processorServiceRegistration.serviceType = :serviceType and "
131 + "j.creatorServiceRegistration.hostRegistration.baseUrl = :host"),
132 @NamedQuery(name = "Job.countByHost.nullType", query = "SELECT COUNT(j) FROM Job j "
133 + "where j.status = :status and j.processorServiceRegistration is not null and "
134 + "j.creatorServiceRegistration.hostRegistration.baseUrl = :host"),
135 @NamedQuery(name = "Job.countByOperation", query = "SELECT COUNT(j) FROM Job j "
136 + "where j.status = :status and j.operation = :operation and "
137 + "j.creatorServiceRegistration.serviceType = :serviceType"),
138 @NamedQuery(name = "Job.countByOperationOnly", query = "SELECT COUNT(j) FROM Job j "
139 + "where j.operation = :operation"),
140 @NamedQuery(name = "Job.fullMonty", query = "SELECT COUNT(j) FROM Job j "
141 + "where j.status = :status and j.operation = :operation "
142 + "and j.processorServiceRegistration is not null and "
143 + "j.processorServiceRegistration.serviceType = :serviceType and "
144 + "j.creatorServiceRegistration.hostRegistration.baseUrl = :host"),
145 @NamedQuery(name = "Job.count.history.failed", query = "SELECT COUNT(j) FROM Job j "
146 + "WHERE j.status = 4 AND j.processorServiceRegistration IS NOT NULL "
147 + "AND j.processorServiceRegistration.serviceType = :serviceType "
148 + "AND j.processorServiceRegistration.hostRegistration.baseUrl = :host "
149 + "AND j.dateCompleted >= j.processorServiceRegistration.stateChanged"),
150 @NamedQuery(name = "Job.countPerHostService", query = "SELECT h.baseUrl, s.serviceType, j.status, count(j) "
151 + "FROM Job j, ServiceRegistration s, HostRegistration h "
152 + "WHERE ((j.processorServiceRegistration IS NOT NULL AND j.processorServiceRegistration = s) "
153 + "OR (j.creatorServiceRegistration IS NOT NULL AND j.creatorServiceRegistration = s)) "
154 + "AND s.hostRegistration = h GROUP BY h.baseUrl, s.serviceType, j.status")
155 })
156 public class JpaJob {
157
158
159 private static final Logger logger = LoggerFactory.getLogger(JpaJob.class);
160
161 @Id
162 @GeneratedValue
163 @Column(name = "id")
164 private long id;
165
166 @Lob
167 @Column(name = "creator", nullable = false, length = 65535)
168 private String creator;
169
170 @Column(name = "organization", nullable = false, length = 128)
171 private String organization;
172
173 @Version
174 @Column(name = "instance_version")
175 private long version;
176
177 @Column(name = "status")
178 private int status;
179
180 @Column(name = "operation", length = 128)
181 private String operation;
182
183 @Lob
184 @Column(name = "argument", length = 2147483647)
185 @OrderColumn(name = "argument_index")
186 @ElementCollection(fetch = FetchType.EAGER)
187 @CollectionTable(name = "oc_job_argument",
188 joinColumns = @JoinColumn(name = "id", referencedColumnName = "id", nullable = false),
189 indexes = {
190 @Index(name = "IX_oc_job_argument_id", columnList = ("id")),
191 }
192 )
193 private List<String> arguments;
194
195 @Column(name = "date_completed")
196 @Temporal(TemporalType.TIMESTAMP)
197 private Date dateCompleted;
198
199 @Column(name = "date_created")
200 @Temporal(TemporalType.TIMESTAMP)
201 private Date dateCreated;
202
203 public Date getDateStarted() {
204 return dateStarted;
205 }
206
207 @Column(name = "date_started")
208 @Temporal(TemporalType.TIMESTAMP)
209 private Date dateStarted;
210
211 @Column(name = "queue_time")
212 private Long queueTime = 0L;
213
214 @Column(name = "run_time")
215 private Long runTime = 0L;
216
217 @Lob
218 @Basic(fetch = FetchType.LAZY)
219 @Column(name = "payload", length = 16777215)
220 private String payload;
221
222 @Column(name = "dispatchable")
223 private boolean dispatchable = true;
224
225 @Column(name = "job_load", nullable = false)
226 private Float jobLoad = 1F;
227
228 @ManyToOne
229 @JoinColumn(name = "creator_service")
230 private ServiceRegistrationJpaImpl creatorServiceRegistration;
231
232 @ManyToOne
233 @JoinColumn(name = "processor_service")
234 private ServiceRegistrationJpaImpl processorServiceRegistration;
235
236
237
238
239
240
241
242 @Column(name = "processor_service", updatable = false, insertable = false)
243 private Long processorServiceRegistrationFK;
244
245 @JoinColumn(name = "parent", referencedColumnName = "id", nullable = true)
246 private JpaJob parentJob = null;
247
248 @OneToOne(fetch = FetchType.LAZY, targetEntity = JpaJob.class, optional = true)
249 @JoinColumn(name = "root", referencedColumnName = "id", nullable = true)
250 private JpaJob rootJob = null;
251
252 @OneToMany(mappedBy = "parentJob", fetch = FetchType.LAZY, cascade = { CascadeType.PERSIST, CascadeType.REFRESH,
253 CascadeType.MERGE })
254 private List<JpaJob> childJobs;
255
256 @Transient
257 private String createdHost;
258
259 @Transient
260 private String processingHost;
261
262 @Transient
263 private Long parentJobId = null;
264
265 @Transient
266 private Long rootJobId = null;
267
268 @Transient
269 private FailureReason failureReason = NONE;
270
271 @Transient
272 private String jobType;
273
274 @Transient
275 private URI uri;
276
277 public JpaJob() {
278 }
279
280 public JpaJob(User currentUser, Organization organization, ServiceRegistrationJpaImpl creatingService,
281 String operation, List<String> arguments, String payload, boolean dispatchable, float load) {
282 this.creator = currentUser.getUsername();
283 this.organization = organization.getId();
284 this.creatorServiceRegistration = creatingService;
285 this.jobType = creatingService.getServiceType();
286 this.operation = operation;
287 this.arguments = arguments;
288 this.payload = payload;
289 this.dispatchable = dispatchable;
290 this.jobLoad = load;
291 this.status = Status.INSTANTIATED.ordinal();
292 }
293
294 public static JpaJob from(Job job) {
295 JpaJob newJob = new JpaJob();
296 newJob.id = job.getId();
297 newJob.dateCompleted = job.getDateCompleted();
298 newJob.dateCreated = job.getDateCreated();
299 newJob.dateStarted = job.getDateStarted();
300 newJob.queueTime = job.getQueueTime();
301 newJob.runTime = job.getRunTime();
302 newJob.version = job.getVersion();
303 newJob.payload = job.getPayload();
304 newJob.jobType = job.getJobType();
305 newJob.operation = job.getOperation();
306 newJob.arguments = job.getArguments();
307 newJob.status = job.getStatus().ordinal();
308 newJob.parentJobId = job.getParentJobId();
309 newJob.rootJobId = job.getRootJobId();
310 newJob.dispatchable = job.isDispatchable();
311 newJob.uri = job.getUri();
312 newJob.creator = job.getCreator();
313 newJob.organization = job.getOrganization();
314 newJob.jobLoad = job.getJobLoad();
315 return newJob;
316 }
317
318 public Job toJob() {
319 return new JobImpl(id, creator, organization, version, jobType, operation, arguments, Status.values()[status],
320 createdHost, processingHost, dateCreated, dateStarted, dateCompleted, queueTime, runTime, payload,
321 parentJobId, rootJobId, dispatchable, uri, jobLoad);
322 }
323
324 @PostLoad
325 public void postLoad() {
326 if (creatorServiceRegistration == null) {
327 logger.warn("creator service registration for job '{}' is null", id);
328 } else {
329 this.createdHost = creatorServiceRegistration.getHost();
330 this.jobType = creatorServiceRegistration.getServiceType();
331 }
332
333 if (processorServiceRegistration == null) {
334 logger.debug("processor service registration for job '{}' is null", id);
335 } else {
336 this.processingHost = processorServiceRegistration.getHost();
337 this.jobType = processorServiceRegistration.getServiceType();
338 }
339
340 if (rootJob != null) {
341 rootJobId = rootJob.id;
342 }
343 if (parentJob != null) {
344 parentJobId = parentJob.id;
345 }
346 }
347
348 public void setProcessorServiceRegistration(ServiceRegistrationJpaImpl processorServiceRegistration) {
349 this.processorServiceRegistration = processorServiceRegistration;
350 if (processorServiceRegistration == null) {
351 this.processingHost = null;
352 } else {
353 this.processingHost = processorServiceRegistration.getHost();
354 }
355 }
356
357 public void setPayload(String payload) {
358 this.payload = payload;
359 }
360
361 public void setStatus(Status status) {
362 this.status = status.ordinal();
363 }
364
365 public void setDispatchable(boolean dispatchable) {
366 this.dispatchable = dispatchable;
367 }
368
369 public void setVersion(long version) {
370 this.version = version;
371 }
372
373 public void setOperation(String operation) {
374 this.operation = operation;
375 }
376
377 public void setArguments(List<String> arguments) {
378 this.arguments = arguments;
379 }
380
381 public void setDateCreated(Date dateCreated) {
382 this.dateCreated = dateCreated;
383 }
384
385 public void setDateStarted(Date dateStarted) {
386 this.dateStarted = dateStarted;
387 }
388
389 public void setQueueTime(long queueTime) {
390 this.queueTime = queueTime;
391 }
392
393 public void setDateCompleted(Date dateCompleted) {
394 this.dateCompleted = dateCompleted;
395 }
396
397 public void setRunTime(long runTime) {
398 this.runTime = runTime;
399 }
400
401 public void setParentJob(JpaJob parentJob) {
402 this.parentJob = parentJob;
403 this.parentJobId = parentJob.id;
404 }
405
406 public void setRootJob(JpaJob rootJob) {
407 this.rootJob = rootJob;
408 this.rootJobId = rootJob.id;
409 }
410
411 public void setStatus(Status status, FailureReason failureReason) {
412 this.status = status.ordinal();
413 this.failureReason = failureReason;
414 }
415
416 public void setUri(URI uri) {
417 this.uri = uri;
418 }
419
420 public long getId() {
421 return id;
422 }
423
424 public ServiceRegistrationJpaImpl getProcessorServiceRegistration() {
425 return processorServiceRegistration;
426 }
427
428 public String getJobType() {
429 return jobType;
430 }
431
432 public String getOperation() {
433 return operation;
434 }
435
436 public Float getJobLoad() {
437 return jobLoad;
438 }
439
440 public Status getStatus() {
441 return Status.values()[status];
442 }
443
444 public boolean isDispatchable() {
445 return dispatchable;
446 }
447
448 public JpaJob getRootJob() {
449 return rootJob;
450 }
451
452 public JpaJob getParentJob() {
453 return parentJob;
454 }
455
456 public List<JpaJob> getChildJobs() {
457 return childJobs;
458 }
459
460 public String getChildJobsString() {
461 StringBuilder sb = new StringBuilder();
462 for (JpaJob job : getChildJobs()) {
463 sb.append(job.getId());
464 sb.append(" ");
465 }
466 return sb.toString();
467 }
468
469 public FailureReason getFailureReason() {
470 return failureReason;
471 }
472
473 public Date getDateCreated() {
474 return dateCreated;
475 }
476
477 public Date getDateCompleted() {
478 return dateCompleted;
479 }
480
481 public String getCreator() {
482 return creator;
483 }
484
485 public String getOrganization() {
486 return organization;
487 }
488
489 @Override
490 public String toString() {
491 return String.format("Job {id:%d, operation:%s, status:%s}", id, operation, getStatus().toString());
492 }
493
494 }