Author: [email protected]
Date: Mon Jun  4 14:54:04 2012
New Revision: 2431

Log:
[AMDATUCASSANDRA-191] Added configuration of the VM in which the external 
Cassandra process is launched. Also improved auto cassandra download/install. 

Added:
   
trunk/amdatu-cassandra/cassandra-launcher/src/main/resources/conf/log4j-server.properties
Modified:
   
trunk/amdatu-cassandra/cassandra-launcher/src/main/java/org/amdatu/cassandra/launcher/LauncherConfigurationService.java
   
trunk/amdatu-cassandra/cassandra-launcher/src/main/java/org/amdatu/cassandra/launcher/osgi/Activator.java
   
trunk/amdatu-cassandra/cassandra-launcher/src/main/java/org/amdatu/cassandra/launcher/service/CompressionUtil.java
   
trunk/amdatu-cassandra/cassandra-launcher/src/main/java/org/amdatu/cassandra/launcher/service/LauncherConfigurationServiceImpl.java
   
trunk/amdatu-cassandra/cassandra-launcher/src/main/java/org/amdatu/cassandra/launcher/service/LauncherServiceImpl.java
   
trunk/amdatu-cassandra/cassandra-launcher/src/main/java/org/amdatu/cassandra/launcher/service/ProcessStreamListenerImpl.java
   
trunk/amdatu-cassandra/config/src/main/resources/amdatu.cassandra.launcher.config.xml

Modified: 
trunk/amdatu-cassandra/cassandra-launcher/src/main/java/org/amdatu/cassandra/launcher/LauncherConfigurationService.java
==============================================================================
--- 
trunk/amdatu-cassandra/cassandra-launcher/src/main/java/org/amdatu/cassandra/launcher/LauncherConfigurationService.java
     (original)
+++ 
trunk/amdatu-cassandra/cassandra-launcher/src/main/java/org/amdatu/cassandra/launcher/LauncherConfigurationService.java
     Mon Jun  4 14:54:04 2012
@@ -89,6 +89,51 @@
     String CLUSTER_NAME = "clustername";
 
     /**
+     * Configuration key for java options to start the JVM with.
+     */
+    String JAVA_OPTS = "java_opts";
+
+    /**
+     * Configuration key for system properties to start the JVM with.
+     */
+    String SYSTEM_PROPERTIES = "system_properties";
+
+    /**
+     * Configuration key for JMX port.
+     */
+    String JMX_PORT = "jmx_port";
+
+    /**
+     * Configuration key for enabling SSL in JMX.
+     */
+    String JMX_SSL = "jmx_ssl";
+
+    /**
+     * Configuration key for enabling authentication in JMX.
+     */
+    String JMX_AUTHENTICATE = "jmx_authenticate";
+
+    /**
+     * Configuration key for the Cassandra download version.
+     */
+    String DOWNLOAD_VERSION = "download_version";
+
+    /**
+     * Configuration key for the Cassandra download url.
+     */
+    String DOWNLOAD_URL = "download_url";
+
+    /**
+     * Configuration key for the installed Cassandra version.
+     */
+    String INSTALLED_VERSION = "installed_version";
+
+    /**
+     * Configuration key for the systemlog directory.
+     */
+    String SYSTEMLOG_DIR = "systemlog_dir";
+
+    /**
      * Returns the RPC address to be used by Thrift clients.
      * 
      * @return the RPC address.
@@ -115,14 +160,90 @@
      * @return the name of the cluster that this node is part of.
      */
     String getClustername();
-    
+
+    /**
+     * Returns the Java options for the VM in which Cassandra is launched.
+     * 
+     * @return the Java options for the VM in which Cassandra is launched.
+     */
+    String getJavaOpts();
+
+    /**
+     * Returns the system properties for the VM in which Cassandra is launched.
+     * 
+     * @return the system properties for the VM in which Cassandra is launched.
+     */
+    String getSystemProperties();
+
+    /**
+     * Returns the port number to enable JMX on in the VM in which Cassandra 
is launched.
+     * May be -1 in which case JMX is disabled.
+     * 
+     * @return the port number to enable JMX on in the VM in which Cassandra 
is launched or
+     *         -1 if JMX disabled
+     */
+    int getJmxPort();
+
+    /**
+     * Returns if SSL is enabled for JMX in the VM in which Cassandra is 
launched.
+     * 
+     * @return true if SSL is enabled for JMX in the VM in which Cassandra is 
launched, false otherwise.
+     */
+    boolean isJmxSsl();
+
+    /**
+     * Returns if authentication is enabled for JMX in the VM in which 
Cassandra is launched.
+     * 
+     * @return true if authentication is enabled for JMX in the VM in which 
Cassandra is launched, false otherwise.
+     */
+    boolean isJmxAuthenticate();
+
+    /**
+     * Returns the installed Cassandra version (may be null).
+     * 
+     * @return the installed Cassandra version (may be null).
+     */
+    String getInstalledVersion();
+
+    /**
+     * Updated the installed version (invoked after a successful update).
+     * 
+     * @param version the new installed version.
+     */
+    void updateInstalledVersion(String version);
+
+    /**
+     * The URL to download and install the target version from.
+     * 
+     * @return The URL to download and install the target version from.
+     */
+    String getDownloadUrl();
+
+    /**
+     * Returns the Cassandra version to download and install.
+     * 
+     * @return the Cassandra version to download and install.
+     */
+    String getDownloadversion();
+
+    /**
+     * Returns if a Cassandra update is required. This is the case if 
Cassandra is not yet installed or
+     * the installed version does not match the download_version.
+     * 
+     * @return true if a Cassandra update is required, false otherwise.
+     */
+    boolean isUpdateRequired();
+
     /**
      * Writes a custom cassandra.yaml to the Cassandra installation, filled 
with properties from
      * Config Admin.
+     * 
      * @param targetFile Location of the target cassandra.yaml file
      * @throws IOException
      * @throws URISyntaxException
      * @throws TemplateException
      */
     void writeCassandraYaml(File targetFile) throws IOException, 
URISyntaxException, TemplateException;
+    
+    void writeLog4jServerProperties(File targetFile) throws IOException, 
URISyntaxException, TemplateException;
 }

Modified: 
trunk/amdatu-cassandra/cassandra-launcher/src/main/java/org/amdatu/cassandra/launcher/osgi/Activator.java
==============================================================================
--- 
trunk/amdatu-cassandra/cassandra-launcher/src/main/java/org/amdatu/cassandra/launcher/osgi/Activator.java
   (original)
+++ 
trunk/amdatu-cassandra/cassandra-launcher/src/main/java/org/amdatu/cassandra/launcher/osgi/Activator.java
   Mon Jun  4 14:54:04 2012
@@ -49,6 +49,7 @@
                 .setImplementation(LauncherConfigurationServiceImpl.class)
                 .setInterface(LauncherConfigurationService.class.getName(), 
null)
                 
.add(createServiceDependency().setService(LogService.class).setRequired(true))
+                
.add(createServiceDependency().setService(ConfigurationAdmin.class).setRequired(true))
                 
.add(createConfigurationDependency().setPid(LauncherConfigurationService.PID)));
 
         // Register the Cassandra launcher service

Modified: 
trunk/amdatu-cassandra/cassandra-launcher/src/main/java/org/amdatu/cassandra/launcher/service/CompressionUtil.java
==============================================================================
--- 
trunk/amdatu-cassandra/cassandra-launcher/src/main/java/org/amdatu/cassandra/launcher/service/CompressionUtil.java
  (original)
+++ 
trunk/amdatu-cassandra/cassandra-launcher/src/main/java/org/amdatu/cassandra/launcher/service/CompressionUtil.java
  Mon Jun  4 14:54:04 2012
@@ -41,9 +41,9 @@
      * @return the decompresses file
      * @throws IOException
      */
-    public static File decompressGz(File file) throws IOException {
+    public static File decompressGz(File file, File targetDir) throws 
IOException {
         String targetFileName = file.getName().substring(0, 
file.getName().lastIndexOf(".gz"));
-        File targetFile = new File(file.getParentFile().getAbsolutePath(), 
targetFileName);
+        File targetFile = new File(targetDir.getAbsolutePath(), 
targetFileName);
         GzipCompressorInputStream gzin = null;
         FileOutputStream fos = null;
         try {
@@ -78,9 +78,9 @@
      * @return Directory containing the decompressed files
      * @throws IOException
      */
-    public static File decompressTar(File file) throws IOException {
+    public static File decompressTar(File file, File dir) throws IOException {
         String targetFileName = file.getName().substring(0, 
file.getName().lastIndexOf(".tar"));
-        File targetDir = new File(file.getParentFile().getAbsolutePath(), 
targetFileName);
+        File targetDir = new File(dir.getAbsolutePath(), targetFileName);
         targetDir.mkdir();
         TarArchiveInputStream tis = null;
         try {

Modified: 
trunk/amdatu-cassandra/cassandra-launcher/src/main/java/org/amdatu/cassandra/launcher/service/LauncherConfigurationServiceImpl.java
==============================================================================
--- 
trunk/amdatu-cassandra/cassandra-launcher/src/main/java/org/amdatu/cassandra/launcher/service/LauncherConfigurationServiceImpl.java
 (original)
+++ 
trunk/amdatu-cassandra/cassandra-launcher/src/main/java/org/amdatu/cassandra/launcher/service/LauncherConfigurationServiceImpl.java
 Mon Jun  4 14:54:04 2012
@@ -36,8 +36,9 @@
 import org.apache.felix.dm.Component;
 import org.apache.felix.dm.DependencyManager;
 import org.apache.felix.dm.ServiceDependency;
-import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
 import org.osgi.service.cm.ConfigurationException;
 import org.osgi.service.cm.ManagedService;
 import org.osgi.service.log.LogService;
@@ -50,18 +51,34 @@
 public class LauncherConfigurationServiceImpl implements 
LauncherConfigurationService, ManagedService {
     // Statics
     private static final String STORAGE_CONF_SOURCE = "conf/cassandra.yaml";
+    private static final String LOG4J_SERVER_PROPERTIES = 
"conf/log4j-server.properties";
 
     // (Reasonable) defaults
     private static final int DEFAULT_RPC_PORT = 9160;
     private static final int DEFAULT_STORAGE_PORT = 9160;
     private static final String DEFAULT_LISTEN_ADDRESS = "127.0.0.1";
     private static final String DEFAULT_CLUSTER_NAME = "Amdatu Cluster";
+    private static final String DEFAULT_JAVA_OPTS = ""
+        + "-Xms1G -Xmx1G -XX:+HeapDumpOnOutOfMemoryError -XX:+UseParNewGC "
+        + "-XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled 
-XX:SurvivorRatio=8 -XX:MaxTenuringThreshold=1 "
+        + "-XX:CMSInitiatingOccupancyFraction=75 
-XX:+UseCMSInitiatingOccupancyOnly";
+    private static final String DEFAULT_SYSTEM_PROPERTIES = ""
+        + "-Dlog4j.configuration=log4j-server.properties 
-Dlog4j.defaultInitOverride=true "
+        + "-Dcassandra -Dcassandra-foreground=yes";
+    private static final int DEFAULT_JMX_PORT = -1; // -1 means disabled
+    private static boolean DEFAULT_JMX_SSL = false;
+    private static boolean DEFAULT_JMX_AUTHENTICATE = false;
+    private static String DEFAULT_COMMITLOG_DIR = "work/cassandra/commitlog";
+    private static String DEFAULT_DATAFILE_DIR = "work/cassandra/data";
+    private static String DEFAULT_SAVEDCACHED_DIR = 
"work/cassandra/saved_caches";
+    private static String DEFAULT_SYSTEMLOG_DIR = "work/cassandra/log";
 
     // Reference to the LogService
     private volatile LogService m_logService;
     private volatile TemplateEngine m_templateEngine;
     private volatile BundleContext m_bundleContext;
     private volatile DependencyManager m_dm;
+    private volatile ConfigurationAdmin m_configAdmin;
 
     // Private members
     @SuppressWarnings("rawtypes")
@@ -70,6 +87,18 @@
     private int m_rpcPort;
     private int m_storagePort;
     private String m_clusterName;
+    private String m_javaOpts;
+    private String m_systemProperties;
+    private int m_jmxPort;
+    private boolean m_jmxSsl;
+    private boolean m_jmxAuthenticate;
+    private String m_downloadVersion;
+    private String m_downloadUrl;
+    private String m_installedVersion;
+    private String m_commitLogDir;
+    private String m_dataFileDir;
+    private String m_savedCachesDir;
+    private String m_systemLogDirectory;
 
     /**
      * The init() method is invoked by the Felix dependency manager. It allows 
us to initialize our service.
@@ -94,9 +123,13 @@
     public void updated(final Dictionary dictionary) throws 
ConfigurationException {
         if (dictionary != null) {
             m_properties = dictionary;
+            // FIXME: workdir can be removed????
             if (dictionary.get(CONFIG_WORKDIR) == null) {
                 throw new ConfigurationException("Missing configuration key", 
CONFIG_WORKDIR);
             }
+            m_commitLogDir = getString(dictionary, COMMITLOG_DIR, 
DEFAULT_COMMITLOG_DIR);
+            m_dataFileDir = getString(dictionary, DATAFILE_DIR, 
DEFAULT_DATAFILE_DIR);
+            m_savedCachesDir = getString(dictionary, SAVEDCACHES_DIR, 
DEFAULT_SAVEDCACHED_DIR);
             m_rpcAddress = getString(dictionary, RPC_ADDRESS, "");
             if (m_rpcAddress.isEmpty()) {
                 m_rpcAddress = getString(dictionary, LISTEN_ADDRESS, 
DEFAULT_LISTEN_ADDRESS);
@@ -104,6 +137,17 @@
             m_rpcPort = getInt(dictionary, RPC_PORT, DEFAULT_RPC_PORT, true);
             m_storagePort = getInt(dictionary, STORAGE_PORT, 
DEFAULT_STORAGE_PORT, true);
             m_clusterName = getString(dictionary, CLUSTER_NAME, 
DEFAULT_CLUSTER_NAME);
+            m_javaOpts = getString(dictionary, JAVA_OPTS, DEFAULT_JAVA_OPTS);
+            m_systemProperties = getString(dictionary, SYSTEM_PROPERTIES, 
DEFAULT_SYSTEM_PROPERTIES);
+            m_jmxPort = getInt(dictionary, JMX_PORT, DEFAULT_JMX_PORT, false);
+            m_jmxSsl = getBoolean(dictionary, JMX_SSL, DEFAULT_JMX_SSL, false);
+            m_jmxAuthenticate = getBoolean(dictionary, JMX_AUTHENTICATE, 
DEFAULT_JMX_AUTHENTICATE, false);
+            // FIXME: temp fix, config files not picked up using old 
fileinstall
+            m_downloadVersion = "1.1.0"; // getString(dictionary, 
DOWNLOAD_VERSION, null);
+            m_downloadUrl = 
"http://apache.cs.uu.nl/dist/cassandra/1.1.0/apache-cassandra-1.1.0-bin.tar.gz";;
+            // getString(dictionary, DOWNLOAD_URL, null);
+            m_installedVersion = getString(dictionary, INSTALLED_VERSION, 
null);
+            m_systemLogDirectory = getString(dictionary, SYSTEMLOG_DIR, 
DEFAULT_SYSTEMLOG_DIR);
         }
     }
 
@@ -119,6 +163,21 @@
     }
 
     @SuppressWarnings("rawtypes")
+    private boolean getBoolean(final Dictionary dictionary, final String key, 
final boolean defaultValue,
+        final boolean log) {
+        Object value = dictionary.get(key);
+        if (value == null) {
+            if (log) {
+                String msg =
+                    "No value set for property '" + key + "', switching to 
default value '" + defaultValue + "'";
+                log(msg);
+            }
+            return defaultValue;
+        }
+        return "true".equalsIgnoreCase(value.toString().trim());
+    }
+
+    @SuppressWarnings("rawtypes")
     private int getInt(final Dictionary dictionary, final String key, final 
int defaultValue, final boolean log) {
         Object value = dictionary.get(key);
         if (value == null) {
@@ -157,11 +216,66 @@
         return m_clusterName;
     }
 
+    public String getJavaOpts() {
+        return m_javaOpts;
+    }
+
+    public String getSystemProperties() {
+        return m_systemProperties;
+    }
+
+    public int getJmxPort() {
+        return m_jmxPort;
+    }
+
+    public boolean isJmxSsl() {
+        return m_jmxSsl;
+    }
+
+    public boolean isJmxAuthenticate() {
+        return m_jmxAuthenticate;
+    }
+
+    public String getDownloadUrl() {
+        return m_downloadUrl;
+    }
+
+    public String getDownloadversion() {
+        return m_downloadVersion;
+    }
+
+    public String getInstalledVersion() {
+        return m_installedVersion;
+    }
+
+    public boolean isUpdateRequired() {
+        if (m_installedVersion == null || 
!m_installedVersion.trim().equals(m_downloadVersion.trim())) {
+            return true;
+        }
+
+        // If installed version is not null and equals download version, 
verify that the directory exists
+        File cassandraHome = m_bundleContext.getDataFile("cassandra-" + 
m_installedVersion);
+        return !cassandraHome.exists();
+    }
+
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    public void updateInstalledVersion(String version) {
+        try {
+            Configuration config = 
m_configAdmin.getConfiguration(LauncherConfigurationService.PID);
+            Dictionary properties = config.getProperties();
+            properties.put(INSTALLED_VERSION, version);
+            config.update(properties);
+            m_installedVersion = version;
+        }
+        catch (IOException e) {
+            m_logService.log(LogService.LOG_ERROR, "Could not update 
installed_version.", e);
+        }
+    }
+
     @SuppressWarnings("rawtypes")
     public void writeCassandraYaml(File targetFile) throws IOException, 
URISyntaxException, TemplateException {
         // Create & fill the context
         TemplateContext context = m_templateEngine.createContext();
-        File sourceFile = new 
File(targetFile.getParentFile().getAbsolutePath(), targetFile.getName() + 
".tmp");
 
         // Copy all properties from config admin
         Enumeration keys = m_properties.keys();
@@ -171,12 +285,38 @@
             context.put(key.toString(), value.toString());
         }
 
+        // Overrule dirs to append workdir (one directory up)
+        String workDir = m_bundleContext.getDataFile("").getAbsolutePath();
+        context.put(COMMITLOG_DIR, (workDir + File.separator + 
m_commitLogDir).replace("\\", "/"));
+        context.put(DATAFILE_DIR, (workDir + File.separator + 
m_dataFileDir).replace("\\", "/"));
+        context.put(SAVEDCACHES_DIR, (workDir + File.separator + 
m_savedCachesDir).replace("\\", "/"));
+
+        // Let the velocity processor replace the config entries and write the 
result
+        processConfigFile(STORAGE_CONF_SOURCE, targetFile, context);
+    }
+
+    public void writeLog4jServerProperties(File targetFile) throws 
IOException, URISyntaxException, TemplateException {
+        // Create & fill the context
+        TemplateContext context = m_templateEngine.createContext();
+        String workDir = m_bundleContext.getDataFile("").getAbsolutePath();
+        String dir =
+            (workDir + File.separator + m_systemLogDirectory + File.separator 
+ "system.log").replace("\\", "/");
+        context.put(SYSTEMLOG_DIR, dir);
+
+        // Set system_log dir property
+        processConfigFile(LOG4J_SERVER_PROPERTIES, targetFile, context);
+    }
+
+    private void processConfigFile(String sourceConfig, File targetFile, 
TemplateContext context)
+        throws TemplateException,
+        IOException {
         // First write the source file to a temporary file
-        Bundle bundle = m_bundleContext.getBundle();
-        toTempFile(bundle.getResource(STORAGE_CONF_SOURCE), sourceFile);
+        File sourceFile = new 
File(targetFile.getParentFile().getAbsolutePath(), targetFile.getName() + 
".tmp");
+        URL sourceURL = m_bundleContext.getBundle().getResource(sourceConfig);
+        toTempFile(sourceURL, sourceFile);
 
         // Create the processor using an input file
-        TemplateProcessor processor = 
m_templateEngine.createProcessor(bundle.getResource(STORAGE_CONF_SOURCE));
+        TemplateProcessor processor = 
m_templateEngine.createProcessor(sourceURL);
 
         // Process the input file and write the result to an output file
         processor.generateFile(context, targetFile);
@@ -185,7 +325,8 @@
         sourceFile.delete();
 
         m_logService
-            .log(LogService.LOG_INFO, "Cassandra.yaml written successfully to 
'" + targetFile.getAbsolutePath());
+            .log(LogService.LOG_INFO, "Config file '" + targetFile.getName() + 
"' successfully written to '"
+                + targetFile.getAbsolutePath());
     }
 
     private void toTempFile(URL url, File targetFile) throws IOException {

Modified: 
trunk/amdatu-cassandra/cassandra-launcher/src/main/java/org/amdatu/cassandra/launcher/service/LauncherServiceImpl.java
==============================================================================
--- 
trunk/amdatu-cassandra/cassandra-launcher/src/main/java/org/amdatu/cassandra/launcher/service/LauncherServiceImpl.java
      (original)
+++ 
trunk/amdatu-cassandra/cassandra-launcher/src/main/java/org/amdatu/cassandra/launcher/service/LauncherServiceImpl.java
      Mon Jun  4 14:54:04 2012
@@ -24,8 +24,10 @@
 import java.io.IOException;
 import java.net.URISyntaxException;
 import java.net.URL;
+import java.util.ArrayList;
 import java.util.Dictionary;
 import java.util.Hashtable;
+import java.util.List;
 
 import org.apache.ace.processlauncher.ProcessLauncherService;
 import org.apache.commons.io.FileUtils;
@@ -42,12 +44,6 @@
  */
 @SuppressWarnings("unchecked")
 public class LauncherServiceImpl {
-    // FIXME: this URL should be configurable. This service should become a 
ManagedService
-    // with some new PID like 'org.amdatu.cassandra.launcher' providing all 
config properties
-    // for the externally launched cassandra.
-    private static final String DOWNLOAD_URL =
-        
"http://apache.cs.uu.nl/dist/cassandra/1.1.0/apache-cassandra-1.1.0-bin.tar.gz";;
-
     private volatile BundleContext m_bundleContext;
     private volatile LogService m_logService;
     private volatile ConfigurationAdmin m_configAdmin;
@@ -57,50 +53,36 @@
 
     @SuppressWarnings("rawtypes")
     public void start() {
-        m_logService.log(LogService.LOG_INFO, "Starting Cassandra 
instance...");
         File dir = m_bundleContext.getDataFile("");
 
         // Step 1. Install and configure Cassandra
         // Step 1a. Find the cassandra.bat. If it is not found, we assume 
Cassandra is not yet installed
         // and we install it
-        if (findFile(dir, "cassandra.bat") == null) {
-            // Step 1b. Download and unzip the Cassandra distribution
-            try {
-                File downloadedFile = download(dir);
-                decompress(downloadedFile);
+        if (m_configService.isUpdateRequired()) {
+            if (installUpdate()) {
+                // Step 1b. Update installed version
+                
m_configService.updateInstalledVersion(m_configService.getDownloadversion());
             }
-            catch (IOException e) {
-                m_logService.log(LogService.LOG_ERROR, "Unable to download and 
decompress file from '" + DOWNLOAD_URL
-                    + "', Cassandra could not be started.", e);
+            else {
+                // Update failed, log error and exit
+                m_logService.log(LogService.LOG_ERROR,
+                    "Installation of Cassandra version '" + 
m_configService.getDownloadversion()
+                        + "' failed. Cassandr acould not be started.");
                 return;
-            }
-
-            // Step 1c. Find the cassandra.yaml and update it
-            File yaml = findFile(dir, "cassandra.yaml");
-            try {
-                m_configService.writeCassandraYaml(yaml);
-            }
-            catch (IOException e) {
-                m_logService.log(LogService.LOG_ERROR, "Unable to update 
cassandra.yaml", e);
-            }
-            catch (URISyntaxException e) {
-                m_logService.log(LogService.LOG_ERROR, "Unable to update 
cassandra.yaml", e);
-            }
-            catch (TemplateException e) {
-                m_logService.log(LogService.LOG_ERROR, "Unable to update 
cassandra.yaml", e);
-            }
+            }   
         }
+        else {
+            m_logService.log(LogService.LOG_INFO, "Existing Cassandra 
installation found. Installed version: "
+                + m_configService.getInstalledVersion());
+        }
+
+        // The target directory is 'cassandra-[installed_version]'
+        String installedVersion = m_configService.getInstalledVersion();
+        File cassandraHome = new File(dir, "cassandra-" + installedVersion);
 
         // Step 2. Run Cassandra
         // Step 2a. Setup the configuration to deploy to the Ace process 
launcher
-        File executable;
-        if (File.separator.equals("\\")) {
-            executable = findFile(dir, "cassandra.bat");
-        }
-        else {
-            executable = findFile(dir, "cassandra.bat");
-        }
-        File cassandraHome = executable.getParentFile().getParentFile();
+
         String exe = buildExecutable(cassandraHome.getAbsolutePath());
 
         Dictionary properties = new Hashtable();
@@ -114,11 +96,16 @@
 
         // Deploy the config
         try {
+            m_logService.log(LogService.LOG_INFO, "Launching Cassandra...");
+            m_logService.log(LogService.LOG_DEBUG, "Executable command:");
+            m_logService.log(LogService.LOG_DEBUG, exe);
             m_config = 
m_configAdmin.createFactoryConfiguration(ProcessLauncherService.PID, null);
             m_config.update(properties);
+            m_logService.log(LogService.LOG_INFO, "Cassandra launched 
successfully.");
         }
         catch (IOException e) {
-            m_logService.log(LogService.LOG_ERROR, "Unable to deploy 
configuration to ace process launcher", e);
+            m_logService.log(LogService.LOG_ERROR,
+                "Unable to deploy configuration to ace process launcher. 
Cassandra could not be launched.", e);
         }
     }
 
@@ -127,6 +114,7 @@
         if (m_config != null) {
             try {
                 m_config.delete();
+                m_logService.log(LogService.LOG_INFO, "Cassandra stopped 
successfully.");
             }
             catch (IOException e) {
                 m_logService.log(LogService.LOG_ERROR, "Could not stop 
Cassandra", e);
@@ -134,24 +122,103 @@
         }
     }
 
-    private File download(File targetDir) throws IOException {
-        String fileName = 
DOWNLOAD_URL.substring(DOWNLOAD_URL.lastIndexOf("/"));
+    private boolean installUpdate() {
+        // Step 1b. Log info about the update
+        File dir = m_bundleContext.getDataFile("");
+        String downloadUrl = m_configService.getDownloadUrl();
+        String downloadVersion = m_configService.getDownloadversion();
+        String installedVersion = m_configService.getInstalledVersion();
+        String msg = "Cassandra update required. Installed version: ";
+        if (installedVersion == null) {
+            msg += "[none], ";
+        }
+        else {
+            msg += installedVersion + ", ";
+        }
+        msg += "target version: " + downloadVersion + ".";
+        m_logService.log(LogService.LOG_INFO, msg);
+
+        m_logService.log(LogService.LOG_INFO, "Downloading Cassandra from '" + 
downloadUrl + "'...");
+
+        // Step 1c. Download and unzip the Cassandra distribution
+        try {
+            File downloadedFile = download(downloadUrl, dir);
+            m_logService.log(LogService.LOG_INFO, "Download finished 
successfully.");
+            m_logService.log(LogService.LOG_INFO, "Deflating file...");
+
+            // The tmp directory is 'cassandra-[installed_version]-tmp'
+            File tmpDir = new File(dir, "cassandra-" + downloadVersion + 
"-tmp");
+            tmpDir.mkdirs();
+            File deflatedDir = decompress(downloadedFile, tmpDir);
+
+            // Now move the deflated stuff to the proper directory
+            File srcDir = findFile(deflatedDir, 
"cassandra.bat").getParentFile().getParentFile();
+
+            // The target directory is 'cassandra-[installed_version]'
+            File targetDir = new File(dir, "cassandra-" + downloadVersion);
+            srcDir.renameTo(targetDir);
+            FileUtils.deleteDirectory(tmpDir);
+            m_logService.log(LogService.LOG_INFO, "Deflating finished 
successfully.");
+        }
+        catch (IOException e) {
+            m_logService.log(LogService.LOG_ERROR, "Unable to download and 
decompress file from '" + downloadUrl
+                + "', Cassandra could not be started.", e);
+            return false;
+        }
+
+        // Step 1d. Find the cassandra.yaml and log4jserver.properties files 
and update them
+        try {
+            File yaml = findFile(dir, "cassandra.yaml");
+            m_logService.log(LogService.LOG_INFO, "Updating 
cassandra.yaml...");
+            m_configService.writeCassandraYaml(yaml);
+            m_logService.log(LogService.LOG_INFO, "Cassandra.yaml updated 
successfully.");
+
+            File log4j = findFile(dir, "log4j-server.properties");
+            m_logService.log(LogService.LOG_INFO, "Updating 
log4j-server.properties...");
+            m_configService.writeLog4jServerProperties(log4j);
+            m_logService.log(LogService.LOG_INFO, "log4j-server.properties 
updated successfully.");
+        }
+        catch (IOException e) {
+            m_logService.log(LogService.LOG_ERROR, "Unable to update 
configuration file.", e);
+            return false;
+        }
+        catch (URISyntaxException e) {
+            m_logService.log(LogService.LOG_ERROR, "Unable to update 
configuration file.", e);
+            return false;
+        }
+        catch (TemplateException e) {
+            m_logService.log(LogService.LOG_ERROR, "Unable to update 
configuration file.", e);
+            return false;
+        }
+
+        // If we reach this code, update is a complete success
+        return true;
+    }
+
+    private File download(String sDownloadUrl, File targetDir) throws 
IOException {
+        String fileName = 
sDownloadUrl.substring(sDownloadUrl.lastIndexOf("/"));
         File targetFile = new File(targetDir, fileName);
-        URL downloadUrl = new URL(DOWNLOAD_URL);
-        m_logService.log(LogService.LOG_INFO, "Downloading '" + DOWNLOAD_URL + 
"' to '" + targetFile.getAbsolutePath()
+        URL downloadUrl = new URL(sDownloadUrl);
+        m_logService.log(LogService.LOG_INFO, "Downloading '" + sDownloadUrl + 
"' to '" + targetFile.getAbsolutePath()
             + "'");
         FileUtils.copyURLToFile(downloadUrl, targetFile);
         m_logService.log(LogService.LOG_INFO, "File downloaded successfully");
         return targetFile;
     }
 
-    private File decompress(File file) throws IOException {
+    private File decompress(File file, File targetDir) throws IOException {
         File currentFile = file;
+        List<File> deleteFiles = new ArrayList<File>();
         if (currentFile.getName().endsWith(".tar.gz")) {
-            currentFile = CompressionUtil.decompressGz(currentFile);
+            deleteFiles.add(currentFile);
+            currentFile = CompressionUtil.decompressGz(currentFile, targetDir);
         }
         if (currentFile.getName().endsWith(".tar")) {
-            currentFile = CompressionUtil.decompressTar(currentFile);
+            deleteFiles.add(currentFile);
+            currentFile = CompressionUtil.decompressTar(currentFile, 
targetDir);
+        }
+        for (File deleteFile : deleteFiles) {
+            deleteFile.delete();
         }
         return currentFile;
     }
@@ -177,23 +244,35 @@
     }
 
     private String buildExecutable(String cassandraHome) {
-        // FIXME: all these options should be configurable. This service 
should become a ManagedService
-        // with some new PID like 'org.amdatu.cassandra.launcher' providing 
all config properties
-        // for the externally launched cassandra.
+        String javaOpts = m_configService.getJavaOpts();
+        String systemProperties = m_configService.getSystemProperties();
+        int jmxPort = m_configService.getJmxPort();
+        String jmx = null;
+        if (jmxPort != -1) {
+            jmx = "-Dcom.sun.management.jmxremote.port=" + jmxPort;
+            jmx += " -Dcom.sun.management.jmxremote.ssl=" + 
m_configService.isJmxSsl();
+            jmx += " -Dcom.sun.management.jmxremote.authenticate=" + 
m_configService.isJmxAuthenticate();
+        }
+
+        // Prepare java executable command
         String sep = File.separator;
         String javaHome = System.getProperty("java.home");
         StringBuffer exe = new StringBuffer();
         exe.append("\"" + javaHome + sep + "bin" + sep + "java" + "\" "); // 
java executable
-        exe.append("-ea -javaagent:" + cassandraHome + sep + "lib" + sep + 
"jamm-0.2.5.jar "); // javaagent
-        exe.append("-Xms1G -Xmx1G -XX:+HeapDumpOnOutOfMemoryError "); // heap
-        exe.append("-XX:+UseParNewGC -XX:+UseConcMarkSweepGC "); // garbage 
collector
-        exe.append("-XX:+CMSParallelRemarkEnabled -XX:SurvivorRatio=8 
-XX:MaxTenuringThreshold=1 ");
-        exe.append("-XX:CMSInitiatingOccupancyFraction=75 
-XX:+UseCMSInitiatingOccupancyOnly ");
-        exe.append("-Dcom.sun.management.jmxremote.port=7199 
-Dcom.sun.management.jmxremote.ssl=false "); // JMX
-        exe.append("-Dcom.sun.management.jmxremote.authenticate=false ");
-        exe.append("-Dlog4j.configuration=log4j-server.properties 
-Dlog4j.defaultInitOverride=true "); // log4j
-        exe.append("-Dcassandra -Dcassandra-foreground=yes "); // cassandra 
opts
-        exe.append("-cp " + buildClasspath(cassandraHome));
+        exe.append("-ea -javaagent:\"" + cassandraHome + sep + "lib" + sep + 
"jamm-0.2.5.jar\""); // javaagent
+
+        // Append java options
+        exe.append(" " + javaOpts);
+
+        // Append system properties
+        exe.append(" " + systemProperties);
+
+        // Append JMX options
+        if (jmx != null) {
+            exe.append(" " + jmx);
+        }
+
+        exe.append(" -cp " + buildClasspath(cassandraHome));
         exe.append(" \"org.apache.cassandra.thrift.CassandraDaemon\"");
         return exe.toString();
     }

Modified: 
trunk/amdatu-cassandra/cassandra-launcher/src/main/java/org/amdatu/cassandra/launcher/service/ProcessStreamListenerImpl.java
==============================================================================
--- 
trunk/amdatu-cassandra/cassandra-launcher/src/main/java/org/amdatu/cassandra/launcher/service/ProcessStreamListenerImpl.java
        (original)
+++ 
trunk/amdatu-cassandra/cassandra-launcher/src/main/java/org/amdatu/cassandra/launcher/service/ProcessStreamListenerImpl.java
        Mon Jun  4 14:54:04 2012
@@ -49,7 +49,9 @@
     }
     
     private void dispatchInput() {
-        // FIXME: output should be disptached to LogService instead of 
System.out
+        // FIXME: output should be dispatched to LogService instead of 
System.out but that will
+        // be difficult since this class is instantiated by the launcher. For 
now we dispatch simply
+        // to System.out
         new Thread(new Runnable() {
             public void run() {
                 try {

Added: 
trunk/amdatu-cassandra/cassandra-launcher/src/main/resources/conf/log4j-server.properties
==============================================================================
--- (empty file)
+++ 
trunk/amdatu-cassandra/cassandra-launcher/src/main/resources/conf/log4j-server.properties
   Mon Jun  4 14:54:04 2012
@@ -0,0 +1,44 @@
+# 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.
+
+# for production, you should probably set pattern to %c instead of %l.
+# (%l is slower.)
+
+# output messages into a rolling log file as well as stdout
+log4j.rootLogger=INFO,stdout,R
+
+# stdout
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%5p %d{HH:mm:ss,SSS} %m%n
+
+# rolling log file
+log4j.appender.R=org.apache.log4j.RollingFileAppender
+log4j.appender.R.maxFileSize=20MB
+log4j.appender.R.maxBackupIndex=50
+log4j.appender.R.layout=org.apache.log4j.PatternLayout
+log4j.appender.R.layout.ConversionPattern=%5p [%t] %d{ISO8601} %F (line %L) 
%m%n
+# Edit the next line to point to your logs directory
+log4j.appender.R.File=${systemlog_dir}
+
+# Application logging options
+#log4j.logger.org.apache.cassandra=DEBUG
+#log4j.logger.org.apache.cassandra.db=DEBUG
+#log4j.logger.org.apache.cassandra.service.StorageProxy=DEBUG
+
+# Adding this to avoid thrift logging disconnect errors.
+log4j.logger.org.apache.thrift.server.TNonblockingServer=ERROR
+

Modified: 
trunk/amdatu-cassandra/config/src/main/resources/amdatu.cassandra.launcher.config.xml
==============================================================================
--- 
trunk/amdatu-cassandra/config/src/main/resources/amdatu.cassandra.launcher.config.xml
       (original)
+++ 
trunk/amdatu-cassandra/config/src/main/resources/amdatu.cassandra.launcher.config.xml
       Mon Jun  4 14:54:04 2012
@@ -12,6 +12,18 @@
     <AD id="rpc_address" type="STRING" cardinality="0" />
     <AD id="rpc_port" type="STRING" cardinality="0" />
     <AD id="storage_port" type="STRING" cardinality="0" />
+
+    <AD id="java_opts" type="STRING" cardinality="0" />
+    <AD id="system_properties" type="STRING" cardinality="0" />
+    <AD id="jmx_port" type="INTEGER" cardinality="0" default="7199"/>
+    <AD id="jmx_ssl" type="BOOLEAN" cardinality="0" default="false"/>
+    <AD id="jmx_authenticate" type="BOOLEAN" cardinality="0" default="false"/>
+
+    <AD id="installed_version" type="STRING" cardinality="0"/>
+    <AD id="download_version" type="STRING" cardinality="0" />
+    <AD id="download_url" type="STRING" cardinality="0" />
+
+    <AD id="systemlog_dir" type="STRING" cardinality="0" />
   </OCD>
   <Designate pid="org.amdatu.cassandra.launcher" bundle="*">
     <Object ocdref="org.amdatu.cassandra.launcher">
@@ -48,6 +60,36 @@
       <Attribute adref="storage_port">
         <Value>7000</Value>
       </Attribute>
+
+      <Attribute adref="java_opts">
+        <Value>-Xms1G -Xmx1G -XX:+HeapDumpOnOutOfMemoryError -XX:+UseParNewGC 
-XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled -XX:SurvivorRatio=8 
-XX:MaxTenuringThreshold=1 -XX:CMSInitiatingOccupancyFraction=75 
-XX:+UseCMSInitiatingOccupancyOnly</Value>
+      </Attribute>
+      <Attribute adref="system_properties">
+        <Value>-Dlog4j.configuration=log4j-server.properties 
-Dlog4j.defaultInitOverride=true -Dcassandra -Dcassandra-foreground=yes</Value>
+      </Attribute>
+      <Attribute adref="jmx_port">
+        <Value>-1</Value>
+      </Attribute>
+      <Attribute adref="jmx_ssl">
+        <Value>false</Value>
+      </Attribute>
+      <Attribute adref="jmx_authenticate">
+        <Value>false</Value>
+      </Attribute>
+
+      <Attribute adref="installed_version">
+        <Value></Value>
+      </Attribute>
+      <Attribute adref="download_version">
+        <Value>1.1.0</Value>
+      </Attribute>
+      <Attribute adref="download_url">
+        
<Value>http://apache.cs.uu.nl/dist/cassandra/1.1.0/apache-cassandra-1.1.0-bin.tar.gz</Value>
+      </Attribute>
+
+      <Attribute adref="systemlog_dir">
+        <Value>work/cassandra/log</Value>
+      </Attribute>
     </Object>
   </Designate>
 </MetaData>
_______________________________________________
Amdatu-commits mailing list
[email protected]
http://lists.amdatu.org/mailman/listinfo/amdatu-commits

Reply via email to