Read config from sidecar.config System Property instead of classpath

Alters configuration processing to read from `sidecar.config` system
property instead of using `Configurations` file resolution, which seems
to read from classpath first.

Also does the following:

* Move `conf` into `src/dist/config`.  This causes the `conf` directory
  to be included in the tar and zip distributions where it previously
  was not.
* Don't add `conf` directory to classpath.  For logging add
  `-Dlogback.configuration` to arguments.  Also add `logback-test.xml`
  to have different logging behavior for tests.
* Copy agents into `build/install/appName/agents` directly instead of
  `src/dist`. Make `copyDist` depend on `copyJolokia`. This also has
  the side effect of having agents copied to the project directory, so
  `bin/CassandraSidecarDaemon` works after `./gradlew build`.
* Improve logging to include full address instead of just port.
* Add generated paths to gitignore

patch by Andrew Tolbert; reviewed by Dinesh Joshi and Vinay Chella for CASSANDRA-15288
diff --git a/.gitignore b/.gitignore
index f5394e6..810dd6b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -78,3 +78,12 @@
 
 src/dist/*
 *.logdir_IS_UNDEFINED
+
+# Sidecar copyDist files copied to root directory
+agents
+bin
+conf
+lib
+
+# Local gradle cache
+.gradle
diff --git a/CHANGES.txt b/CHANGES.txt
index f9fbc29..dcba20e 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,5 +1,6 @@
 1.0.0
 -----
+ * Read sidecar.yaml from sidecar.config System Property instead of classpath (CASSANDRA-15288)
  * Add integration tests task (CASSANDRA-15031)
  * Add support for SSL and bindable address (CASSANDRA-15030)
  * Autogenerate API docs for sidecar (CASSANDRA-15028)
diff --git a/build.gradle b/build.gradle
index 093cca5..947a6bd 100644
--- a/build.gradle
+++ b/build.gradle
@@ -22,11 +22,11 @@
 applicationName = 'CassandraSidecarDaemon'
 
 // Config file location should be in file:/// format for local files,
-// when we have the fix for adding /conf directory to classpaht, we can get away with below default JvmArg
 def confFile = "file:" + File.separator + File.separator + "APP_HOME_TO_REPLACE/conf/sidecar.yaml"
 
 applicationDefaultJvmArgs = ["-Dsidecar.logdir=./logs",
                              "-Dsidecar.config=" + confFile,
+                             "-Dlogback.configurationFile=./conf/logback.xml",
                              "-Dvertx.logger-delegate-factory-class-name=io.vertx.core.logging.SLF4JLogDelegateFactory",
                              "-javaagent:APP_HOME_TO_REPLACE/agents/jolokia-jvm-1.6.0-agent.jar=port=7777,host=localhost"]
 startScripts {
@@ -39,22 +39,12 @@
     confFile = "file:" + File.separator + File.separator + "$projectDir/conf/sidecar.yaml"
     jvmArgs = ["-Dsidecar.logdir=./logs",
                                  "-Dsidecar.config=" + confFile,
+                                 "-Dlogback.configurationFile=./conf/logback.xml",
                                  "-Dvertx.logger-delegate-factory-class-name=io.vertx.core.logging.SLF4JLogDelegateFactory",
-                                 "-javaagent:$projectDir/src/dist/agents/jolokia-jvm-1.6.0-agent.jar=port=7777,host=localhost"]
+                                 "-javaagent:$projectDir/agents/jolokia-jvm-1.6.0-agent.jar=port=7777,host=localhost"]
 }
 
 sourceSets {
-    // This is needed as gradle considers `src/main/resources` as the default resources folder
-    main {
-        resources {
-            srcDirs = ['conf', 'setup', 'src/main/resources']
-        }
-    }
-    test {
-        resources {
-            srcDirs = [main.resources, "src/test/resources"]
-        }
-    }
     integrationTest {
         java {
             compileClasspath += main.output + test.output
@@ -129,17 +119,15 @@
 
 task copyJolokia(type: Copy) {
     from configurations.jolokia
-    into "$projectDir/src/dist/agents"
+    into "$projectDir/src/main/dist/agents"
 }
 
-// Lets clean /bin and /lib directories along with default build directories.
-clean {
-    println "Deleting directory $projectDir/bin"
-    delete "$projectDir/bin"
-    println "Deleting directory $projectDir/lib"
-    delete "$projectDir/lib"
-    println "Deleting agents $projectDir/src/dist/agents"
-    delete "$projectDir/src/dist/agents"
+// Lets clean distribution directories along with default build directories.
+clean.doLast {
+    ["agents", "bin", "conf", "lib"].each {
+        println "Deleting directory $projectDir/$it"
+        delete "$projectDir/$it"
+    }
     println "Deleting generated docs $projectDir/src/main/resources/docs"
     delete "$projectDir/src/main/resources/docs"
 }
@@ -173,6 +161,7 @@
 }
 
 // copyDist gets called on every build
-copyDist.dependsOn installDist
+copyDist.dependsOn installDist, copyJolokia
 check.dependsOn checkstyleMain, checkstyleTest, integrationTest, jacocoTestReport
 build.dependsOn copyDist, generateReDoc, generateSwaggerUI, copyJolokia
+run.dependsOn build
diff --git a/conf/logback.xml b/src/main/dist/conf/logback.xml
similarity index 100%
rename from conf/logback.xml
rename to src/main/dist/conf/logback.xml
diff --git a/conf/sidecar.yaml b/src/main/dist/conf/sidecar.yaml
similarity index 100%
rename from conf/sidecar.yaml
rename to src/main/dist/conf/sidecar.yaml
diff --git a/src/main/java/org/apache/cassandra/sidecar/CassandraSidecarDaemon.java b/src/main/java/org/apache/cassandra/sidecar/CassandraSidecarDaemon.java
index a06e3f6..64c5e47 100644
--- a/src/main/java/org/apache/cassandra/sidecar/CassandraSidecarDaemon.java
+++ b/src/main/java/org/apache/cassandra/sidecar/CassandraSidecarDaemon.java
@@ -53,7 +53,7 @@
     {
         banner(System.out);
         validate();
-        logger.info("Starting Cassandra Sidecar on port {}", config.getPort());
+        logger.info("Starting Cassandra Sidecar on {}:{}", config.getHost(), config.getPort());
         healthService.start();
         server.listen(config.getPort(), config.getHost());
     }
diff --git a/src/main/java/org/apache/cassandra/sidecar/MainModule.java b/src/main/java/org/apache/cassandra/sidecar/MainModule.java
index 08b66c0..38a53f8 100644
--- a/src/main/java/org/apache/cassandra/sidecar/MainModule.java
+++ b/src/main/java/org/apache/cassandra/sidecar/MainModule.java
@@ -18,11 +18,14 @@
 
 package org.apache.cassandra.sidecar;
 
-import java.io.File;
+import java.net.MalformedURLException;
+import java.net.URL;
 
 import org.apache.commons.configuration2.YAMLConfiguration;
 import org.apache.commons.configuration2.builder.fluent.Configurations;
 import org.apache.commons.configuration2.ex.ConfigurationException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import com.google.inject.AbstractModule;
 import com.google.inject.Provides;
@@ -43,6 +46,8 @@
  */
 public class MainModule extends AbstractModule
 {
+    private static final Logger logger = LoggerFactory.getLogger(MainModule.class);
+
     @Provides
     @Singleton
     public Vertx getVertx()
@@ -103,21 +108,29 @@
     @Singleton
     public Configuration configuration() throws ConfigurationException
     {
-        Configurations confs = new Configurations();
-        File propFile = new File("sidecar.yaml");
-        YAMLConfiguration yamlConf = confs.fileBased(YAMLConfiguration.class, propFile);
-
-        return new Configuration.Builder()
-                           .setCassandraHost(yamlConf.get(String.class, "cassandra.host"))
-                           .setCassandraPort(yamlConf.get(Integer.class, "cassandra.port"))
-                           .setHost(yamlConf.get(String.class, "sidecar.host"))
-                           .setPort(yamlConf.get(Integer.class, "sidecar.port"))
-                           .setHealthCheckFrequency(yamlConf.get(Integer.class, "healthcheck.poll_freq_millis"))
-                           .setKeyStorePath(yamlConf.get(String.class, "sidecar.ssl.keystore.path", null))
-                           .setKeyStorePassword(yamlConf.get(String.class, "sidecar.ssl.keystore.password", null))
-                           .setTrustStorePath(yamlConf.get(String.class, "sidecar.ssl.truststore.path", null))
-                           .setTrustStorePassword(yamlConf.get(String.class, "sidecar.ssl.truststore.password", null))
-                           .setSslEnabled(yamlConf.get(Boolean.class, "sidecar.ssl.enabled", false))
-                           .build();
+        final String confPath = System.getProperty("sidecar.config", "file://./conf/config.yaml");
+        logger.info("Reading configuration from {}", confPath);
+        try
+        {
+            Configurations confs = new Configurations();
+            URL url = new URL(confPath);
+            YAMLConfiguration yamlConf = confs.fileBased(YAMLConfiguration.class, url);
+            return new Configuration.Builder()
+                    .setCassandraHost(yamlConf.get(String.class, "cassandra.host"))
+                    .setCassandraPort(yamlConf.get(Integer.class, "cassandra.port"))
+                    .setHost(yamlConf.get(String.class, "sidecar.host"))
+                    .setPort(yamlConf.get(Integer.class, "sidecar.port"))
+                    .setHealthCheckFrequency(yamlConf.get(Integer.class, "healthcheck.poll_freq_millis"))
+                    .setKeyStorePath(yamlConf.get(String.class, "sidecar.ssl.keystore.path", null))
+                    .setKeyStorePassword(yamlConf.get(String.class, "sidecar.ssl.keystore.password", null))
+                    .setTrustStorePath(yamlConf.get(String.class, "sidecar.ssl.truststore.path", null))
+                    .setTrustStorePassword(yamlConf.get(String.class, "sidecar.ssl.truststore.password", null))
+                    .setSslEnabled(yamlConf.get(Boolean.class, "sidecar.ssl.enabled", false))
+                    .build();
+        }
+        catch (MalformedURLException e)
+        {
+            throw new ConfigurationException("Failed reading from sidebar.config path: " + confPath, e);
+        }
     }
 }
diff --git a/src/test/resources/logback-test.xml b/src/test/resources/logback-test.xml
new file mode 100644
index 0000000..7260e88
--- /dev/null
+++ b/src/test/resources/logback-test.xml
@@ -0,0 +1,37 @@
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements.  See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership.  The ASF licenses this file
+  ~ to you under the Apache License, Version 2.0 (the
+  ~ "License"); you may not use this file except in compliance
+  ~ with the License.  You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<configuration>
+
+  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+    <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
+      <level>DEBUG</level>
+    </filter>
+    <encoder>
+      <pattern>%-5level [%thread] %date{ISO8601} %F:%L - %msg%n</pattern>
+    </encoder>
+  </appender>
+
+  <root level="INFO">
+    <appender-ref ref="STDOUT" />
+  </root>
+
+
+  <logger name="com.datastax.driver.core" level="ERROR" />
+  <logger name="com.datastax.driver.core.ControlConnection" level="OFF" />
+</configuration>