001 /* 002 * SonarQube, open source software quality management tool. 003 * Copyright (C) 2008-2014 SonarSource 004 * mailto:contact AT sonarsource DOT com 005 * 006 * SonarQube is free software; you can redistribute it and/or 007 * modify it under the terms of the GNU Lesser General Public 008 * License as published by the Free Software Foundation; either 009 * version 3 of the License, or (at your option) any later version. 010 * 011 * SonarQube is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014 * Lesser General Public License for more details. 015 * 016 * You should have received a copy of the GNU Lesser General Public License 017 * along with this program; if not, write to the Free Software Foundation, 018 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 019 */ 020 package org.sonar.process.monitor; 021 022 import org.apache.commons.lang.StringUtils; 023 import org.slf4j.LoggerFactory; 024 import org.sonar.process.ProcessCommands; 025 import org.sonar.process.ProcessEntryPoint; 026 import org.sonar.process.ProcessUtils; 027 028 import java.io.File; 029 import java.io.FileOutputStream; 030 import java.io.OutputStream; 031 import java.util.ArrayList; 032 import java.util.Arrays; 033 import java.util.List; 034 import java.util.Properties; 035 036 public class JavaProcessLauncher { 037 038 private final Timeouts timeouts; 039 040 public JavaProcessLauncher(Timeouts timeouts) { 041 this.timeouts = timeouts; 042 } 043 044 ProcessRef launch(JavaCommand command) { 045 Process process = null; 046 try { 047 // cleanup existing monitor files 048 ProcessCommands commands = new ProcessCommands(command.getTempDir(), command.getKey()); 049 commands.prepare(); 050 051 ProcessBuilder processBuilder = create(command); 052 LoggerFactory.getLogger(getClass()).info("Launch process[{}]: {}", 053 command.getKey(), StringUtils.join(processBuilder.command(), " ")); 054 process = processBuilder.start(); 055 StreamGobbler inputGobbler = new StreamGobbler(process.getInputStream(), command.getKey()); 056 inputGobbler.start(); 057 058 return new ProcessRef(command.getKey(), commands, process, inputGobbler); 059 060 } catch (Exception e) { 061 // just in case 062 ProcessUtils.sendKillSignal(process); 063 throw new IllegalStateException("Fail to launch " + command.getKey(), e); 064 } 065 } 066 067 private ProcessBuilder create(JavaCommand javaCommand) { 068 List<String> commands = new ArrayList<String>(); 069 commands.add(buildJavaPath()); 070 commands.addAll(javaCommand.getJavaOptions()); 071 // TODO warning - does it work if temp dir contains a whitespace ? 072 commands.add(String.format("-Djava.io.tmpdir=%s", javaCommand.getTempDir().getAbsolutePath())); 073 commands.addAll(buildClasspath(javaCommand)); 074 commands.add(javaCommand.getClassName()); 075 commands.add(buildPropertiesFile(javaCommand).getAbsolutePath()); 076 077 ProcessBuilder processBuilder = new ProcessBuilder(); 078 processBuilder.command(commands); 079 processBuilder.directory(javaCommand.getWorkDir()); 080 processBuilder.environment().putAll(javaCommand.getEnvVariables()); 081 processBuilder.redirectErrorStream(true); 082 return processBuilder; 083 } 084 085 private String buildJavaPath() { 086 String separator = System.getProperty("file.separator"); 087 return new File(new File(System.getProperty("java.home")), 088 "bin" + separator + "java").getAbsolutePath(); 089 } 090 091 private List<String> buildClasspath(JavaCommand javaCommand) { 092 return Arrays.asList("-cp", StringUtils.join(javaCommand.getClasspath(), System.getProperty("path.separator"))); 093 } 094 095 private File buildPropertiesFile(JavaCommand javaCommand) { 096 File propertiesFile = null; 097 try { 098 propertiesFile = File.createTempFile("sq-process", "properties"); 099 Properties props = new Properties(); 100 props.putAll(javaCommand.getArguments()); 101 props.setProperty(ProcessEntryPoint.PROPERTY_PROCESS_KEY, javaCommand.getKey()); 102 props.setProperty(ProcessEntryPoint.PROPERTY_TERMINATION_TIMEOUT, String.valueOf(timeouts.getTerminationTimeout())); 103 props.setProperty(ProcessEntryPoint.PROPERTY_SHARED_PATH, javaCommand.getTempDir().getAbsolutePath()); 104 OutputStream out = new FileOutputStream(propertiesFile); 105 props.store(out, String.format("Temporary properties file for command [%s]", javaCommand.getKey())); 106 out.close(); 107 return propertiesFile; 108 } catch (Exception e) { 109 throw new IllegalStateException("Cannot write temporary settings to " + propertiesFile, e); 110 } 111 } 112 }