Writing a Java Task Part 2

In this tutorial we examine the anatomy of a task to use some of the features already present in the framework backing the created task.

Please ensure you have run the dependent module Part 1 before following this tutorial.

Extending abstract classes

You may add any number of layers of abstract classes in between the MidVision abstraction layer and your concrete classes. The main MidVision abstract classes you should aim to extend are one of:

Class Purpose
AbstractDeploymentTask Abstract task for all code deployment classes and most other classes.
AbstractControlTask Abstract class for control operation and binary install classes such as stop, start, restart type classes.
AbstractFileDeploymentTask Abstract task for all file based code deployment classes. This task extends AbstractDeploymentTask.

Finding out what is available in the superclasses

In the runTask method, type "this." to see all methods from all superclasses.

Finding out what is available in the "helper" classes

The main helper classes, accessible from any task are CoreTaskHelper, OsUtils, ProprtyUtils and the third party commons FileUtils. Many additional packages are available, such as the full range of ANT Java tasks that can be written directly into our classes.

Getting Parameters from the Task

The following code demonstrates getting a Boolean (failOnError) or a String (scriptToRunPath) from the parameters for this task:

Boolean failOnError = Boolean.valueOf((String)getResources().get( "failOnError" ));
String scriptToRunPath = (String)getResources().get( "scriptToRunPath" );

These parameters are likely to be environment neutral properties (such as failOnError or a relative path to a resource inside the deployment archive). However, they can also be environment specific if they are tokenised with a token that exists in the dictionary file for this environment, e.g. a path to a script on the server that differs on different machines.

Getting the Environment domain object relating to this Job

Each job runs in an environment context. The environment details are passed to the job execution on the target server, along with the deployment package. The deployment package contains a domain xml file for each environment for which this job can be run. In order to get the properties for this specific environment we get the domain object.

The following code gets the environment definition parameters for this deployment, by reading the domain XML into the domain object. The example is for a task in the Docker plugin. You would replace DockerEnvironmentDomain with the correct domain object for your task.

private DockerEnvironmentDomain domain = null;
domain = (DockerEnvironmentDomain) this.initEnvironmentDomain(DockerEnvironmentDomain.class);

Now we can load properties from the environment using the getters on that domain object, for example:

String dockerHost = domain.getDockerHost();

Getting the Deployment Archive Path Relating to this Job

All tasks are run within the context of an environment (discussed above) and an environment neutral orchestration (sequence of tasks). By the time your task is run for a target environment on a target server, the deployment package will already have been copied over and expanded into a temporary location.

It is quite likely that the task will need to know this location in order to access resources contained in the archive, such as scripts, compiled code or other payload artifacts relating to this job.

The getArchiveRoot() method returns a string representation of the root of the expanded archive. The following code gives an example:

File srcDir = new File(getArchiveRoot() + OsUtils.getFileSep() + getTemplatePath());

Here we construct a path based on the archive root, and a relative path returned from getTemplatePath(). getTemplatePath() might be a method getting a resource from the task, since the relative path to a particular resource inside the archive will always be the same, no matter where we deploy to and so is a good candidate for a task parameter.

Cleaning Up

You should always use try/catch/finally blocks in your runTask method. Here is an example:

        try {
 
                // Do something (that might fail!)
 
        } catch (Exception e){
                cleanUp(this.getClass().getSimpleName(), lbooleanFail, e);
        } finally {
                // Close any open resources here. 
        }

The cleanup method determines if the failure should fail the whole deployment (depending on the failOnError boolean) and ensures temporary files are cleaned up if the deployment should fail, or if they should be retained for debug purposes.