org.eclipse.gyrex.jobs.internal.externalprocess.ExternalProcessJob.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.gyrex.jobs.internal.externalprocess.ExternalProcessJob.java

Source

/*******************************************************************************
 * Copyright (c) 2013 AGETO Service GmbH and others.
 * All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
 * and is available at http://www.eclipse.org/legal/epl-v10.html.
 *
 * Contributors:
 *     Gunnar Wagenknecht - initial API and implementation
 *******************************************************************************/
package org.eclipse.gyrex.jobs.internal.externalprocess;

import java.io.File;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.eclipse.gyrex.common.identifiers.IdHelper;
import org.eclipse.gyrex.jobs.internal.JobsActivator;
import org.eclipse.gyrex.jobs.internal.externalprocess.AsyncLoggingInputStreamReader.Level;
import org.eclipse.gyrex.server.Platform;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;

import org.apache.commons.lang.StringUtils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ExternalProcessJob extends Job {

    private static final Logger DEFAULT_LOG = LoggerFactory.getLogger(ExternalProcessJob.class);

    private final String jobId;
    private final List<String> command;
    private File workingDirectory;
    private final Logger log;
    private boolean clearEnvironment;
    private Map<String, String> additionalEnvironment;
    private int exitValue = 0;

    public ExternalProcessJob(final String jobId, final List<String> command, final Logger log) {
        super(jobId);
        this.jobId = jobId;
        this.command = command;
        this.log = null != log ? log : DEFAULT_LOG;
        setPriority(LONG);

        if (!IdHelper.isValidId(jobId))
            throw new IllegalArgumentException("Invalid job id: " + jobId);

        if ((null == command) || command.isEmpty())
            throw new IllegalArgumentException("Command must not be null or empty!");
    }

    public int getExitValue() {
        return exitValue;
    }

    @Override
    protected IStatus run(final IProgressMonitor monitor) {
        final ProcessBuilder builder = new ProcessBuilder();

        log.debug("Command: {}", command);
        builder.command(command);

        if (workingDirectory != null) {
            log.debug("Using working directory: {}", workingDirectory);
            builder.directory(workingDirectory);
        }

        if (clearEnvironment) {
            builder.environment().clear();
            log.debug("Cleared environment!");
        } else {
            // remove all Gyrex specific settings for security reasons
            final Iterator<Entry<String, String>> entries = builder.environment().entrySet().iterator();
            while (entries.hasNext()) {
                final Map.Entry<java.lang.String, java.lang.String> e = entries.next();
                if (StringUtils.startsWithIgnoreCase(e.getKey(), "gyrex")) {
                    log.debug("Removing Gyrex specific environment variable: {}", e.getKey());
                    entries.remove();
                }
            }
        }

        setEnvironmentVariable(builder, "WORKSPACE", Platform.getInstanceLocation().toOSString());
        setEnvironmentVariable(builder, "JOB_ID", jobId);

        if (additionalEnvironment != null) {
            for (final Entry<String, String> e : additionalEnvironment.entrySet()) {
                log.debug("Additional environment variable: {} = {}", e.getKey(), e.getValue());
                builder.environment().put(e.getKey(), e.getValue());
            }
        }

        AsyncLoggingInputStreamReader inputStreamReader = null, errorStreamReader = null;
        try {
            final Process p = builder.start();
            inputStreamReader = new AsyncLoggingInputStreamReader(jobId + " [OUT Reader]", p.getInputStream(), log,
                    Level.INFO);
            errorStreamReader = new AsyncLoggingInputStreamReader(jobId + " [ERR Reader]", p.getErrorStream(), log,
                    Level.ERROR);

            final int result = p.waitFor();
            if (result != exitValue)
                return new Status(IStatus.ERROR, JobsActivator.SYMBOLIC_NAME,
                        "Process finished with unexpected exit value: " + result);

        } catch (final InterruptedException e) {
            log.warn("Interrupted while waiting for the process to finish.", e);
            Thread.currentThread().interrupt();
            return Status.CANCEL_STATUS;
        } catch (final Exception | AssertionError | LinkageError e) {
            log.error("Error starting process. {} ", e.getMessage(), e);
            return new Status(IStatus.ERROR, JobsActivator.SYMBOLIC_NAME,
                    "Error starting process: " + e.getMessage(), e);
        } finally {
            if (inputStreamReader != null) {
                inputStreamReader.close();
            }
            if (errorStreamReader != null) {
                errorStreamReader.close();
            }
        }

        if (StringUtils.isNotBlank(inputStreamReader.getLastLine()))
            return new Status(IStatus.OK, JobsActivator.SYMBOLIC_NAME, inputStreamReader.getLastLine());

        return Status.OK_STATUS;
    }

    public void setAdditionalEnvironment(final Map<String, String> additionalEnvironment) {
        this.additionalEnvironment = additionalEnvironment;
    }

    public void setClearEnvironment(final boolean clearEnvironment) {
        this.clearEnvironment = clearEnvironment;
    }

    private void setEnvironmentVariable(final ProcessBuilder builder, final String key, final String value) {
        log.debug("Setting environment variable: {} = {}", key, value);
        builder.environment().put(key, value);
    }

    public void setExitValue(final int exitValue) {
        this.exitValue = exitValue;
    }

    public void setWorkingDirectory(final File workingDirectory) {
        this.workingDirectory = workingDirectory;
    }
}