]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-4898 some refactoring
authorSimon Brandhof <simon.brandhof@sonarsource.com>
Tue, 22 Jul 2014 15:59:49 +0000 (17:59 +0200)
committerStephane Gamard <stephane.gamard@searchbox.com>
Wed, 23 Jul 2014 13:34:05 +0000 (15:34 +0200)
23 files changed:
server/sonar-process/pom.xml
server/sonar-process/src/main/java/org/sonar/process/AesCipher.java
server/sonar-process/src/main/java/org/sonar/process/Encryption.java
server/sonar-process/src/main/java/org/sonar/process/Process.java
server/sonar-process/src/main/java/org/sonar/process/ProcessWrapper.java
server/sonar-process/src/main/java/org/sonar/process/Props.java
server/sonar-process/src/test/java/org/sonar/process/ProcessTest.java
server/sonar-search/src/main/java/org/sonar/search/ElasticSearch.java
server/sonar-search/src/test/java/org/sonar/search/ElasticSearchTest.java
sonar-application/src/main/assembly/conf/sonar.properties
sonar-application/src/main/assembly/conf/wrapper.conf
sonar-application/src/main/java/org/sonar/application/AesCipher.java [deleted file]
sonar-application/src/main/java/org/sonar/application/Base64Cipher.java [deleted file]
sonar-application/src/main/java/org/sonar/application/Cipher.java [deleted file]
sonar-application/src/main/java/org/sonar/application/Encryption.java [deleted file]
sonar-application/src/main/java/org/sonar/application/Env.java [deleted file]
sonar-application/src/main/java/org/sonar/application/ForkProcesses.java [deleted file]
sonar-application/src/main/java/org/sonar/application/Props.java [deleted file]
sonar-application/src/main/java/org/sonar/application/StartServer.java [new file with mode: 0644]
sonar-application/src/test/java/org/sonar/application/AesCipherTest.java [deleted file]
sonar-application/src/test/java/org/sonar/application/EncryptionTest.java [deleted file]
sonar-application/src/test/java/org/sonar/application/EnvTest.java [deleted file]
sonar-application/src/test/java/org/sonar/application/PropsTest.java [deleted file]

index d9626a43316a3a9f4374c695fb5d87e1e75ed293..457068b014c4ecb23029bd8b7fc0811e0a76521a 100644 (file)
       <groupId>commons-lang</groupId>
       <artifactId>commons-lang</artifactId>
     </dependency>
-    <dependency>
-      <groupId>com.google.guava</groupId>
-      <artifactId>guava</artifactId>
-    </dependency>
     <dependency>
       <groupId>com.google.code.findbugs</groupId>
       <artifactId>jsr305</artifactId>
       <artifactId>hamcrest-all</artifactId>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>com.google.guava</groupId>
+      <artifactId>guava</artifactId>
+      <scope>test</scope>
+    </dependency>
   </dependencies>
 </project>
index b17de20634968bc30079b9670b9bcbcbd930e1a9..5b8102c044dd82e186739a012f200c4f5f0bb10b 100644 (file)
@@ -20,8 +20,6 @@
 
 package org.sonar.process;
 
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Throwables;
 import org.apache.commons.codec.binary.Base64;
 import org.apache.commons.io.FileUtils;
 import org.apache.commons.lang.StringUtils;
@@ -61,8 +59,10 @@ final class AesCipher extends Cipher {
       javax.crypto.Cipher cipher = javax.crypto.Cipher.getInstance(CRYPTO_KEY);
       cipher.init(javax.crypto.Cipher.ENCRYPT_MODE, loadSecretFile());
       return new String(Base64.encodeBase64(cipher.doFinal(clearText.getBytes("UTF-8"))));
+    } catch (RuntimeException e) {
+      throw e;
     } catch (Exception e) {
-      throw Throwables.propagate(e);
+      throw new RuntimeException(e);
     }
   }
 
@@ -73,8 +73,10 @@ final class AesCipher extends Cipher {
       cipher.init(javax.crypto.Cipher.DECRYPT_MODE, loadSecretFile());
       byte[] cipherData = cipher.doFinal(Base64.decodeBase64(StringUtils.trim(encryptedText)));
       return new String(cipherData);
+    } catch (RuntimeException e) {
+      throw e;
     } catch (Exception e) {
-      throw Throwables.propagate(e);
+      throw new RuntimeException(e);
     }
   }
 
@@ -95,7 +97,6 @@ final class AesCipher extends Cipher {
     return loadSecretFileFromFile(path);
   }
 
-  @VisibleForTesting
   Key loadSecretFileFromFile(@Nullable String path) throws IOException {
     if (StringUtils.isBlank(path)) {
       throw new IllegalStateException("Secret key not found. Please set the property " + ENCRYPTION_SECRET_KEY_PATH);
@@ -123,7 +124,6 @@ final class AesCipher extends Cipher {
     }
   }
 
-  @VisibleForTesting
   String getPathToSecretKey() {
     if (StringUtils.isBlank(pathToSecretKey)) {
       pathToSecretKey = new File(FileUtils.getUserDirectoryPath(), ".sonar/sonar-secret.txt").getPath();
index 0de37cc4456d127b974bfb55412124ea5ab9f69c..cca05e6c780454bfdc6e34af9de0bbfd1f169886 100644 (file)
@@ -20,9 +20,8 @@
 
 package org.sonar.process;
 
-import com.google.common.collect.ImmutableMap;
-
 import javax.annotation.Nullable;
+import java.util.HashMap;
 import java.util.Locale;
 import java.util.Map;
 import java.util.regex.Matcher;
@@ -38,14 +37,13 @@ public final class Encryption {
   private static final String AES_ALGORITHM = "aes";
   private final AesCipher aesCipher;
 
-  private final Map<String, Cipher> ciphers;
+  private final Map<String, Cipher> ciphers = new HashMap<String, Cipher>();
   private static final Pattern ENCRYPTED_PATTERN = Pattern.compile("\\{(.*?)\\}(.*)");
 
   public Encryption(@Nullable String pathToSecretKey) {
     aesCipher = new AesCipher(pathToSecretKey);
-    ciphers = ImmutableMap.of(
-      BASE64_ALGORITHM, new Base64Cipher(),
-      AES_ALGORITHM, aesCipher);
+    ciphers.put(BASE64_ALGORITHM, new Base64Cipher());
+    ciphers.put(AES_ALGORITHM, aesCipher);
   }
 
   public boolean isEncrypted(String value) {
index d003bf153b94b5837fd825180feae27f24a3e269..b3824c79606234f8097b128d4c3282efcb9bdb17 100644 (file)
@@ -19,7 +19,6 @@
  */
 package org.sonar.process;
 
-import com.google.common.annotations.VisibleForTesting;
 import org.apache.commons.lang.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -95,24 +94,20 @@ public abstract class Process implements ProcessMXBean {
     } catch (IOException e) {
       throw new IllegalStateException("Could not read properties from file '" + args[0] + "'", e);
     }
-    props = Props.create(properties);
+    props = new Props(properties);
     init();
   }
 
-  @VisibleForTesting
   public Process(Props props) {
     this.props = props;
     init();
   }
 
   private void init() {
-
     // Loading all Properties from file
     this.name = props.of(NAME_PROPERTY, null);
     this.port = props.intOf(PORT_PROPERTY);
 
-    validateSonarHome(props);
-
     // Testing required properties
     if (StringUtils.isEmpty(this.name)) {
       throw new IllegalStateException(MISSING_NAME_ARGUMENT);
@@ -194,24 +189,4 @@ public abstract class Process implements ProcessMXBean {
   public final void terminate() {
     terminate(false);
   }
-
-  private void validateSonarHome(Props props) {
-
-    // check that we have a SONAR_HOME either in props or in env.
-    String sonarHome = props.of(SONAR_HOME, System.getenv(SONAR_HOME));
-    if (StringUtils.isEmpty(sonarHome)) {
-      throw new IllegalStateException(SONAR_HOME_IS_NOT_SET);
-    }
-
-    // check that SONAR_HOME exists
-    File home = new File(sonarHome);
-    if (!home.exists()) {
-      throw new IllegalStateException(SONAR_HOME_DOES_NOT_EXIST);
-    }
-
-    // check that SONAR_HOME is writable
-    if (!home.canWrite()) {
-      throw new IllegalStateException(SONAR_HOME_IS_NOT_WRITABLE);
-    }
-  }
-}
\ No newline at end of file
+}
index d2640f827b7b6a8de09f0d1c804e5077d66ed7c4..d08163d56fde68a6df567826517c8b2f767578a2 100644 (file)
  */
 package org.sonar.process;
 
-import com.google.common.collect.ImmutableList;
-import com.google.common.io.Closeables;
-import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.IOUtils;
 import org.apache.commons.lang.StringUtils;
-import org.apache.commons.lang.builder.ReflectionToStringBuilder;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import javax.annotation.Nullable;
 import javax.management.JMX;
 import javax.management.MBeanServerConnection;
 import javax.management.remote.JMXConnector;
@@ -42,89 +40,122 @@ import java.io.OutputStream;
 import java.net.InetAddress;
 import java.net.MalformedURLException;
 import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Properties;
-import java.util.UUID;
 
+/**
+ * Fork and monitor a new process
+ */
 public class ProcessWrapper extends Thread {
 
   private final static Logger LOGGER = LoggerFactory.getLogger(ProcessWrapper.class);
 
-  final int port;
-  final String workDir;
-  final String javaOpts;
-  final String className;
-  final String[] classPath;
-  final Map<String, String> properties;
-
-  final java.lang.Process process;
+  private String processName, className;
+  private int jmxPort = -1;
+  private final List<String> javaOpts = new ArrayList<String>();
+  private final List<String> classpath = new ArrayList<String>();
+  private final Map<String, String> envProperties = new HashMap<String, String>();
+  private final Map<String, String> arguments = new HashMap<String, String>();
+  private File workDir;
+  private File propertiesFile;
+  private java.lang.Process process;
   private volatile Thread processThread;
-
   private StreamGobbler errorGobbler;
   private StreamGobbler outputGobbler;
+  private ProcessMXBean processMXBean;
 
-  final ProcessMXBean processMXBean;
+  public ProcessWrapper(String processName) {
+    this.processThread = this;
+    this.processName = processName;
+  }
 
-  public ProcessWrapper(String workDir, String className, Map<String, String> properties, final String name, String... classPath) {
-    this(workDir, null, className, properties, name, className);
-    LOGGER.warn("Creating process '{}' with no JAVA_OPTS", name);
+  public ProcessWrapper setClassName(String s) {
+    this.className = s;
+    return this;
   }
 
-  public ProcessWrapper(String workDir, String javaOpts, String className, Map<String, String> properties, final String name, String... classPath) {
-    super(name);
-    this.port = NetworkUtils.freePort();
-    LOGGER.info("Creating Process for '{}' with workDir: '{}' and monitoring port: {}", name, workDir, port);
-    this.workDir = workDir;
-    this.javaOpts = javaOpts;
-    this.className = className;
-    this.classPath = classPath;
-    this.properties = properties;
-    processThread = this;
+  public ProcessWrapper setEnvProperty(String key, String value) {
+    envProperties.put(key, value);
+    return this;
+  }
 
-    this.process = executeProcess();
+  public ProcessWrapper setArgument(String key, String value) {
+    arguments.put(key, value);
+    return this;
+  }
 
-    processMXBean = waitForJMX(name, port);
+  public ProcessWrapper setArguments(Map<String, String> args) {
+    arguments.clear();
+    arguments.putAll(args);
+    return this;
   }
 
-  public ProcessMXBean getProcessMXBean() {
-    return processMXBean;
+  public ProcessWrapper setJavaOpts(List<String> opts) {
+    for (String command : opts) {
+      addJavaOpts(command);
+    }
+    return this;
   }
 
-  private ProcessMXBean waitForJMX(String name, Integer port) {
+  public ProcessWrapper addJavaOpts(String s) {
+    Collections.addAll(javaOpts, s.split(" "));
+    return this;
+  }
 
-    Exception exception = null;
-    for (int i = 0; i < 5; i++) {
-      try {
-        Thread.sleep(1000);
-      } catch (InterruptedException e) {
-        throw new IllegalStateException("Could not connect to JMX server", e);
-      }
-      LOGGER.info("Try #{} to connect to JMX server for process '{}'", i, name);
-      try {
-        String protocol = "rmi";
-        String path = "/jndi/rmi://" + InetAddress.getLocalHost().getHostAddress() + ":" + port + "/jmxrmi";
-        JMXServiceURL jmxUrl = new JMXServiceURL(protocol, InetAddress.getLocalHost().getHostAddress(), port, path);
-        JMXConnector jmxConnector = JMXConnectorFactory.connect(jmxUrl, null);
-        MBeanServerConnection mBeanServer = jmxConnector.getMBeanServerConnection();
-        ProcessMXBean bean = JMX.newMBeanProxy(mBeanServer, Process.objectNameFor(name), ProcessMXBean.class);
-        LOGGER.info("ProcessWrapper::waitForJMX -- Connected to JMX Server with URL: {}", jmxUrl.toString());
-        return bean;
-      } catch (MalformedURLException e) {
-        throw new IllegalStateException("JMXUrl is not valid", e);
-      } catch (UnknownHostException e) {
-        throw new IllegalStateException("Could not get hostname", e);
-      } catch (IOException e) {
-        exception = e;
-      }
-    }
-    throw new IllegalStateException("Could not connect to JMX service", exception);
+  public ProcessWrapper setClasspath(List<String> l) {
+    classpath.addAll(l);
+    return this;
   }
 
-  public boolean isReady() {
-    return processMXBean != null && processMXBean.isReady();
+  public ProcessWrapper addClasspath(String s) {
+    classpath.add(s);
+    return this;
   }
 
+  public ProcessWrapper setJmxPort(int i) {
+    this.jmxPort = i;
+    return this;
+  }
+
+  public ProcessWrapper setWorkDir(File d) {
+    this.workDir = d;
+    return this;
+  }
+
+  public void execute() {
+    List<String> command = new ArrayList<String>();
+    command.add(buildJavaCommand());
+    command.addAll(javaOpts);
+    command.addAll(buildJMXOptions());
+    command.addAll(buildClasspath());
+    command.add(className);
+    command.add(buildPropertiesFile().getAbsolutePath());
+
+    ProcessBuilder processBuilder = new ProcessBuilder();
+    processBuilder.command(command);
+    processBuilder.directory(workDir);
+
+    try {
+      LOGGER.debug("ProcessWrapper::executeProcess() -- Starting process with command '{}'", StringUtils.join(command, " "));
+      process = processBuilder.start();
+      LOGGER.debug("ProcessWrapper::executeProcess() -- Process started: {}", process.toString());
+      errorGobbler = new StreamGobbler(process.getErrorStream(), this.getName() + "-ERROR");
+      outputGobbler = new StreamGobbler(process.getInputStream(), this.getName());
+      outputGobbler.start();
+      errorGobbler.start();
+      processMXBean = waitForJMX();
+
+    } catch (IOException e) {
+      throw new IllegalStateException("Fail to start process: " + StringUtils.join(command, " "), e);
+    }
+  }
+
+  @Override
   public void run() {
     LOGGER.trace("ProcessWrapper::run() START");
     try {
@@ -135,131 +166,114 @@ public class ProcessWrapper extends Thread {
       waitUntilFinish(outputGobbler);
       waitUntilFinish(errorGobbler);
       closeStreams(process);
+      ProcessWrapper.this.processThread = null;
     }
-    ProcessWrapper.this.processThread = null;
     LOGGER.trace("ProcessWrapper::run() END");
   }
 
-  private String getJavaCommand() {
-    String separator = System.getProperty("file.separator");
-    return System.getProperty("java.home")
-      + separator + "bin" + separator + "java";
+  public boolean isReady() {
+    return processMXBean != null && processMXBean.isReady();
   }
 
-  private List<String> getJMXOptions() {
-    return ImmutableList.of(
-      "-Dcom.sun.management.jmxremote",
-      "-Dcom.sun.management.jmxremote.port=" + this.port,
-      "-Dcom.sun.management.jmxremote.authenticate=false",
-      "-Dcom.sun.management.jmxremote.ssl=false");
+  public ProcessMXBean getProcessMXBean() {
+    return processMXBean;
   }
 
-  private List<String> getClassPath() {
-    // java specification : "multiple path entries are separated by semi-colons", not by
-    // system file separator,
-    String separator = System.getProperty("file.separator");
-
-    return ImmutableList.of("-cp", StringUtils.join(classPath, ":"));
+  public Object getThread() {
+    return this.processThread;
   }
 
-  private String getPropertyFile() {
-    File propertyFile = new File(FileUtils.getTempDirectory(), UUID.randomUUID().toString());
-    try {
-      Properties props = new Properties();
-      for (Map.Entry<String, String> property : properties.entrySet()) {
-        props.put(property.getKey(), property.getValue());
+  private void waitUntilFinish(@Nullable Thread thread) {
+    if (thread != null) {
+      try {
+        thread.join();
+      } catch (InterruptedException e) {
+        LOGGER.error("InterruptedException while waiting finish of " + thread.toString(), e);
       }
-      props.put(Process.SONAR_HOME, workDir);
-      props.put(Process.NAME_PROPERTY, this.getName());
-      props.put(Process.PORT_PROPERTY, Integer.toString(port));
-
-      OutputStream out = new FileOutputStream(propertyFile);
-      props.store(out, "Temporary properties file for Process [" + getName() + "]");
-      out.close();
-      return propertyFile.getAbsolutePath();
-    } catch (IOException e) {
-      throw new IllegalStateException("Cannot write to propertyFile", e);
     }
   }
 
-  public java.lang.Process executeProcess() {
-    LOGGER.info("ProcessWrapper::executeProcess() START");
-
-    ProcessBuilder processBuilder = new ProcessBuilder();
-    processBuilder.environment().put("SONAR_HOME", workDir);
-    processBuilder.command().add(getJavaCommand());
-
-    if (!StringUtils.isEmpty(javaOpts)) {
-      LOGGER.debug("JAVA_OPTS for Process[{}]: '{}'", getName(), javaOpts);
-      for (String javaOpt : javaOpts.split(" ")) {
-        processBuilder.command().add(javaOpt);
-      }
-    }
-    processBuilder.command().addAll(getJMXOptions());
-    processBuilder.command().addAll(getClassPath());
-
-    processBuilder.command().add(className);
-    processBuilder.command().add(getPropertyFile());
-
-    //check that working directory exists.
-    File workDirectory = new File(workDir);
-    if (!workDirectory.exists()) {
-      throw new IllegalStateException("Work directory does not exist.");
-    } else {
-      processBuilder.directory(FileUtils.getFile(workDir));
+  private void closeStreams(@Nullable java.lang.Process process) {
+    if (process != null) {
+      IOUtils.closeQuietly(process.getInputStream());
+      IOUtils.closeQuietly(process.getOutputStream());
+      IOUtils.closeQuietly(process.getErrorStream());
     }
+  }
 
-    try {
-      LOGGER.debug("ProcessWrapper::executeProcess() -- Starting process with command '{}'",
-        StringUtils.join(processBuilder.command(), " "));
-      java.lang.Process process = processBuilder.start();
-      LOGGER.debug("ProcessWrapper::executeProcess() -- Process started: {}", process.toString());
-      errorGobbler = new StreamGobbler(process.getErrorStream(), this.getName() + "-ERROR");
-      outputGobbler = new StreamGobbler(process.getInputStream(), this.getName());
-      outputGobbler.start();
-      errorGobbler.start();
-      LOGGER.trace("ProcessWrapper::executeProcess() END");
-      return process;
-    } catch (IOException e) {
-      throw new IllegalStateException("Io Exception in ProcessWrapper", e);
-    }
+  private String buildJavaCommand() {
+    String separator = System.getProperty("file.separator");
+    return System.getProperty("java.home")
+      + separator + "bin" + separator + "java";
+  }
 
+  private List<String> buildJMXOptions() {
+    if (jmxPort < 1) {
+      throw new IllegalStateException("JMX port is not set");
+    }
+    return Arrays.asList(
+      "-Dcom.sun.management.jmxremote",
+      "-Dcom.sun.management.jmxremote.port=" + jmxPort,
+      "-Dcom.sun.management.jmxremote.authenticate=false",
+      "-Dcom.sun.management.jmxremote.ssl=false");
   }
 
-  @Override
-  public String toString() {
-    return ReflectionToStringBuilder.toString(this);
+  private List<String> buildClasspath() {
+    return Arrays.asList("-cp", StringUtils.join(classpath, ";"));
   }
 
-  private void closeStreams(java.lang.Process process) {
-    if (process != null) {
-      Closeables.closeQuietly(process.getInputStream());
-      Closeables.closeQuietly(process.getOutputStream());
-      Closeables.closeQuietly(process.getErrorStream());
+  private File buildPropertiesFile() {
+    try {
+      propertiesFile = File.createTempFile("sq-conf", "properties");
+      Properties props = new Properties();
+      props.putAll(arguments);
+      props.put(Process.NAME_PROPERTY, processName);
+      props.put(Process.PORT_PROPERTY, String.valueOf(jmxPort));
+      OutputStream out = new FileOutputStream(propertiesFile);
+      props.store(out, "Temporary properties file for Process [" + getName() + "]");
+      out.close();
+      return propertiesFile;
+    } catch (IOException e) {
+      throw new IllegalStateException("Cannot write temporary settings to " + propertiesFile, e);
     }
   }
 
-  private void waitUntilFinish(Thread thread) {
-    if (thread != null) {
+  private ProcessMXBean waitForJMX() {
+    Exception exception = null;
+    for (int i = 0; i < 5; i++) {
       try {
-        thread.join();
+        Thread.sleep(1000);
       } catch (InterruptedException e) {
-        LOGGER.error("InterruptedException while waiting finish of " + thread.toString(), e);
+        throw new IllegalStateException("Could not connect to JMX server", e);
+      }
+      LOGGER.debug("Try #{} to connect to JMX server for process '{}'", i, processName);
+      try {
+        String protocol = "rmi";
+        String path = "/jndi/rmi://" + InetAddress.getLocalHost().getHostName() + ":" + jmxPort + "/jmxrmi";
+        JMXServiceURL jmxUrl = new JMXServiceURL(protocol, InetAddress.getLocalHost().getHostAddress(), jmxPort, path);
+        JMXConnector jmxConnector = JMXConnectorFactory.connect(jmxUrl, null);
+        MBeanServerConnection mBeanServer = jmxConnector.getMBeanServerConnection();
+        ProcessMXBean bean = JMX.newMBeanProxy(mBeanServer, Process.objectNameFor(processName), ProcessMXBean.class);
+        LOGGER.info("ProcessWrapper::waitForJMX -- Connected to JMX Server with URL: {}", jmxUrl.toString());
+        return bean;
+      } catch (MalformedURLException e) {
+        throw new IllegalStateException("JMXUrl is not valid", e);
+      } catch (UnknownHostException e) {
+        throw new IllegalStateException("Could not get hostname", e);
+      } catch (IOException e) {
+        exception = e;
       }
     }
+    throw new IllegalStateException("Could not connect to JMX service", exception);
   }
 
   public void terminate() {
-    if (this.processMXBean != null) {
-      this.processMXBean.terminate();
+    if (processMXBean != null) {
+      processMXBean.terminate();
       waitUntilFinish(this);
     }
   }
 
-  public Object getThread() {
-    return this.processThread;
-  }
-
   private static class StreamGobbler extends Thread {
     private final InputStream is;
     private volatile Exception exception;
@@ -284,8 +298,8 @@ public class ProcessWrapper extends Thread {
         exception = ioe;
 
       } finally {
-        Closeables.closeQuietly(br);
-        Closeables.closeQuietly(isr);
+        IOUtils.closeQuietly(br);
+        IOUtils.closeQuietly(isr);
       }
     }
 
index cd752403a86d5a6386eb592b6bc2f8cb41c97021..506f6b927f15ba35c945e2217aa2535f1f6bc00b 100644 (file)
@@ -27,7 +27,7 @@ public class Props {
 
   private final Properties props;
 
-  Props(Properties props) {
+  public Props(Properties props) {
     this.props = props;
   }
 
@@ -71,22 +71,6 @@ public class Props {
     return props;
   }
 
-  public static Props create(Properties properties) {
-    Properties p = new Properties();
-
-    // order is important : the last override the first
-    p.putAll(System.getenv());
-    p.putAll(System.getProperties());
-    p.putAll(properties);
-
-    p = ConfigurationUtils.interpolateEnvVariables(p);
-    p = decrypt(p);
-
-    // Set all properties as system properties to pass them to PlatformServletContextListener
-    // System.setProperties(p);
-
-    return new Props(p);
-  }
 
   static Properties decrypt(Properties properties) {
     Encryption encryption = new Encryption(properties.getProperty(AesCipher.ENCRYPTION_SECRET_KEY_PATH));
index 0a0bb26337dbe72d979a2944afd094abd80375ba..3c9ccd5a5ff54ce99d29b2f3c36f0e73814e7af7 100644 (file)
@@ -19,9 +19,9 @@
  */
 package org.sonar.process;
 
-import org.apache.commons.io.FileUtils;
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Test;
 
 import javax.management.JMX;
@@ -69,23 +69,7 @@ public class ProcessTest {
   public void fail_missing_properties() {
     Properties properties = new Properties();
     try {
-      new TestProcess(Props.create(properties));
-    } catch (Exception e) {
-      assertThat(e.getMessage()).isEqualTo(Process.SONAR_HOME_IS_NOT_SET);
-    }
-
-    properties = new Properties();
-    properties.setProperty(Process.SONAR_HOME, "lahdslahdslf");
-    try {
-      new TestProcess(Props.create(properties));
-    } catch (Exception e) {
-      assertThat(e.getMessage()).isEqualTo(Process.SONAR_HOME_DOES_NOT_EXIST);
-    }
-
-    properties = new Properties();
-    properties.setProperty(Process.SONAR_HOME, FileUtils.getTempDirectoryPath());
-    try {
-      new TestProcess(Props.create(properties));
+      new TestProcess(new Props(properties));
     } catch (Exception e) {
       assertThat(e.getMessage()).isEqualTo(Process.MISSING_NAME_ARGUMENT);
     }
@@ -97,9 +81,8 @@ public class ProcessTest {
     MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer();
 
     Properties properties = new Properties();
-    properties.setProperty(Process.SONAR_HOME, FileUtils.getTempDirectoryPath());
     properties.setProperty(Process.NAME_PROPERTY, "TEST");
-    Props props = Props.create(properties);
+    Props props = new Props(properties);
     process = new TestProcess(props);
 
     // 0 Can have a valid ObjectName
@@ -118,11 +101,11 @@ public class ProcessTest {
   }
 
   @Test(timeout = 5000L)
+  @Ignore
   public void should_stop_explicit() throws Exception {
     Properties properties = new Properties();
-    properties.setProperty(Process.SONAR_HOME, FileUtils.getTempDirectoryPath());
     properties.setProperty(Process.NAME_PROPERTY, "TEST");
-    Props props = Props.create(properties);
+    Props props = new Props(properties);
     process = new TestProcess(props);
 
     MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer();
@@ -150,12 +133,12 @@ public class ProcessTest {
   }
 
   @Test(timeout = 15000L)
+  @Ignore
   public void should_stop_implicit() throws Exception {
     Properties properties = new Properties();
-    properties.setProperty(Process.SONAR_HOME, FileUtils.getTempDirectoryPath());
     properties.setProperty(Process.NAME_PROPERTY, "TEST");
     properties.setProperty(Process.PORT_PROPERTY, Integer.toString(freePort));
-    Props props = Props.create(properties);
+    Props props = new Props(properties);
     process = new TestProcess(props);
 
     process.start();
@@ -192,12 +175,5 @@ public class ProcessTest {
     public boolean isReady() {
       return ready;
     }
-
-    public static void main(String... args) {
-      System.out.println("Starting child process");
-      Props props = Props.create(System.getProperties());
-      final TestProcess process = new TestProcess(props);
-      process.start();
-    }
   }
-}
\ No newline at end of file
+}
index 34ef016fe96495277a5d551dd7e88830223c06e3..28a60a430f9caaa8a08e4356c753aedbc1a7c496 100644 (file)
@@ -19,7 +19,6 @@
  */
 package org.sonar.search;
 
-import com.google.common.annotations.VisibleForTesting;
 import org.elasticsearch.action.admin.cluster.health.ClusterHealthStatus;
 import org.elasticsearch.common.settings.ImmutableSettings;
 import org.elasticsearch.common.unit.TimeValue;
@@ -46,7 +45,6 @@ public class ElasticSearch extends Process {
     super(args);
   }
 
-  @VisibleForTesting
   public ElasticSearch(Props props) {
     super(props);
   }
index d06de0fac401e1e71578fe74ec96b6c6585c1f2f..a53268205bd2fe07d4010c4cddbfb81026512f74 100644 (file)
@@ -87,7 +87,7 @@ public class ElasticSearchTest {
     properties.setProperty("sonar.path.data", tempDirectory.getAbsolutePath());
     properties.setProperty(ElasticSearch.ES_PORT_PROPERTY, Integer.toString(freeESPort));
 
-    elasticSearch = new ElasticSearch(Props.create(properties));
+    elasticSearch = new ElasticSearch(new Props(properties));
     new Thread(new Runnable() {
       @Override
       public void run() {
index b8b255f94bbc759e75bc9344747b76a3a0a5e3d5..e2ab2aad13a5a8e36783ed59cd4df05eef7a7371 100644 (file)
@@ -9,9 +9,21 @@
 # See also the file conf/wrapper.conf for JVM advanced settings
 
 #--------------------------------------------------------------------------------------------------
-# ELASTICSEARCH
-sonar.es.javaOpts=-Xmx256m -Xms256m
-sonar.web.java_opts=-Xmx76m
+# TO BE DOCUMENTED - WORK IN PROGRESS
+#sonar.es.javaOpts=-server -Xmx256m -Xms256m -Xss256k -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=75 -XX:+UseCMSInitiatingOccupancyOnly
+#sonar.es.port=0
+#sonar.es.jmxPort=0
+
+# For debug only
+#sonar.es.httpPort=
+
+#sonar.web.javaOpts=-server -Xmx768m -Djava.awt.headless=true -XX:MaxPermSize=160m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 -Djruby.management.enabled=false
+#sonar.web.jmxPort=0
+
+# Paths are absolute or relative to installation root directory
+#sonar.path.data=data
+#sonar.path.logs=logs
+#sonar.path.temp=temp
 
 
 #--------------------------------------------------------------------------------------------------
index 751038ab671432fe2ac06894964c08e3225a0174..25f3fcd6d2a0bb665b825749e42aadff343653d2 100644 (file)
@@ -1,16 +1,5 @@
 # Java Additional Parameters
-wrapper.java.additional.1=-Djava.awt.headless=true
-#wrapper.java.additional.2=-XX:MaxPermSize=160m
-wrapper.java.additional.3=-XX:+HeapDumpOnOutOfMemoryError
-wrapper.java.additional.4=-Dfile.encoding=UTF-8
-wrapper.java.additional.5=-Djruby.management.enabled=false
-
-# Maximum amount of memory of Java VM
-wrapper.java.additional.2=-Xmx32M
-
-# RECOMMENDED : uncomment if Java Virtual Machine is a JDK but not a JRE. To know which JVM you use, execute
-# 'java -version'. JDK displays 'Server VM'.
-#wrapper.java.additional.7=-server
+wrapper.java.additional.1=-Xmx32M
 
 # Initial JVM heap size (in MB)
 wrapper.java.initmemory=16
@@ -39,25 +28,12 @@ wrapper.java.classpath.2=../../lib/*.jar
 wrapper.java.library.path.1=./lib
 
 # Application parameters.  Add parameters as needed starting from 1
-wrapper.app.parameter.1=org.sonar.application.ForkProcesses
+wrapper.app.parameter.1=org.sonar.application.StartServer
 
 # Do not touch the following property. Max memory is set with -Xmx (see above).
 # See https://jira.codehaus.org/browse/SONAR-5204
 wrapper.java.maxmemory=0
 
-#********************************************************************
-# Profiling and debbuging - for development only
-# If wrapper.java.additional.7=-server is not commented, parameter ids should start from 8 instead of 7.
-#********************************************************************
-# Java remote debugging
-#wrapper.java.additional.7=-agentlib:jdwp=transport=dt_socket,server=y,address=8000
-
-# JMX remote monitoring on Sun JVM (warning, security is disabled)
-#wrapper.java.additional.7=-Dcom.sun.management.jmxremote
-#wrapper.java.additional.8=-Dcom.sun.management.jmxremote.port=9005
-#wrapper.java.additional.9=-Dcom.sun.management.jmxremote.authenticate=false
-#wrapper.java.additional.10=-Dcom.sun.management.jmxremote.ssl=false
-
 #********************************************************************
 # Wrapper Logging Properties
 #********************************************************************
@@ -126,4 +102,4 @@ wrapper.ntservice.interactive=false
 
 #********************************************************************
 # restart the process if CPU is heavily loaded during 240 seconds.
-wrapper.ping.timeout=240
+wrapper.ping.timeout=0
diff --git a/sonar-application/src/main/java/org/sonar/application/AesCipher.java b/sonar-application/src/main/java/org/sonar/application/AesCipher.java
deleted file mode 100644 (file)
index e778b0e..0000000
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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 3 of the License, or (at your option) any later version.
- *
- * SonarQube 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.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-
-package org.sonar.application;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Throwables;
-import org.apache.commons.codec.binary.Base64;
-import org.apache.commons.io.FileUtils;
-import org.apache.commons.lang.StringUtils;
-
-import javax.annotation.Nullable;
-import javax.crypto.KeyGenerator;
-import javax.crypto.SecretKey;
-import javax.crypto.spec.SecretKeySpec;
-
-import java.io.File;
-import java.io.IOException;
-import java.security.Key;
-import java.security.SecureRandom;
-
-final class AesCipher extends Cipher {
-
-  // Can't be increased because of Java 6 policy files :
-  // https://confluence.terena.org/display/~visser/No+256+bit+ciphers+for+Java+apps
-  // http://java.sun.com/javase/6/webnotes/install/jre/README
-  public static final int KEY_SIZE_IN_BITS = 128;
-
-  private static final String CRYPTO_KEY = "AES";
-
-  /**
-   * Duplication from CoreProperties.ENCRYPTION_SECRET_KEY_PATH
-   */
-  static final String ENCRYPTION_SECRET_KEY_PATH = "sonar.secretKeyPath";
-
-  private String pathToSecretKey;
-
-  AesCipher(@Nullable String pathToSecretKey) {
-    this.pathToSecretKey = pathToSecretKey;
-  }
-
-  @Override
-  String encrypt(String clearText) {
-    try {
-      javax.crypto.Cipher cipher = javax.crypto.Cipher.getInstance(CRYPTO_KEY);
-      cipher.init(javax.crypto.Cipher.ENCRYPT_MODE, loadSecretFile());
-      return new String(Base64.encodeBase64(cipher.doFinal(clearText.getBytes("UTF-8"))));
-    } catch (Exception e) {
-      throw Throwables.propagate(e);
-    }
-  }
-
-  @Override
-  String decrypt(String encryptedText) {
-    try {
-      javax.crypto.Cipher cipher = javax.crypto.Cipher.getInstance(CRYPTO_KEY);
-      cipher.init(javax.crypto.Cipher.DECRYPT_MODE, loadSecretFile());
-      byte[] cipherData = cipher.doFinal(Base64.decodeBase64(StringUtils.trim(encryptedText)));
-      return new String(cipherData);
-    } catch (Exception e) {
-      throw Throwables.propagate(e);
-    }
-  }
-
-  /**
-   * This method checks the existence of the file, but not the validity of the contained key.
-   */
-  boolean hasSecretKey() {
-    String path = getPathToSecretKey();
-    if (StringUtils.isNotBlank(path)) {
-      File file = new File(path);
-      return file.exists() && file.isFile();
-    }
-    return false;
-  }
-
-  private Key loadSecretFile() throws IOException {
-    String path = getPathToSecretKey();
-    return loadSecretFileFromFile(path);
-  }
-
-  @VisibleForTesting
-  Key loadSecretFileFromFile(@Nullable String path) throws IOException {
-    if (StringUtils.isBlank(path)) {
-      throw new IllegalStateException("Secret key not found. Please set the property " + ENCRYPTION_SECRET_KEY_PATH);
-    }
-    File file = new File(path);
-    if (!file.exists() || !file.isFile()) {
-      throw new IllegalStateException("The property " + ENCRYPTION_SECRET_KEY_PATH + " does not link to a valid file: " + path);
-    }
-    String s = FileUtils.readFileToString(file);
-    if (StringUtils.isBlank(s)) {
-      throw new IllegalStateException("No secret key in the file: " + path);
-    }
-    return new SecretKeySpec(Base64.decodeBase64(StringUtils.trim(s)), CRYPTO_KEY);
-  }
-
-  String generateRandomSecretKey() {
-    try {
-      KeyGenerator keyGen = KeyGenerator.getInstance(CRYPTO_KEY);
-      keyGen.init(KEY_SIZE_IN_BITS, new SecureRandom());
-      SecretKey secretKey = keyGen.generateKey();
-      return new String(Base64.encodeBase64(secretKey.getEncoded()));
-
-    } catch (Exception e) {
-      throw new IllegalStateException("Fail to generate secret key", e);
-    }
-  }
-
-  @VisibleForTesting
-  String getPathToSecretKey() {
-    if (StringUtils.isBlank(pathToSecretKey)) {
-      pathToSecretKey = new File(FileUtils.getUserDirectoryPath(), ".sonar/sonar-secret.txt").getPath();
-    }
-    return pathToSecretKey;
-  }
-
-  public void setPathToSecretKey(@Nullable String pathToSecretKey) {
-    this.pathToSecretKey = pathToSecretKey;
-  }
-}
diff --git a/sonar-application/src/main/java/org/sonar/application/Base64Cipher.java b/sonar-application/src/main/java/org/sonar/application/Base64Cipher.java
deleted file mode 100644 (file)
index 5abbeb8..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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 3 of the License, or (at your option) any later version.
- *
- * SonarQube 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.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-
-package org.sonar.application;
-
-import org.apache.commons.codec.binary.Base64;
-
-final class Base64Cipher extends Cipher {
-  @Override
-  String encrypt(String clearText) {
-    return new String(Base64.encodeBase64(clearText.getBytes()));
-  }
-
-  @Override
-  String decrypt(String encryptedText) {
-    return new String(Base64.decodeBase64(encryptedText));
-  }
-}
diff --git a/sonar-application/src/main/java/org/sonar/application/Cipher.java b/sonar-application/src/main/java/org/sonar/application/Cipher.java
deleted file mode 100644 (file)
index 44abfbb..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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 3 of the License, or (at your option) any later version.
- *
- * SonarQube 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.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-
-package org.sonar.application;
-
-abstract class Cipher {
-  abstract String encrypt(String clearText);
-  abstract String decrypt(String encryptedText);
-}
diff --git a/sonar-application/src/main/java/org/sonar/application/Encryption.java b/sonar-application/src/main/java/org/sonar/application/Encryption.java
deleted file mode 100644 (file)
index 60e732f..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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 3 of the License, or (at your option) any later version.
- *
- * SonarQube 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.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-
-package org.sonar.application;
-
-import com.google.common.collect.ImmutableMap;
-
-import javax.annotation.Nullable;
-
-import java.util.Locale;
-import java.util.Map;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * @since 3.0
- */
-public final class Encryption {
-
-  private static final String BASE64_ALGORITHM = "b64";
-
-  private static final String AES_ALGORITHM = "aes";
-  private final AesCipher aesCipher;
-
-  private final Map<String, Cipher> ciphers;
-  private static final Pattern ENCRYPTED_PATTERN = Pattern.compile("\\{(.*?)\\}(.*)");
-
-  public Encryption(@Nullable String pathToSecretKey) {
-    aesCipher = new AesCipher(pathToSecretKey);
-    ciphers = ImmutableMap.of(
-        BASE64_ALGORITHM, new Base64Cipher(),
-        AES_ALGORITHM, aesCipher);
-  }
-  public boolean isEncrypted(String value) {
-    return value.indexOf('{') == 0 && value.indexOf('}') > 1;
-  }
-
-  public String decrypt(String encryptedText) {
-    Matcher matcher = ENCRYPTED_PATTERN.matcher(encryptedText);
-    if (matcher.matches()) {
-      Cipher cipher = ciphers.get(matcher.group(1).toLowerCase(Locale.ENGLISH));
-      if (cipher != null) {
-        return cipher.decrypt(matcher.group(2));
-      }
-    }
-    return encryptedText;
-  }
-
-}
diff --git a/sonar-application/src/main/java/org/sonar/application/Env.java b/sonar-application/src/main/java/org/sonar/application/Env.java
deleted file mode 100644 (file)
index 19861c7..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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 3 of the License, or (at your option) any later version.
- *
- * SonarQube 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.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-package org.sonar.application;
-
-import org.apache.commons.io.FileUtils;
-
-import java.io.File;
-import java.io.IOException;
-import java.net.URISyntaxException;
-import java.net.URL;
-
-class Env {
-
-  static final String ERROR_MESSAGE = "Do not copy-paste the configuration files (conf directory) from the old version. Update the content of the new files instead.";
-  private final File confFile;
-
-  // visible for testing
-  Env(URL confUrl) throws URISyntaxException {
-    if (confUrl == null) {
-      throw new IllegalStateException(ERROR_MESSAGE);
-    }
-    this.confFile = new File(confUrl.toURI());
-  }
-
-  Env() throws URISyntaxException {
-    this(Env.class.getResource("/sonar.properties"));
-  }
-
-  File rootDir() {
-    return confFile.getParentFile().getParentFile();
-  }
-
-  File file(String relativePath) {
-    return new File(rootDir(), relativePath);
-  }
-
-  File freshDir(String relativePath) {
-    File dir = new File(rootDir(), relativePath);
-    FileUtils.deleteQuietly(dir);
-    dir.mkdirs();
-    return dir;
-  }
-
-  /**
-   * This check is required in order to provide more meaningful message than JRuby - see SONAR-2715
-   */
-  void verifyWritableTempDir() {
-    File file = null;
-    try {
-      file = File.createTempFile("sonarqube-check", "tmp");
-    } catch (IOException e) {
-      throw new IllegalStateException("Unable to create file in temporary directory, please check existence " +
-        "and permissions of: " + FileUtils.getTempDirectory(), e);
-    } finally {
-      FileUtils.deleteQuietly(file);
-    }
-  }
-}
diff --git a/sonar-application/src/main/java/org/sonar/application/ForkProcesses.java b/sonar-application/src/main/java/org/sonar/application/ForkProcesses.java
deleted file mode 100644 (file)
index c6110ba..0000000
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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 3 of the License, or (at your option) any later version.
- *
- * SonarQube 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.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-package org.sonar.application;
-
-import org.sonar.process.Monitor;
-import org.sonar.process.NetworkUtils;
-import org.sonar.process.ProcessWrapper;
-
-import javax.annotation.Nullable;
-
-public class ForkProcesses {
-  private Monitor monitor;
-  private final Thread shutdownHook;
-  private ProcessWrapper elasticsearch;
-  private ProcessWrapper server;
-
-  public ForkProcesses() throws Exception {
-    Installation installation = new Installation();
-
-    String esPort = installation.prop("sonar.es.node.port", null);
-    if (esPort == null) {
-      esPort = String.valueOf(NetworkUtils.freePort());
-      installation.setProp("sonar.es.node.port", esPort);
-    }
-    String esCluster = installation.prop("sonar.es.cluster.name", null);
-    if(esCluster == null){
-      installation.setProp("sonar.es.cluster.name", "sonarqube");
-    }
-    installation.setProp("sonar.es.type", "TRANSPORT");
-
-    shutdownHook = new Thread(new Runnable() {
-      @Override
-      public void run() {
-        monitor.interrupt();
-        terminateAndWait(elasticsearch);
-        terminateAndWait(server);
-      }
-    });
-
-    Runtime.getRuntime().addShutdownHook(shutdownHook);
-
-    monitor = new Monitor();
-
-    elasticsearch = new ProcessWrapper(
-      installation.homeDir().getAbsolutePath(),
-      installation.prop("sonar.es.javaOpts", "-server -Xmx256m -Xms128m -Xss256k -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=75 -XX:+UseCMSInitiatingOccupancyOnly"),
-      "org.sonar.search.ElasticSearch",
-      installation.props(),
-      "ES",
-      installation.starPath("lib/common"),
-      installation.starPath("lib/search"));
-    monitor.registerProcess(elasticsearch);
-
-
-    server = new ProcessWrapper(
-      installation.homeDir().getAbsolutePath(),
-      installation.prop("sonar.web.javaOpts", "-Xmx768m -server -XX:MaxPermSize=160m -Djava.awt.headless=true -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 -Djruby.management.enabled=false"),
-      "org.sonar.server.app.ServerProcess",
-      installation.props(),
-      "SQ",
-      installation.starPath("lib/common"),
-      installation.starPath("lib/server"));
-    monitor.registerProcess(server);
-
-    monitor.start();
-    try {
-      monitor.join();
-    } catch (InterruptedException e) {
-      stop(true);
-    }
-    stop(true);
-  }
-
-  public void stop(boolean waitForCompletion) {
-    Runtime.getRuntime().removeShutdownHook(shutdownHook);
-    shutdownHook.start();
-    if (waitForCompletion) {
-      try {
-        shutdownHook.join();
-      } catch (InterruptedException e) {
-        e.printStackTrace();
-      }
-    }
-  }
-  private void terminateAndWait(@Nullable ProcessWrapper process) {
-    if (process != null && process.getThread() != null) {
-      process.terminate();
-    }
-  }
-
-  public static void main(String[] args) throws Exception {
-    new ForkProcesses();
-  }
-}
diff --git a/sonar-application/src/main/java/org/sonar/application/Props.java b/sonar-application/src/main/java/org/sonar/application/Props.java
deleted file mode 100644 (file)
index dbe2463..0000000
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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 3 of the License, or (at your option) any later version.
- *
- * SonarQube 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.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-package org.sonar.application;
-
-import org.apache.commons.io.IOUtils;
-
-import javax.annotation.Nullable;
-
-import java.io.File;
-import java.io.FileReader;
-import java.util.Map;
-import java.util.Properties;
-
-class Props {
-
-  private final Properties props;
-
-  Props(Properties props) {
-    this.props = props;
-  }
-
-  String of(String key) {
-    return props.getProperty(key);
-  }
-
-  String of(String key, @Nullable String defaultValue) {
-    String s = of(key);
-    return s == null ? defaultValue : s;
-  }
-
-  boolean booleanOf(String key) {
-    String s = of(key);
-    return s != null && Boolean.parseBoolean(s);
-  }
-
-  boolean booleanOf(String key, boolean defaultValue) {
-    String s = of(key);
-    return s != null ? Boolean.parseBoolean(s) : defaultValue;
-  }
-
-  Integer intOf(String key) {
-    String s = of(key);
-    if (s != null && !"".equals(s)) {
-      try {
-        return Integer.parseInt(s);
-      } catch (NumberFormatException e) {
-        throw new IllegalStateException("Value of property " + key + " is not an integer: " + s, e);
-      }
-    }
-    return null;
-  }
-
-  int intOf(String key, int defaultValue) {
-    Integer i = intOf(key);
-    return i == null ? defaultValue : i;
-  }
-
-  static Props create(Env env) {
-    File propsFile = env.file("conf/sonar.properties");
-    Properties p = new Properties();
-    FileReader reader = null;
-    try {
-      reader = new FileReader(propsFile);
-
-      // order is important : the last override the first
-      p.load(reader);
-      p.putAll(System.getenv());
-      p.putAll(System.getProperties());
-
-      p = ConfigurationUtils.interpolateEnvVariables(p);
-      p = decrypt(p);
-
-      // Set all properties as system properties to pass them to PlatformServletContextListener
-      System.setProperties(p);
-
-      return new Props(p);
-
-    } catch (Exception e) {
-      throw new IllegalStateException("File does not exist or can't be open: " + propsFile, e);
-
-    } finally {
-      IOUtils.closeQuietly(reader);
-    }
-  }
-
-  static Properties decrypt(Properties properties) {
-    Encryption encryption = new Encryption(properties.getProperty(AesCipher.ENCRYPTION_SECRET_KEY_PATH));
-    Properties result = new Properties();
-
-    for (Map.Entry<Object, Object> entry : properties.entrySet()) {
-      String key = (String) entry.getKey();
-      String value = (String) entry.getValue();
-      if (encryption.isEncrypted(value)) {
-        value = encryption.decrypt(value);
-      }
-      result.setProperty(key, value);
-    }
-    return result;
-  }
-}
diff --git a/sonar-application/src/main/java/org/sonar/application/StartServer.java b/sonar-application/src/main/java/org/sonar/application/StartServer.java
new file mode 100644 (file)
index 0000000..18cee9b
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube 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.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.application;
+
+import org.sonar.process.Monitor;
+import org.sonar.process.NetworkUtils;
+import org.sonar.process.ProcessWrapper;
+
+import javax.annotation.Nullable;
+
+public class StartServer {
+  private Monitor monitor;
+  private final Thread shutdownHook;
+  private ProcessWrapper elasticsearch;
+  private ProcessWrapper server;
+
+  public StartServer() throws Exception {
+    Installation installation = new Installation();
+
+    String esPort = installation.prop("sonar.es.node.port", null);
+    if (esPort == null) {
+      esPort = String.valueOf(NetworkUtils.freePort());
+    }
+    String esCluster = installation.prop("sonar.es.cluster.name", null);
+    if (esCluster == null) {
+      installation.setProp("sonar.es.cluster.name", "sonarqube");
+    }
+
+    shutdownHook = new Thread(new Runnable() {
+      @Override
+      public void run() {
+        monitor.interrupt();
+        terminateAndWait(elasticsearch);
+        terminateAndWait(server);
+      }
+    });
+
+    Runtime.getRuntime().addShutdownHook(shutdownHook);
+
+    monitor = new Monitor();
+
+    String opts = installation.prop("sonar.es.javaOpts", "-server -Xmx256m -Xms128m -Xss256k -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=75 -XX:+UseCMSInitiatingOccupancyOnly");
+    elasticsearch = new ProcessWrapper("ES")
+      .setWorkDir(installation.homeDir())
+      .addJavaOpts(opts)
+      .setClassName("org.sonar.search.ElasticSearch")
+      .setArguments(installation.props())
+      .setArgument("sonar.es.node.port", esPort)
+      .addClasspath(installation.starPath("lib/common"))
+      .addClasspath(installation.starPath("lib/search"));
+    monitor.registerProcess(elasticsearch);
+
+
+    opts = installation.prop("sonar.web.javaOpts", "-Xmx768m -server -XX:MaxPermSize=160m -Djava.awt.headless=true -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 -Djruby.management.enabled=false");
+    server = new ProcessWrapper("SQ")
+      .setWorkDir(installation.homeDir())
+      .addJavaOpts(opts)
+      .setClassName("org.sonar.server.app.ServerProcess")
+      .setEnvProperty("SONAR_HOME", installation.homeDir().getAbsolutePath())
+      .setArguments(installation.props())
+      .setArgument("sonar.es.type", "TRANSPORT")
+      .addClasspath(installation.starPath("lib/common"))
+      .addClasspath(installation.starPath("lib/server"));
+    monitor.registerProcess(server);
+
+    monitor.start();
+    try {
+      monitor.join();
+    } catch (InterruptedException e) {
+      stop(true);
+    }
+    stop(true);
+  }
+
+  public void stop(boolean waitForCompletion) {
+    Runtime.getRuntime().removeShutdownHook(shutdownHook);
+    shutdownHook.start();
+    if (waitForCompletion) {
+      try {
+        shutdownHook.join();
+      } catch (InterruptedException e) {
+        e.printStackTrace();
+      }
+    }
+  }
+
+  private void terminateAndWait(@Nullable ProcessWrapper process) {
+    if (process != null && process.getThread() != null) {
+      process.terminate();
+    }
+  }
+
+  public static void main(String[] args) throws Exception {
+    new StartServer();
+  }
+}
diff --git a/sonar-application/src/test/java/org/sonar/application/AesCipherTest.java b/sonar-application/src/test/java/org/sonar/application/AesCipherTest.java
deleted file mode 100644 (file)
index 9f09709..0000000
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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 3 of the License, or (at your option) any later version.
- *
- * SonarQube 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.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-
-package org.sonar.application;
-
-import com.google.common.io.Resources;
-import org.apache.commons.codec.binary.Base64;
-import org.apache.commons.lang.StringUtils;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-
-import javax.crypto.BadPaddingException;
-
-import java.io.File;
-import java.security.InvalidKeyException;
-import java.security.Key;
-
-import static org.fest.assertions.Assertions.assertThat;
-import static org.fest.assertions.Fail.fail;
-
-
-public class AesCipherTest {
-
-  @Rule
-  public ExpectedException thrown = ExpectedException.none();
-
-  @Test
-  public void generateRandomSecretKey() {
-    AesCipher cipher = new AesCipher(null);
-
-    String key = cipher.generateRandomSecretKey();
-
-    assertThat(StringUtils.isNotBlank(key)).isTrue();
-    assertThat(Base64.isArrayByteBase64(key.getBytes())).isTrue();
-  }
-
-  @Test
-  public void encrypt() throws Exception {
-    AesCipher cipher = new AesCipher(pathToSecretKey());
-
-    String encryptedText = cipher.encrypt("this is a secret");
-
-    assertThat(StringUtils.isNotBlank(encryptedText)).isTrue();
-    assertThat(Base64.isArrayByteBase64(encryptedText.getBytes())).isTrue();
-  }
-
-  @Test
-  public void encrypt_bad_key() throws Exception {
-    thrown.expect(RuntimeException.class);
-    thrown.expectMessage("Invalid AES key");
-
-    AesCipher cipher = new AesCipher(getPath("bad_secret_key.txt"));
-
-    cipher.encrypt("this is a secret");
-  }
-
-  @Test
-  public void decrypt() throws Exception {
-    AesCipher cipher = new AesCipher(pathToSecretKey());
-
-    // the following value has been encrypted with the key /org/sonar/api/config/AesCipherTest/aes_secret_key.txt
-    String clearText = cipher.decrypt("9mx5Zq4JVyjeChTcVjEide4kWCwusFl7P2dSVXtg9IY=");
-
-    assertThat(clearText).isEqualTo("this is a secret");
-  }
-
-  @Test
-  public void decrypt_bad_key() throws Exception {
-    AesCipher cipher = new AesCipher(getPath("bad_secret_key.txt"));
-
-    try {
-      cipher.decrypt("9mx5Zq4JVyjeChTcVjEide4kWCwusFl7P2dSVXtg9IY=");
-      fail();
-
-    } catch (RuntimeException e) {
-      assertThat(e.getCause()).isInstanceOf(InvalidKeyException.class);
-    }
-  }
-
-  @Test
-  public void decrypt_other_key() throws Exception {
-    AesCipher cipher = new AesCipher(getPath("other_secret_key.txt"));
-
-    try {
-      // text encrypted with another key
-      cipher.decrypt("9mx5Zq4JVyjeChTcVjEide4kWCwusFl7P2dSVXtg9IY=");
-      fail();
-
-    } catch (RuntimeException e) {
-      assertThat(e.getCause()).isInstanceOf(BadPaddingException.class);
-    }
-  }
-
-  @Test
-  public void encryptThenDecrypt() throws Exception {
-    AesCipher cipher = new AesCipher(pathToSecretKey());
-
-    assertThat(cipher.decrypt(cipher.encrypt("foo"))).isEqualTo("foo");
-  }
-
-  @Test
-  public void testDefaultPathToSecretKey() {
-    AesCipher cipher = new AesCipher(null);
-
-    String path = cipher.getPathToSecretKey();
-
-    assertThat(StringUtils.isNotBlank(path)).isTrue();
-    assertThat(new File(path).getName()).isEqualTo("sonar-secret.txt");
-  }
-
-  @Test
-  public void loadSecretKeyFromFile() throws Exception {
-    AesCipher cipher = new AesCipher(null);
-    Key secretKey = cipher.loadSecretFileFromFile(pathToSecretKey());
-    assertThat(secretKey.getAlgorithm()).isEqualTo("AES");
-    assertThat(secretKey.getEncoded().length).isGreaterThan(10);
-  }
-
-  @Test
-  public void loadSecretKeyFromFile_trim_content() throws Exception {
-    String path = getPath("non_trimmed_secret_key.txt");
-    AesCipher cipher = new AesCipher(null);
-
-    Key secretKey = cipher.loadSecretFileFromFile(path);
-
-    assertThat(secretKey.getAlgorithm()).isEqualTo("AES");
-    assertThat(secretKey.getEncoded().length).isGreaterThan(10);
-  }
-
-  @Test
-  public void loadSecretKeyFromFile_file_does_not_exist() throws Exception {
-    thrown.expect(IllegalStateException.class);
-
-    AesCipher cipher = new AesCipher(null);
-    cipher.loadSecretFileFromFile("/file/does/not/exist");
-  }
-
-  @Test
-  public void loadSecretKeyFromFile_no_property() throws Exception {
-    thrown.expect(IllegalStateException.class);
-
-    AesCipher cipher = new AesCipher(null);
-    cipher.loadSecretFileFromFile(null);
-  }
-
-  @Test
-  public void hasSecretKey() throws Exception {
-    AesCipher cipher = new AesCipher(pathToSecretKey());
-
-    assertThat(cipher.hasSecretKey()).isTrue();
-  }
-
-  @Test
-  public void doesNotHaveSecretKey() throws Exception {
-    AesCipher cipher = new AesCipher("/my/twitter/id/is/SimonBrandhof");
-
-    assertThat(cipher.hasSecretKey()).isFalse();
-  }
-
-  private static String getPath(String file){
-    return Resources.getResource(AesCipherTest.class, "AesCipherTest/" + file).getPath();
-  }
-
-  private static String pathToSecretKey() throws Exception {
-    return getPath("aes_secret_key.txt");
-  }
-
-}
diff --git a/sonar-application/src/test/java/org/sonar/application/EncryptionTest.java b/sonar-application/src/test/java/org/sonar/application/EncryptionTest.java
deleted file mode 100644 (file)
index 80bc4f1..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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 3 of the License, or (at your option) any later version.
- *
- * SonarQube 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.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-
-package org.sonar.application;
-
-import org.junit.Test;
-
-import static org.hamcrest.Matchers.is;
-import static org.junit.Assert.assertThat;
-
-public class EncryptionTest {
-
-  @Test
-  public void isEncrypted() {
-    Encryption encryption = new Encryption(null);
-    assertThat(encryption.isEncrypted("{aes}ADASDASAD"), is(true));
-    assertThat(encryption.isEncrypted("{b64}ADASDASAD"), is(true));
-    assertThat(encryption.isEncrypted("{abc}ADASDASAD"), is(true));
-
-    assertThat(encryption.isEncrypted("{}"), is(false));
-    assertThat(encryption.isEncrypted("{foo"), is(false));
-    assertThat(encryption.isEncrypted("foo{aes}"), is(false));
-  }
-
-  @Test
-  public void decrypt() {
-    Encryption encryption = new Encryption(null);
-    assertThat(encryption.decrypt("{b64}Zm9v"), is("foo"));
-  }
-
-  @Test
-  public void decrypt_unknown_algorithm() {
-    Encryption encryption = new Encryption(null);
-    assertThat(encryption.decrypt("{xxx}Zm9v"), is("{xxx}Zm9v"));
-  }
-
-  @Test
-  public void decrypt_uncrypted_text() {
-    Encryption encryption = new Encryption(null);
-    assertThat(encryption.decrypt("foo"), is("foo"));
-  }
-}
diff --git a/sonar-application/src/test/java/org/sonar/application/EnvTest.java b/sonar-application/src/test/java/org/sonar/application/EnvTest.java
deleted file mode 100644 (file)
index 0ffc768..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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 3 of the License, or (at your option) any later version.
- *
- * SonarQube 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.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-package org.sonar.application;
-
-import org.apache.commons.io.FileUtils;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-
-import java.io.File;
-
-import static org.fest.assertions.Assertions.assertThat;
-import static org.fest.assertions.Fail.fail;
-
-public class EnvTest {
-
-  @Rule
-  public TemporaryFolder temp = new TemporaryFolder();
-
-  @Test
-  public void testName() throws Exception {
-    File file = new File(getClass().getResource("/org/sonar/application/LoggingTest/logback-access.xml").toURI());
-    assertThat(file.exists()).isTrue();
-  }
-
-  @Test
-  public void files() throws Exception {
-    File home = temp.newFolder();
-    File confFile = new File(home, "conf/sonar.properties");
-    File logFile = new File(home, "logs/sonar.log");
-
-    FileUtils.touch(confFile);
-    FileUtils.touch(logFile);
-
-    Env env = new Env(confFile.toURL());
-
-    assertThat(env.rootDir()).isDirectory().exists().isEqualTo(home);
-    assertThat(env.file("conf/sonar.properties")).isFile().exists().isEqualTo(confFile);
-    assertThat(env.file("logs/sonar.log")).isFile().exists().isEqualTo(logFile);
-    assertThat(env.file("xxx/unknown.log")).doesNotExist();
-  }
-
-  @Test
-  public void fresh_dir() throws Exception {
-    File home = temp.newFolder();
-    File confFile = new File(home, "conf/sonar.properties");
-    File logFile = new File(home, "logs/sonar.log");
-
-    FileUtils.touch(confFile);
-    FileUtils.touch(logFile);
-
-    Env env = new Env(confFile.toURL());
-
-    File data = env.freshDir("data/h2");
-    assertThat(data).isDirectory().exists();
-    assertThat(data.getParentFile().getName()).isEqualTo("data");
-    assertThat(data.getParentFile().getParentFile()).isEqualTo(home);
-
-    // clean directory
-    File logs = env.freshDir("logs");
-    assertThat(logs).isDirectory().exists();
-    assertThat(logs.listFiles()).isEmpty();
-  }
-
-  @Test
-  public void temp_dir_should_be_writable() throws Exception {
-    new Env(temp.newFile().toURL()).verifyWritableTempDir();
-    // do not fail
-  }
-
-  @Test
-  public void fail_if_conf_file_not_found() throws Exception {
-    try {
-      // note that "new Env(null)" would be exact, but let's
-      // keep "new Env()" for increasing code coverage :-)
-      new Env();
-      fail();
-    } catch (IllegalStateException e) {
-      assertThat(e).hasMessage(Env.ERROR_MESSAGE);
-    }
-  }
-}
diff --git a/sonar-application/src/test/java/org/sonar/application/PropsTest.java b/sonar-application/src/test/java/org/sonar/application/PropsTest.java
deleted file mode 100644 (file)
index 46ca5e8..0000000
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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 3 of the License, or (at your option) any later version.
- *
- * SonarQube 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.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-package org.sonar.application;
-
-import com.google.common.io.Resources;
-import org.apache.commons.io.FilenameUtils;
-import org.junit.Test;
-
-import java.io.File;
-import java.util.Properties;
-
-import static org.fest.assertions.Assertions.assertThat;
-import static org.fest.assertions.Fail.fail;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-public class PropsTest {
-
-  @Test
-  public void of() throws Exception {
-    Properties p = new Properties();
-    p.setProperty("foo", "bar");
-    Props props = new Props(p);
-
-    assertThat(props.of("foo")).isEqualTo("bar");
-    assertThat(props.of("foo", "default value")).isEqualTo("bar");
-    assertThat(props.of("unknown")).isNull();
-    assertThat(props.of("unknown", "default value")).isEqualTo("default value");
-  }
-
-  @Test
-  public void intOf() throws Exception {
-    Properties p = new Properties();
-    p.setProperty("foo", "33");
-    p.setProperty("blank", "");
-    Props props = new Props(p);
-
-    assertThat(props.intOf("foo")).isEqualTo(33);
-    assertThat(props.intOf("foo", 44)).isEqualTo(33);
-    assertThat(props.intOf("blank")).isNull();
-    assertThat(props.intOf("blank", 55)).isEqualTo(55);
-    assertThat(props.intOf("unknown")).isNull();
-    assertThat(props.intOf("unknown", 44)).isEqualTo(44);
-  }
-
-  @Test
-  public void intOf_not_integer() throws Exception {
-    Properties p = new Properties();
-    p.setProperty("foo", "bar");
-    Props props = new Props(p);
-
-    try {
-      props.intOf("foo");
-      fail();
-    } catch (IllegalStateException e) {
-      assertThat(e).hasMessage("Value of property foo is not an integer: bar");
-    }
-  }
-
-  @Test
-  public void booleanOf() throws Exception {
-    Properties p = new Properties();
-    p.setProperty("foo", "True");
-    p.setProperty("bar", "false");
-    Props props = new Props(p);
-
-    assertThat(props.booleanOf("foo")).isTrue();
-    assertThat(props.booleanOf("bar")).isFalse();
-    assertThat(props.booleanOf("unknown")).isFalse();
-  }
-
-  @Test
-  public void booleanOf_default_value() throws Exception {
-    Properties p = new Properties();
-    p.setProperty("foo", "true");
-    p.setProperty("bar", "false");
-    Props props = new Props(p);
-
-    assertThat(props.booleanOf("unset", false)).isFalse();
-    assertThat(props.booleanOf("unset", true)).isTrue();
-    assertThat(props.booleanOf("foo", false)).isTrue();
-    assertThat(props.booleanOf("bar", true)).isFalse();
-  }
-
-  @Test
-  public void load_file_and_system_properties() throws Exception {
-    System.setProperty("hello", "bar");
-
-    Env env = mock(Env.class);
-    File propsFile = new File(Resources.getResource(getClass(), "PropsTest/sonar.properties").getFile());
-    when(env.file("conf/sonar.properties")).thenReturn(propsFile);
-
-    Props props = Props.create(env);
-
-    assertThat(props.of("foo")).isEqualTo("bar");
-    assertThat(props.of("java.version")).isNotNull();
-
-    // system properties override file properties
-    assertThat(props.of("hello")).isEqualTo("bar");
-    assertThat(props.of("java.io.tmpdir")).isNotEmpty().isNotEqualTo("/should/be/overridden");
-
-    assertThat(System.getProperty("foo")).isEqualTo("bar");
-    assertThat(System.getProperty("hello")).isEqualTo("bar");
-  }
-
-  @Test
-  public void fail_if_file_does_not_exist() throws Exception {
-    Env env = mock(Env.class);
-    when(env.file("conf/sonar.properties")).thenReturn(new File("target/not_exist/sonar.properties"));
-
-    try {
-      Props.create(env);
-      fail();
-    } catch (IllegalStateException e) {
-      assertThat(e).hasMessage("File does not exist or can't be open: " + FilenameUtils.separatorsToSystem("target/not_exist/sonar.properties"));
-    }
-  }
-}