Package com.polarion.platform.jobs
package com.polarion.platform.jobs
Provides classes and interfaces for handling jobs.
Usage Scenarios
Simple job without parameters
Let's say we want to provide job named my.job (convention says that job name has logical components delimited by periods). This job will not be configurable (or even visible) by job configuration UI (like scheduler UI or similar).Step 1 - provide job unit
We will provide job based onAbstractJobUnit
, because
it implements everything we need:
private class MyJobUnit extends AbstractJobUnit {
public int getWorkLength() {
// can be based on some parameters and set during activate()
return 10;
}
protected void runInternal(IProgressMonitor progress) {
getLogger().info("Started");
try {
progress.beginTask("Starting", 0); // totalWork is ignored
// since getWorkLength() returns 10 we must work at most 10 work units
for (int i = 1; i <= 10; i++) {
if (progress.isCanceled()) {
return getStatusCancelled("Cancelled");
}
progress.subtask("Tick number " + i);
// here some work can be done, possibly with temporary output written to getWorkDir()
progress.worked(1);
}
} catch (Exception e) {
return getStatusFailed("Failure", e);
} finally {
progress.setTaskName("Finished");
progress.done();
}
return getStatusOK("Success");
}
}
Step 2 - register proper factory for your job unit
Place into some hivemodule.xml:<contribution configuration-id="com.polarion.platform.jobs.configuration"> <jobUnitFactory name="my.job" factory="myJobUnitFactory"/> </contribution> <service-point id="myJobUnitFactory" interface="com.polarion.platform.jobs.IJobUnitFactory"> <invoke-factory> <construct class="com.polarion.platform.jobs.spi.GenericJobUnitFactory"> <string>my.job</string> <string>My Job</string> <object>class:package.MyJobUnit</object> </construct> </invoke-factory> </service-point>This will register new job unit factory for job unit my.job creating instances of
package.MyJobUnit
.
Step 3 - spawn job based on your job unit
IJobService jobService = ...;
IJobManager mgr = jobService.getJobManager();
IJobUnitRepository repo = jobService.getJobUnitRepository();
IJobUnit unit = (IJobUnit) repo.getJobUnitFactory("my.job")
.createJobUnit("My job started at " + System.currentTimeMillis());
IJob job = mgr.spawnJob(unit, null);
job.schedule();
// now the activation phase finished (see next usage scenarios) and job started (or is waiting for start)
// we can wait for the job to end or just leave it alone and use state listeners on IJob
job.join();
// now the job finished and its status can be inspected
if (job.getStatus().getType() != JobStatusType.STATUS_TYPE_OK) {
// deal with failure
}
Names explained
Jobs have various names (all are required):- job factory name
-
Returned from
IJobUnitFactory.getName()
and passed toIJobUnitRepository.getJobUnitFactory()
. Is kind of job unit class name (but more human-readable). Should be unique (although that fact is not checked). Examples are "master.build", "cleanup". - job name
-
Returned from
IJobUnit.getName()
andIJob.getName()
. Name of given instance of job unit (and thus the whole job). Should be short, human-readable and contain some information based on job's configuration. Is immutable during job's life. Examples are "Build of org.polarion.subversive", "Cleanup of /tmp". - job label
-
Returned from
IJobDescriptor.getLabel()
. Short, human-readable name of given job unit. Kind of job factory name, but even more human-readable. Is visible in job configuration UI (like scheduler UI). Examples are "Project builds", "Directory cleanup".
Job with typed interface
It is considered good practice to provide typed interface for job units if those jobs have some parameters:public interface IMyJobUnit extends IJobUnit { public static final String JOB_NAME = "my.job"; void setSomeParameter(String value); String getSomeResult(); ... } private class MyJobUnit extends AbstractJobUnit implements IMyJobUnit { private String someParameter; private String someResult; public void setSomeParameter(String value) { someParameter = value; } public String getSomeResult() { return someResult; } public void activate() { // check parameters if (someParameter == null) { throw new IllegalArgumentException("setSomeParameter() was not called"); } ... } protected void runInternal(...) { ... // set results (of course this can be set even during activation or at start of runInternal()) someResult = ...; return getStatusOK(...); } }Those who want to spawn jobs based on this job unit may do this:
IJobService jobService = ...; IJobManager mgr = jobService.getJobManager(); IJobUnitRepository repo = jobService.getJobUnitRepository(); IMyJobUnit unit = (IMyJobUnit) repo.getJobUnitFactory(IMyJobUnit.JOB_NAME).createJobUnit(...); unit.setSomeParameter(...); IJob job = mgr.spawnJob(unit, null); job.schedule(); // let's wait for the result job.join(); return job.getSomeResult();
Job with dependencies
Job may depend on arbitrary number of other jobs (which are called child jobs).public void activate() { IJobUnit unit = ...; // normal job unit creation using some job unit factory unit.setWorkDir(getWorkDir()); // pass it the same work dir getJob().getJobManager().spawnJob(unit, getJob()); ... }Child jobs can be spawned only inside
activate()
.
Parent job's run()
will be executed after child jobs complete regardless of their status.
Job units based on AbstractJobUnit
will get their runInternal()
executed only if all child jobs
finish successfully.
Job with resource locking
Job may lock resources to which it wants to have exclusive access. Job manager will ensure that no two jobs claiming the same resource (or, better said, conflicting resources) run at the same time. Resources are locked since the first child runs until the job is finished. Resources locked by children are automatically locked by parents.public void activate() { IJobResource resource = new SomeJobResourceImplementation(...); getJob().addResource(resource); ... }Resources can be locked only inside
activate()
.
Platform-aware job
For more complicated jobs, especially those who want to have injected services and configuration, specialIJobUnitFactory
should be created and job unit placed as nested non-static class
with access to factory's injected parameters. Example:
public class MyJobUnitFactory implements IJobUnitFactory { protected ISomeService someService; public void setSomeService(ISomeService someService) { this.someService = someService; } private class MyJobUnit extends AbstractJobUnit { protected void runInternal(...) { ... someService.someMethod(); ... } } public IJobUnit createJobUnit(String name) throws GenericJobException { return new MyJobUnit(name, this); } }
ISomeService
can be auto-wired or set explicitly in hivemodule.xml:
<service-point id="myJobUnitFactory" interface="com.polarion.platform.jobs.IJobUnitFactory"> <invoke-factory> <construct class="package.MyJobUnitFactory"> <set-service property="someService" service-id="someServiceId"/> </construct> </invoke-factory> </service-point>
-
ClassDescriptionGeneric jobs-related exception.This job will remove work dirs of other jobs which were last modified before given time.Execute system command.Job.Job (unit) descriptor.Job parameter descriptor.Choice.Optional "flavor" type adding choice support to any type.Parameter group.List type (ordered list of items of same type).Specialized multi-choice list.Primitive type (single value).Structure type (map).Job parameter type.Extension to
ILogEvent
which allows to track which jobs send what events.Job manager.Multi-status (status encapsulating zero or more other statuses).Resource used for determination of what jobs can be run simultaneously.Job service.Listener which will react on changes ofIJob.getState()
.Common interface for everyone willing to fire notifications forIJobStateListener
.Job status (result of job's execution).Job status type "enumeration".Job unit.Factory forIJobUnit
s (job implementations).Repository ofIJobUnitFactory
s.Recorded log event.Log event severity "enumeration".Logging subsystem interface.This job will remove log files which are too old.This job will execute multiple jobs at once (sequentially or in parallel).Can be thrown when invoking methods on an inaccessible job.Leveraged directly from Eclipse: TheIProgressMonitor
interface is implemented by objects that monitor the progress of an activity; the methods in this interface are invoked by code that performs the activity.Structured log message forILogger
.This job will synchronize Polarion users, belonging to specific User Groups, with LDAP based on the LDAP search filter set up in the respective User Groups.This job will synchronize Polarion users with LDAP based on the LDAP search filter set up in Polarion administration.Interface indicating that object can be represented as XML element.Job state "enumeration".Multi-job execution request.