Author: ivol37 at gmail.com
Date: Thu Jan 6 17:47:21 2011
New Revision: 573
Log:
[AMDATU-243] Enhanced config template manager with pluggable callback handler.
This was required since the new 'seeds' property is a multi-value field with
different syntax in the cassandra.yaml. Furthermore, moved cluster related
configruation to ConfigurationAdmin.
Added:
trunk/amdatu-core/config-templates/src/main/java/org/amdatu/core/config/templates/ConfigTemplateCallbackHandler.java
Modified:
trunk/amdatu-cassandra/cassandra-application/src/main/java/org/amdatu/cassandra/application/CassandraConfigurationService.java
trunk/amdatu-cassandra/cassandra-application/src/main/java/org/amdatu/cassandra/application/service/CassandraConfigurationServiceImpl.java
trunk/amdatu-cassandra/cassandra-application/src/main/java/org/amdatu/cassandra/application/service/CassandraDaemonServiceImpl.java
trunk/amdatu-cassandra/cassandra-application/src/main/resources/conf/cassandra.yaml
trunk/amdatu-core/config-filebased/src/main/resources/conf/org.amdatu.core.cassandra.application.cfg
trunk/amdatu-core/config-templates/src/main/java/org/amdatu/core/config/templates/ConfigTemplateManager.java
trunk/amdatu-core/config-templates/src/main/java/org/amdatu/core/config/templates/service/ConfigTemplateManagerImpl.java
Modified:
trunk/amdatu-cassandra/cassandra-application/src/main/java/org/amdatu/cassandra/application/CassandraConfigurationService.java
==============================================================================
---
trunk/amdatu-cassandra/cassandra-application/src/main/java/org/amdatu/cassandra/application/CassandraConfigurationService.java
(original)
+++
trunk/amdatu-cassandra/cassandra-application/src/main/java/org/amdatu/cassandra/application/CassandraConfigurationService.java
Thu Jan 6 17:47:21 2011
@@ -41,4 +41,10 @@
* Configuration key for the working directory to use for Cassandra
*/
public static final String CONFIG_WORKDIR = "workdir";
+
+ /**
+ * Configuration key that stores a list of IP addresses that are part of
this cluster. The IP addresses
+ * are stored comma separated in ConfigurationAdmin.
+ */
+ public static final String SEEDS = "seeds";
}
Modified:
trunk/amdatu-cassandra/cassandra-application/src/main/java/org/amdatu/cassandra/application/service/CassandraConfigurationServiceImpl.java
==============================================================================
---
trunk/amdatu-cassandra/cassandra-application/src/main/java/org/amdatu/cassandra/application/service/CassandraConfigurationServiceImpl.java
(original)
+++
trunk/amdatu-cassandra/cassandra-application/src/main/java/org/amdatu/cassandra/application/service/CassandraConfigurationServiceImpl.java
Thu Jan 6 17:47:21 2011
@@ -22,6 +22,7 @@
import java.util.Dictionary;
import org.amdatu.cassandra.application.CassandraConfigurationService;
+import org.amdatu.core.config.templates.ConfigTemplateCallbackHandler;
import org.amdatu.core.config.templates.ConfigTemplateManager;
import org.apache.log4j.PropertyConfigurator;
import org.osgi.framework.Bundle;
@@ -39,6 +40,7 @@
// Statics
private static final String STORAGE_CONF_SOURCE = "conf/cassandra.yaml";
private static final String LOG4J_CONF_SOURCE = "conf/log4j.properties";
+ private static final String EOL = System.getProperty("line.separator");
// Reference to the logservice
private volatile LogService m_logService;
@@ -64,7 +66,7 @@
try {
if (!storageConfigFile.exists()) {
// Only write this file if it does not yet exist
- m_configTemplateManager.writeConfiguration(url,
storageConfigFile);
+ m_configTemplateManager.writeConfiguration(url,
storageConfigFile, new CassandraCallbackHandler());
}
// Cassandra uses this system property to find its storage
location.
System.setProperty("cassandra.config",
storageConfigFile.toURI().toString());
@@ -102,4 +104,22 @@
m_workDir = new File(workBaseDir, (String)
dictionary.get(CONFIG_WORKDIR));
}
}
+
+ class CassandraCallbackHandler implements ConfigTemplateCallbackHandler {
+ public String getValue(String pid, String property, Object
configValue) {
+ if (CassandraConfigurationService.PID.equals(pid) &&
CassandraConfigurationService.SEEDS.equals(property)) {
+ // We must convert the comma separated list of IP addresses to
the cassandra yaml format
+ String[] seeds = configValue.toString().split(",");
+ String result = "";
+ for (String seed : seeds) {
+ result += EOL + "- " + seed;
+ }
+ return result;
+ } else {
+ // Return the value as-is
+ return configValue.toString();
+ }
+ }
+
+ }
}
Modified:
trunk/amdatu-cassandra/cassandra-application/src/main/java/org/amdatu/cassandra/application/service/CassandraDaemonServiceImpl.java
==============================================================================
---
trunk/amdatu-cassandra/cassandra-application/src/main/java/org/amdatu/cassandra/application/service/CassandraDaemonServiceImpl.java
(original)
+++
trunk/amdatu-cassandra/cassandra-application/src/main/java/org/amdatu/cassandra/application/service/CassandraDaemonServiceImpl.java
Thu Jan 6 17:47:21 2011
@@ -82,10 +82,9 @@
if (m_daemonHasShutdown) {
throw new RuntimeException("CassandraDaemon has already been
shutdown and cannot be restarted.");
}
-
m_daemon.activate();
m_cassandraServer = new CassandraServer();
- m_logService.log(LogService.LOG_INFO, "Cassandra Daemon started.
State="+ m_cassandraServer.state());
+ m_logService.log(LogService.LOG_INFO, "Cassandra Daemon started.");
}
public void stop() {
Modified:
trunk/amdatu-cassandra/cassandra-application/src/main/resources/conf/cassandra.yaml
==============================================================================
---
trunk/amdatu-cassandra/cassandra-application/src/main/resources/conf/cassandra.yaml
(original)
+++
trunk/amdatu-cassandra/cassandra-application/src/main/resources/conf/cassandra.yaml
Thu Jan 6 17:47:21 2011
@@ -1,13 +1,13 @@
-# Cassandra storage config YAML
+# Cassandra storage config YAML
-#NOTE !!!!!!!! NOTE
+#NOTE !!!!!!!! NOTE
# See http://wiki.apache.org/cassandra/StorageConfiguration for
# full explanations of configuration directives
-#NOTE !!!!!!!! NOTE
+#NOTE !!!!!!!! NOTE
# The name of the cluster. This is mainly used to prevent machines in
# one logical cluster from joining another.
-cluster_name: 'Amdatu Cluster'
+cluster_name: ${org.amdatu.core.cassandra.application/clustername}
# You should always specify InitialToken when setting up a production
# cluster for the first time, and often when adding capacity later.
@@ -51,17 +51,17 @@
# directories where Cassandra should store data on disk.
data_file_directories:
- ${org.amdatu.core.cassandra.application/datafiledir}
-
+
# commit log
commitlog_directory: ${org.amdatu.core.cassandra.application/commitlogdir}
# saved caches
saved_caches_directory: ${org.amdatu.core.cassandra.application/savedcachesdir}
-# Size to allow commitlog to grow to before creating a new segment
+# Size to allow commitlog to grow to before creating a new segment
commitlog_rotation_threshold_in_mb: 128
-# commitlog_sync may be either "periodic" or "batch."
+# commitlog_sync may be either "periodic" or "batch."
# When in batch mode, Cassandra won't ack writes until the commit log
# has been fsynced to disk. It will wait up to
# CommitLogSyncBatchWindowInMS milliseconds for other writes, before
@@ -73,12 +73,11 @@
# milliseconds.
commitlog_sync_period_in_ms: 10000
-# Addresses of hosts that are deemed contact points.
+# Addresses of hosts that are deemed contact points.
# Cassandra nodes use this list of hosts to find each other and learn
# the topology of the ring. You must change this if you are running
# multiple nodes!
-seeds:
- - 127.0.0.1
+seeds: ${org.amdatu.core.cassandra.application/seeds}
# Access mode. mmapped i/o is substantially faster, but only practical on
# a 64bit machine (which notably does not include EC2 "small" instances)
@@ -105,7 +104,7 @@
# By default this will be set to the amount of data directories defined.
#memtable_flush_writers: 1
-# Buffer size to use when performing contiguous column slices.
+# Buffer size to use when performing contiguous column slices.
# Increase this to the size of the column slices you typically perform
sliced_buffer_size_in_kb: 64
@@ -115,19 +114,19 @@
# Address to bind to and tell other Cassandra nodes to connect to. You
# _must_ change this if you want multiple nodes to be able to
# communicate!
-#
+#
# Leaving it blank leaves it up to InetAddress.getLocalHost(). This
# will always do the Right Thing *if* the node is properly configured
# (hostname, name resolution, etc), and the Right Thing is to use the
# address associated with the hostname (it might not be).
#
# Setting this to 0.0.0.0 is always wrong.
-listen_address: localhost
+listen_address: ${org.amdatu.core.cassandra.application/listen_address}
# The address to bind the Thrift RPC service to -- clients connect
# here. Unlike ListenAddress above, you *can* specify 0.0.0.0 here if
# you want Thrift to listen on all interfaces.
-#
+#
# Leaving this blank has the same effect it does for ListenAddress,
# (i.e. it will be based on the configured hostname of the node).
rpc_address: localhost
@@ -178,7 +177,7 @@
# will be logged specifying the row key.
in_memory_compaction_limit_in_mb: 64
-# Time to wait for a reply from other nodes before failing the command
+# Time to wait for a reply from other nodes before failing the command
rpc_timeout_in_ms: 10000
# phi value that must be reached for a host to be marked down.
@@ -208,7 +207,7 @@
dynamic_snitch: true
# controls how often to perform the more expensive part of host score
# calculation
-dynamic_snitch_update_interval_in_ms: 100
+dynamic_snitch_update_interval_in_ms: 100
# controls how often to reset all host scores, allowing a bad host to
# possibly recover
dynamic_snitch_reset_interval_in_ms: 600000
@@ -236,7 +235,7 @@
# NoScheduler - Has no options
# RoundRobin
# - throttle_limit -- The throttle_limit is the number of in-flight
-# requests per client. Requests beyond
+# requests per client. Requests beyond
# that limit are queued up until
# running requests can complete.
# The value of 80 here is twice the number of
Modified:
trunk/amdatu-core/config-filebased/src/main/resources/conf/org.amdatu.core.cassandra.application.cfg
==============================================================================
---
trunk/amdatu-core/config-filebased/src/main/resources/conf/org.amdatu.core.cassandra.application.cfg
(original)
+++
trunk/amdatu-core/config-filebased/src/main/resources/conf/org.amdatu.core.cassandra.application.cfg
Thu Jan 6 17:47:21 2011
@@ -8,4 +8,30 @@
datafiledir=work/cassandra/data
# Directory in which the caches are saved
-savedcachesdir=work/cassandra/saved_caches
\ No newline at end of file
+savedcachesdir=work/cassandra/saved_caches
+
+
+
+###############################
+# Clustering related properties
+###############################
+
+# Name of the Cassandra cluster to join. If a seed is defined in the 'seeds'
property
+# that defines a different clustername, a clustername mismatch error will be
displayed
+# and that seed will not become part of this cluster.
+clustername='Amdatu Cluster'
+
+# Comma separated list of IP addresses of nodes in the cluster to connect to.
+# Note that does not need to be a full listing of all IP addresses of all nodes
+# in the cluster, it may be a subset of it. This property determines with what
+# other nodes in the cluster this node will synchronize its data.
+# When cassandra is executed in stand-alone mode, this value should be
127.0.0.1
+#seeds=127.0.0.1
+seeds=172.16.10.109,172.16.10.203
+
+# The IP address of this node that other cassandra nodes will use to connect
to.
+# This IP address must thus be accessible from the other nodes in the cluster
(to
+# be precise; those that provided this node as one of its seeds).
+# When cassandra is executed in stand-alone mode, this value should be
localhost
+#listen_address=localhost
+listen_address=172.16.11.108
\ No newline at end of file
Added:
trunk/amdatu-core/config-templates/src/main/java/org/amdatu/core/config/templates/ConfigTemplateCallbackHandler.java
==============================================================================
--- (empty file)
+++
trunk/amdatu-core/config-templates/src/main/java/org/amdatu/core/config/templates/ConfigTemplateCallbackHandler.java
Thu Jan 6 17:47:21 2011
@@ -0,0 +1,28 @@
+/*
+ Copyright (C) 2010 Amdatu.org
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.amdatu.core.config.templates;
+
+public interface ConfigTemplateCallbackHandler {
+ /**
+ *
+ * @param pid The PID of the detected configuration entry
+ * @param property The propername of the detected configution entry
+ * @param configValue The value retrieved from ConfigurationAdmin
+ * @return The actual value to replace the placeholder with
+ */
+ String getValue(String pid, String property, Object configValue);
+}
Modified:
trunk/amdatu-core/config-templates/src/main/java/org/amdatu/core/config/templates/ConfigTemplateManager.java
==============================================================================
---
trunk/amdatu-core/config-templates/src/main/java/org/amdatu/core/config/templates/ConfigTemplateManager.java
(original)
+++
trunk/amdatu-core/config-templates/src/main/java/org/amdatu/core/config/templates/ConfigTemplateManager.java
Thu Jan 6 17:47:21 2011
@@ -24,10 +24,10 @@
/**
* The Config Template Manager facilitates automatic replacement of
configuration entries in static plain
* text files (such as text, XML or RDF files). The manager will replace
occurrences of ${[configid]} whenever
- * there is a configuration entry in the ConfigAdminService available matching
[configid]. Several getConfiguration
+ * there is a configuration entry in the ConfigAdminService available matching
[configid]. Several getConfiguration
* methods are available to do this for URLs, Files or StringBuffers.
* When your service needs to act upon when any of the configuration entries
used in your configuration files
- * are changed, you need to register a ConfigTemplateListener.
+ * are changed, you need to register a ConfigTemplateListener.
* @author ivol
*/
public interface ConfigTemplateManager {
@@ -35,9 +35,9 @@
* The PID of the configuration of this bundle.
*/
public final static String PID =
ConfigTemplateManager.class.getPackage().getName();
-
+
/**
- * Replaces all occurrences of configuration entries in the plain text
file pointed to
+ * Replaces all occurrences of configuration entries in the plain text
file pointed to
* by the given URL with the value of these entries from the
ConfigAdminService and returns
* a new URL with the replacements.
* By default the converted configuration file is cached forever. To
remove a URL from the cache,
@@ -47,9 +47,9 @@
* @throws IOException when an exception occurred during building the new
URLof the converted config file
*/
URL getConfigurationAsURL(URL templateURL) throws IOException;
-
+
/**
- * Replaces all occurrences of configuration entries in the plain text
file pointed to
+ * Replaces all occurrences of configuration entries in the plain text
file pointed to
* by the given URL with the value of these entries from the
ConfigAdminService and returns
* the result as StringBuffer with the replacements.
* By default the converted configuration file is cached forever. To
remove a URL from the cache,
@@ -59,9 +59,9 @@
* @throws IOException when an exception occurred during building the new
URLof the converted config file
*/
StringBuffer getConfigurationAsString(URL templateURL) throws IOException;
-
+
/**
- * Replaces all occurrences of configuration entries in the plain text
file pointed to
+ * Replaces all occurrences of configuration entries in the plain text
file pointed to
* by the given URL with the value of these entries from the
ConfigAdminService and writes the
* result to the target file
* @param templateURL The URL to the plain text file to replace
configuration entries in
@@ -70,9 +70,22 @@
* @throws IOException when an exception occurred during writing the
converted config file to disk
*/
void writeConfiguration(URL templateURL, File targetFile) throws
IOException;
-
+
/**
- * Replaces all occurrences of configuration entries in the plain text
file pointed to
+ * Replaces all occurrences of configuration entries in the plain text
file pointed to
+ * by the given URL with the value of these entries from the
ConfigAdminService and writes the
+ * result to the target file
+ * @param templateURL The URL to the plain text file to replace
configuration entries in
+ * @param targetFile The target file to write to
+ * @param handler A custom ConfigTemplateCallbackHandler which will be
invoked when replacing configuration
+ * entries. The callback handler defines the value to replace the
placeholder with
+ * @return true if replacing all configuration entries succeeded, false
otherwise
+ * @throws IOException when an exception occurred during writing the
converted config file to disk
+ */
+ void writeConfiguration(URL templateURL, File targetFile,
ConfigTemplateCallbackHandler handler) throws IOException;
+
+ /**
+ * Replaces all occurrences of configuration entries in the plain text
file pointed to
* by the given URL with the value of these entries from the
ConfigAdminService and writes the
* result to the target file
* @param templateURL The URL to the plain text file to replace
configuration entries in
@@ -81,7 +94,7 @@
* @throws IOException when an exception occurred during writing the
converted config file to disk
*/
void writeConfiguration(URL templateURL, BufferedWriter writer) throws
IOException;
-
+
/**
* Removes the URL from the cache.
* @param templateURL The URL to remove from the cache.
Modified:
trunk/amdatu-core/config-templates/src/main/java/org/amdatu/core/config/templates/service/ConfigTemplateManagerImpl.java
==============================================================================
---
trunk/amdatu-core/config-templates/src/main/java/org/amdatu/core/config/templates/service/ConfigTemplateManagerImpl.java
(original)
+++
trunk/amdatu-core/config-templates/src/main/java/org/amdatu/core/config/templates/service/ConfigTemplateManagerImpl.java
Thu Jan 6 17:47:21 2011
@@ -32,6 +32,7 @@
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import org.amdatu.core.config.templates.ConfigTemplateCallbackHandler;
import org.amdatu.core.config.templates.ConfigTemplateManager;
import org.osgi.service.cm.Configuration;
import org.osgi.service.cm.ConfigurationAdmin;
@@ -45,7 +46,7 @@
*/
public class ConfigTemplateManagerImpl implements ConfigTemplateManager,
ManagedService {
// Regular expression to match configuration entries. Syntax:
${[pid].[configentry]}
- private static final Pattern CONFIG_ENTRY_REGEX =
Pattern.compile("\\$\\{([A-Za-z0-9\\.-])+/([A-Za-z0-9\\.-])+\\}");
+ private static final Pattern CONFIG_ENTRY_REGEX =
Pattern.compile("\\$\\{([A-Za-z0-9\\.-_])+/([A-Za-z0-9\\.-_])+\\}");
// Services injected by the Felix dependency manager
private volatile LogService m_logService;
@@ -94,7 +95,7 @@
return new URL(cachedUrl);
} catch (MalformedURLException e) {
m_logService.log(LogService.LOG_ERROR, "Could not create URL
from cached URI'" + cachedUrl
- + "'. Refreshing cache", e);
+ + "'. Refreshing cache", e);
m_urlCache.remove(templateURL.toString());
}
}
@@ -134,11 +135,15 @@
}
public void writeConfiguration(URL templateURL, File targetFile) throws
IOException {
+ writeConfiguration(templateURL, targetFile, null);
+ }
+
+ public void writeConfiguration(URL templateURL, File targetFile,
ConfigTemplateCallbackHandler handler) throws IOException {
if (!targetFile.exists()) {
if (targetFile.getParentFile() != null &&
!targetFile.getParentFile().exists()) {
if (!targetFile.getParentFile().mkdir()) {
throw new IOException("Could not create parent directory '"
- + targetFile.getParentFile().getAbsolutePath() +
"'");
+ + targetFile.getParentFile().getAbsolutePath() + "'");
}
}
if (!targetFile.createNewFile()) {
@@ -150,7 +155,7 @@
BufferedWriter writer = null;
try {
writer = new BufferedWriter(new FileWriter(targetFile));
- writeConfiguration(templateURL, writer);
+ writeConfiguration(templateURL, writer, handler);
} finally {
if (writer != null) {
writer.close();
@@ -159,6 +164,10 @@
}
public void writeConfiguration(URL templateURL, BufferedWriter writer)
throws IOException {
+ writeConfiguration(templateURL, writer, null);
+ }
+
+ public void writeConfiguration(URL templateURL, BufferedWriter writer,
ConfigTemplateCallbackHandler handler) throws IOException {
// Now write the converted entries to the writer
BufferedReader reader = null;
try {
@@ -168,7 +177,7 @@
String inputLine;
String outputLine;
while ((inputLine = reader.readLine()) != null) {
- outputLine = replaceConfigEntries(inputLine);
+ outputLine = replaceConfigEntries(inputLine, handler);
writer.write(outputLine + "\r\n");
}
} finally {
@@ -192,7 +201,7 @@
if (file.exists()) {
if (!file.delete()) {
m_logService.log(LogService.LOG_INFO, "Failed to remove
file '" + file.getAbsolutePath()
- + "' from cache");
+ + "' from cache");
}
}
}
@@ -212,7 +221,7 @@
* @param line
* @return
*/
- private String replaceConfigEntries(String line) {
+ private String replaceConfigEntries(String line,
ConfigTemplateCallbackHandler handler) {
// For performance reasons, return immediately if the line does not
contain ${
if (line.indexOf("${") == -1) {
return line;
@@ -231,12 +240,17 @@
Object entry = config.getProperties().get(configentry);
if (entry != null) {
String value = entry.toString();
- newLine = newLine.replace(key, value);
+ if (handler != null) {
+ value = handler.getValue(pid, configentry, entry);
+ newLine = newLine.replace(key, value);
+ } else {
+ newLine = newLine.replace(key, value);
+ }
}
}
} catch (IOException e) {
m_logService.log(LogService.LOG_WARNING, "Configuration for
pid '" + pid
- + "' does not exist, entry ignored", e);
+ + "' does not exist, entry ignored", e);
}
}
return newLine;
@@ -257,4 +271,8 @@
}
}
+
+
+
+
}