fr.cnes.sitools.extensions.astro.application.uws.jobmanager.AbstractJobTask.java Source code

Java tutorial

Introduction

Here is the source code for fr.cnes.sitools.extensions.astro.application.uws.jobmanager.AbstractJobTask.java

Source

/*******************************************************************************
* Copyright 2010-2014 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2.  If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
package fr.cnes.sitools.extensions.astro.application.uws.jobmanager;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URI;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;

import javax.xml.bind.JAXBElement;
import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;

import net.ivoa.xml.uws.v1.ErrorSummary;
import net.ivoa.xml.uws.v1.ExecutionPhase;
import net.ivoa.xml.uws.v1.JobSummary;
import net.ivoa.xml.uws.v1.JobSummary.JobInfo;
import net.ivoa.xml.uws.v1.Parameters;
import net.ivoa.xml.uws.v1.Results;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.restlet.data.Form;
import org.restlet.data.MediaType;
import org.restlet.data.Parameter;
import org.restlet.data.Reference;
import org.restlet.data.Status;
import org.restlet.engine.Engine;
import org.restlet.ext.fileupload.RestletFileUpload;
import org.restlet.representation.OutputRepresentation;
import org.restlet.representation.Representation;
import org.restlet.resource.ClientResource;

import fr.cnes.sitools.common.SitoolsSettings;
import fr.cnes.sitools.common.application.ContextAttributes;
import fr.cnes.sitools.extensions.astro.application.UwsApplicationPlugin;
import fr.cnes.sitools.extensions.astro.application.uws.common.Constants;
import fr.cnes.sitools.extensions.astro.application.uws.common.UniversalWorkerException;
import fr.cnes.sitools.extensions.astro.application.uws.common.Util;
import fr.cnes.sitools.xml.uws.v1.Job;

/**
 * The AbstractJobTask handles a specific JobTask and contains the needed
 * information to represent a JobSummary element.
 *
 * @author Jean-Christophe Malapert
 */
public abstract class AbstractJobTask implements JobTaskRunnable {

    private volatile Thread blinker;
    private String jobTaskId;
    private ExecutionPhase phase;
    private int executionDuration;
    private XMLGregorianCalendar destructionTime;
    private ErrorSummary error;
    private JAXBElement<XMLGregorianCalendar> quote;
    private Results results;
    private Parameters parameters;
    private XMLGregorianCalendar startTime;
    private XMLGregorianCalendar endTime;
    private String ownerId;
    private String storagePath;
    private JobInfo jobInfo;
    private String storagePublic;

    /**
     * Load dynamically a specific jobTask.
     *
     * @param app UWS application
     * @param jobTaskId Job task identifier
     * @param entity www-form-urlencoded form
     * @return Returns an instance of a specific jobTask
     * @throws UniversalWorkerException Returns an Internal error
     */
    public static AbstractJobTask create(final UwsApplicationPlugin app, final String jobTaskId,
            final Representation entity) throws UniversalWorkerException {
        AbstractJobTask jobTask = null;
        try {
            jobTask = (AbstractJobTask) Class.forName(app.getJobTaskImplementation()).newInstance();
            jobTask.doInit(app, jobTaskId, entity);
        } catch (InstantiationException ex) {
            throw new UniversalWorkerException(Status.SERVER_ERROR_INTERNAL, ex);
        } catch (IllegalAccessException ex) {
            throw new UniversalWorkerException(Status.SERVER_ERROR_INTERNAL, ex);
        } catch (ClassNotFoundException ex) {
            throw new UniversalWorkerException(Status.SERVER_ERROR_INTERNAL, ex);
        }
        return jobTask;
    }

    /**
     * Init the specific JobTask.
     *
     * @param app Uws application
     * @param jobTaskId Job task identifier
     * @param entity www-form-urlencoded form
     * @throws UniversalWorkerException
     */
    protected final void doInit(final UwsApplicationPlugin app, final String jobTaskId, final Representation entity)
            throws UniversalWorkerException {
        final long delay = Long.parseLong(UwsApplicationPlugin.APP_DESTRUCTION_DELAY);
        final SitoolsSettings settings = (SitoolsSettings) app.getContext().getAttributes()
                .get(ContextAttributes.SETTINGS);
        final String uwsAttachUrl = app.getAttachementRef();
        this.storagePublic = settings.getPublicHostDomain() + uwsAttachUrl;
        this.storagePath = app.getStorageDirectory();
        this.jobTaskId = jobTaskId;
        this.executionDuration = 0;
        try {
            this.destructionTime = Util.computeDestructionTime(new Date(), delay);
        } catch (DatatypeConfigurationException ex) {
            throw new UniversalWorkerException(Status.SERVER_ERROR_INTERNAL, ex);
        }
        this.error = null;
        this.quote = null;
        this.results = new Results();
        try {
            this.startTime = DatatypeFactory.newInstance().newXMLGregorianCalendar();
        } catch (DatatypeConfigurationException ex) {
            throw new UniversalWorkerException(Status.SERVER_ERROR_INTERNAL, ex);
        }
        try {
            this.endTime = DatatypeFactory.newInstance().newXMLGregorianCalendar();
        } catch (DatatypeConfigurationException ex) {
            throw new UniversalWorkerException(Status.SERVER_ERROR_INTERNAL, ex);
        }
        this.ownerId = Constants.NO_OWNER;
        createUserSpace();
        final Form form = computeForm(entity);
        this.phase = setPhaseAtCreation(form);
        this.parameters = createParametersForJob(form, true);
        JobTaskManager.getInstance().updateJobTask(this);
    }

    /**
     * Returns the form from a entity.
     * <p>
     * The entity must be either MULTIPART_FORM_DATA or APPLICATION_WWW_FORM.
     * </p>
     *
     * @param entity representation that is sent by the user
     * @return the form
     * @throws UniversalWorkerException This style of representation is not
     * implemented
     */
    private Form computeForm(final Representation entity) throws UniversalWorkerException {
        Form form = null;
        if (!Util.isSet(entity)) {
            return form;
        }
        if (MediaType.MULTIPART_FORM_DATA.equals(entity.getMediaType(), true)) {
            try {
                form = uploadFile(entity);
            } catch (FileUploadException ex) {
                throw new UniversalWorkerException(Status.SERVER_ERROR_INTERNAL, ex);
            } catch (Exception ex) {
                throw new UniversalWorkerException(Status.SERVER_ERROR_INTERNAL, ex);
            }
        } else if (MediaType.APPLICATION_WWW_FORM.equals(entity.getMediaType(), true)) {
            form = new Form(entity);
        } else {
            throw new UniversalWorkerException(Status.SERVER_ERROR_NOT_IMPLEMENTED,
                    "This style of representation is not implemented");
        }
        doCheckForm(form);
        return form;
    }

    protected void doCheckForm(Form form) throws UniversalWorkerException {
    }

    /**
     * Set the Job phase at creation. By default, set job phase to PENDING. When
     * a user set PHASE=RUN, the job phase is set to QUEUED
     *
     * @param form www-form-urlencoded form
     * @return Returns the ExecutionPhase
     * @throws UniversalWorkerException only RUN value is accepted for PHASE
     * keyword
     */
    private ExecutionPhase setPhaseAtCreation(final Form form) throws UniversalWorkerException {
        if (Util.isSet(form) && Util.isSet(form.getFirst(Constants.PHASE))) {
            if (form.getFirst(Constants.PHASE).getValue().equals(Constants.PHASE_RUN)) {
                return ExecutionPhase.QUEUED;
            } else {
                throw new UniversalWorkerException(Status.CLIENT_ERROR_BAD_REQUEST,
                        "only RUN value is accepted for PHASE keyword");
            }

        } else {
            return ExecutionPhase.PENDING;
        }
    }

    /**
     * Get job parameters from Job form. All parameters of the form are set
     * excepted for PHASE parameter
     *
     * @param form www-form-urlencoded form
     * @param isPost Set isPost=true for parameters sent by the user
     * @return Returns job parameters
     */
    private Parameters createParametersForJob(final Form form, final boolean isPost) {
        //TODO encoder les paramtres si ce sont des URLS
        final Parameters parametersUWS = new Parameters();
        if (form != null && !form.isEmpty()) {
            final Iterator<Parameter> iterParam = form.iterator();
            while (iterParam.hasNext()) {
                final Parameter param = iterParam.next();
                if (!param.getName().equals(Constants.PHASE)) {
                    final net.ivoa.xml.uws.v1.Parameter parameterUWS = new net.ivoa.xml.uws.v1.Parameter();
                    parameterUWS.setId(param.getName());
                    parameterUWS.setContent(Reference.decode(param.getValue()));
                    parametersUWS.getParameter().add(parameterUWS);
                    parameterUWS.setIsPost(isPost);
                    if (param.getValue().startsWith("http")) {
                        parameterUWS.setByReference(true);
                    }
                }
            }
        }
        return parametersUWS;
    }

    /**
     * Asynchronous run.
     */
    @Override
    public abstract void run();

    /**
     * Returns the get capabilities of the runnable job.
     *
     * @return the get capabilities of the runnable job
     */
    public abstract Job getCapabilities();

    /**
     * Returns the get Capabilities of the Runnable job.
     *
     * @param className runnable class
     * @return the get Capabilities of the Runnable job
     */
    public static final Job getCapabilities(final String className) {
        Job job = null;
        try {
            final Class c = Class.forName(className);
            final Object obj = c.newInstance();
            final Method m = c.getDeclaredMethod("getCapabilities", null);
            job = (Job) m.invoke(obj, null);
        } catch (ClassNotFoundException ex) {
            Engine.getLogger(AbstractJobTask.class.getName()).log(Level.SEVERE, null, ex);
        } catch (NoSuchMethodException ex) {
            Engine.getLogger(AbstractJobTask.class.getName()).log(Level.SEVERE, null, ex);
        } catch (SecurityException ex) {
            Engine.getLogger(AbstractJobTask.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            Engine.getLogger(AbstractJobTask.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IllegalArgumentException ex) {
            Engine.getLogger(AbstractJobTask.class.getName()).log(Level.SEVERE, null, ex);
        } catch (InvocationTargetException ex) {
            Engine.getLogger(AbstractJobTask.class.getName()).log(Level.SEVERE, null, ex);
        } catch (InstantiationException ex) {
            Engine.getLogger(AbstractJobTask.class.getName()).log(Level.SEVERE, null, ex);
        }
        return job;
    }

    /**
     * sets the Thread.
     *
     * @param blinker Thread
     */
    public void setBlinker(final Thread blinker) {
        this.blinker = blinker;
    }

    /**
     * Returns the JobSummary object.
     *
     * @return Returns the JobSummary object
     */
    public final JobSummary getJobSummary() {
        final JobSummary jobSummary = new JobSummary();
        jobSummary.setJobId(getJobTaskId());
        jobSummary.setPhase(getPhase());
        jobSummary.setExecutionDuration(getExecutionDuration());
        jobSummary.setDestruction(getDestructionTime());
        jobSummary.setStartTime(getStartTime());
        jobSummary.setEndTime(getEndTime());
        jobSummary.setParameters(getParameters());
        jobSummary.setOwnerId(getOwnerId());
        jobSummary.setResults(getResults());
        jobSummary.setErrorSummary(getError());
        jobSummary.setJobInfo(getJobInfo());
        return jobSummary;
    }

    /**
     * Cancel the thread.
     */
    public final void cancel() {
        final Thread tmpBlinker = blinker;
        blinker = null;
        if (tmpBlinker != null) {
            tmpBlinker.interrupt();
        }
        this.setPhase(ExecutionPhase.ABORTED);
    }

    /**
     * Returns the execution duration.
     *
     * @return Returns the executionDuraction
     */
    protected final int getExecutionDuration() {
        return executionDuration;
    }

    /**
     * Sets the execution duration and update the JobTaskManager
     *
     * @param executionDuraction the executionDuraction to set
     */
    protected final void setExecutionDuration(final int executionDuraction) {
        this.executionDuration = executionDuraction;
        JobTaskManager.getInstance().updateJobTask(this);
    }

    /**
     * Returns the Job task identifier.
     *
     * @return the job task indentifier
     */
    protected final String getJobTaskId() {
        return this.jobTaskId;
    }

    /**
     * Returns the job phase.
     *
     * @return the phase
     */
    protected final ExecutionPhase getPhase() {
        return phase;
    }

    /**
     * Sets the job phase and update the JobTaskManager when mustBeUpdated =
     * true.
     *
     * @param phaseVal Phase to set
     * @param mustBeUpdated true calls the JobTaskManager otherwise false
     * otherwise false
     */
    protected final void setPhase(final ExecutionPhase phaseVal, final boolean mustBeUpdated) {
        this.phase = phaseVal;
        if (mustBeUpdated) {
            JobTaskManager.getInstance().updateJobTask(this);
        }
    }

    /**
     * Sets the phase and updates the JobTaskManager.
     *
     * @param phaseVal phase
     */
    protected void setPhase(ExecutionPhase phaseVal) {
        this.phase = phaseVal;
        JobTaskManager.getInstance().updateJobTask(this);
    }

    /**
     * Returns the destruction time.
     *
     * @return Returns the destructionTime
     */
    protected final XMLGregorianCalendar getDestructionTime() {
        return destructionTime;
    }

    /**
     * Sets the destruction time and update the JobTaskManager.
     *
     * @param destructionTime the destructionTime to set
     * @param mustBeUpdated
     */
    protected void setDestructionTime(final XMLGregorianCalendar destructionTime, final boolean mustBeUpdated) {
        this.destructionTime = destructionTime;
        if (mustBeUpdated) {
            JobTaskManager.getInstance().updateJobTask(this);
        }
    }

    /**
     * Sets the destruction time and update the JobTaskManager
     *
     * @param destructionTime the destructionTime to set
     */
    protected void setDestructionTime(final XMLGregorianCalendar destructionTime) {
        this.destructionTime = destructionTime;
        JobTaskManager.getInstance().updateJobTask(this);
    }

    /**
     * Returns the error.
     *
     * @return the error
     */
    protected final ErrorSummary getError() {
        return error;
    }

    /**
     * Sets the error and update the JobTaskManager.
     *
     * @param error the error to set
     * @param mustBeUpdated
     */
    protected final void setError(final ErrorSummary error, final boolean mustBeUpdated) {
        this.error = error;
        if (mustBeUpdated) {
            JobTaskManager.getInstance().updateJobTask(this);
        }
    }

    /**
     * Set the error and update the JobTaskManager.
     *
     * @param error the error to set
     */
    protected final void setError(final ErrorSummary error) {
        this.error = error;
        JobTaskManager.getInstance().updateJobTask(this);
    }

    protected final JobInfo getJobInfo() {
        return this.jobInfo;
    }

    protected final void setJobInfo(final JobInfo jobInfo, final boolean mustBeUpdated) {
        this.jobInfo = jobInfo;
        if (mustBeUpdated) {
            JobTaskManager.getInstance().updateJobTask(this);
        }
    }

    protected final void setJobInfo(final JobInfo jobInfo) {
        this.jobInfo = jobInfo;
        JobTaskManager.getInstance().updateJobTask(this);
    }

    /**
     * Returns the quote.
     *
     * @return the quote
     */
    protected final JAXBElement<XMLGregorianCalendar> getQuote() {
        return quote;
    }

    /**
     * Sets the quote and update the JobTaskManager.
     *
     * @param quote the quote to set
     * @param mustBeUpdated
     */
    protected final void setQuote(final JAXBElement<XMLGregorianCalendar> quote, final boolean mustBeUpdated) {
        this.quote = quote;
        if (mustBeUpdated) {
            JobTaskManager.getInstance().updateJobTask(this);
        }
    }

    /**
     * Sets the quote and updates the JobTaskManager.
     *
     * @param quote the quote to set
     */
    protected final void setQuote(final JAXBElement<XMLGregorianCalendar> quote) {
        this.quote = quote;
        JobTaskManager.getInstance().updateJobTask(this);
    }

    /**
     * Returns the results.
     *
     * @return the results
     */
    protected final Results getResults() {
        return results;
    }

    /**
     * Sets the results and updates the JobTaskManager.
     *
     * @param results the results to set
     * @param mustBeUpdated
     */
    protected final void setResults(final Results results, final boolean mustBeUpdated) {
        this.results = results;
        if (mustBeUpdated) {
            JobTaskManager.getInstance().updateJobTask(this);
        }
    }

    /**
     * Sets results and update the JobTaskManager.
     *
     * @param results the results to set
     */
    protected final void setResults(final Results results) {
        this.results = results;
        JobTaskManager.getInstance().updateJobTask(this);
    }

    /**
     * Returns the parameters.
     *
     * @return the parameters The parameters to set
     */
    protected final Parameters getParameters() {
        return parameters;
    }

    /**
     * Sets the parameters.
     *
     * @param parameters the parameters to set
     * @param mustBeUpdated
     */
    protected final void setParameters(final Parameters parameters, final boolean mustBeUpdated) {
        this.parameters = parameters;
        if (mustBeUpdated) {
            JobTaskManager.getInstance().updateJobTask(this);
        }
    }

    /**
     * Sets the parameters.
     *
     * @param parameters the parameters to set
     */
    protected final void setParameters(final Parameters parameters) {
        this.parameters = parameters;
        JobTaskManager.getInstance().updateJobTask(this);
    }

    /**
     * Returns the value of parameter name.
     *
     * @param parameterName Parameter name to find
     * @return Returns the value of the parameter name
     */
    protected final String getParameterValue(final String parameterName) {
        String valueParam = null;
        final Iterator<net.ivoa.xml.uws.v1.Parameter> iterParam = this.parameters.getParameter().iterator();
        while (iterParam.hasNext()) {
            final net.ivoa.xml.uws.v1.Parameter parameter = iterParam.next();
            if (parameter.getId().equals(parameterName)) {
                valueParam = parameter.getContent();
            }
        }
        return valueParam;
    }

    /**
     * Sets a value to a parameter name.
     *
     * @param key Key
     * @param value Value
     * @param mustBeUpdated
     */
    protected final void setParameterValue(final String key, final String value, final boolean mustBeUpdated) {
        final Iterator<net.ivoa.xml.uws.v1.Parameter> iterParam = this.parameters.getParameter().iterator();
        while (iterParam.hasNext()) {
            final net.ivoa.xml.uws.v1.Parameter parameter = iterParam.next();
            if (parameter.getId().equals(key)) {
                parameter.setContent(value);
            }
        }
        if (mustBeUpdated) {
            JobTaskManager.getInstance().updateJobTask(this);
        }
    }

    /**
     * Sets a value to a parameter name.
     *
     * @param key Key
     * @param value Value
     */
    protected final void setParameterValue(final String key, final String value) {
        final Iterator<net.ivoa.xml.uws.v1.Parameter> iterParam = this.parameters.getParameter().iterator();
        while (iterParam.hasNext()) {
            final net.ivoa.xml.uws.v1.Parameter parameter = iterParam.next();
            if (parameter.getId().equals(key)) {
                parameter.setContent(value);
            }
        }
        JobTaskManager.getInstance().updateJobTask(this);
    }

    /**
     * Returns the start time.
     *
     * @return the startTime
     */
    protected final XMLGregorianCalendar getStartTime() {
        return startTime;
    }

    /**
     * Sets the start time.
     *
     * @param startTime the startTime to set
     */
    protected final void setStartTime(final XMLGregorianCalendar startTime) {
        this.startTime = startTime;
    }

    /**
     * Returns the end time.
     *
     * @return the endTime
     */
    protected final XMLGregorianCalendar getEndTime() {
        return endTime;
    }

    /**
     * Sets the end time.
     *
     * @param endTime the endTime to set
     */
    protected final void setEndTime(final XMLGregorianCalendar endTime) {
        this.endTime = endTime;
    }

    /**
     * Returns the ownerID.
     *
     * @return the ownerId
     */
    protected final String getOwnerId() {
        return ownerId;
    }

    /**
     * Sets the owner ID.
     *
     * @param ownerId the ownerId to set
     * @param mustBeUpdated
     */
    protected final void setOwnerId(final String ownerId, final boolean mustBeUpdated) {
        this.ownerId = (ownerId == null) ? Constants.NO_OWNER : ownerId;
        if (mustBeUpdated) {
            JobTaskManager.getInstance().updateJobTask(this);
        }
    }

    /**
     * Sets the owner ID.
     *
     * @param ownerId the ownerId to set
     */
    protected final void setOwnerId(final String ownerId) {
        this.ownerId = (ownerId == null) ? Constants.NO_OWNER : ownerId;
        JobTaskManager.getInstance().updateJobTask(this);
    }

    /**
     * Returns the Thread.
     *
     * @return the thread
     */
    protected final Thread getBlinker() {
        return this.blinker;
    }

    private Form uploadFile(final Representation rep) throws FileUploadException, Exception {

        // The Apache FileUpload project parses HTTP requests which
        // conform to RFC 1867, "Form-based File Upload in HTML". That
        // is, if an HTTP request is submitted using the POST method,
        // and with a content type of "multipart/form-data", then
        // FileUpload can parse that request, and get all uploaded files
        // as FileItem.
        // 1/ Create a factory for disk-based file items
        final DiskFileItemFactory factory = new DiskFileItemFactory();
        factory.setSizeThreshold(1000240);

        // 2/ Create a new file upload handler based on the Restlet
        // FileUpload extension that will parse Restlet requests and
        // generates FileItems.
        final RestletFileUpload upload = new RestletFileUpload(factory);
        List items;

        // 3/ Request is parsed by the handler which generates a
        // list of FileItems
        items = upload.parseRepresentation(rep);
        // Process only the uploaded item  and save it on disk
        final Form form = new Form();
        for (final Iterator it = items.iterator(); it.hasNext();) {
            final FileItem fi = (FileItem) it.next();
            if (fi.isFormField()) {
                form.add(fi.getFieldName(), fi.getString());
            } else {
                form.add(fi.getFieldName(), fi.getName());
                this.copyFile(fi);
            }
        }
        return form;
    }

    protected final void retrieveFile(final URI url, final File fileDestination) {
        final ClientResource client = new ClientResource(url);
        OutputStream os = null;
        if (client.getStatus().isSuccess()) {
            InputStream is = null;
            try {
                final Representation rep = client.get();
                is = rep.getStream();
                os = new FileOutputStream(fileDestination);
                byte[] buffer = new byte[4096];
                int bytesRead;
                while ((bytesRead = is.read(buffer)) != -1) {
                    os.write(buffer, 0, bytesRead);
                }
            } catch (IOException ex) {
                Engine.getLogger(AbstractJobTask.class.getName()).log(Level.SEVERE, null, ex);
            } finally {
                try {
                    is.close();
                } catch (IOException ex) {
                    Engine.getLogger(AbstractJobTask.class.getName()).log(Level.SEVERE, null, ex);
                }
                try {
                    os.close();
                } catch (IOException ex) {
                    Engine.getLogger(AbstractJobTask.class.getName()).log(Level.SEVERE, null, ex);
                }
                client.release();
            }
        } else {
            client.release();
        }
    }

    protected final void moveFile(final File fileToCopy) throws UniversalWorkerException {
        final String uri = "riap://application/jobCache/" + jobTaskId + "/" + fileToCopy.getName();
        final ClientResource client = new ClientResource(uri);
        client.put(new OutputRepresentation(MediaType.ALL) {

            @Override
            public void write(final OutputStream outputStream) {
                FileInputStream fileOs = null;
                try {
                    fileOs = new FileInputStream(fileToCopy);
                    int c;
                    while ((c = fileOs.read()) != -1) {
                        outputStream.write(c);
                    }
                    fileOs.close();
                    outputStream.close();
                } catch (IOException ex) {
                    Engine.getLogger(AbstractJobTask.class.getName()).log(Level.SEVERE, null, ex);
                } finally {
                    try {
                        if (fileOs != null) {
                            fileOs.close();
                        }
                    } catch (IOException ex) {
                        Engine.getLogger(AbstractJobTask.class.getName()).log(Level.SEVERE, null, ex);
                    }
                }
            }
        });
        if (!client.getStatus().isSuccess()) {
            client.release();
            throw new UniversalWorkerException(client.getStatus(), "Cannot copy " + fileToCopy.getName());
        }
        client.release();
        if (!fileToCopy.delete()) {
            throw new UniversalWorkerException(Status.SERVER_ERROR_INTERNAL,
                    "Cannot delete " + fileToCopy.getName());
        }
    }

    protected final void copyFile(final FileItem fi) throws UniversalWorkerException {
        final String uri = "riap://application/jobCache/" + jobTaskId + "/" + fi.getName();
        final ClientResource client = new ClientResource(uri);
        client.put(fi.getString());
        client.release();
    }

    /**
     * Creates user space.
     *
     * @throws UniversalWorkerException
     */
    private void createUserSpace() throws UniversalWorkerException {
        final String uri = "riap://application/jobCache";
        final ClientResource client = new ClientResource(uri);
        client.post(jobTaskId);
        client.release();
    }

    /**
     * Deletes user space disk for a specific jobId
     *
     * @param jobTaskId
     * @throws UniversalWorkerException Returns an CLIENT_ERROR_BAD_REQUEST
     */
    protected final void deleteUserSpace() throws UniversalWorkerException {
        final String uri = "riap://application/jobCache/" + jobTaskId;
        final ClientResource client = new ClientResource(uri);
        client.delete();
        client.release();
    }

    /**
     * Returns the storage public URL.
     *
     * @return the storage public URL
     */
    protected final String getStoragePublicUrl() {
        return this.storagePublic + "/storage";
    }

    /**
     * Returns the storage path job.
     *
     * @return the storage path job
     */
    protected final String getStoragePathJob() {
        return this.storagePath + File.separator + getJobTaskId();
    }
}