All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.liferay.portal.kernel.process.ProcessUtil Maven / Gradle / Ivy

Go to download

Contains interfaces for the portal services. Interfaces are only loaded by the global class loader and are shared by all plugins.

There is a newer version: 7.0.0-nightly
Show newest version
/**
 * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 *
 * This library 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 Lesser General Public License for more
 * details.
 */

package com.liferay.portal.kernel.process;

import com.liferay.portal.kernel.util.NamedThreadFactory;
import com.liferay.portal.kernel.util.ObjectValuePair;
import com.liferay.portal.kernel.util.PortalClassLoaderUtil;

import java.io.IOException;

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

/**
 * @author Shuyang Zhou
 */
public class ProcessUtil {

	public static final ConsumerOutputProcessor CONSUMER_OUTPUT_PROCESSOR =
		new ConsumerOutputProcessor();

	public static final LoggingOutputProcessor LOGGING_OUTPUT_PROCESSOR =
		new LoggingOutputProcessor();

	public static  Future> execute(
			OutputProcessor outputProcessor, List arguments)
		throws ProcessException {

		if (outputProcessor == null) {
			throw new NullPointerException("Output processor is null");
		}

		if (arguments == null) {
			throw new NullPointerException("Arguments is null");
		}

		ProcessBuilder processBuilder = new ProcessBuilder(arguments);

		try {
			Process process = processBuilder.start();

			ExecutorService executorService = _getExecutorService();

			try {
				Future stdOutFuture = executorService.submit(
					new ProcessStdOutCallable(outputProcessor, process));

				Future stdErrFuture = executorService.submit(
					new ProcessStdErrCallable(outputProcessor, process));

				return new BindedFuture(
					stdOutFuture, stdErrFuture, process);
			}
			catch (RejectedExecutionException ree) {
				process.destroy();

				throw new ProcessException(
					"Cancelled execution because of a concurrent destroy", ree);
			}
		}
		catch (IOException ioe) {
			throw new ProcessException(ioe);
		}
	}

	public static  Future> execute(
			OutputProcessor outputProcessor, String... arguments)
		throws ProcessException {

		return execute(outputProcessor, Arrays.asList(arguments));
	}

	public void destroy() {
		if (_executorService == null) {
			return;
		}

		synchronized (ProcessUtil.class) {
			if (_executorService != null) {
				_executorService.shutdownNow();

				_executorService = null;
			}
		}
	}

	private static ExecutorService _getExecutorService() {
		if (_executorService != null) {
			return _executorService;
		}

		synchronized (ProcessUtil.class) {
			if (_executorService == null) {
				_executorService = Executors.newCachedThreadPool(
					new NamedThreadFactory(
						ProcessUtil.class.getName(), Thread.MIN_PRIORITY,
						PortalClassLoaderUtil.getClassLoader()));
			}
		}

		return _executorService;
	}

	private static volatile ExecutorService _executorService;

	private static class BindedFuture
		implements Future> {

		public BindedFuture(
			Future stdOutFuture, Future stdErrFuture, Process process) {

			_stdOutFuture = stdOutFuture;
			_stdErrFuture = stdErrFuture;
			_process = process;
		}

		@Override
		public boolean cancel(boolean mayInterruptIfRunning) {
			if (_stdOutFuture.isCancelled() || _stdOutFuture.isDone()) {
				return false;
			}

			_stdErrFuture.cancel(true);
			_stdOutFuture.cancel(true);
			_process.destroy();

			return true;
		}

		@Override
		public ObjectValuePair get()
			throws ExecutionException, InterruptedException {

			E stdErrResult = _stdErrFuture.get();
			O stdOutResult = _stdOutFuture.get();

			return new ObjectValuePair(stdOutResult, stdErrResult);
		}

		@Override
		public ObjectValuePair get(long timeout, TimeUnit unit)
			throws ExecutionException, InterruptedException, TimeoutException {

			long startTime = System.currentTimeMillis();

			E stdErrResult = _stdErrFuture.get(timeout, unit);

			long elapseTime = System.currentTimeMillis() - startTime;

			long secondTimeout =
				timeout - unit.convert(elapseTime, TimeUnit.MILLISECONDS);

			O stdOutResult = _stdOutFuture.get(secondTimeout, unit);

			return new ObjectValuePair(stdOutResult, stdErrResult);
		}

		@Override
		public boolean isCancelled() {
			return _stdOutFuture.isCancelled();
		}

		@Override
		public boolean isDone() {
			return _stdOutFuture.isDone();
		}

		private final Future _stdErrFuture;
		private final Future _stdOutFuture;
		private final Process _process;

	}

	private static class ProcessStdErrCallable implements Callable {

		public ProcessStdErrCallable(
			OutputProcessor outputProcessor, Process process) {

			_outputProcessor = outputProcessor;
			_process = process;
		}

		@Override
		public T call() throws Exception {
			return _outputProcessor.processStdErr(_process.getErrorStream());
		}

		private final OutputProcessor _outputProcessor;
		private final Process _process;

	}

	private static class ProcessStdOutCallable implements Callable {

		public ProcessStdOutCallable(
			OutputProcessor outputProcessor, Process process) {

			_outputProcessor = outputProcessor;
			_process = process;
		}

		@Override
		public T call() throws Exception {
			try {
				return _outputProcessor.processStdOut(
					_process.getInputStream());
			}
			finally {
				try {
					int exitCode = _process.waitFor();

					if (exitCode != 0) {
						throw new ProcessException(
							"Subprocess terminated with exit code " + exitCode);
					}
				}
				catch (InterruptedException ie) {
					_process.destroy();

					throw new ProcessException(
						"Forcibly killed subprocess on interruption", ie);
				}
			}
		}

		private final OutputProcessor _outputProcessor;
		private final Process _process;

	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy