[rhq] modules/plugins
by John Sanda
modules/plugins/rhq-storage/src/main/java/org/rhq/plugins/storage/StorageNodeConfigDelegate.java | 35 +++++
modules/plugins/rhq-storage/src/main/resources/META-INF/rhq-plugin.xml | 18 ++
modules/plugins/rhq-storage/src/test/java/org/rhq/plugins/storage/StorageNodeConfigDelegateTest.java | 61 +++++++++-
3 files changed, 107 insertions(+), 7 deletions(-)
New commits:
commit 632eb18cc8984f12c794678c6d13a455048a2096
Author: John Sanda <jsanda(a)redhat.com>
Date: Mon Jul 15 15:35:48 2013 -0400
adding validation checks for heap and thread args
diff --git a/modules/plugins/rhq-storage/src/main/java/org/rhq/plugins/storage/StorageNodeConfigDelegate.java b/modules/plugins/rhq-storage/src/main/java/org/rhq/plugins/storage/StorageNodeConfigDelegate.java
index c87d2ac..a0220ba 100644
--- a/modules/plugins/rhq-storage/src/main/java/org/rhq/plugins/storage/StorageNodeConfigDelegate.java
+++ b/modules/plugins/rhq-storage/src/main/java/org/rhq/plugins/storage/StorageNodeConfigDelegate.java
@@ -42,7 +42,8 @@ public class StorageNodeConfigDelegate implements ConfigurationFacet {
config.put(new PropertySimple("minHeapSize", heapMinProp.substring(4)));
config.put(new PropertySimple("maxHeapSize", heapMaxProp.substring(4)));
config.put(new PropertySimple("heapNewSize", heapNewProp.substring(4)));
- config.put(new PropertySimple("threadStackSize", threadStackSizeProp.substring(4)));
+ config.put(new PropertySimple("threadStackSize", threadStackSizeProp.substring(4,
+ threadStackSizeProp.length() - 1)));
if (!StringUtil.isEmpty(heapDumpOnOOMError)) {
config.put(new PropertySimple("heapDumpOnOOMError", true));
@@ -70,6 +71,7 @@ public class StorageNodeConfigDelegate implements ConfigurationFacet {
String maxHeapSize = config.getSimpleValue("maxHeapSize");
if (!StringUtil.isEmpty(maxHeapSize)) {
+ validateHeapArg("maxHeapSize", maxHeapSize);
// We want min and max heap to be the same
properties.setProperty("heap_min", "-Xms" + maxHeapSize);
properties.setProperty("heap_max", "-Xmx" + maxHeapSize);
@@ -77,12 +79,14 @@ public class StorageNodeConfigDelegate implements ConfigurationFacet {
String heapNewSize = config.getSimpleValue("heapNewSize");
if (!StringUtil.isEmpty(heapNewSize)) {
+ validateHeapArg("heapNewSize", heapNewSize);
properties.setProperty("heap_new", "-Xmn" + heapNewSize);
}
String threadStackSize = config.getSimpleValue("threadStackSize");
if (!StringUtil.isEmpty(threadStackSize)) {
- properties.setProperty("thread_stack_size", "-Xss" + threadStackSize);
+ validateStackArg(threadStackSize);
+ properties.setProperty("thread_stack_size", "-Xss" + threadStackSize + "k");
}
PropertySimple heapDumpOnOMMError = config.getSimple("heapDumpOnOOMError");
@@ -102,9 +106,36 @@ public class StorageNodeConfigDelegate implements ConfigurationFacet {
propertiesUpdater.update(properties);
configurationUpdateReport.setStatus(ConfigurationUpdateStatus.SUCCESS);
+ } catch (IllegalArgumentException e) {
+ configurationUpdateReport.setErrorMessage("No configuration update was applied: " + e.getMessage());
} catch (IOException e) {
configurationUpdateReport.setErrorMessageFromThrowable(e);
}
+ }
+
+ private void validateHeapArg(String name, String value) {
+ if (value.length() < 2) {
+ throw new IllegalArgumentException(value + " is not a legal value for the property [" + name + "]");
+ }
+
+ char[] chars = value.toCharArray();
+ for (int i = 0; i < chars.length - 1; ++i) {
+ if (!Character.isDigit(chars[i])) {
+ throw new IllegalArgumentException(value + " is not a legal value for the property [" + name + "]");
+ }
+ }
+ char lastChar = Character.toUpperCase(chars[chars.length - 1]);
+ if (!(lastChar == 'M' || lastChar == 'G')) {
+ throw new IllegalArgumentException(value + " is not a legal value for the property [" + name + "]");
+ }
+ }
+
+ private void validateStackArg(String value) {
+ try {
+ Integer.parseInt(value);
+ } catch (NumberFormatException e) {
+ throw new IllegalArgumentException(value + " is not a legal value for the property [threadStackSize]");
+ }
}
}
diff --git a/modules/plugins/rhq-storage/src/main/resources/META-INF/rhq-plugin.xml b/modules/plugins/rhq-storage/src/main/resources/META-INF/rhq-plugin.xml
index c700257..5a60d19 100644
--- a/modules/plugins/rhq-storage/src/main/resources/META-INF/rhq-plugin.xml
+++ b/modules/plugins/rhq-storage/src/main/resources/META-INF/rhq-plugin.xml
@@ -118,12 +118,24 @@
description="The minimum heap size. This value will be used with the -Xms JVM option. This
is read only because it is automatically set to the same value as Max Heap Size."/>
<c:simple-property name="maxHeapSize"
- description="The maximum heap size. This value will be used with the -Xmx JVM option."/>
+ description="The maximum heap size. This value will be used with the -Xmx JVM option. The
+ value should be an integer with a suffix of M or G to indicate megabytes or gigabytes.">
+ <c:constraint>
+ <c:regex-constraint expression="\d+[mMgG]"/>
+ </c:constraint>
+ </c:simple-property>
<c:simple-property name="heapNewSize"
description="The size of the new generation portion of the heap. This value will be used with
- the -Xmn JVM option."/>
+ the -Xmn JVM option. The value should be an integer with a suffix of M or G to indicate
+ megabytes or gigabytes.">
+ <c:constraint>
+ <c:regex-constraint expression="\d+[mMgG]"/>
+ </c:constraint>
+ </c:simple-property>
<c:simple-property name="threadStackSize"
- description="The thread stack size. This memory is allocated to each thread off heap."/>
+ type="integer"
+ description="The thread stack size. This memory is allocated to each thread off heap. The
+ value should be an integer that will be interpreted in kilobytes."/>
<c:simple-property name="heapDumpOnOOMError" displayName="Heap Dump on OutOfMemoryError" type="boolean"
default="true"
description="Generate a heap dump when an OutOfMemoryError occurs"/>
diff --git a/modules/plugins/rhq-storage/src/test/java/org/rhq/plugins/storage/StorageNodeConfigDelegateTest.java b/modules/plugins/rhq-storage/src/test/java/org/rhq/plugins/storage/StorageNodeConfigDelegateTest.java
index ee34f43..64d14b2 100644
--- a/modules/plugins/rhq-storage/src/test/java/org/rhq/plugins/storage/StorageNodeConfigDelegateTest.java
+++ b/modules/plugins/rhq-storage/src/test/java/org/rhq/plugins/storage/StorageNodeConfigDelegateTest.java
@@ -13,8 +13,10 @@ import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import org.rhq.core.domain.configuration.Configuration;
+import org.rhq.core.domain.configuration.ConfigurationUpdateStatus;
import org.rhq.core.domain.configuration.PropertySimple;
import org.rhq.core.pluginapi.configuration.ConfigurationUpdateReport;
+import org.rhq.core.util.file.FileUtil;
/**
* @author John Sanda
@@ -29,6 +31,7 @@ public class StorageNodeConfigDelegateTest {
public void initDirs(Method test) throws Exception {
File dir = new File(getClass().getResource(".").toURI());
basedir = new File(dir, getClass().getSimpleName() + "/" + test.getName());
+ FileUtil.purge(basedir, true);
configDelegate = new StorageNodeConfigDelegate(basedir);
}
@@ -42,7 +45,7 @@ public class StorageNodeConfigDelegateTest {
assertEquals(config.getSimpleValue("minHeapSize"), "512M", "Failed to load property [minHeapSize]");
assertEquals(config.getSimpleValue("maxHeapSize"), "512M", "Failed to load property [maxHepSize]");
assertEquals(config.getSimpleValue("heapNewSize"), "128M", "Failed to load property [heapNewSize]");
- assertEquals(config.getSimpleValue("threadStackSize"), "180k", "Failed to load property [threadStackSize]");
+ assertEquals(config.getSimpleValue("threadStackSize"), "180", "Failed to load property [threadStackSize]");
assertEquals(config.getSimple("heapDumpOnOOMError").getBooleanValue(), (Boolean) true,
"Failed to load property [heapDumpOnOOMError]");
assertEquals(new File(config.getSimpleValue("heapDumpDir")), binDir(), "Failed to load property [heapDumpDir]");
@@ -56,7 +59,7 @@ public class StorageNodeConfigDelegateTest {
config.put(new PropertySimple("minHeapSize", "1024M"));
config.put(new PropertySimple("maxHeapSize", "1024M"));
config.put(new PropertySimple("heapNewSize", "256M"));
- config.put(new PropertySimple("threadStackSize", "240k"));
+ config.put(new PropertySimple("threadStackSize", "240"));
config.put(new PropertySimple("heapDumpOnOOMError", true));
config.put(new PropertySimple("heapDumpDir", confDir()));
@@ -96,6 +99,60 @@ public class StorageNodeConfigDelegateTest {
"should be the same as [maxHeapSize].");
}
+ @Test
+ public void disableHeapDumps() throws Exception {
+ createDefaultConfig();
+
+ ConfigurationUpdateReport report = new ConfigurationUpdateReport(Configuration.builder()
+ .addSimple("heapDumpOnOOMError", false).build());
+
+ configDelegate.updateResourceConfiguration(report);
+
+ Properties properties = loadCassandraJvmProps();
+
+ assertEquals(properties.getProperty("heap_dump_on_OOMError"), "", "Failed to disable property " +
+ "[heapDumpOnOOMError]");
+ }
+
+ @Test
+ public void updateShouldFailWhenMaxHeapSizeIsInvalid() throws Exception {
+ createDefaultConfig();
+
+ ConfigurationUpdateReport report = new ConfigurationUpdateReport(Configuration.builder()
+ .addSimple("maxHeapSize", "256GB").build());
+
+ configDelegate.updateResourceConfiguration(report);
+
+ assertEquals(report.getStatus(), ConfigurationUpdateStatus.FAILURE, "The configuration update should fail " +
+ "when [maxHeapSize] has an invalid value.");
+ }
+
+ @Test
+ public void updateShouldFailWhenHeapNewSizeIsInvalid() throws Exception {
+ createDefaultConfig();
+
+ ConfigurationUpdateReport report = new ConfigurationUpdateReport(Configuration.builder()
+ .addSimple("heapNewSize", "25^G").build());
+
+ configDelegate.updateResourceConfiguration(report);
+
+ assertEquals(report.getStatus(), ConfigurationUpdateStatus.FAILURE, "The configuration update should fail " +
+ "when [heapNewSize] has an invalid value.");
+ }
+
+ @Test
+ public void updateShouldFailWhenThreadStackSizeIsInvalid() throws Exception {
+ createDefaultConfig();
+
+ ConfigurationUpdateReport report = new ConfigurationUpdateReport(Configuration.builder()
+ .addSimple("threadStackSize", "128M").build());
+
+ configDelegate.updateResourceConfiguration(report);
+
+ assertEquals(report.getStatus(), ConfigurationUpdateStatus.FAILURE, "The configuration update should fail " +
+ "when [threadStackSize] has an invalid value.");
+ }
+
private void createDefaultConfig() throws IOException {
Properties properties = new Properties();
properties.setProperty("heap_min", "-Xms512M");
10 years, 11 months
[rhq] modules/core
by Thomas Segismont
modules/core/native-system/src/main/java/org/rhq/core/system/SigarAccess.java | 44 --
modules/core/native-system/src/main/java/org/rhq/core/system/SigarAccessHandler.java | 201 ++++++++++
modules/core/native-system/src/test/java/org/rhq/core/system/SigarAccessHandlerTest.java | 172 ++++++++
3 files changed, 377 insertions(+), 40 deletions(-)
New commits:
commit fe38a28bd0ba7df967ec8b6a7f5f2b4a6bb839d6
Author: Thomas Segismont <tsegismo(a)redhat.com>
Date: Wed Jul 3 12:27:55 2013 +0200
Bug 923400 - Sigar creates high number of blocked threads (unbounded) if mount is gone
diff --git a/modules/core/native-system/src/main/java/org/rhq/core/system/SigarAccess.java b/modules/core/native-system/src/main/java/org/rhq/core/system/SigarAccess.java
index 4319f9a..8c7cea9 100644
--- a/modules/core/native-system/src/main/java/org/rhq/core/system/SigarAccess.java
+++ b/modules/core/native-system/src/main/java/org/rhq/core/system/SigarAccess.java
@@ -1,6 +1,6 @@
/*
* RHQ Management Platform
- * Copyright (C) 2005-2008 Red Hat, Inc.
+ * Copyright (C) 2005-2013 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -13,17 +13,13 @@
* 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, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * 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.rhq.core.system;
-import java.lang.reflect.InvocationHandler;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
-import org.hyperic.sigar.Sigar;
import org.hyperic.sigar.SigarProxy;
/**
@@ -34,7 +30,6 @@ import org.hyperic.sigar.SigarProxy;
* @author John Mazzitelli
*/
public class SigarAccess {
-
private static SigarAccessHandler invocationHandler;
private static SigarProxy sigarProxy;
@@ -83,35 +78,4 @@ public class SigarAccess {
}
- private static class SigarAccessHandler implements InvocationHandler {
- private Sigar sigar;
-
- public Object invoke(Object proxy, Method meth, Object[] args) throws Throwable {
- // its possible in the time between this handler's creation and now, someone disabled the native layer.
- // throw a runtime exception if the native system was disabled
- if (SystemInfoFactory.isNativeSystemInfoDisabled()) {
- throw new SystemInfoException("Native system has been disabled");
- }
-
- try {
- synchronized (this) {
- if (sigar == null) {
- this.sigar = new Sigar();
- }
-
- return meth.invoke(sigar, args);
- }
- } catch (InvocationTargetException e) {
- throw e.getTargetException();
- }
- }
-
- public synchronized void close() {
- if (this.sigar != null) {
- this.sigar.close();
- this.sigar = null;
- }
- }
- }
-
-}
\ No newline at end of file
+}
diff --git a/modules/core/native-system/src/main/java/org/rhq/core/system/SigarAccessHandler.java b/modules/core/native-system/src/main/java/org/rhq/core/system/SigarAccessHandler.java
new file mode 100644
index 0000000..a781641
--- /dev/null
+++ b/modules/core/native-system/src/main/java/org/rhq/core/system/SigarAccessHandler.java
@@ -0,0 +1,201 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2013 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * 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 version 2 of the License.
+ *
+ * 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, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+package org.rhq.core.system;
+
+import static java.util.concurrent.TimeUnit.MINUTES;
+import static java.util.concurrent.TimeUnit.SECONDS;
+
+import java.lang.management.ManagementFactory;
+import java.lang.management.ThreadInfo;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.locks.ReentrantLock;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hyperic.sigar.Sigar;
+
+/**
+ * An {@link InvocationHandler} for a {@link org.hyperic.sigar.SigarProxy}.
+ * <p>A single instance of this class will be created by the {@link SigarAccess} class.</p>
+ * This class holds a shared {@link Sigar} instance and serializes calls. If a thread waits more than
+ * 'sharedSigarLockMaxWait' seconds, it will be given a new Sigar instance, which will be destroyed at the end of the
+ * call.
+ * <p>Every 5 minutes, a background task checks that 'localSigarInstancesWarningThreshold' has not been exceeded. It it
+ * has, a warning message will be logged, optionally with a thread dump.
+ * <p>This class is configurable with System properties:
+ * <ul>
+ * <li><strong>sharedSigarLockMaxWait</strong>: maximum time in seconds a thread will wait for the shared Sigar lock
+ * acquistion; defaults to 2 seconds</li>
+ * <li><strong>localSigarInstancesWarningThreshold</strong>: threshold of currently living Sigar instances at which
+ * the background task will print warning messages; defaults to 50</li>
+ * <li><strong>maxLocalSigarInstances</strong>: maximum number of local Sigar instances which can be created, zero
+ * and negative values being interpreted as 'no limit'; defaults to 50</li>
+ * <li><strong>threadDumpOnlocalSigarInstancesWarningThreshold</strong>: if set to true (case insensitive), the
+ * background task will also log a thread dump when <strong>localSigarInstancesWarningThreshold</strong> is met</li>
+ * </ul>
+ * </p>
+ *
+ * @author Thomas Segismont
+ */
+class SigarAccessHandler implements InvocationHandler {
+ private static final Log LOG = LogFactory.getLog(SigarAccessHandler.class);
+
+ private static final String LINE_SEPARATOR = System.getProperty("line.separator");
+ private static final int SHARED_SIGAR_LOCK_MAX_WAIT = Integer.getInteger("sharedSigarLockMaxWait", 2);
+ private static final int LOCAL_SIGAR_INSTANCES_WARNING_THRESHOLD = Integer.getInteger(
+ "localSigarInstancesWarningThreshold", 50);
+ private static final int MAX_LOCAL_SIGAR_INSTANCES = Integer.getInteger("maxLocalSigarInstances", 50);
+ private static final boolean LIMIT_LOCAL_SIGAR_INSTANCES = MAX_LOCAL_SIGAR_INSTANCES > 0;
+ private static final boolean THREAD_DUMP_ON_SIGAR_INSTANCES_THRESHOLD = Boolean
+ .getBoolean("threadDumpOnlocalSigarInstancesWarningThreshold");
+
+ private final SigarFactory sigarFactory;
+ private final ReentrantLock sharedSigarLock;
+ private final ReentrantLock localSigarLock;
+ private final ScheduledExecutorService scheduledExecutorService;
+ private volatile int localSigarInstancesCount;
+ private Sigar sharedSigar;
+
+ SigarAccessHandler() {
+ this(new DefaultSigarFactory());
+ }
+
+ SigarAccessHandler(SigarFactory sigarFactory) {
+ this.sigarFactory = sigarFactory;
+ sharedSigarLock = new ReentrantLock();
+ localSigarLock = new ReentrantLock();
+ scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
+ scheduledExecutorService.scheduleWithFixedDelay(new ThresholdChecker(), 1, 5, MINUTES);
+ localSigarInstancesCount = 0;
+ }
+
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ // its possible in the time between this handler's creation and now, someone disabled the native layer.
+ // throw a runtime exception if the native system was disabled
+ if (SystemInfoFactory.isNativeSystemInfoDisabled()) {
+ throw new SystemInfoException("Native system has been disabled");
+ }
+
+ // Acquire lock for shared Sigar instance. Wait 'sharedSigarLockMaxWait' seconds at most
+ boolean acquiredLock = sharedSigarLock.tryLock(SHARED_SIGAR_LOCK_MAX_WAIT, SECONDS);
+ if (acquiredLock) {
+ if (sharedSigar == null) {
+ this.sharedSigar = sigarFactory.createSigarInstance();
+ }
+ try {
+ return method.invoke(sharedSigar, args);
+ } catch (InvocationTargetException e) {
+ throw e.getTargetException();
+ } finally {
+ sharedSigarLock.unlock();
+ }
+ } else {
+ Sigar localSigar = createLocalSigarInstance();
+ try {
+ return method.invoke(localSigar, args);
+ } catch (InvocationTargetException e) {
+ throw e.getTargetException();
+ } finally {
+ closeLocalSigarInstance(localSigar);
+ }
+ }
+ }
+
+ private Sigar createLocalSigarInstance() {
+ localSigarLock.lock();
+ try {
+ if (LIMIT_LOCAL_SIGAR_INSTANCES && localSigarInstancesCount >= MAX_LOCAL_SIGAR_INSTANCES) {
+ throw new RuntimeException("Too many Sigar instances created");
+ }
+ Sigar sigarInstance = sigarFactory.createSigarInstance();
+ localSigarInstancesCount++;
+ return sigarInstance;
+ } finally {
+ localSigarLock.unlock();
+ }
+ }
+
+ private void closeLocalSigarInstance(Sigar sigar) {
+ localSigarLock.lock();
+ try {
+ sigar.close();
+ localSigarInstancesCount--;
+ } finally {
+ localSigarLock.unlock();
+ }
+ }
+
+ void close() {
+ if (sharedSigar != null) {
+ sharedSigarLock.lock();
+ try {
+ sharedSigar.close();
+ sharedSigar = null;
+ } finally {
+ sharedSigarLock.unlock();
+ }
+ }
+ scheduledExecutorService.shutdownNow();
+ }
+
+ int localSigarInstancesCount() {
+ return localSigarInstancesCount;
+ }
+
+ interface SigarFactory {
+ Sigar createSigarInstance();
+ }
+
+ private static class DefaultSigarFactory implements SigarFactory {
+ @Override
+ public Sigar createSigarInstance() {
+ return new Sigar();
+ }
+ }
+
+ private class ThresholdChecker implements Runnable {
+ @Override
+ public void run() {
+ int currentCount = localSigarInstancesCount;
+ if (currentCount > LOCAL_SIGAR_INSTANCES_WARNING_THRESHOLD) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("There are ").append(currentCount).append(" local Sigar instances currently active. ")
+ .append("This may indicate that a call to the shared Sigar instance did not complete.");
+ if (THREAD_DUMP_ON_SIGAR_INSTANCES_THRESHOLD) {
+ sb.append(LINE_SEPARATOR);
+ threadDump(sb);
+ }
+ LOG.warn(sb.toString());
+ }
+ }
+
+ private void threadDump(StringBuilder sb) {
+ ThreadInfo[] threadInfos = ManagementFactory.getThreadMXBean().dumpAllThreads(true, true);
+ for (ThreadInfo threadInfo : threadInfos) {
+ sb.append(threadInfo);
+ sb.append(LINE_SEPARATOR);
+ }
+ }
+ }
+}
diff --git a/modules/core/native-system/src/test/java/org/rhq/core/system/SigarAccessHandlerTest.java b/modules/core/native-system/src/test/java/org/rhq/core/system/SigarAccessHandlerTest.java
new file mode 100644
index 0000000..e993725
--- /dev/null
+++ b/modules/core/native-system/src/test/java/org/rhq/core/system/SigarAccessHandlerTest.java
@@ -0,0 +1,172 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2013 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * 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 version 2 of the License.
+ *
+ * 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, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+package org.rhq.core.system;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+import java.lang.reflect.Method;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+
+import org.hyperic.sigar.Sigar;
+import org.hyperic.sigar.SigarProxy;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+/**
+ * @author Thomas Segismont
+ */
+@Test(singleThreaded = true)
+public class SigarAccessHandlerTest {
+ private static final int THREAD_POOL_SIZE = 100;
+
+ private Method getSwapMethod;
+ private Method getFileSystemMapMethod;
+ private Sigar sigarMock;
+ private ExecutorService executorService;
+ private SigarAccessHandler sigarAccessHandler;
+
+ @BeforeClass
+ private void setFields() throws Exception {
+ getSwapMethod = SigarProxy.class.getMethod("getSwap", new Class[0]);
+ getFileSystemMapMethod = SigarProxy.class.getMethod("getFileSystemMap", new Class[0]);
+ sigarMock = mock(Sigar.class);
+ // Wait 15 seconds on call to getSwap
+ when(sigarMock.getSwap()).then(new Answer<Object>() {
+ @Override
+ public Object answer(InvocationOnMock invocation) throws Throwable {
+ Thread.sleep(1000 * 15);
+ return null;
+ }
+ });
+ }
+
+ @BeforeMethod
+ public void setUp() throws Exception {
+ sigarAccessHandler = new SigarAccessHandler(new SigarAccessHandler.SigarFactory() {
+ @Override
+ public Sigar createSigarInstance() {
+ return sigarMock;
+ }
+ });
+ executorService = Executors.newFixedThreadPool(THREAD_POOL_SIZE);
+ }
+
+ @AfterMethod
+ public void tearDown() throws Exception {
+ sigarAccessHandler.close();
+ executorService.shutdownNow();
+
+ }
+
+ @Test(timeOut = 1000 * 30)
+ public void testOnDemandSigarInstanceCreation() throws Throwable {
+ // Start concurrent invocations of the long running getSwap method
+ for (int i = 0; i < 10; i++) {
+ executorService.submit(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ sigarAccessHandler.invoke(null, getSwapMethod, new Object[0]);
+ } catch (Throwable ignore) {
+ }
+ }
+ });
+ }
+ Thread.sleep(1000 * 8);
+
+ assertEquals(sigarAccessHandler.localSigarInstancesCount(), 9);
+ }
+
+ @Test(timeOut = 1000 * 30)
+ public void testSigarInstanceDestruction() throws Throwable {
+ // Start concurrent invocations of the short running getFileSystemMapMethod method and an invocation of the long
+ // running getSwap method
+ for (int i = 0; i < 10; i++) {
+ if (i == 0) {
+ executorService.submit(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ sigarAccessHandler.invoke(null, getSwapMethod, new Object[0]);
+ } catch (Throwable ignore) {
+ }
+ }
+ });
+ } else {
+ executorService.submit(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ sigarAccessHandler.invoke(null, getFileSystemMapMethod, new Object[0]);
+ } catch (Throwable ignore) {
+ }
+ }
+ });
+ }
+ }
+ Thread.sleep(1000 * 8);
+
+ assertEquals(sigarAccessHandler.localSigarInstancesCount(), 0);
+ }
+
+ @Test(timeOut = 1000 * 30)
+ public void testMaxSigarInstanceCreation() throws Throwable {
+ // Start concurrent invocations of the long running getSwap method
+ List<Future<Throwable>> futures = new LinkedList<Future<Throwable>>();
+ for (int i = 0; i < 60; i++) {
+ futures.add(executorService.submit(new Callable<Throwable>() {
+ @Override
+ public Throwable call() throws Exception {
+ try {
+ sigarAccessHandler.invoke(null, getSwapMethod, new Object[0]);
+ } catch (Throwable throwable) {
+ return throwable;
+ }
+ return null;
+ }
+ }));
+ }
+ Thread.sleep(1000 * 8);
+
+ assertEquals(sigarAccessHandler.localSigarInstancesCount(), 50);
+ int failedCallsCount = 0;
+ for (Future<Throwable> future : futures) {
+ Throwable throwable = future.get();
+ if (throwable != null) {
+ failedCallsCount++;
+ assertTrue(throwable instanceof RuntimeException);
+ assertEquals(throwable.getMessage(), "Too many Sigar instances created");
+ }
+ }
+ assertEquals(failedCallsCount, 9);
+ }
+}
10 years, 11 months
[rhq] modules/plugins
by Thomas Segismont
modules/plugins/jboss-as-5/src/main/java/org/rhq/plugins/jbossas5/ApplicationServerComponent.java | 64 +++++++++-
1 file changed, 62 insertions(+), 2 deletions(-)
New commits:
commit 05ff27a9dec1422f46c91f69d524a3b388b3e421
Author: Thomas Segismont <tsegismo(a)redhat.com>
Date: Mon Jul 15 19:57:08 2013 +0200
Bug 885655 - Datasource - Security Deployment Type is by default set to "Domain and application" instead of "None" as stated in description
Set default value in #createResource if needed
Update resource after creation as Security deployment type value is ignored by EAP servers
diff --git a/modules/plugins/jboss-as-5/src/main/java/org/rhq/plugins/jbossas5/ApplicationServerComponent.java b/modules/plugins/jboss-as-5/src/main/java/org/rhq/plugins/jbossas5/ApplicationServerComponent.java
index 0d45594..e0699b0 100644
--- a/modules/plugins/jboss-as-5/src/main/java/org/rhq/plugins/jbossas5/ApplicationServerComponent.java
+++ b/modules/plugins/jboss-as-5/src/main/java/org/rhq/plugins/jbossas5/ApplicationServerComponent.java
@@ -19,12 +19,15 @@
package org.rhq.plugins.jbossas5;
+import static org.rhq.core.domain.resource.CreateResourceStatus.SUCCESS;
+
import java.io.File;
import java.io.InputStream;
import java.io.Serializable;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -47,13 +50,17 @@ import org.jboss.deployers.spi.management.deploy.ProgressEvent;
import org.jboss.deployers.spi.management.deploy.ProgressListener;
import org.jboss.managed.api.ComponentType;
import org.jboss.managed.api.ManagedComponent;
+import org.jboss.managed.api.ManagedProperty;
+import org.jboss.metatype.api.values.MetaValue;
import org.jboss.metatype.api.values.SimpleValue;
import org.jboss.on.common.jbossas.JBPMWorkflowManager;
import org.jboss.on.common.jbossas.JBossASPaths;
import org.jboss.on.common.jbossas.JmxConnectionHelper;
import org.rhq.core.domain.configuration.Configuration;
+import org.rhq.core.domain.configuration.PropertyMap;
import org.rhq.core.domain.configuration.PropertySimple;
+import org.rhq.core.domain.configuration.definition.ConfigurationDefinition;
import org.rhq.core.domain.content.PackageType;
import org.rhq.core.domain.content.transfer.DeployPackageStep;
import org.rhq.core.domain.content.transfer.DeployPackagesResponse;
@@ -81,6 +88,8 @@ import org.rhq.core.pluginapi.inventory.ResourceContext;
import org.rhq.core.pluginapi.measurement.MeasurementFacet;
import org.rhq.core.pluginapi.operation.OperationFacet;
import org.rhq.core.pluginapi.operation.OperationResult;
+import org.rhq.plugins.jbossas5.adapter.api.PropertyAdapter;
+import org.rhq.plugins.jbossas5.adapter.api.PropertyAdapterFactory;
import org.rhq.plugins.jbossas5.connection.LocalProfileServiceConnectionProvider;
import org.rhq.plugins.jbossas5.connection.ProfileServiceConnection;
import org.rhq.plugins.jbossas5.connection.ProfileServiceConnectionProvider;
@@ -88,6 +97,7 @@ import org.rhq.plugins.jbossas5.connection.RemoteProfileServiceConnectionProvide
import org.rhq.plugins.jbossas5.helper.CreateChildResourceFacetDelegate;
import org.rhq.plugins.jbossas5.helper.InPluginControlActionFacade;
import org.rhq.plugins.jbossas5.helper.JBossAS5ConnectionTypeDescriptor;
+import org.rhq.plugins.jbossas5.util.ConversionUtils;
import org.rhq.plugins.jbossas5.util.ManagedComponentUtils;
/**
@@ -300,8 +310,58 @@ public class ApplicationServerComponent<T extends ResourceComponent<?>> implemen
// CreateChildResourceFacet --------------------------------------------
- public CreateResourceReport createResource(CreateResourceReport createResourceReport) {
- return this.createChildResourceDelegate.createResource(createResourceReport);
+ public CreateResourceReport createResource(CreateResourceReport report) {
+ if (creatingDatasourceOrConnectionFactory(report)) {
+ report = preCreateDatasourceOrConnectionFactory(report);
+ }
+ report = this.createChildResourceDelegate.createResource(report);
+ if (report.getStatus() != SUCCESS) {
+ return report;
+ }
+ if (creatingDatasourceOrConnectionFactory(report)) {
+ report = postCreateDatasourceOrConnectionFactory(report);
+ }
+ return report;
+ }
+
+ private CreateResourceReport preCreateDatasourceOrConnectionFactory(CreateResourceReport report) {
+ Configuration resourceConfiguration = report.getResourceConfiguration();
+ PropertyMap securityDomainPropertyMap = (PropertyMap) resourceConfiguration.get("security-domain");
+ PropertySimple securityDeploymentType = securityDomainPropertyMap.getSimple("securityDeploymentType");
+ if (securityDeploymentType.getStringValue() == null) {
+ securityDeploymentType.setValue("NONE");
+ }
+ return report;
+ }
+
+ private CreateResourceReport postCreateDatasourceOrConnectionFactory(CreateResourceReport report) {
+ Configuration resourceConfiguration = report.getResourceConfiguration();
+ ConfigurationDefinition resourceConfigurationDefinition = report.getResourceType()
+ .getResourceConfigurationDefinition();
+ ComponentType componentType = ConversionUtils.getComponentType(report.getResourceType());
+ String componentName = report.getResourceKey();
+ try {
+ ManagementView managementView = getConnection().getManagementView();
+ ManagedComponent managedComponent = managementView.getComponent(componentName, componentType);
+ Map<String, ManagedProperty> managedProperties = managedComponent.getProperties();
+ ManagedProperty managedProperty = managedProperties.get("security-domain");
+ MetaValue metaValue = managedProperty.getValue();
+ PropertyAdapter propertyAdapter = PropertyAdapterFactory.getPropertyAdapter(metaValue);
+ propertyAdapter.populateMetaValueFromProperty(resourceConfiguration.get("security-domain"), metaValue,
+ resourceConfigurationDefinition.get("security-domain"));
+ managementView.updateComponent(managedComponent);
+ managementView.load();
+ } catch (Exception e) {
+ report.setErrorMessage("Resource was created but an error occured while updating security-domain property");
+ report.setException(e);
+ }
+ return report;
+ }
+
+ private boolean creatingDatasourceOrConnectionFactory(CreateResourceReport report) {
+ String resourceTypeName = report.getResourceType().getName();
+ return Arrays.asList("No Tx Datasource", "Local Tx Datasource", "XA Datasource", "No Tx ConnectionFactory",
+ "Tx ConnectionFactory").contains(resourceTypeName);
}
// ProgressListener --------------------------------------------
10 years, 11 months
[rhq] 2 commits - modules/common modules/plugins
by John Sanda
modules/common/cassandra-installer/src/main/java/org/rhq/storage/installer/StorageInstaller.java | 9 +-
modules/plugins/rhq-storage/src/main/java/org/rhq/plugins/storage/StorageNodeConfigDelegate.java | 39 +++++++---
modules/plugins/rhq-storage/src/test/java/org/rhq/plugins/storage/StorageNodeConfigDelegateTest.java | 35 +++++++-
3 files changed, 66 insertions(+), 17 deletions(-)
New commits:
commit 68d4c3d2c3c5eb67c09cde41ac78f77f6b32ec33
Author: John Sanda <jsanda(a)redhat.com>
Date: Mon Jul 15 10:34:28 2013 -0400
[BZ 984433] revert changes for empty directory check
diff --git a/modules/common/cassandra-installer/src/main/java/org/rhq/storage/installer/StorageInstaller.java b/modules/common/cassandra-installer/src/main/java/org/rhq/storage/installer/StorageInstaller.java
index 386cda7..9a6a1c0 100644
--- a/modules/common/cassandra-installer/src/main/java/org/rhq/storage/installer/StorageInstaller.java
+++ b/modules/common/cassandra-installer/src/main/java/org/rhq/storage/installer/StorageInstaller.java
@@ -55,7 +55,6 @@ import org.apache.commons.cli.PosixParser;
import org.apache.commons.exec.DefaultExecutor;
import org.apache.commons.exec.Executor;
import org.apache.commons.exec.PumpStreamHandler;
-import org.apache.commons.io.FileUtils;
import org.apache.commons.io.output.NullOutputStream;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -450,7 +449,13 @@ public class StorageInstaller {
}
private boolean isDirectoryEmpty(File dir) {
- return FileUtils.sizeOf(dir) == 0;
+ // TODO need to check subdirectories
+ if (dir.isDirectory()) {
+ File[] files = dir.listFiles();
+ return (files == null || files.length == 0);
+ } else {
+ return true;
+ }
}
private int getPort(CommandLine cmdLine, String option, int defaultValue) {
commit 0bc81e9df0976365252b5ca11795b25d78172ec4
Author: John Sanda <jsanda(a)redhat.com>
Date: Mon Jul 15 10:13:35 2013 -0400
check that properties are set before trying to update them
diff --git a/modules/plugins/rhq-storage/src/main/java/org/rhq/plugins/storage/StorageNodeConfigDelegate.java b/modules/plugins/rhq-storage/src/main/java/org/rhq/plugins/storage/StorageNodeConfigDelegate.java
index e82f290..c87d2ac 100644
--- a/modules/plugins/rhq-storage/src/main/java/org/rhq/plugins/storage/StorageNodeConfigDelegate.java
+++ b/modules/plugins/rhq-storage/src/main/java/org/rhq/plugins/storage/StorageNodeConfigDelegate.java
@@ -68,19 +68,36 @@ public class StorageNodeConfigDelegate implements ConfigurationFacet {
Configuration config = configurationUpdateReport.getConfiguration();
- // We want min and max heap to be the same
- properties.setProperty("heap_min", "-Xms" + config.getSimpleValue("maxHeapSize"));
- properties.setProperty("heap_max", "-Xmx" + config.getSimpleValue("maxHeapSize"));
- properties.setProperty("heap_new", "-Xmn" + config.getSimpleValue("heapNewSize"));
- properties.setProperty("thread_stack_size", "-Xss" + config.getSimpleValue("threadStackSize"));
-
- if (config.getSimple("heapDumpOnOOMError").getBooleanValue()) {
- properties.setProperty("heap_dump_on_OOMError", "-XX:+HeapDumpOnOutOfMemoryError");
- } else {
- properties.setProperty("heap_dump_on_OOMError", "");
+ String maxHeapSize = config.getSimpleValue("maxHeapSize");
+ if (!StringUtil.isEmpty(maxHeapSize)) {
+ // We want min and max heap to be the same
+ properties.setProperty("heap_min", "-Xms" + maxHeapSize);
+ properties.setProperty("heap_max", "-Xmx" + maxHeapSize);
}
- properties.setProperty("heap_dump_dir", config.getSimpleValue("heapDumpDir"));
+ String heapNewSize = config.getSimpleValue("heapNewSize");
+ if (!StringUtil.isEmpty(heapNewSize)) {
+ properties.setProperty("heap_new", "-Xmn" + heapNewSize);
+ }
+
+ String threadStackSize = config.getSimpleValue("threadStackSize");
+ if (!StringUtil.isEmpty(threadStackSize)) {
+ properties.setProperty("thread_stack_size", "-Xss" + threadStackSize);
+ }
+
+ PropertySimple heapDumpOnOMMError = config.getSimple("heapDumpOnOOMError");
+ if (heapDumpOnOMMError != null) {
+ if (heapDumpOnOMMError.getBooleanValue()) {
+ properties.setProperty("heap_dump_on_OOMError", "-XX:+HeapDumpOnOutOfMemoryError");
+ } else {
+ properties.setProperty("heap_dump_on_OOMError", "");
+ }
+ }
+
+ String heapDumpDir = config.getSimpleValue("heapDumpDir");
+ if (!StringUtil.isEmpty(heapDumpDir)) {
+ properties.setProperty("heap_dump_dir", heapDumpDir);
+ }
propertiesUpdater.update(properties);
diff --git a/modules/plugins/rhq-storage/src/test/java/org/rhq/plugins/storage/StorageNodeConfigDelegateTest.java b/modules/plugins/rhq-storage/src/test/java/org/rhq/plugins/storage/StorageNodeConfigDelegateTest.java
index 5c5f089..ee34f43 100644
--- a/modules/plugins/rhq-storage/src/test/java/org/rhq/plugins/storage/StorageNodeConfigDelegateTest.java
+++ b/modules/plugins/rhq-storage/src/test/java/org/rhq/plugins/storage/StorageNodeConfigDelegateTest.java
@@ -23,10 +23,13 @@ public class StorageNodeConfigDelegateTest {
private File basedir;
+ private StorageNodeConfigDelegate configDelegate;
+
@BeforeMethod
public void initDirs(Method test) throws Exception {
File dir = new File(getClass().getResource(".").toURI());
basedir = new File(dir, getClass().getSimpleName() + "/" + test.getName());
+ configDelegate = new StorageNodeConfigDelegate(basedir);
}
@@ -34,7 +37,6 @@ public class StorageNodeConfigDelegateTest {
public void loadValidConfig() throws Exception {
createDefaultConfig();
- StorageNodeConfigDelegate configDelegate = new StorageNodeConfigDelegate(basedir);
Configuration config = configDelegate.loadResourceConfiguration();
assertEquals(config.getSimpleValue("minHeapSize"), "512M", "Failed to load property [minHeapSize]");
@@ -60,11 +62,9 @@ public class StorageNodeConfigDelegateTest {
ConfigurationUpdateReport report = new ConfigurationUpdateReport(config);
- StorageNodeConfigDelegate configDelegate = new StorageNodeConfigDelegate(basedir);
configDelegate.updateResourceConfiguration(report);
- Properties properties = new Properties();
- properties.load(new FileInputStream(new File(confDir(), "cassandra-jvm.properties")));
+ Properties properties = loadCassandraJvmProps();
assertEquals(properties.getProperty("heap_min"), "-Xms1024M", "Failed to update property [minHeapSize]");
assertEquals(properties.getProperty("heap_max"), "-Xmx1024M", "Failed to update property [maxHeapSize]");
@@ -77,6 +77,25 @@ public class StorageNodeConfigDelegateTest {
"Failed to update property [heap_dump_dir]");
}
+ @Test
+ public void minHeapSizeShouldBeTheSameAsMaxHeapSize() throws Exception {
+ createDefaultConfig();
+
+ Configuration config = new Configuration();
+ config.put(new PropertySimple("minHeapSize", "512M"));
+ config.put(new PropertySimple("maxHeapSize", "768M"));
+
+ ConfigurationUpdateReport report = new ConfigurationUpdateReport(config);
+
+ configDelegate.updateResourceConfiguration(report);
+
+ Properties properties = loadCassandraJvmProps();
+
+ assertEquals(properties.getProperty("heap_max"), "-Xmx768M", "Failed to update property [maxHeapSize]");
+ assertEquals(properties.getProperty("heap_min"), "-Xms768M", "Failed to update property [maxHeapSize]. It " +
+ "should be the same as [maxHeapSize].");
+ }
+
private void createDefaultConfig() throws IOException {
Properties properties = new Properties();
properties.setProperty("heap_min", "-Xms512M");
@@ -84,10 +103,18 @@ public class StorageNodeConfigDelegateTest {
properties.setProperty("heap_new", "-Xmn128M");
properties.setProperty("thread_stack_size", "-Xss180k");
properties.setProperty("heap_dump_on_OOMError", "-XX:+HeapDumpOnOutOfMemoryError");
+ properties.setProperty("heap_dump_dir", binDir().getAbsolutePath());
properties.store(new FileOutputStream(new File(confDir(), "cassandra-jvm.properties")), "");
}
+ private Properties loadCassandraJvmProps() throws Exception {
+ Properties properties = new Properties();
+ properties.load(new FileInputStream(new File(confDir(), "cassandra-jvm.properties")));
+
+ return properties;
+ }
+
private File confDir() {
return mkdirIfNecessary(basedir, "conf");
}
10 years, 11 months
[rhq] 3 commits - modules/core
by lkrejci
modules/core/domain/src/main/java/org/rhq/core/domain/configuration/Configuration.java | 247 +++++++++-
modules/core/domain/src/test/java/org/rhq/core/domain/configuration/ConfigurationBuilderTest.java | 237 +++++++++
2 files changed, 481 insertions(+), 3 deletions(-)
New commits:
commit 46ae96d60f17d0215185c0f79b8e004bdbc9c1ee
Author: Lukas Krejci <lkrejci(a)redhat.com>
Date: Thu May 23 11:03:31 2013 +0200
Trivial: javadoc clean up.
diff --git a/modules/core/domain/src/main/java/org/rhq/core/domain/configuration/Configuration.java b/modules/core/domain/src/main/java/org/rhq/core/domain/configuration/Configuration.java
index 13b1e32..4dae88a 100644
--- a/modules/core/domain/src/main/java/org/rhq/core/domain/configuration/Configuration.java
+++ b/modules/core/domain/src/main/java/org/rhq/core/domain/configuration/Configuration.java
@@ -850,10 +850,9 @@ public class Configuration implements Serializable, Cloneable, AbstractPropertyM
*
* @return a clone of this configuration
*
- * @throws CloneNotSupportedException
- *
* @see #deepCopy()
*/
+ @SuppressWarnings("override")
//@Override //GWT trips over this, WTH!
public Configuration clone() {
return deepCopy();
@@ -1002,7 +1001,7 @@ public class Configuration implements Serializable, Cloneable, AbstractPropertyM
/**
* Getter for the properties reference.
*
- * @return Map<String, Property>
+ * @return {@code Map<String, Property>}
*/
public Map<String, Property> getAllProperties() {
return this.properties;
commit b415c386059131057d91060a3bebef41699fcb3d
Author: Lukas Krejci <lkrejci(a)redhat.com>
Date: Thu May 23 10:46:16 2013 +0200
Added missing generic type decls.
diff --git a/modules/core/domain/src/main/java/org/rhq/core/domain/configuration/Configuration.java b/modules/core/domain/src/main/java/org/rhq/core/domain/configuration/Configuration.java
index b006425..13b1e32 100644
--- a/modules/core/domain/src/main/java/org/rhq/core/domain/configuration/Configuration.java
+++ b/modules/core/domain/src/main/java/org/rhq/core/domain/configuration/Configuration.java
@@ -271,7 +271,7 @@ public class Configuration implements Serializable, Cloneable, AbstractPropertyM
}
}
- public static class MapInList<Parent extends AbstractPropertyListBuilder> extends AbstractPropertyMapBuilder<PropertyMap, MapInList<Parent>> {
+ public static class MapInList<Parent extends AbstractPropertyListBuilder<?>> extends AbstractPropertyMapBuilder<PropertyMap, MapInList<Parent>> {
private Parent parent;
public MapInList(Parent parent, String name) {
@@ -307,7 +307,7 @@ public class Configuration implements Serializable, Cloneable, AbstractPropertyM
}
}
- public static class ListInList<Parent extends AbstractPropertyListBuilder> extends AbstractPropertyListBuilder<ListInList<Parent>> {
+ public static class ListInList<Parent extends AbstractPropertyListBuilder<?>> extends AbstractPropertyListBuilder<ListInList<Parent>> {
private Parent parent;
private ListInList(Parent parent, String name, String memberName) {
commit abbbf13986af10b65cf812ce9b0a2a49c297934a
Author: Lukas Krejci <lkrejci(a)redhat.com>
Date: Wed May 22 19:24:00 2013 +0200
A configuration instance builder.
This should greatly simplify the process of creating complex configuration
objects.
diff --git a/modules/core/domain/src/main/java/org/rhq/core/domain/configuration/Configuration.java b/modules/core/domain/src/main/java/org/rhq/core/domain/configuration/Configuration.java
index b1e6e22..b006425 100644
--- a/modules/core/domain/src/main/java/org/rhq/core/domain/configuration/Configuration.java
+++ b/modules/core/domain/src/main/java/org/rhq/core/domain/configuration/Configuration.java
@@ -143,6 +143,244 @@ public class Configuration implements Serializable, Cloneable, AbstractPropertyM
public static final String QUERY_DELETE_RAW_CONFIGURATIONS_CONFIGURATION_IDS = "Configuration.deleteRawByConfigurationIds";
public static final String QUERY_DELETE_CONFIGURATIONS_BY_CONFIGURATION_IDs = "Configuration.deleteByConfigurationIdS";
+ private static abstract class AbstractPropertyMapBuilder<T extends AbstractPropertyMap, This extends AbstractPropertyMapBuilder<T, This>> {
+ private T map;
+
+ protected AbstractPropertyMapBuilder(T map) {
+ this.map = map;
+ }
+
+ /**
+ * Adds a simple property.
+ * @param name the name of the simple property
+ * @param value the value of the simple property
+ * @return continue with the definition
+ */
+ public This addSimple(String name, Object value) {
+ getMap().put(new PropertySimple(name, value));
+ return castThis();
+ }
+
+ /**
+ * Starts defining a new sub list.
+ * @param name the name of the sub list
+ * @param memberName the names of the member properties of the sub list
+ * @return the builder of the list
+ */
+ public Builder.ListInMap<This> openList(String name, String memberName) {
+ return new Builder.ListInMap<This>(castThis(), name, memberName);
+ }
+
+ /**
+ * Starts defining a new sub map.
+ * @param name the name of the sub map
+ * @return the builder of the map
+ */
+ public Builder.MapInMap<This> openMap(String name) {
+ return new Builder.MapInMap<This>(castThis(), name);
+ }
+
+ protected T getMap() {
+ return map;
+ }
+
+ @SuppressWarnings("unchecked")
+ private This castThis() {
+ return (This) this;
+ }
+ }
+
+ private static abstract class AbstractPropertyListBuilder<This extends AbstractPropertyListBuilder<This>> {
+ private PropertyList list;
+
+ private AbstractPropertyListBuilder(String name, String memberName) {
+ this.list = new PropertyList(name);
+ this.list.memberPropertyName = memberName;
+ }
+
+ /**
+ * Adds a simple property. The name of the property is the member name defined by this list.
+ * @param value the value of the simple property
+ * @return continue with the definition
+ */
+ public This addSimple(Object value) {
+ list.add(new PropertySimple(list.memberPropertyName, value));
+ return castThis();
+ }
+
+ /**
+ * Adds a number of simple properties. The names of the properties are the member name defined by this list.
+ * @param values the values of the simple properties
+ * @return continue with the definition
+ */
+ public This addSimples(Object... values) {
+ for(Object v : values) {
+ list.add(new PropertySimple(list.memberPropertyName, v));
+ }
+
+ return castThis();
+ }
+
+ /**
+ * Starts defining a new sub map.
+ * @return the builder of the map
+ */
+ public Builder.MapInList<This> openMap() {
+ return new Builder.MapInList<This>(castThis(), list.memberPropertyName);
+ }
+
+ /**
+ * Starts defining a new sub list.
+ * @param memberName the names of the member properties of the sub list
+ * @return the builder of the list
+ */
+ public Builder.ListInList<This> openList(String memberName) {
+ return new Builder.ListInList<This>(castThis(), list.memberPropertyName, memberName);
+ }
+
+ protected PropertyList getList() {
+ return list;
+ }
+
+ @SuppressWarnings("unchecked")
+ private This castThis() {
+ return (This) this;
+ }
+ }
+
+ /**
+ * A builder to easily build Configuration instances using a fluent API.
+ */
+ public static class Builder extends AbstractPropertyMapBuilder<Configuration, Builder> {
+
+ public static class MapInMap<Parent extends AbstractPropertyMapBuilder<?, ?>> extends AbstractPropertyMapBuilder<PropertyMap, MapInMap<Parent>> {
+ private Parent parent;
+
+ private MapInMap(Parent parent, String name) {
+ super(new PropertyMap(name));
+ this.parent = parent;
+ }
+
+ /**
+ * Closes the definition of the current map and returns to the parent context.
+ * @return the parent context
+ */
+ public Parent closeMap() {
+ parent.getMap().put(getMap());
+ return parent;
+ }
+ }
+
+ public static class MapInList<Parent extends AbstractPropertyListBuilder> extends AbstractPropertyMapBuilder<PropertyMap, MapInList<Parent>> {
+ private Parent parent;
+
+ public MapInList(Parent parent, String name) {
+ super(new PropertyMap(name));
+ this.parent = parent;
+ }
+
+ /**
+ * Closes the definition of the current map and returns to the parent context.
+ * @return the parent context
+ */
+ public Parent closeMap() {
+ parent.getList().add(getMap());
+ return parent;
+ }
+ }
+
+ public static class ListInMap<Parent extends AbstractPropertyMapBuilder<?, ?>> extends AbstractPropertyListBuilder<ListInMap<Parent>> {
+ private Parent parent;
+
+ private ListInMap(Parent parent, String name, String memberName) {
+ super(name, memberName);
+ this.parent = parent;
+ }
+
+ /**
+ * Closes the definition of the current list and returns to the parent context.
+ * @return the parent context
+ */
+ public Parent closeList() {
+ parent.getMap().put(getList());
+ return parent;
+ }
+ }
+
+ public static class ListInList<Parent extends AbstractPropertyListBuilder> extends AbstractPropertyListBuilder<ListInList<Parent>> {
+ private Parent parent;
+
+ private ListInList(Parent parent, String name, String memberName) {
+ super(name, memberName);
+ this.parent = parent;
+ }
+
+ /**
+ * Closes the definition of the current list and returns to the parent context.
+ * @return the parent context
+ */
+ public Parent closeList() {
+ parent.getList().add(getList());
+ return parent;
+ }
+ }
+
+ public class RawConfigurationBuilder {
+
+ private RawConfiguration rawConfig;
+
+ public RawConfigurationBuilder() {
+ rawConfig = new RawConfiguration();
+ rawConfig.setConfiguration(getMap());
+ }
+
+ public RawConfigurationBuilder withPath(String path) {
+ rawConfig.setPath(path);
+ return this;
+ }
+
+ public RawConfigurationBuilder withContents(String content, String sha256) {
+ rawConfig.setContents(content, sha256);
+ return this;
+ }
+
+ /**
+ * Closes the definition of the current raw configuration and returns to the parent context.
+ * @return the parent context
+ */
+ public Builder closeRawConfiguration() {
+ getMap().getRawConfigurations().add(rawConfig);
+ return Builder.this;
+ }
+ }
+
+ public Builder() {
+ super(new Configuration());
+ }
+
+ public Builder withNotes(String notes) {
+ getMap().setNotes(notes);
+ return this;
+ }
+
+ public Builder withVersion(long version) {
+ getMap().setVersion(version);
+ return this;
+ }
+
+ /**
+ * Starts defining a new raw configuration that will become part of this configuration.
+ * @return the builder of the raw configuration
+ */
+ public RawConfigurationBuilder openRawConfiguration() {
+ return new RawConfigurationBuilder();
+ }
+
+ public Configuration build() {
+ return getMap();
+ }
+ }
+
@GeneratedValue(generator = "RHQ_CONFIG_ID_SEQ", strategy = GenerationType.AUTO)
@Id
private int id;
@@ -283,6 +521,10 @@ public class Configuration implements Serializable, Cloneable, AbstractPropertyM
@Column(name = "MTIME")
private long mtime = System.currentTimeMillis();
+ public static Builder builder() {
+ return new Builder();
+ }
+
public Configuration() {
}
diff --git a/modules/core/domain/src/test/java/org/rhq/core/domain/configuration/ConfigurationBuilderTest.java b/modules/core/domain/src/test/java/org/rhq/core/domain/configuration/ConfigurationBuilderTest.java
new file mode 100644
index 0000000..ad071ee
--- /dev/null
+++ b/modules/core/domain/src/test/java/org/rhq/core/domain/configuration/ConfigurationBuilderTest.java
@@ -0,0 +1,237 @@
+package org.rhq.core.domain.configuration;
+
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertSame;
+
+/**
+ * @author Lukas Krejci
+ */
+@Test
+public class ConfigurationBuilderTest {
+
+ public void testConfigurationProperties() {
+ Configuration config = Configuration.builder().withNotes("notes").withVersion(2).build();
+ assert "notes".equals(config.getNotes()) : "Unexpected notes";
+ assert 2 == config.getVersion() : "Unexpected version";
+ }
+
+ public void testSimples() {
+ Configuration config = Configuration.builder().addSimple("1", 1).addSimple("2", 2).build();
+
+ assert config.getSimpleValue("1").equals("1") : "1 != 1";
+ assert config.getSimpleValue("2").equals("2") : "2 != 2";
+
+ assert config.getSimple("1").getConfiguration() == config : "Configuration not set on property";
+ }
+
+ public void testListOfSimples() {
+ Configuration config = Configuration.builder().openList("l1", "m").addSimple(1).addSimple(2).closeList()
+ .openList("l2", "m").addSimples(1, 2).closeList().build();
+
+ PropertyList l1 = config.getList("l1");
+ PropertyList l2 = config.getList("l2");
+
+ assert l1 != null : "Could not find l1";
+ assert l2 != null : "Could not find l2";
+
+ assert l1.getConfiguration() == config : "Configuration on l1 not set";
+ assert l2.getConfiguration() == config : "Configuration on l2 not set";
+
+ assert l1.getList().size() == 2 : "Unexpected number of props in the list 1";
+ assert l2.getList().size() == 2 : "Unexpected number of props in the list 2";
+
+ testSimple((PropertySimple) l1.getList().get(0), null, l1, "1");
+ testSimple((PropertySimple) l1.getList().get(1), null, l1, "2");
+ testSimple((PropertySimple) l2.getList().get(0), null, l2, "1");
+ testSimple((PropertySimple) l2.getList().get(1), null, l2, "2");
+ }
+
+ public void testMapOfSimples() {
+ Configuration config = Configuration.builder().openMap("m").addSimple("1", 1).addSimple("2", 2).closeMap()
+ .build();
+
+ PropertyMap m = config.getMap("m");
+
+ assert m != null : "Cound not find map";
+
+ assert m.getConfiguration() == config : "Configuration on the map not set";
+
+ testSimple(m.getSimple("1"), m, null, "1");
+ testSimple(m.getSimple("2"), m, null, "2");
+ }
+
+ public void testListOfLists() {
+ Configuration config = new Configuration.Builder().openList("l", "m").openList("ml1").addSimples(1, 2)
+ .closeList().openList("ml2").addSimple(1).addSimple(2).closeList().closeList().build();
+
+ PropertyList l = config.getList("l");
+
+ assert l != null : "Could not find top-level list";
+
+ assert l.getList().size() == 2 : "Unexpected number of props in the top level list";
+
+ PropertyList m1 = (PropertyList) l.getList().get(0);
+ PropertyList m2 = (PropertyList) l.getList().get(1);
+
+ assert m1.getParentList() == l : "Parent list on m1 not set";
+ assert m1.getParentMap() == null : "Unexpected parent map on m1";
+ assert m2.getParentList() == l : "Parent list on m2 not set";
+ assert m1.getParentMap() == null : "Unexpected parent map on m2";
+
+ assert m1.getList().size() == 2 : "Unexpected number of props in the list 1";
+ assert m2.getList().size() == 2 : "Unexpected number of props in the list 2";
+
+ testSimple((PropertySimple) m1.getList().get(0), null, m1, "1");
+ testSimple((PropertySimple) m1.getList().get(1), null, m1, "2");
+ testSimple((PropertySimple) m2.getList().get(0), null, m2, "1");
+ testSimple((PropertySimple) m2.getList().get(1), null, m2, "2");
+ }
+
+ public void testListOfMaps() {
+ Configuration config = Configuration.builder().openList("l", "m").openMap().addSimple("c1", 1)
+ .addSimple("c2", 2).closeMap()
+ .openMap().addSimple("c1", 3).addSimple("c2", 4).closeMap().closeList().build();
+
+ PropertyList l = config.getList("l");
+
+ assert l != null : "Could not find top-level list";
+
+ assert l.getList().size() == 2 : "Unexpected number of props in the top level list";
+
+ PropertyMap m1 = (PropertyMap) l.getList().get(0);
+ PropertyMap m2 = (PropertyMap) l.getList().get(1);
+
+ assert m1.getParentList() == l : "Parent list on m1 not set";
+ assert m1.getParentMap() == null : "Unexpected parent map on m1";
+ assert m2.getParentList() == l : "Parent list on m2 not set";
+ assert m1.getParentMap() == null : "Unexpected parent map on m2";
+
+ assert m1.getMap().size() == 2 : "Unexpected number of props in the list 1";
+ assert m2.getMap().size() == 2 : "Unexpected number of props in the list 2";
+
+ testSimple(m1.getSimple("c1"), m1, null, "1");
+ testSimple(m1.getSimple("c2"), m1, null, "2");
+ testSimple(m2.getSimple("c1"), m2, null, "3");
+ testSimple(m2.getSimple("c2"), m2, null, "4");
+ }
+
+ public void testMapOfMaps() {
+ Configuration config = Configuration.builder().openMap("m").openMap("im1").addSimple("c1", 1).addSimple("c2", 2)
+ .closeMap().openMap("im2").addSimple("c1", 3).addSimple("c2", 4).closeMap().closeMap().build();
+
+ PropertyMap m = config.getMap("m");
+
+ assert m != null : "Could not find the top level map";
+
+ assert m.getMap().size() == 2 : "Unexpected number of props in the top level map";
+
+ PropertyMap m1 = m.getMap("im1");
+ PropertyMap m2 = m.getMap("im2");
+
+ assert m1 != null : "Could not find im1";
+ assert m2 != null : "Could not find im2";
+
+ assert m1.getParentList() == null : "Unexpected parent list on m1";
+ assert m1.getParentMap() == m : "Unexpected parent map on m1";
+ assert m2.getParentList() == null : "Unexpected parent list on m2";
+ assert m1.getParentMap() == m : "Unexpected parent map on m2";
+
+ testSimple(m1.getSimple("c1"), m1, null, "1");
+ testSimple(m1.getSimple("c2"), m1, null, "2");
+ testSimple(m2.getSimple("c1"), m2, null, "3");
+ testSimple(m2.getSimple("c2"), m2, null, "4");
+ }
+
+ public void testMapOfLists() {
+ Configuration config = Configuration.builder().openMap("m").openList("il1", "m").addSimples(1, 2)
+ .closeList().openList("il2", "m").addSimples(3, 4).closeList().closeMap().build();
+
+ PropertyMap m = config.getMap("m");
+
+ assert m != null : "Could not find the top level map";
+
+ assert m.getMap().size() == 2 : "Unexpected number of props in the top level map";
+
+ PropertyList l1 = m.getList("il1");
+ PropertyList l2 = m.getList("il2");
+
+ assert l1 != null : "Could not find il1";
+ assert l2 != null : "Could not find il2";
+
+ assert l1.getParentList() == null : "Unexpected parent list on l1";
+ assert l1.getParentMap() == m : "Unexpected parent map on l1";
+ assert l2.getParentList() == null : "Unexpected parent list on l2";
+ assert l2.getParentMap() == m : "Unexpected parent map on l2";
+
+ testSimple((PropertySimple) l1.getList().get(0), null, l1, "1");
+ testSimple((PropertySimple) l1.getList().get(1), null, l1, "2");
+ testSimple((PropertySimple) l2.getList().get(0), null, l2, "3");
+ testSimple((PropertySimple) l2.getList().get(1), null, l2, "4");
+ }
+
+ public void testUtterMess() {
+ Configuration config = Configuration.builder()
+ .openList("l", "m") //
+ /**/.openMap() //
+ /**//**/.openMap("innerMap") //
+ /**//**//**/.addSimple("c1", 1) //
+ /**//**//**/.openList("c2", "m") //
+ /**//**//**/.closeList() //
+ /**//**/.closeMap() //
+ /**//**/.addSimple("simple", 2) //
+ /**//**/.openList("innerList", "m") //
+ /**//**/.closeList() //
+ /**/.closeMap() //
+ /**/.addSimple(3) //
+ /**/.openList("im") //
+ /**//**/.openList("iim") //
+ /**//**/.closeList() //
+ /**//**/.openMap() //
+ /**//**/.closeMap() //
+ /**/.closeList() //
+ .closeList().build();
+
+ PropertyList l = config.getList("l");
+ PropertyMap lm = (PropertyMap) l.getList().get(0);
+ PropertyMap innerMap = lm.getMap("innerMap");
+ PropertySimple c1 = innerMap.getSimple("c1");
+ PropertyList c2 = innerMap.getList("c2");
+ PropertySimple simple = lm.getSimple("simple");
+ PropertyList innerList = lm.getList("innerList");
+ PropertySimple ls = (PropertySimple) l.getList().get(1);
+ PropertyList ll = (PropertyList) l.getList().get(2);
+ PropertyList lll = (PropertyList) ll.getList().get(0);
+ PropertyMap llm = (PropertyMap) ll.getList().get(1);
+
+ //all the aspects of the above mess have been tested in the previous tests
+ //this just really is here to prove the point of how messy our configs can be
+
+ assert c1 != null;
+ assert c2 != null;
+ assert simple != null;
+ assert innerList != null;
+ assert ls != null;
+ assert lll != null;
+ assert llm != null;
+ }
+
+ public void testRawConfigs() {
+ Configuration config = Configuration.builder().openRawConfiguration().withPath("a/b")
+ .withContents("asdf", "123").closeRawConfiguration().build();
+
+ RawConfiguration r = config.getRawConfigurations().iterator().next();
+ assert r.getPath().equals("a/b") : "Unexpected path";
+ assert r.getContents().equals("asdf") : "Unexpected contents";
+ assert r.getSha256().equals("123") : "Unexpected sha256";
+ assert r.getConfiguration() == config : "Unexpected raw config owning configuration";
+ }
+
+ private void testSimple(PropertySimple p, PropertyMap expectedParentMap, PropertyList expectedParentList,
+ String expectedValue) {
+ assertSame(p.getParentMap(), expectedParentMap, "Unexpected parent map");
+ assertSame(p.getParentList(), expectedParentList, "Unexpected parent list");
+ assertEquals(p.getStringValue(), expectedValue, "Unexpected value");
+ }
+}
10 years, 11 months
[rhq] modules/helpers
by Heiko W. Rupp
modules/helpers/pluginGen/pom.xml | 15
modules/helpers/pluginGen/src/main/java/org/rhq/helpers/pluginGen/Generator.java | 295 ++++++++++
modules/helpers/pluginGen/src/main/java/org/rhq/helpers/pluginGen/PluginGen.java | 4
modules/helpers/pluginGen/src/main/java/org/rhq/helpers/pluginGen/Prop.java | 114 +++
modules/helpers/pluginGen/src/main/java/org/rhq/helpers/pluginGen/Props.java | 2
5 files changed, 427 insertions(+), 3 deletions(-)
New commits:
commit eb3c52f1ba91a70fa7bdb45405849a1af4aa524a
Author: Heiko W. Rupp <hwr(a)redhat.com>
Date: Mon Jul 15 10:18:15 2013 +0200
Add a JavaFX frontend to the PluginGenerator.
diff --git a/modules/helpers/pluginGen/pom.xml b/modules/helpers/pluginGen/pom.xml
index e9a5e29..5aa512c 100644
--- a/modules/helpers/pluginGen/pom.xml
+++ b/modules/helpers/pluginGen/pom.xml
@@ -22,6 +22,14 @@
<build>
<plugins>
+ <plugin>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>1.7</source>
+ <target>1.7</target>
+ </configuration>
+ </plugin>
+
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
@@ -98,6 +106,13 @@
<artifactId>rhq-pluginAnnotations</artifactId>
<version>4.8.0-SNAPSHOT</version>
</dependency>
+ <dependency>
+ <groupId>com.oracle</groupId>
+ <artifactId>javafx</artifactId>
+ <version>2.0</version>
+ <systemPath>${java.home}/lib/jfxrt.jar</systemPath>
+ <scope>system</scope>
+ </dependency>
</dependencies>
</project>
diff --git a/modules/helpers/pluginGen/src/main/java/org/rhq/helpers/pluginGen/Generator.java b/modules/helpers/pluginGen/src/main/java/org/rhq/helpers/pluginGen/Generator.java
new file mode 100644
index 0000000..06f3fec
--- /dev/null
+++ b/modules/helpers/pluginGen/src/main/java/org/rhq/helpers/pluginGen/Generator.java
@@ -0,0 +1,295 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2013 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * 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 version 2 of the License.
+ *
+ * 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, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+package org.rhq.helpers.pluginGen;
+
+import java.io.File;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javafx.application.Application;
+import javafx.beans.value.ChangeListener;
+import javafx.beans.value.ObservableValue;
+import javafx.collections.ObservableList;
+import javafx.event.ActionEvent;
+import javafx.event.EventHandler;
+import javafx.geometry.Insets;
+import javafx.geometry.Pos;
+import javafx.scene.Node;
+import javafx.scene.Scene;
+import javafx.scene.control.*;
+import javafx.scene.layout.BorderPane;
+import javafx.scene.layout.GridPane;
+import javafx.scene.layout.HBox;
+import javafx.scene.layout.VBox;
+import javafx.scene.paint.Color;
+import javafx.scene.text.Font;
+import javafx.scene.text.FontPosture;
+import javafx.scene.text.FontWeight;
+import javafx.scene.text.Text;
+import javafx.scene.text.TextAlignment;
+import javafx.stage.DirectoryChooser;
+import javafx.stage.Stage;
+
+/**
+ * JavaFX version of the plugin generator
+ * @author Heiko W. Rupp
+ */
+public class Generator extends Application{
+
+ Props props = new Props();
+ private Text errorMessage;
+ private Stage primaryStage;
+
+ public static void main(String[] args) {
+ launch(args);
+ }
+
+
+ @Override
+ public void start(Stage stage) throws Exception {
+ primaryStage = stage;
+
+ Button createButton = new Button();
+ createButton.setText("Create!");
+ createButton.setAlignment(Pos.BOTTOM_RIGHT);
+ createButton.setOnAction(new EventHandler<ActionEvent>() {
+ @Override
+ public void handle(ActionEvent actionEvent) {
+
+ PluginGen pluginGen = new PluginGen();
+ pluginGen.postprocess(props);
+ try {
+ pluginGen.generate(props);
+ setInfoMessage("Generated!");
+
+ }
+ catch (Exception e) {
+ setErrorMessage("Error during generation: " + e.getMessage());
+ }
+ }
+ });
+
+ GridPane pluginLevelPane = new GridPane();
+ pluginLevelPane.setPadding(new Insets(10));
+ Text pluginLevelDescription = new Text("Plugin level properties");
+ pluginLevelDescription.setTextAlignment(TextAlignment.CENTER);
+ pluginLevelDescription.setFont(Font.font("Arial", FontWeight.BOLD, 14));
+
+ Text resourceLevelDescription = new Text("ResourceType level properties");
+ resourceLevelDescription.setTextAlignment(TextAlignment.CENTER);
+ resourceLevelDescription.setFont(Font.font("Arial", FontWeight.BOLD, 14));
+
+ Text descriptionDescription = new Text("Field description");
+ descriptionDescription.setTextAlignment(TextAlignment.CENTER);
+ descriptionDescription.setFont(Font.font("Arial", FontWeight.BOLD, 14));
+
+ HBox msgBox = getMessagesBox();
+
+ GridPane resourceLevelPane = new GridPane();
+ resourceLevelPane.setPadding(new Insets(10));
+ Text descriptionText = new Text();
+ descriptionText.setFont(Font.font("Arial", FontPosture.ITALIC,12));
+
+ VBox innerBox = new VBox();
+ innerBox.setAlignment(Pos.CENTER_LEFT);
+ innerBox.setPadding(new Insets(25, 25, 25, 25));
+ innerBox.setSpacing(8);
+
+ addFields(pluginLevelPane, true, descriptionText);
+ addFields(resourceLevelPane, false, descriptionText);
+
+ ObservableList<Node> children = innerBox.getChildren();
+ children.add(pluginLevelDescription);
+ children.add(pluginLevelPane);
+ children.add(resourceLevelDescription);
+ children.add(resourceLevelPane);
+
+
+ ScrollPane scrollPane = new ScrollPane();
+ scrollPane.setContent(innerBox);
+
+ BorderPane outerBox = new BorderPane();
+ outerBox.setTop(msgBox);
+ outerBox.setPadding(new Insets(5));
+ outerBox.setCenter(scrollPane);
+
+ VBox descriptionBox = new VBox();
+ descriptionBox.getChildren().add(descriptionDescription);
+ descriptionBox.getChildren().add(descriptionText);
+ outerBox.setBottom(descriptionBox);
+
+ outerBox.setRight(createButton);
+
+
+ stage.setScene(new Scene(outerBox, 600, 550));
+ stage.show();
+ }
+
+ private HBox getMessagesBox() {
+ HBox msgBox = new HBox();
+ Label label = new Label("Messages:");
+ msgBox.getChildren().add(label);
+ errorMessage = new Text();
+ errorMessage.setFont(Font.font("Arial", FontWeight.SEMI_BOLD, 12));
+ errorMessage.setId("errorMessage");
+ msgBox.getChildren().add(errorMessage);
+ return msgBox;
+ }
+
+ private int addFields(final GridPane root, boolean pluginLevel, final Text descriptionField) {
+
+ int row = 0;
+ for (final Prop prop : Prop.values()) {
+
+ if (!prop.isPluginLevel()==pluginLevel) {
+ continue;
+ }
+
+ // Add the label
+ String name = prop.readableName();
+ Label fieldName = new Label(name);
+ root.add(fieldName,0,row);
+
+ // Now add the field itself
+ final Class propType = prop.getType();
+ if (propType.equals(String.class)) {
+ final Pattern pattern = Pattern.compile(prop.getValidationRegex());
+
+ final TextField input = new TextField();
+ // Add field leave event to fill in the props with the result
+ input.focusedProperty().addListener(new ChangeListener<Boolean>() {
+ @Override
+ public void changed(ObservableValue<? extends Boolean> observableValue, Boolean oldState,
+ Boolean newState) {
+ if (newState) { // User entered input field
+ descriptionField.setText(prop.getDescription());
+ }
+ else { // User left input field
+ descriptionField.setText("");
+ setPropsValue(prop.getVariableName(),input.getText(), propType); // TODO right place?
+ }
+ }
+ });
+ // Add validation of the input
+ input.textProperty().addListener(new ChangeListener<String>() {
+ @Override
+ public void changed(ObservableValue<? extends String> observableValue, String s, String newText) {
+ Matcher m = pattern.matcher(newText);
+ if (!m.matches()) {
+ setErrorMessage("Input does not match " + prop.getValidationRegex());
+ } else {
+ clearErrorMessage();
+ }
+
+ }
+ });
+ root.add(input, 1, row);
+ } else if (propType.equals(Boolean.class) || propType.equals(boolean.class)) {
+ final ChoiceBox choiceBox = new ChoiceBox();
+ choiceBox.getItems().addAll("Yes", "No");
+ choiceBox.getSelectionModel().selectLast(); // NO is default
+ choiceBox.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<String>() {
+ @Override
+ public void changed(ObservableValue<? extends String> observableValue, String s, String newValue) {
+ setPropsValue(prop.getVariableName(),newValue.equals("Yes"),propType);
+ }
+ });
+
+ root.add(choiceBox,1,row);
+ } else if (propType.equals(ResourceCategory.class)) {
+ final ChoiceBox choiceBox = new ChoiceBox();
+ for (ResourceCategory cat : ResourceCategory.values()) {
+ choiceBox.getItems().add(cat.getLowerName());
+ }
+ choiceBox.getSelectionModel().selectLast(); // service is default
+ choiceBox.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<String>() {
+ @Override
+ public void changed(ObservableValue<? extends String> observableValue, String s, String newValue) {
+ ResourceCategory newCategory = ResourceCategory.valueOf(newValue.toUpperCase());
+ setPropsValue(prop.getVariableName(),newCategory,propType);
+ }
+ });
+
+ root.add(choiceBox,1,row);
+ } else if (propType.equals(File.class)) {
+ // Can not add this directly, so add a button to trigger it
+ final Text text = new Text();
+ text.setText("Pick a directory");
+ root.add(text,1,row);
+ Button pickButton = new Button("Pick");
+ pickButton.setOnAction(new EventHandler<ActionEvent>() {
+ @Override
+ public void handle(ActionEvent actionEvent) {
+ DirectoryChooser chooser = new DirectoryChooser();
+ chooser.setTitle("Pick a directory where the plugin will be put in.");
+ File dir = chooser.showDialog(primaryStage);
+ if (dir != null) {
+ String dirName = dir.getAbsolutePath();
+ props.setFileSystemRoot(dirName);
+ clearErrorMessage();
+ text.setText(dirName);
+ } else {
+ setErrorMessage("No directory selected");
+ text.setText("Pick a directory");
+ }
+ }
+ });
+
+ root.add(pickButton,2,row);
+ }
+
+ row++;
+
+ }
+
+ return row;
+ }
+
+ private void setInfoMessage(String message) {
+ errorMessage.setText(message);
+ errorMessage.setFill(Color.DARKGREEN);
+ }
+ private void setErrorMessage(String message) {
+ errorMessage.setText(message);
+ errorMessage.setFill(Color.RED);
+ }
+
+ private void clearErrorMessage() {
+ errorMessage.setText("");
+ errorMessage.setFill(Color.WHITE);
+ }
+
+ private void setPropsValue(String variableName, Object value, Class type) {
+
+ String var = variableName.substring(0,1).toUpperCase() + variableName.substring(1);
+ String setterName = "set"+ var;
+
+ try {
+ Method setter = Props.class.getDeclaredMethod(setterName,type);
+ setter.invoke(props,value);
+ } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
+ e.printStackTrace(); // TODO: Customise this generated block
+ setErrorMessage(e.getMessage());
+ }
+ }
+
+}
diff --git a/modules/helpers/pluginGen/src/main/java/org/rhq/helpers/pluginGen/PluginGen.java b/modules/helpers/pluginGen/src/main/java/org/rhq/helpers/pluginGen/PluginGen.java
index 223a57f..64b5509 100644
--- a/modules/helpers/pluginGen/src/main/java/org/rhq/helpers/pluginGen/PluginGen.java
+++ b/modules/helpers/pluginGen/src/main/java/org/rhq/helpers/pluginGen/PluginGen.java
@@ -115,7 +115,7 @@ public class PluginGen {
* Do some post processing over the input received.
* @param props The properties just recorded from the user input
*/
- private void postprocess(Props props) {
+ protected void postprocess(Props props) {
// Set the package
String pkg = props.getPackagePrefix() + "." + props.getName();
@@ -231,7 +231,7 @@ public class PluginGen {
* Trigger the generation of the directory hierarchy.
* @param props Parameters to take into account
*/
- private void generate(Props props) {
+ protected void generate(Props props) {
log.info("Generating...");
diff --git a/modules/helpers/pluginGen/src/main/java/org/rhq/helpers/pluginGen/Prop.java b/modules/helpers/pluginGen/src/main/java/org/rhq/helpers/pluginGen/Prop.java
new file mode 100644
index 0000000..73c4cd9
--- /dev/null
+++ b/modules/helpers/pluginGen/src/main/java/org/rhq/helpers/pluginGen/Prop.java
@@ -0,0 +1,114 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2013 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * 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 version 2 of the License.
+ *
+ * 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, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+package org.rhq.helpers.pluginGen;
+
+import java.io.File;
+
+/**
+ * All the properties that can be configured along with type, description and simple validation rules
+ * @author Heiko W. Rupp
+ */
+public enum Prop {
+
+ PLUGIN_NAME("pluginName", String.class,"Name of the plugin", "\\w+" , true ),
+ PLUGIN_DESCRIPTION("pluginDescription", String.class,"Description of the plugin",".*" , true ),
+ PACKAGE("packagePrefix", String.class,"Default Package","[a-zA-Z\\.]+",true ),
+ FILE_ROOT("fileSystemRoot", File.class,"Root directory to put the plugin",".*",true ),
+ RHQ_VERSION("rhqVersion",String.class,"RHQ version to use","[0-9][0-9\\.]+",true),
+
+ CATEGORY("category", ResourceCategory.class, "Category of the resource type (platform = host level)",null),
+ TYPE_NAME("name", String.class, "Name of the resource type", "\\w+"),
+ DESCRIPTION("description", String.class, "Description of the type", ".*"),
+ DISCOVERY_CLASS("discoveryClass", String.class, "Discovery class", "[A-Z][a-zA-Z0-9]*"),
+ COMPONENT_CLASS("componentClass", String.class, "Discovery class", "[A-Z][a-zA-Z0-9]*"),
+ IS_SINGLETON("singleton",Boolean.class,"Is this type a singleton, which means that" +
+ " there can only be one resource of that type for the given parent?",null),
+ HAS_METRICS("hasMetrics",boolean.class,"Does this type support taking metrics?",null),
+ HAS_OPERATIONS("hasOperations",boolean.class,"Does this type support operations?",null),
+ HAS_EVENTS("events",boolean.class,"Does this type support events?",null),
+ HAS_SUPPORT_FACET("supportFacet",boolean.class,"Does this type support the support facet?",null),
+ RESOURCE_CONFIGURATION("resourceConfiguration",boolean.class,"Does this type support " +
+ "configuring the resource?",".*"),
+ CAN_CREATE_CHILDREN("createChildren",boolean.class,"Can the type create child resources?",null),
+ CAN_DELETE_CHILDREN("deleteChildren",boolean.class,"Can the type delete child resources?",null),
+
+ // TODO add the remaining properties from Prop.class
+
+ ;
+
+ private String variableName;
+ private Class type;
+ private String description;
+ private boolean pluginLevel;
+ private String validationRegex;
+
+ private Prop(String variableName, Class type, String description, String validationRegex, boolean pluginLevel) {
+ this.variableName = variableName;
+ this.type = type;
+ this.description = description;
+ this.validationRegex = validationRegex;
+ this.pluginLevel = pluginLevel;
+ }
+
+ private Prop(String variableName, Class type, String description, String validationRegex) {
+ this.variableName = variableName;
+ this.type = type;
+ this.description = description;
+ this.validationRegex = validationRegex;
+ }
+
+ public String getVariableName() {
+ return variableName;
+ }
+
+ public Class getType() {
+ return type;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public boolean isPluginLevel() {
+ return pluginLevel;
+ }
+
+ public String getValidationRegex() {
+ return validationRegex;
+ }
+
+ public String readableName() {
+
+ String name = name();
+ name = name.replaceAll("_", " ");
+ String[] parts = name.split(" ");
+ StringBuilder builder = new StringBuilder();
+ for (int i = 0; i < parts.length; i++) {
+ String part = parts[i];
+ part = part.substring(0,1).toUpperCase() + part.substring(1).toLowerCase();
+ builder.append(part);
+ if (i < parts.length-1) {
+ builder.append(" ");
+ }
+ }
+ return builder.toString();
+ }
+
+}
diff --git a/modules/helpers/pluginGen/src/main/java/org/rhq/helpers/pluginGen/Props.java b/modules/helpers/pluginGen/src/main/java/org/rhq/helpers/pluginGen/Props.java
index 484d591..237f5ad 100644
--- a/modules/helpers/pluginGen/src/main/java/org/rhq/helpers/pluginGen/Props.java
+++ b/modules/helpers/pluginGen/src/main/java/org/rhq/helpers/pluginGen/Props.java
@@ -36,7 +36,7 @@ import org.rhq.helpers.pluginAnnotations.agent.Units;
public class Props {
/** What category is this ? */
- private ResourceCategory category;
+ private ResourceCategory category = ResourceCategory.SERVICE;
/** The name of this item */
private String name;
/** A description of the plugin */
10 years, 11 months
[rhq] modules/plugins
by John Sanda
modules/plugins/rhq-storage/src/main/java/org/rhq/plugins/storage/StorageNodeConfigDelegate.java | 24 ++++
modules/plugins/rhq-storage/src/main/resources/META-INF/rhq-plugin.xml | 5
modules/plugins/rhq-storage/src/test/java/org/rhq/plugins/storage/StorageNodeConfigDelegateTest.java | 55 +++++++---
3 files changed, 69 insertions(+), 15 deletions(-)
New commits:
commit 18c42dafe1e9e51a16a5ceba068a1e27cb8788c0
Author: John Sanda <jsanda(a)redhat.com>
Date: Sun Jul 14 22:36:40 2013 -0400
adding heap dump properties to resource configuration
The heap dump directory defaults to <rhq-storage-basedir>/bin and we are
generating heap dumps by default. Also refactoring and updating tests some.
diff --git a/modules/plugins/rhq-storage/src/main/java/org/rhq/plugins/storage/StorageNodeConfigDelegate.java b/modules/plugins/rhq-storage/src/main/java/org/rhq/plugins/storage/StorageNodeConfigDelegate.java
index 99ba48b..e82f290 100644
--- a/modules/plugins/rhq-storage/src/main/java/org/rhq/plugins/storage/StorageNodeConfigDelegate.java
+++ b/modules/plugins/rhq-storage/src/main/java/org/rhq/plugins/storage/StorageNodeConfigDelegate.java
@@ -11,6 +11,7 @@ import org.rhq.core.domain.configuration.PropertySimple;
import org.rhq.core.pluginapi.configuration.ConfigurationFacet;
import org.rhq.core.pluginapi.configuration.ConfigurationUpdateReport;
import org.rhq.core.util.PropertiesFileUpdate;
+import org.rhq.core.util.StringUtil;
/**
* @author John Sanda
@@ -35,12 +36,27 @@ public class StorageNodeConfigDelegate implements ConfigurationFacet {
String heapMaxProp = properties.getProperty("heap_max");
String heapNewProp = properties.getProperty("heap_new");
String threadStackSizeProp = properties.getProperty("thread_stack_size");
+ String heapDumpOnOOMError = properties.getProperty("heap_dump_on_OOMError");
+ String heapDumpDir = properties.getProperty("heap_dump_dir");
config.put(new PropertySimple("minHeapSize", heapMinProp.substring(4)));
config.put(new PropertySimple("maxHeapSize", heapMaxProp.substring(4)));
config.put(new PropertySimple("heapNewSize", heapNewProp.substring(4)));
config.put(new PropertySimple("threadStackSize", threadStackSizeProp.substring(4)));
+ if (!StringUtil.isEmpty(heapDumpOnOOMError)) {
+ config.put(new PropertySimple("heapDumpOnOOMError", true));
+ } else {
+ config.put(new PropertySimple("heapDumpOnOOMError", false));
+ }
+
+ if (!StringUtil.isEmpty(heapDumpDir)) {
+ config.put(new PropertySimple("heapDumpDir", heapDumpDir));
+ } else {
+ File basedir = jvmOptsFile.getParentFile().getParentFile();
+ config.put(new PropertySimple("heapDumpDir", new File(basedir, "bin").getAbsolutePath()));
+ }
+
return config;
}
@@ -58,6 +74,14 @@ public class StorageNodeConfigDelegate implements ConfigurationFacet {
properties.setProperty("heap_new", "-Xmn" + config.getSimpleValue("heapNewSize"));
properties.setProperty("thread_stack_size", "-Xss" + config.getSimpleValue("threadStackSize"));
+ if (config.getSimple("heapDumpOnOOMError").getBooleanValue()) {
+ properties.setProperty("heap_dump_on_OOMError", "-XX:+HeapDumpOnOutOfMemoryError");
+ } else {
+ properties.setProperty("heap_dump_on_OOMError", "");
+ }
+
+ properties.setProperty("heap_dump_dir", config.getSimpleValue("heapDumpDir"));
+
propertiesUpdater.update(properties);
configurationUpdateReport.setStatus(ConfigurationUpdateStatus.SUCCESS);
diff --git a/modules/plugins/rhq-storage/src/main/resources/META-INF/rhq-plugin.xml b/modules/plugins/rhq-storage/src/main/resources/META-INF/rhq-plugin.xml
index 5713288..c700257 100644
--- a/modules/plugins/rhq-storage/src/main/resources/META-INF/rhq-plugin.xml
+++ b/modules/plugins/rhq-storage/src/main/resources/META-INF/rhq-plugin.xml
@@ -124,6 +124,11 @@
the -Xmn JVM option."/>
<c:simple-property name="threadStackSize"
description="The thread stack size. This memory is allocated to each thread off heap."/>
+ <c:simple-property name="heapDumpOnOOMError" displayName="Heap Dump on OutOfMemoryError" type="boolean"
+ default="true"
+ description="Generate a heap dump when an OutOfMemoryError occurs"/>
+ <c:simple-property name="heapDumpDir" displayName="Heap Dump Directory" required="false"
+ description="The directory in which heap dumps will be written."/>
</c:group>
</resource-configuration>
diff --git a/modules/plugins/rhq-storage/src/test/java/org/rhq/plugins/storage/StorageNodeConfigDelegateTest.java b/modules/plugins/rhq-storage/src/test/java/org/rhq/plugins/storage/StorageNodeConfigDelegateTest.java
index f8d7bdc..5c5f089 100644
--- a/modules/plugins/rhq-storage/src/test/java/org/rhq/plugins/storage/StorageNodeConfigDelegateTest.java
+++ b/modules/plugins/rhq-storage/src/test/java/org/rhq/plugins/storage/StorageNodeConfigDelegateTest.java
@@ -6,8 +6,10 @@ import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.lang.reflect.Method;
import java.util.Properties;
+import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import org.rhq.core.domain.configuration.Configuration;
@@ -19,16 +21,18 @@ import org.rhq.core.pluginapi.configuration.ConfigurationUpdateReport;
*/
public class StorageNodeConfigDelegateTest {
+ private File basedir;
+
+ @BeforeMethod
+ public void initDirs(Method test) throws Exception {
+ File dir = new File(getClass().getResource(".").toURI());
+ basedir = new File(dir, getClass().getSimpleName() + "/" + test.getName());
+ }
@Test
public void loadValidConfig() throws Exception {
- File dir = new File(getClass().getResource(".").toURI());
- File basedir = new File(dir, getClass().getSimpleName() + "/loadValidConfig");
- File confDir = new File(basedir, "conf");
-
- confDir.mkdirs();
- createDefaultConfig(confDir);
+ createDefaultConfig();
StorageNodeConfigDelegate configDelegate = new StorageNodeConfigDelegate(basedir);
Configuration config = configDelegate.loadResourceConfiguration();
@@ -37,22 +41,22 @@ public class StorageNodeConfigDelegateTest {
assertEquals(config.getSimpleValue("maxHeapSize"), "512M", "Failed to load property [maxHepSize]");
assertEquals(config.getSimpleValue("heapNewSize"), "128M", "Failed to load property [heapNewSize]");
assertEquals(config.getSimpleValue("threadStackSize"), "180k", "Failed to load property [threadStackSize]");
+ assertEquals(config.getSimple("heapDumpOnOOMError").getBooleanValue(), (Boolean) true,
+ "Failed to load property [heapDumpOnOOMError]");
+ assertEquals(new File(config.getSimpleValue("heapDumpDir")), binDir(), "Failed to load property [heapDumpDir]");
}
@Test
public void updateValidConfig() throws Exception {
- File dir = new File(getClass().getResource(".").toURI());
- File basedir = new File(dir, getClass().getSimpleName() + "/updateValidConfig");
- File confDir = new File(basedir, "conf");
-
- confDir.mkdirs();
- createDefaultConfig(confDir);
+ createDefaultConfig();
Configuration config = new Configuration();
config.put(new PropertySimple("minHeapSize", "1024M"));
config.put(new PropertySimple("maxHeapSize", "1024M"));
config.put(new PropertySimple("heapNewSize", "256M"));
config.put(new PropertySimple("threadStackSize", "240k"));
+ config.put(new PropertySimple("heapDumpOnOOMError", true));
+ config.put(new PropertySimple("heapDumpDir", confDir()));
ConfigurationUpdateReport report = new ConfigurationUpdateReport(config);
@@ -60,23 +64,44 @@ public class StorageNodeConfigDelegateTest {
configDelegate.updateResourceConfiguration(report);
Properties properties = new Properties();
- properties.load(new FileInputStream(new File(confDir, "cassandra-jvm.properties")));
+ properties.load(new FileInputStream(new File(confDir(), "cassandra-jvm.properties")));
assertEquals(properties.getProperty("heap_min"), "-Xms1024M", "Failed to update property [minHeapSize]");
assertEquals(properties.getProperty("heap_max"), "-Xmx1024M", "Failed to update property [maxHeapSize]");
assertEquals(properties.getProperty("heap_new"), "-Xmn256M", "Failed to update property [heapNewSize]");
assertEquals(properties.getProperty("thread_stack_size"), "-Xss240k",
"Failed to update property [threadStackSize]");
+ assertEquals(properties.getProperty("heap_dump_on_OOMError"), "-XX:+HeapDumpOnOutOfMemoryError",
+ "Failed to update property [heap_dump_on_OOMError]");
+ assertEquals(properties.getProperty("heap_dump_dir"), confDir().getAbsolutePath(),
+ "Failed to update property [heap_dump_dir]");
}
- private void createDefaultConfig(File confDir) throws IOException {
+ private void createDefaultConfig() throws IOException {
Properties properties = new Properties();
properties.setProperty("heap_min", "-Xms512M");
properties.setProperty("heap_max", "-Xmx512M");
properties.setProperty("heap_new", "-Xmn128M");
properties.setProperty("thread_stack_size", "-Xss180k");
+ properties.setProperty("heap_dump_on_OOMError", "-XX:+HeapDumpOnOutOfMemoryError");
+
+ properties.store(new FileOutputStream(new File(confDir(), "cassandra-jvm.properties")), "");
+ }
+
+ private File confDir() {
+ return mkdirIfNecessary(basedir, "conf");
+ }
+
+ private File binDir() {
+ return mkdirIfNecessary(basedir, "bin");
+ }
- properties.store(new FileOutputStream(new File(confDir, "cassandra-jvm.properties")), "");
+ private File mkdirIfNecessary(File parent, String path) {
+ File dir = new File(parent, path);
+ if (!dir.exists()) {
+ dir.mkdirs();
+ }
+ return dir;
}
}
10 years, 11 months
[rhq] modules/plugins
by John Sanda
modules/plugins/rhq-storage/pom.xml | 97 ----------
modules/plugins/rhq-storage/src/main/java/org/rhq/plugins/storage/StorageNodeComponent.java | 30 ---
modules/plugins/rhq-storage/src/main/java/org/rhq/plugins/storage/StorageNodeConfigDelegate.java | 69 +++++++
modules/plugins/rhq-storage/src/main/resources/META-INF/rhq-plugin.xml | 3
modules/plugins/rhq-storage/src/test/java/org/rhq/plugins/storage/StorageNodeConfigDelegateTest.java | 82 ++++++++
5 files changed, 159 insertions(+), 122 deletions(-)
New commits:
commit 1130a8be9a9a44c6e4670053bd7347aed4e01f30
Author: John Sanda <jsanda(a)redhat.com>
Date: Sun Jul 14 09:44:04 2013 -0400
adding initial support for resource config updates of StorageNodeComponent
Also making minHeapSize read only as we also want it the same as maxHeapSize.
diff --git a/modules/plugins/rhq-storage/pom.xml b/modules/plugins/rhq-storage/pom.xml
index ea3b9ea..a88f56e 100644
--- a/modules/plugins/rhq-storage/pom.xml
+++ b/modules/plugins/rhq-storage/pom.xml
@@ -39,103 +39,6 @@
<profiles>
<profile>
- <id>integration-tests</id>
- <activation>
- <property>
- <name>maven.test.skip</name>
- <value>!true</value>
- </property>
- </activation>
-
- <build>
- <plugins>
-
- <plugin>
- <artifactId>maven-antrun-plugin</artifactId>
- <executions>
- <execution>
- <phase>pre-integration-test</phase>
- <configuration>
- <target>
- <echo>Setting up plugin dependencies...</echo>
- <property name="settings.localRepository" location="${user.home}/.m2/repository" />
- <mkdir dir="target/itest" />
- <mkdir dir="target/itest/plugins" />
- <mkdir dir="target/itest/lib" />
- <copy toDir="target/itest/plugins" flatten="true">
- <!-- Plugin dependencies on other plugins -->
- <fileset dir="${settings.localRepository}/">
- <include name="org/rhq/rhq-platform-plugin/${project.version}/rhq-platform-plugin-${project.version}.jar" />
- <include name="org/rhq/rhq-jmx-plugin/${project.version}/rhq-jmx-plugin-${project.version}.jar" />
- <include name="org/rhq/rhq-jboss-as-7-jmx-plugin/${project.version}/rhq-jboss-as-7-jmx-plugin-${project.version}.jar" />
- </fileset>
- <fileset dir="${project.build.directory}">
- <include name="rhq-rhqserver-plugin-${project.version}.jar" />
- </fileset>
- </copy>
- <unzip dest="target/itest/lib">
- <fileset dir="${settings.localRepository}/org/hyperic/sigar-dist/${sigar.version}" includes="*.zip" />
- <patternset>
- <include name="**/lib/sigar.jar" />
- <include name="**/lib/bcel*.jar" />
- <include name="**/lib/*.so" />
- <include name="**/lib/*.sl" />
- <include name="**/lib/*.dll" />
- <include name="**/lib/*.dylib" />
- </patternset>
- </unzip>
- <move todir="target/itest/lib" flatten="true">
- <fileset dir="target/itest/lib">
- <include name="**/lib/*" />
- </fileset>
- </move>
- <delete dir="target/itest/lib/hyperic-sigar-${sigar.version}" />
- </target>
- </configuration>
- <goals>
- <goal>run</goal>
- </goals>
- </execution>
- </executions>
- </plugin>
-
- <plugin>
- <artifactId>maven-surefire-plugin</artifactId>
- <configuration>
- <skip>true</skip>
- </configuration>
- <executions>
- <execution>
- <id>surefire-it</id>
- <phase>integration-test</phase>
- <goals>
- <goal>test</goal>
- </goals>
- <configuration>
- <skip>${maven.test.skip}</skip>
- <excludedGroups>${rhq.testng.excludedGroups}</excludedGroups>
- <useSystemClassLoader>false</useSystemClassLoader>
- <argLine>${jacoco.integration-test.args} -Dorg.hyperic.sigar.path=${basedir}/target/itest/lib</argLine>
- <systemProperties>
- <property>
- <name>project.artifactId</name>
- <value>${project.artifactId}</value>
- </property>
- <property>
- <name>project.version</name>
- <value>${project.version}</value>
- </property>
- </systemProperties>
- </configuration>
- </execution>
- </executions>
- </plugin>
-
- </plugins>
- </build>
- </profile>
-
- <profile>
<id>dev</id>
<properties>
diff --git a/modules/plugins/rhq-storage/src/main/java/org/rhq/plugins/storage/StorageNodeComponent.java b/modules/plugins/rhq-storage/src/main/java/org/rhq/plugins/storage/StorageNodeComponent.java
index 737dded..6194146 100644
--- a/modules/plugins/rhq-storage/src/main/java/org/rhq/plugins/storage/StorageNodeComponent.java
+++ b/modules/plugins/rhq-storage/src/main/java/org/rhq/plugins/storage/StorageNodeComponent.java
@@ -26,9 +26,7 @@
package org.rhq.plugins.storage;
import java.io.File;
-import java.io.FileInputStream;
import java.util.List;
-import java.util.Properties;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -62,25 +60,13 @@ public class StorageNodeComponent extends CassandraNodeComponent implements Oper
@Override
public Configuration loadResourceConfiguration() throws Exception {
- File confDir = new File(getBasedir(), "conf");
- File jvmOptsFile = new File(confDir, "cassandra-jvm.properties");
-
- Properties properties = new Properties();
- properties.load(new FileInputStream(jvmOptsFile));
-
- Configuration config = new Configuration();
-
- String heapMinProp = properties.getProperty("heap_min");
- String heapMaxProp = properties.getProperty("heap_max");
- String heapNewProp = properties.getProperty("heap_new");
- String threadStackSizeProp = properties.getProperty("thread_stack_size");
-
- config.put(new PropertySimple("minHeapSize", heapMinProp.substring(4)));
- config.put(new PropertySimple("maxHeapSize", heapMaxProp.substring(4)));
- config.put(new PropertySimple("heapNewSize", heapNewProp.substring(4)));
- config.put(new PropertySimple("threadStackSize", threadStackSizeProp.substring(4)));
+ return new StorageNodeConfigDelegate(getBasedir()).loadResourceConfiguration();
+ }
- return config;
+ @Override
+ public void updateResourceConfiguration(ConfigurationUpdateReport configurationUpdateReport) {
+ StorageNodeConfigDelegate configDelegate = new StorageNodeConfigDelegate(getBasedir());
+ configDelegate.updateResourceConfiguration(configurationUpdateReport);
}
private File getBasedir() {
@@ -89,10 +75,6 @@ public class StorageNodeComponent extends CassandraNodeComponent implements Oper
}
@Override
- public void updateResourceConfiguration(ConfigurationUpdateReport configurationUpdateReport) {
- }
-
- @Override
public OperationResult invokeOperation(String name, Configuration parameters) throws Exception {
if (name.equals("addNodeMaintenance")) {
return nodeAdded(parameters);
diff --git a/modules/plugins/rhq-storage/src/main/java/org/rhq/plugins/storage/StorageNodeConfigDelegate.java b/modules/plugins/rhq-storage/src/main/java/org/rhq/plugins/storage/StorageNodeConfigDelegate.java
new file mode 100644
index 0000000..99ba48b
--- /dev/null
+++ b/modules/plugins/rhq-storage/src/main/java/org/rhq/plugins/storage/StorageNodeConfigDelegate.java
@@ -0,0 +1,69 @@
+package org.rhq.plugins.storage;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.Properties;
+
+import org.rhq.core.domain.configuration.Configuration;
+import org.rhq.core.domain.configuration.ConfigurationUpdateStatus;
+import org.rhq.core.domain.configuration.PropertySimple;
+import org.rhq.core.pluginapi.configuration.ConfigurationFacet;
+import org.rhq.core.pluginapi.configuration.ConfigurationUpdateReport;
+import org.rhq.core.util.PropertiesFileUpdate;
+
+/**
+ * @author John Sanda
+ */
+public class StorageNodeConfigDelegate implements ConfigurationFacet {
+
+ private File jvmOptsFile;
+
+ public StorageNodeConfigDelegate(File basedir) {
+ File confDir = new File(basedir, "conf");
+ jvmOptsFile = new File(confDir, "cassandra-jvm.properties");
+ }
+
+ @Override
+ public Configuration loadResourceConfiguration() throws Exception {
+ Properties properties = new Properties();
+ properties.load(new FileInputStream(jvmOptsFile));
+
+ Configuration config = new Configuration();
+
+ String heapMinProp = properties.getProperty("heap_min");
+ String heapMaxProp = properties.getProperty("heap_max");
+ String heapNewProp = properties.getProperty("heap_new");
+ String threadStackSizeProp = properties.getProperty("thread_stack_size");
+
+ config.put(new PropertySimple("minHeapSize", heapMinProp.substring(4)));
+ config.put(new PropertySimple("maxHeapSize", heapMaxProp.substring(4)));
+ config.put(new PropertySimple("heapNewSize", heapNewProp.substring(4)));
+ config.put(new PropertySimple("threadStackSize", threadStackSizeProp.substring(4)));
+
+ return config;
+ }
+
+ @Override
+ public void updateResourceConfiguration(ConfigurationUpdateReport configurationUpdateReport) {
+ try {
+ PropertiesFileUpdate propertiesUpdater = new PropertiesFileUpdate(jvmOptsFile.getAbsolutePath());
+ Properties properties = propertiesUpdater.loadExistingProperties();
+
+ Configuration config = configurationUpdateReport.getConfiguration();
+
+ // We want min and max heap to be the same
+ properties.setProperty("heap_min", "-Xms" + config.getSimpleValue("maxHeapSize"));
+ properties.setProperty("heap_max", "-Xmx" + config.getSimpleValue("maxHeapSize"));
+ properties.setProperty("heap_new", "-Xmn" + config.getSimpleValue("heapNewSize"));
+ properties.setProperty("thread_stack_size", "-Xss" + config.getSimpleValue("threadStackSize"));
+
+ propertiesUpdater.update(properties);
+
+ configurationUpdateReport.setStatus(ConfigurationUpdateStatus.SUCCESS);
+ } catch (IOException e) {
+ configurationUpdateReport.setErrorMessageFromThrowable(e);
+ }
+
+ }
+}
diff --git a/modules/plugins/rhq-storage/src/main/resources/META-INF/rhq-plugin.xml b/modules/plugins/rhq-storage/src/main/resources/META-INF/rhq-plugin.xml
index b012f1c..5713288 100644
--- a/modules/plugins/rhq-storage/src/main/resources/META-INF/rhq-plugin.xml
+++ b/modules/plugins/rhq-storage/src/main/resources/META-INF/rhq-plugin.xml
@@ -114,8 +114,9 @@
<resource-configuration>
<c:group name="MemorySettings">
<c:simple-property name="minHeapSize"
+ readOnly="true"
description="The minimum heap size. This value will be used with the -Xms JVM option. This
- should always be the same as Max Heap Size."/>
+ is read only because it is automatically set to the same value as Max Heap Size."/>
<c:simple-property name="maxHeapSize"
description="The maximum heap size. This value will be used with the -Xmx JVM option."/>
<c:simple-property name="heapNewSize"
diff --git a/modules/plugins/rhq-storage/src/test/java/org/rhq/plugins/storage/StorageNodeConfigDelegateTest.java b/modules/plugins/rhq-storage/src/test/java/org/rhq/plugins/storage/StorageNodeConfigDelegateTest.java
new file mode 100644
index 0000000..f8d7bdc
--- /dev/null
+++ b/modules/plugins/rhq-storage/src/test/java/org/rhq/plugins/storage/StorageNodeConfigDelegateTest.java
@@ -0,0 +1,82 @@
+package org.rhq.plugins.storage;
+
+import static org.testng.Assert.assertEquals;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.Properties;
+
+import org.testng.annotations.Test;
+
+import org.rhq.core.domain.configuration.Configuration;
+import org.rhq.core.domain.configuration.PropertySimple;
+import org.rhq.core.pluginapi.configuration.ConfigurationUpdateReport;
+
+/**
+ * @author John Sanda
+ */
+public class StorageNodeConfigDelegateTest {
+
+
+
+ @Test
+ public void loadValidConfig() throws Exception {
+ File dir = new File(getClass().getResource(".").toURI());
+ File basedir = new File(dir, getClass().getSimpleName() + "/loadValidConfig");
+ File confDir = new File(basedir, "conf");
+
+ confDir.mkdirs();
+ createDefaultConfig(confDir);
+
+ StorageNodeConfigDelegate configDelegate = new StorageNodeConfigDelegate(basedir);
+ Configuration config = configDelegate.loadResourceConfiguration();
+
+ assertEquals(config.getSimpleValue("minHeapSize"), "512M", "Failed to load property [minHeapSize]");
+ assertEquals(config.getSimpleValue("maxHeapSize"), "512M", "Failed to load property [maxHepSize]");
+ assertEquals(config.getSimpleValue("heapNewSize"), "128M", "Failed to load property [heapNewSize]");
+ assertEquals(config.getSimpleValue("threadStackSize"), "180k", "Failed to load property [threadStackSize]");
+ }
+
+ @Test
+ public void updateValidConfig() throws Exception {
+ File dir = new File(getClass().getResource(".").toURI());
+ File basedir = new File(dir, getClass().getSimpleName() + "/updateValidConfig");
+ File confDir = new File(basedir, "conf");
+
+ confDir.mkdirs();
+ createDefaultConfig(confDir);
+
+ Configuration config = new Configuration();
+ config.put(new PropertySimple("minHeapSize", "1024M"));
+ config.put(new PropertySimple("maxHeapSize", "1024M"));
+ config.put(new PropertySimple("heapNewSize", "256M"));
+ config.put(new PropertySimple("threadStackSize", "240k"));
+
+ ConfigurationUpdateReport report = new ConfigurationUpdateReport(config);
+
+ StorageNodeConfigDelegate configDelegate = new StorageNodeConfigDelegate(basedir);
+ configDelegate.updateResourceConfiguration(report);
+
+ Properties properties = new Properties();
+ properties.load(new FileInputStream(new File(confDir, "cassandra-jvm.properties")));
+
+ assertEquals(properties.getProperty("heap_min"), "-Xms1024M", "Failed to update property [minHeapSize]");
+ assertEquals(properties.getProperty("heap_max"), "-Xmx1024M", "Failed to update property [maxHeapSize]");
+ assertEquals(properties.getProperty("heap_new"), "-Xmn256M", "Failed to update property [heapNewSize]");
+ assertEquals(properties.getProperty("thread_stack_size"), "-Xss240k",
+ "Failed to update property [threadStackSize]");
+ }
+
+ private void createDefaultConfig(File confDir) throws IOException {
+ Properties properties = new Properties();
+ properties.setProperty("heap_min", "-Xms512M");
+ properties.setProperty("heap_max", "-Xmx512M");
+ properties.setProperty("heap_new", "-Xmn128M");
+ properties.setProperty("thread_stack_size", "-Xss180k");
+
+ properties.store(new FileOutputStream(new File(confDir, "cassandra-jvm.properties")), "");
+ }
+
+}
10 years, 11 months
[rhq] 4 commits - modules/common modules/plugins
by John Sanda
modules/common/cassandra-ccm/cassandra-ccm-core/pom.xml | 3
modules/common/cassandra-ccm/cassandra-ccm-core/src/main/bundle/cassandra/bin/cassandra | 193 +++++++
modules/common/cassandra-ccm/cassandra-ccm-core/src/main/bundle/cassandra/conf/cassandra-jvm.properties | 112 ++++
modules/common/cassandra-ccm/cassandra-ccm-core/src/main/bundle/deploy.xml | 221 --------
modules/common/cassandra-ccm/cassandra-ccm-core/src/main/cassandra/cli/dbsetup.script | 40 -
modules/common/cassandra-ccm/cassandra-ccm-core/src/main/cassandra/cql/create_keyspace.cql | 1
modules/common/cassandra-ccm/cassandra-ccm-core/src/main/cassandra/cql/dbsetup.cql | 42 -
modules/common/cassandra-ccm/cassandra-ccm-core/src/main/java/org/rhq/cassandra/Deployer.java | 32 +
modules/common/cassandra-ccm/cassandra-ccm-core/src/test/java/org/rhq/cassandra/DeployerITest.java | 4
modules/common/cassandra-ccm/cassandra-ccm-core/src/test/resources/expected.cassandra-env.sh | 247 ----------
modules/common/cassandra-ccm/cassandra-ccm-core/src/test/resources/expected.cassandra-jvm.properties | 112 ++++
modules/common/cassandra-ccm/cassandra-ccm-core/src/test/resources/expected.cassandra.yaml | 2
modules/plugins/rhq-storage/src/main/java/org/rhq/plugins/storage/StorageNodeComponent.java | 39 +
modules/plugins/rhq-storage/src/main/resources/META-INF/rhq-plugin.xml | 15
14 files changed, 506 insertions(+), 557 deletions(-)
New commits:
commit cabe99fea2aa6ecbd2e26f2040ed70951c451dc2
Author: John Sanda <jsanda(a)redhat.com>
Date: Sat Jul 13 16:30:19 2013 -0400
initial support for resource configuration with StorageNodeComponent
This commit introduces initial support for reading JVM options.
diff --git a/modules/plugins/rhq-storage/src/main/java/org/rhq/plugins/storage/StorageNodeComponent.java b/modules/plugins/rhq-storage/src/main/java/org/rhq/plugins/storage/StorageNodeComponent.java
index cc34fe3..737dded 100644
--- a/modules/plugins/rhq-storage/src/main/java/org/rhq/plugins/storage/StorageNodeComponent.java
+++ b/modules/plugins/rhq-storage/src/main/java/org/rhq/plugins/storage/StorageNodeComponent.java
@@ -25,7 +25,10 @@
package org.rhq.plugins.storage;
+import java.io.File;
+import java.io.FileInputStream;
import java.util.List;
+import java.util.Properties;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -38,6 +41,8 @@ import org.rhq.core.domain.configuration.Configuration;
import org.rhq.core.domain.configuration.PropertyList;
import org.rhq.core.domain.configuration.PropertyMap;
import org.rhq.core.domain.configuration.PropertySimple;
+import org.rhq.core.pluginapi.configuration.ConfigurationFacet;
+import org.rhq.core.pluginapi.configuration.ConfigurationUpdateReport;
import org.rhq.core.pluginapi.operation.OperationFacet;
import org.rhq.core.pluginapi.operation.OperationResult;
import org.rhq.core.util.exception.ThrowableUtil;
@@ -47,7 +52,7 @@ import org.rhq.plugins.cassandra.util.KeyspaceService;
/**
* @author John Sanda
*/
-public class StorageNodeComponent extends CassandraNodeComponent implements OperationFacet {
+public class StorageNodeComponent extends CassandraNodeComponent implements OperationFacet, ConfigurationFacet {
private Log log = LogFactory.getLog(StorageNodeComponent.class);
@@ -56,6 +61,38 @@ public class StorageNodeComponent extends CassandraNodeComponent implements Oper
private static final String RHQ_KEYSPACE = "rhq";
@Override
+ public Configuration loadResourceConfiguration() throws Exception {
+ File confDir = new File(getBasedir(), "conf");
+ File jvmOptsFile = new File(confDir, "cassandra-jvm.properties");
+
+ Properties properties = new Properties();
+ properties.load(new FileInputStream(jvmOptsFile));
+
+ Configuration config = new Configuration();
+
+ String heapMinProp = properties.getProperty("heap_min");
+ String heapMaxProp = properties.getProperty("heap_max");
+ String heapNewProp = properties.getProperty("heap_new");
+ String threadStackSizeProp = properties.getProperty("thread_stack_size");
+
+ config.put(new PropertySimple("minHeapSize", heapMinProp.substring(4)));
+ config.put(new PropertySimple("maxHeapSize", heapMaxProp.substring(4)));
+ config.put(new PropertySimple("heapNewSize", heapNewProp.substring(4)));
+ config.put(new PropertySimple("threadStackSize", threadStackSizeProp.substring(4)));
+
+ return config;
+ }
+
+ private File getBasedir() {
+ Configuration pluginConfig = getResourceContext().getPluginConfiguration();
+ return new File(pluginConfig.getSimpleValue("baseDir"));
+ }
+
+ @Override
+ public void updateResourceConfiguration(ConfigurationUpdateReport configurationUpdateReport) {
+ }
+
+ @Override
public OperationResult invokeOperation(String name, Configuration parameters) throws Exception {
if (name.equals("addNodeMaintenance")) {
return nodeAdded(parameters);
diff --git a/modules/plugins/rhq-storage/src/main/resources/META-INF/rhq-plugin.xml b/modules/plugins/rhq-storage/src/main/resources/META-INF/rhq-plugin.xml
index f02c8e6..b012f1c 100644
--- a/modules/plugins/rhq-storage/src/main/resources/META-INF/rhq-plugin.xml
+++ b/modules/plugins/rhq-storage/src/main/resources/META-INF/rhq-plugin.xml
@@ -111,6 +111,21 @@
</parameters>
</operation>
+ <resource-configuration>
+ <c:group name="MemorySettings">
+ <c:simple-property name="minHeapSize"
+ description="The minimum heap size. This value will be used with the -Xms JVM option. This
+ should always be the same as Max Heap Size."/>
+ <c:simple-property name="maxHeapSize"
+ description="The maximum heap size. This value will be used with the -Xmx JVM option."/>
+ <c:simple-property name="heapNewSize"
+ description="The size of the new generation portion of the heap. This value will be used with
+ the -Xmn JVM option."/>
+ <c:simple-property name="threadStackSize"
+ description="The thread stack size. This memory is allocated to each thread off heap."/>
+ </c:group>
+ </resource-configuration>
+
<server name="Cassandra Server JVM"
sourcePlugin="JMX" sourceType="JMX Server"
discovery="org.rhq.plugins.jmx.EmbeddedJMXServerDiscoveryComponent"
commit 5d1cb191a0ea22dd4f24379597645aeff3934df7
Author: John Sanda <jsanda(a)redhat.com>
Date: Sat Jul 13 13:09:41 2013 -0400
updating/fixing integration test failure
diff --git a/modules/common/cassandra-ccm/cassandra-ccm-core/src/test/java/org/rhq/cassandra/DeployerITest.java b/modules/common/cassandra-ccm/cassandra-ccm-core/src/test/java/org/rhq/cassandra/DeployerITest.java
index 91a5459..76ff090 100644
--- a/modules/common/cassandra-ccm/cassandra-ccm-core/src/test/java/org/rhq/cassandra/DeployerITest.java
+++ b/modules/common/cassandra-ccm/cassandra-ccm-core/src/test/java/org/rhq/cassandra/DeployerITest.java
@@ -103,8 +103,8 @@ public class DeployerITest {
}
@Test(dependsOnMethods = "applyConfigChanges")
- public void verifyConfigChangesToCassandraEnv() throws Exception {
- assertFileDeployedAndUpdated("cassandra-env.sh");
+ public void verifyConfigChangesToCassandraJvmOpts() throws Exception {
+ assertFileDeployedAndUpdated("cassandra-jvm.properties");
}
private void assertFileDeployedAndUpdated(String fileName) throws Exception {
diff --git a/modules/common/cassandra-ccm/cassandra-ccm-core/src/test/resources/expected.cassandra-env.sh b/modules/common/cassandra-ccm/cassandra-ccm-core/src/test/resources/expected.cassandra-env.sh
deleted file mode 100644
index 62dc0f2..0000000
--- a/modules/common/cassandra-ccm/cassandra-ccm-core/src/test/resources/expected.cassandra-env.sh
+++ /dev/null
@@ -1,247 +0,0 @@
-# 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.
-
-calculate_heap_sizes()
-{
- case "`uname`" in
- Linux)
- system_memory_in_mb=`free -m | awk '/Mem:/ {print $2}'`
- system_cpu_cores=`egrep -c 'processor([[:space:]]+):.*' /proc/cpuinfo`
- ;;
- FreeBSD)
- system_memory_in_bytes=`sysctl hw.physmem | awk '{print $2}'`
- system_memory_in_mb=`expr $system_memory_in_bytes / 1024 / 1024`
- system_cpu_cores=`sysctl hw.ncpu | awk '{print $2}'`
- ;;
- SunOS)
- system_memory_in_mb=`prtconf | awk '/Memory size:/ {print $3}'`
- system_cpu_cores=`psrinfo | wc -l`
- ;;
- Darwin)
- system_memory_in_bytes=`sysctl hw.memsize | awk '{print $2}'`
- system_memory_in_mb=`expr $system_memory_in_bytes / 1024 / 1024`
- system_cpu_cores=`sysctl hw.ncpu | awk '{print $2}'`
- ;;
- *)
- # assume reasonable defaults for e.g. a modern desktop or
- # cheap server
- system_memory_in_mb="2048"
- system_cpu_cores="2"
- ;;
- esac
-
- # some systems like the raspberry pi don't report cores, use at least 1
- if [ "$system_cpu_cores" -lt "1" ]
- then
- system_cpu_cores="1"
- fi
-
- # set max heap size based on the following
- # max(min(1/2 ram, 1024MB), min(1/4 ram, 8GB))
- # calculate 1/2 ram and cap to 1024MB
- # calculate 1/4 ram and cap to 8192MB
- # pick the max
- half_system_memory_in_mb=`expr $system_memory_in_mb / 2`
- quarter_system_memory_in_mb=`expr $half_system_memory_in_mb / 2`
- if [ "$half_system_memory_in_mb" -gt "1024" ]
- then
- half_system_memory_in_mb="1024"
- fi
- if [ "$quarter_system_memory_in_mb" -gt "8192" ]
- then
- quarter_system_memory_in_mb="8192"
- fi
- if [ "$half_system_memory_in_mb" -gt "$quarter_system_memory_in_mb" ]
- then
- max_heap_size_in_mb="$half_system_memory_in_mb"
- else
- max_heap_size_in_mb="$quarter_system_memory_in_mb"
- fi
- MAX_HEAP_SIZE="${max_heap_size_in_mb}M"
-
- # Young gen: min(max_sensible_per_modern_cpu_core * num_cores, 1/4 * heap size)
- max_sensible_yg_per_core_in_mb="100"
- max_sensible_yg_in_mb=`expr $max_sensible_yg_per_core_in_mb "*" $system_cpu_cores`
-
- desired_yg_in_mb=`expr $max_heap_size_in_mb / 4`
-
- if [ "$desired_yg_in_mb" -gt "$max_sensible_yg_in_mb" ]
- then
- HEAP_NEWSIZE="${max_sensible_yg_in_mb}M"
- else
- HEAP_NEWSIZE="${desired_yg_in_mb}M"
- fi
-}
-
-# Determine the sort of JVM we'll be running on.
-
-java_ver_output=`"${JAVA:-java}" -version 2>&1`
-
-jvmver=`echo "$java_ver_output" | awk -F'"' 'NR==1 {print $2}'`
-JVM_VERSION=${jvmver%_*}
-JVM_PATCH_VERSION=${jvmver#*_}
-
-jvm=`echo "$java_ver_output" | awk 'NR==2 {print $1}'`
-case "$jvm" in
- OpenJDK)
- JVM_VENDOR=OpenJDK
- # this will be "64-Bit" or "32-Bit"
- JVM_ARCH=`echo "$java_ver_output" | awk 'NR==3 {print $2}'`
- ;;
- "Java(TM)")
- JVM_VENDOR=Oracle
- # this will be "64-Bit" or "32-Bit"
- JVM_ARCH=`echo "$java_ver_output" | awk 'NR==3 {print $3}'`
- ;;
- *)
- # Help fill in other JVM values
- JVM_VENDOR=other
- JVM_ARCH=unknown
- ;;
-esac
-
-
-# Override these to set the amount of memory to allocate to the JVM at
-# start-up. For production use you may wish to adjust this for your
-# environment. MAX_HEAP_SIZE is the total amount of memory dedicated
-# to the Java heap; HEAP_NEWSIZE refers to the size of the young
-# generation. Both MAX_HEAP_SIZE and HEAP_NEWSIZE should be either set
-# or not (if you set one, set the other).
-#
-# The main trade-off for the young generation is that the larger it
-# is, the longer GC pause times will be. The shorter it is, the more
-# expensive GC will be (usually).
-#
-# The example HEAP_NEWSIZE assumes a modern 8-core+ machine for decent pause
-# times. If in doubt, and if you do not particularly want to tweak, go with
-# 100 MB per physical CPU core.
-
-#MAX_HEAP_SIZE="4G"
-#HEAP_NEWSIZE="800M"
-
-if [ "x$MAX_HEAP_SIZE" = "x" ] && [ "x$HEAP_NEWSIZE" = "x" ]; then
- calculate_heap_sizes
-else
- if [ "x$MAX_HEAP_SIZE" = "x" ] || [ "x$HEAP_NEWSIZE" = "x" ]; then
- echo "please set or unset MAX_HEAP_SIZE and HEAP_NEWSIZE in pairs (see cassandra-env.sh)"
- exit 1
- fi
-fi
-
-# Specifies the default port over which Cassandra will be available for
-# JMX connections.
-JMX_PORT="7200"
-
-
-# Here we create the arguments that will get passed to the jvm when
-# starting cassandra.
-
-# enable assertions. disabling this in production will give a modest
-# performance benefit (around 5%).
-JVM_OPTS="$JVM_OPTS -ea"
-
-# add the jamm javaagent
-if [ "$JVM_VENDOR" != "OpenJDK" -o "$JVM_VERSION" \> "1.6.0" ] \
- || [ "$JVM_VERSION" = "1.6.0" -a "$JVM_PATCH_VERSION" -ge 23 ]
-then
- JVM_OPTS="$JVM_OPTS -javaagent:$CASSANDRA_HOME/lib/jamm-0.2.5.jar"
-fi
-
-# enable thread priorities, primarily so we can give periodic tasks
-# a lower priority to avoid interfering with client workload
-JVM_OPTS="$JVM_OPTS -XX:+UseThreadPriorities"
-# allows lowering thread priority without being root. see
-# http://tech.stolsvik.com/2010/01/linux-java-thread-priorities-workaround....
-JVM_OPTS="$JVM_OPTS -XX:ThreadPriorityPolicy=42"
-
-# min and max heap sizes should be set to the same value to avoid
-# stop-the-world GC pauses during resize, and so that we can lock the
-# heap in memory on startup to prevent any of it from being swapped
-# out.
-JVM_OPTS="$JVM_OPTS -Xms${MAX_HEAP_SIZE}"
-JVM_OPTS="$JVM_OPTS -Xmx${MAX_HEAP_SIZE}"
-JVM_OPTS="$JVM_OPTS -Xmn${HEAP_NEWSIZE}"
-JVM_OPTS="$JVM_OPTS -XX:+HeapDumpOnOutOfMemoryError"
-
-# set jvm HeapDumpPath with CASSANDRA_HEAPDUMP_DIR
-if [ "x$CASSANDRA_HEAPDUMP_DIR" != "x" ]; then
- JVM_OPTS="$JVM_OPTS -XX:HeapDumpPath=$CASSANDRA_HEAPDUMP_DIR/cassandra-`date +%s`-pid$$.hprof"
-fi
-
-
-startswith() { [ "${1#$2}" != "$1" ]; }
-
-if [ "`uname`" = "Linux" ] ; then
- # reduce the per-thread stack size to minimize the impact of Thrift
- # thread-per-client. (Best practice is for client connections to
- # be pooled anyway.) Only do so on Linux where it is known to be
- # supported.
- # u34 and greater need 180k
- JVM_OPTS="$JVM_OPTS -Xss180k"
-fi
-echo "xss = $JVM_OPTS"
-
-# GC tuning options
-JVM_OPTS="$JVM_OPTS -XX:+UseParNewGC"
-JVM_OPTS="$JVM_OPTS -XX:+UseConcMarkSweepGC"
-JVM_OPTS="$JVM_OPTS -XX:+CMSParallelRemarkEnabled"
-JVM_OPTS="$JVM_OPTS -XX:SurvivorRatio=8"
-JVM_OPTS="$JVM_OPTS -XX:MaxTenuringThreshold=1"
-JVM_OPTS="$JVM_OPTS -XX:CMSInitiatingOccupancyFraction=75"
-JVM_OPTS="$JVM_OPTS -XX:+UseCMSInitiatingOccupancyOnly"
-JVM_OPTS="$JVM_OPTS -XX:+UseTLAB"
-# note: bash evals '1.7.x' as > '1.7' so this is really a >= 1.7 jvm check
-if [ "$JVM_VERSION" \> "1.7" ] ; then
- JVM_OPTS="$JVM_OPTS -XX:+UseCondCardMark"
-fi
-
-# GC logging options -- uncomment to enable
-# JVM_OPTS="$JVM_OPTS -XX:+PrintGCDetails"
-# JVM_OPTS="$JVM_OPTS -XX:+PrintGCDateStamps"
-# JVM_OPTS="$JVM_OPTS -XX:+PrintHeapAtGC"
-# JVM_OPTS="$JVM_OPTS -XX:+PrintTenuringDistribution"
-# JVM_OPTS="$JVM_OPTS -XX:+PrintGCApplicationStoppedTime"
-# JVM_OPTS="$JVM_OPTS -XX:+PrintPromotionFailure"
-# JVM_OPTS="$JVM_OPTS -XX:PrintFLSStatistics=1"
-# JVM_OPTS="$JVM_OPTS -Xloggc:/var/log/cassandra/gc-`date +%s`.log"
-# If you are using JDK 6u34 7u2 or later you can enable GC log rotation
-# don't stick the date in the log name if rotation is on.
-# JVM_OPTS="$JVM_OPTS -Xloggc:/var/log/cassandra/gc.log"
-# JVM_OPTS="$JVM_OPTS -XX:+UseGCLogFileRotation"
-# JVM_OPTS="$JVM_OPTS -XX:NumberOfGCLogFiles=10"
-# JVM_OPTS="$JVM_OPTS -XX:GCLogFileSize=10M"
-
-# uncomment to have Cassandra JVM listen for remote debuggers/profilers on port 1414
-# JVM_OPTS="$JVM_OPTS -Xdebug -Xnoagent -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=1414"
-
-# Prefer binding to IPv4 network intefaces (when net.ipv6.bindv6only=1). See
-# http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6342561 (short version:
-# comment out this entry to enable IPv6 support).
-JVM_OPTS="$JVM_OPTS -Djava.net.preferIPv4Stack=true"
-
-# jmx: metrics and administration interface
-#
-# add this if you're having trouble connecting:
-# JVM_OPTS="$JVM_OPTS -Djava.rmi.server.hostname=<public name>"
-#
-# see
-# https://blogs.oracle.com/jmxetc/entry/troubleshooting_connection_problems...
-# for more on configuring JMX through firewalls, etc. (Short version:
-# get it working with no firewall first.)
-JVM_OPTS="$JVM_OPTS -Dcom.sun.management.jmxremote.port=$JMX_PORT"
-JVM_OPTS="$JVM_OPTS -Dcom.sun.management.jmxremote.ssl=false"
-JVM_OPTS="$JVM_OPTS -Dcom.sun.management.jmxremote.authenticate=false"
-JVM_OPTS="$JVM_OPTS $JVM_EXTRA_OPTS"
diff --git a/modules/common/cassandra-ccm/cassandra-ccm-core/src/test/resources/expected.cassandra-jvm.properties b/modules/common/cassandra-ccm/cassandra-ccm-core/src/test/resources/expected.cassandra-jvm.properties
new file mode 100644
index 0000000..a90d23c
--- /dev/null
+++ b/modules/common/cassandra-ccm/cassandra-ccm-core/src/test/resources/expected.cassandra-jvm.properties
@@ -0,0 +1,112 @@
+enable_assertions="-ea"
+
+# JMX settings
+jmx_port=7200
+
+use_thread_priorities="-XX:+UseThreadPriorities"
+
+thread_priority_policy="-XX:ThreadPriorityPolicy=42"
+
+heap_min=-Xms${MAX_HEAP_SIZE}
+heap_max=-Xmx${MAX_HEAP_SIZE}
+heap_new=-Xmn${HEAP_NEWSIZE}
+
+heap_dump_on_OOMError="-XX:+HeapDumpOnOutOfMemoryError"
+
+heap_dump_dir=""
+
+thread_stack_size=-Xss180k
+
+java_agent=""
+# Enable jamm when running on Java 6 patch version 23 or higher.
+#java_agent="-javaagent:$CASSANDRA_HOME/lib/jamm-0.2.5.jar"
+
+# GC tuning options
+#
+# Uses a parallel version of the young generation copying collector alongside
+# the default collector. This minimizes pauses by using all available CPUs in
+# parallel. The collector is compatible with both the default collector and the
+# Concurrent Mark and Sweep (CMS) collector.
+# This is a parallel collector option.
+use_par_new_gc="-XX:+UseParNewGC"
+
+# Whether parallel remark enabled (only if ParNewGC)
+# This is a parallel collector option.
+cms_parallel_remark_enabled="-XX:+CMSParallelRemarkEnabled"
+
+# Uses the Concurrent Mark and Sweep collector. It is a mostly concurrent
+# collector with a low pause time. It is a good match for multi-core systems.
+use_concur_mark_sweep_gc="-XX:+UseConcMarkSweepGC"
+
+# Ratio of eden/survivor space size. The default value is 8.
+# This is a Garbage First (G1) garbage collector option.
+survivor_ratio="-XX:SurvivorRatio=8"
+
+# Maximum value for tenuring threshold.
+# Young collection tuning option.
+max_tenuring_threshold="-XX:MaxTenuringThreshold=1"
+
+# Percentage CMS generation occupancy to start a CMS collection cycle (A
+# negative value means that CMSTirggerRatio is used).
+# This is a CMS tuning option.
+cms_initiating_occupancy_fraction="-XX:CMSInitiatingOccupancyFraction=75"
+
+# Only use occupancy as a criterion for starting a CMS collection.
+# This is a CMS tuning option.
+use_cms_initiating_occupancy_only="-XX:+UseCMSInitiatingOccupancyOnly"
+
+# Use thread local allocation blocks in young space. Enabled by default.
+# This is a young collection tuning option.
+use_tlab="-XX:+UseTLAB"
+
+#####################
+# GC logging options
+#####################
+# Print more details at garbage collection
+#print_gc_details="-XX:+PrintGCDetails"
+print_gc_details=""
+
+# Prefix logging statements with wall clock time.
+#print_gc_datestamps="XX:+PrintGCDateStamps"
+print_gc_datestamps=""
+
+# Print heap layout before and after each garbage collection.
+#print_heap_at_gc="-XX:+PrintHeapAtGC"
+print_heap_at_gc=""
+
+# Print tenuring age information.
+#print_tenuring_distribution="-XX:+PrintTenuringDistribution"
+print_tenuring_distribution=""
+
+# Print the time the application has been stopped.
+#print_gc_application_stopped_time="-XX:+PrintGCApplicationStoppedTime"
+print_gc_application_stopped_time=""
+
+# Print more details about promotion failures.
+#print_promotion_failure="-XX:+PrintPromotionFailure"
+print_promotion_failure=""
+
+# Print statistics for CMS' FreeListSpace.
+#print_flss_stats="-XX:PrintFLSStatistics=1"
+print_flss_stats=""
+
+# Redirects GC output to file instead of console.
+#gc_log_file="-Xloggc:/var/log/cassandra/gc-`date +%s`.log"
+gc_log_file=""
+
+###############################################################################
+# THE FOLLOWING IS READ ONLY
+# Now build the JVM_OPTS variable. The following variables should NOT be
+# directly modified. Instead update the preceding variables. The following
+# variables build up the JVM_OPTS variable that is read by the cassandra and
+# cassandra.bat scripts.
+###############################################################################
+HEAP_OPTS="${heap_min} ${heap_max} ${heap_new} ${heap_dump_on_OOMError} ${thread_stack_size}"
+
+GC_TUNING_OPTS="${use_par_new_gc} ${use_concur_mark_sweep_gc} ${cms_parallel_remark_enabled} ${survivor_ratio} ${max_tenuring_threshold} ${cms_initiating_occupancy_fraction} ${use_cms_initiating_occupancy_only} ${use_tlab}"
+
+GC_LOGGING_OPTS="${print_gc_details} ${print_gc_datestamps} ${print_heap_at_gc} ${print_tenuring_distribution} ${print_gc_application_stopped_time} ${print_promotion_failure} ${print_flss_stats} ${gc_log_file}"
+
+JMX_OPTS="-Dcom.sun.management.jmxremote.port=${jmx_port} -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false"
+
+JVM_OPTS="${enable_assertions} ${java_agent} ${use_thread_priorities} ${thread_priority_policy} ${HEAP_OPTS} ${GC_TUNING_OPTS} ${GC_LOGGING_OPTS} ${JMX_OPTS}"
diff --git a/modules/common/cassandra-ccm/cassandra-ccm-core/src/test/resources/expected.cassandra.yaml b/modules/common/cassandra-ccm/cassandra-ccm-core/src/test/resources/expected.cassandra.yaml
index 82778c9..15d08f2 100644
--- a/modules/common/cassandra-ccm/cassandra-ccm-core/src/test/resources/expected.cassandra.yaml
+++ b/modules/common/cassandra-ccm/cassandra-ccm-core/src/test/resources/expected.cassandra.yaml
@@ -681,7 +681,7 @@ client_encryption_options:
# can be: all - all traffic is compressed
# dc - traffic between different datacenters is compressed
# none - nothing is compressed.
-internode_compression: all
+internode_compression: none
# Enable or disable tcp_nodelay for inter-dc communication.
# Disabling it will result in larger (but fewer) network packets being sent,
commit bf78527f20bfeb95fe6040ae5f744bf633d08140
Author: John Sanda <jsanda(a)redhat.com>
Date: Sat Jul 13 12:46:07 2013 -0400
remove usage of cassandra-env.sh for cassandra start up
We want to manage C* heap settings and other options/arguments passed to the
C* JVM command line. On linux, the JVM options are set using the JVM_OPTS
shell script variable which is done in cassandra-env.sh. The cassandra-env.sh
script however does not lend itself well to our structured, resource
configuration. The JVM_OPTS variable is now built up in
cassandra-jvm.properties which is a java properties file that also uses legal
shell syntax. The file is sourced from the cassandra start script. This paves
the way for resource configuration of the Cassandra JVM options.
I am also hoping that we can do something similar for Windows where we can use
cassandra-jvm.properties. This would substantially reduce the need for platform
specific code in the storage plugin.
diff --git a/modules/common/cassandra-ccm/cassandra-ccm-core/pom.xml b/modules/common/cassandra-ccm/cassandra-ccm-core/pom.xml
index 0b015b4..42f6c8b 100644
--- a/modules/common/cassandra-ccm/cassandra-ccm-core/pom.xml
+++ b/modules/common/cassandra-ccm/cassandra-ccm-core/pom.xml
@@ -167,6 +167,9 @@
<copy file="${settings.localRepository}/org/xerial/snappy/snappy-java/${cassandra.snappy.version}/snappy-java-${cassandra.snappy.version}.jar"
todir="${cassandra.dir}/lib"/>
<move file="${project.build.outputDirectory}/cassandra/conf" todir="${cassandra.dir}"/>
+ <delete file="${cassandra.dir}/bin/cassandra"/>
+ <move file="${project.build.outputDirectory}/cassandra/bin/cassandra" todir="${cassandra.dir}/bin"/>
+ <delete dir="${project.build.outputDirectory}/cassandra"/>
<delete dir="${cassandra.dir}/javadoc"/>
<zip basedir="${cassandra.dir}" destfile="${cassandra.distro.zip}"/>
diff --git a/modules/common/cassandra-ccm/cassandra-ccm-core/src/main/bundle/cassandra/bin/cassandra b/modules/common/cassandra-ccm/cassandra-ccm-core/src/main/bundle/cassandra/bin/cassandra
new file mode 100755
index 0000000..742d9c0
--- /dev/null
+++ b/modules/common/cassandra-ccm/cassandra-ccm-core/src/main/bundle/cassandra/bin/cassandra
@@ -0,0 +1,193 @@
+#!/bin/sh
+# 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.
+
+
+# OPTIONS:
+# -f: start in foreground
+# -p <filename>: log the pid to a file (useful to kill it later)
+# -v: print version string and exit
+
+# CONTROLLING STARTUP:
+#
+# This script relies on few environment variables to determine startup
+# behavior, those variables are:
+#
+# CLASSPATH -- A Java classpath containing everything necessary to run.
+# JVM_OPTS -- Additional arguments to the JVM for heap size, etc
+# CASSANDRA_CONF -- Directory containing Cassandra configuration files.
+#
+# As a convenience, a fragment of shell is sourced in order to set one or
+# more of these variables. This so-called `include' can be placed in a
+# number of locations and will be searched for in order. The lowest
+# priority search path is the same directory as the startup script, and
+# since this is the location of the sample in the project tree, it should
+# almost work Out Of The Box.
+#
+# Any serious use-case though will likely require customization of the
+# include. For production installations, it is recommended that you copy
+# the sample to one of /usr/share/cassandra/cassandra.in.sh,
+# /usr/local/share/cassandra/cassandra.in.sh, or
+# /opt/cassandra/cassandra.in.sh and make your modifications there.
+#
+# Another option is to specify the full path to the include file in the
+# environment. For example:
+#
+# $ CASSANDRA_INCLUDE=/path/to/in.sh cassandra -p /var/run/cass.pid
+#
+# Note: This is particularly handy for running multiple instances on a
+# single installation, or for quick tests.
+#
+# Finally, developers and enthusiasts who frequently run from an SVN
+# checkout, and do not want to locally modify bin/cassandra.in.sh, can put
+# a customized include file at ~/.cassandra.in.sh.
+#
+# If you would rather configure startup entirely from the environment, you
+# can disable the include by exporting an empty CASSANDRA_INCLUDE, or by
+# ensuring that no include files exist in the aforementioned search list.
+# Be aware that you will be entirely responsible for populating the needed
+# environment variables.
+
+# NB: Developers should be aware that this script should remain compatible with
+# POSIX sh and Solaris sh. This means, in particular, no $(( )) and no $( ).
+
+# If an include wasn't specified in the environment, then search for one...
+if [ "x$CASSANDRA_INCLUDE" = "x" ]; then
+ # Locations (in order) to use when searching for an include file.
+ for include in /usr/share/cassandra/cassandra.in.sh \
+ /usr/local/share/cassandra/cassandra.in.sh \
+ /opt/cassandra/cassandra.in.sh \
+ "$HOME/.cassandra.in.sh" \
+ "`dirname $0`/cassandra.in.sh"; do
+ if [ -r "$include" ]; then
+ . "$include"
+ break
+ fi
+ done
+# ...otherwise, source the specified include.
+elif [ -r "$CASSANDRA_INCLUDE" ]; then
+ . "$CASSANDRA_INCLUDE"
+fi
+
+# Use JAVA_HOME if set, otherwise look for java in PATH
+if [ -n "$JAVA_HOME" ]; then
+ JAVA="$JAVA_HOME/bin/java"
+else
+ JAVA=java
+fi
+
+# If numactl is available, use it. For Cassandra, the priority is to
+# avoid disk I/O. Even for the purpose of CPU efficiency, we don't
+# really have CPU<->data affinity anyway. Also, empirically test that numactl
+# works before trying to use it (CASSANDRA-3245).
+NUMACTL_ARGS="--interleave=all"
+if which numactl >/dev/null 2>/dev/null && numactl $NUMACTL_ARGS ls / >/dev/null 2>/dev/null
+then
+ NUMACTL="numactl $NUMACTL_ARGS"
+else
+ NUMACTL=""
+fi
+
+if [ -z "$CASSANDRA_CONF" -o -z "$CLASSPATH" ]; then
+ echo "You must set the CASSANDRA_CONF and CLASSPATH vars" >&2
+ exit 1
+fi
+
+if [ -f "$CASSANDRA_CONF/cassandra-env.sh" ]; then
+ #. "$CASSANDRA_CONF/cassandra-env.sh"
+ . "$CASSANDRA_CONF/cassandra-jvm.properties"
+fi
+
+# Special-case path variables.
+case "`uname`" in
+ CYGWIN*)
+ CLASSPATH=`cygpath -p -w "$CLASSPATH"`
+ CASSANDRA_CONF=`cygpath -p -w "$CASSANDRA_CONF"`
+ ;;
+esac
+
+launch_service()
+{
+ pidpath=$1
+ foreground=$2
+ props=$3
+ class=$4
+ cassandra_parms="-Dlog4j.configuration=log4j-server.properties -Dlog4j.defaultInitOverride=true"
+
+ if [ "x$pidpath" != "x" ]; then
+ cassandra_parms="$cassandra_parms -Dcassandra-pidfile=$pidpath"
+ fi
+
+ # The cassandra-foreground option will tell CassandraDaemon not
+ # to close stdout/stderr, but it's up to us not to background.
+ if [ "x$foreground" != "x" ]; then
+ cassandra_parms="$cassandra_parms -Dcassandra-foreground=yes"
+ exec $NUMACTL "$JAVA" $JVM_OPTS $cassandra_parms -cp "$CLASSPATH" $props "$class"
+ # Startup CassandraDaemon, background it, and write the pid.
+ else
+ exec $NUMACTL "$JAVA" $JVM_OPTS $cassandra_parms -cp "$CLASSPATH" $props "$class" <&- &
+ [ ! -z "$pidpath" ] && printf "%d" $! > "$pidpath"
+ true
+ fi
+
+ return $?
+}
+
+# Parse any command line options.
+args=`getopt vfhp:bD: "$@"`
+eval set -- "$args"
+
+classname="org.apache.cassandra.service.CassandraDaemon"
+
+while true; do
+ case "$1" in
+ -p)
+ pidfile="$2"
+ shift 2
+ ;;
+ -f)
+ foreground="yes"
+ shift
+ ;;
+ -h)
+ echo "Usage: $0 [-f] [-h] [-p pidfile]"
+ exit 0
+ ;;
+ -v)
+ "$JAVA" -cp "$CLASSPATH" org.apache.cassandra.tools.GetVersion
+ exit 0
+ ;;
+ -D)
+ properties="$properties -D$2"
+ shift 2
+ ;;
+ --)
+ shift
+ break
+ ;;
+ *)
+ echo "Error parsing arguments!" >&2
+ exit 1
+ ;;
+ esac
+done
+
+# Start up the service
+launch_service "$pidfile" "$foreground" "$properties" "$classname"
+
+exit $?
+
+# vi:ai sw=4 ts=4 tw=0 et
diff --git a/modules/common/cassandra-ccm/cassandra-ccm-core/src/main/bundle/cassandra/conf/cassandra-jvm.properties b/modules/common/cassandra-ccm/cassandra-ccm-core/src/main/bundle/cassandra/conf/cassandra-jvm.properties
new file mode 100644
index 0000000..612c65e
--- /dev/null
+++ b/modules/common/cassandra-ccm/cassandra-ccm-core/src/main/bundle/cassandra/conf/cassandra-jvm.properties
@@ -0,0 +1,112 @@
+enable_assertions="-ea"
+
+# JMX settings
+jmx_port="7299"
+
+use_thread_priorities="-XX:+UseThreadPriorities"
+
+thread_priority_policy="-XX:ThreadPriorityPolicy=42"
+
+heap_min="-Xms256M"
+heap_max="-Xms256M"
+heap_new="-Xmn64M"
+
+heap_dump_on_OOMError="-XX:+HeapDumpOnOutOfMemoryError"
+
+heap_dump_dir=""
+
+thread_stack_size="-Xss180k"
+
+java_agent=""
+# Enable jamm when running on Java 6 patch version 23 or higher.
+#java_agent="-javaagent:$CASSANDRA_HOME/lib/jamm-0.2.5.jar"
+
+# GC tuning options
+#
+# Uses a parallel version of the young generation copying collector alongside
+# the default collector. This minimizes pauses by using all available CPUs in
+# parallel. The collector is compatible with both the default collector and the
+# Concurrent Mark and Sweep (CMS) collector.
+# This is a parallel collector option.
+use_par_new_gc="-XX:+UseParNewGC"
+
+# Whether parallel remark enabled (only if ParNewGC)
+# This is a parallel collector option.
+cms_parallel_remark_enabled="-XX:+CMSParallelRemarkEnabled"
+
+# Uses the Concurrent Mark and Sweep collector. It is a mostly concurrent
+# collector with a low pause time. It is a good match for multi-core systems.
+use_concur_mark_sweep_gc="-XX:+UseConcMarkSweepGC"
+
+# Ratio of eden/survivor space size. The default value is 8.
+# This is a Garbage First (G1) garbage collector option.
+survivor_ratio="-XX:SurvivorRatio=8"
+
+# Maximum value for tenuring threshold.
+# Young collection tuning option.
+max_tenuring_threshold="-XX:MaxTenuringThreshold=1"
+
+# Percentage CMS generation occupancy to start a CMS collection cycle (A
+# negative value means that CMSTirggerRatio is used).
+# This is a CMS tuning option.
+cms_initiating_occupancy_fraction="-XX:CMSInitiatingOccupancyFraction=75"
+
+# Only use occupancy as a criterion for starting a CMS collection.
+# This is a CMS tuning option.
+use_cms_initiating_occupancy_only="-XX:+UseCMSInitiatingOccupancyOnly"
+
+# Use thread local allocation blocks in young space. Enabled by default.
+# This is a young collection tuning option.
+use_tlab="-XX:+UseTLAB"
+
+#####################
+# GC logging options
+#####################
+# Print more details at garbage collection
+#print_gc_details="-XX:+PrintGCDetails"
+print_gc_details=""
+
+# Prefix logging statements with wall clock time.
+#print_gc_datestamps="XX:+PrintGCDateStamps"
+print_gc_datestamps=""
+
+# Print heap layout before and after each garbage collection.
+#print_heap_at_gc="-XX:+PrintHeapAtGC"
+print_heap_at_gc=""
+
+# Print tenuring age information.
+#print_tenuring_distribution="-XX:+PrintTenuringDistribution"
+print_tenuring_distribution=""
+
+# Print the time the application has been stopped.
+#print_gc_application_stopped_time="-XX:+PrintGCApplicationStoppedTime"
+print_gc_application_stopped_time=""
+
+# Print more details about promotion failures.
+#print_promotion_failure="-XX:+PrintPromotionFailure"
+print_promotion_failure=""
+
+# Print statistics for CMS' FreeListSpace.
+#print_flss_stats="-XX:PrintFLSStatistics=1"
+print_flss_stats=""
+
+# Redirects GC output to file instead of console.
+#gc_log_file="-Xloggc:/var/log/cassandra/gc-`date +%s`.log"
+gc_log_file=""
+
+###############################################################################
+# THE FOLLOWING IS READ ONLY
+# Now build the JVM_OPTS variable. The following variables should NOT be
+# directly modified. Instead update the preceding variables. The following
+# variables build up the JVM_OPTS variable that is read by the cassandra and
+# cassandra.bat scripts.
+###############################################################################
+HEAP_OPTS="${heap_min} ${heap_max} ${heap_new} ${heap_dump_on_OOMError} ${thread_stack_size}"
+
+GC_TUNING_OPTS="${use_par_new_gc} ${use_concur_mark_sweep_gc} ${cms_parallel_remark_enabled} ${survivor_ratio} ${max_tenuring_threshold} ${cms_initiating_occupancy_fraction} ${use_cms_initiating_occupancy_only} ${use_tlab}"
+
+GC_LOGGING_OPTS="${print_gc_details} ${print_gc_datestamps} ${print_heap_at_gc} ${print_tenuring_distribution} ${print_gc_application_stopped_time} ${print_promotion_failure} ${print_flss_stats} ${gc_log_file}"
+
+JMX_OPTS="-Dcom.sun.management.jmxremote.port=${jmx_port} -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false"
+
+JVM_OPTS="${enable_assertions} ${java_agent} ${use_thread_priorities} ${thread_priority_policy} ${HEAP_OPTS} ${GC_TUNING_OPTS} ${GC_LOGGING_OPTS} ${JMX_OPTS}"
diff --git a/modules/common/cassandra-ccm/cassandra-ccm-core/src/main/java/org/rhq/cassandra/Deployer.java b/modules/common/cassandra-ccm/cassandra-ccm-core/src/main/java/org/rhq/cassandra/Deployer.java
index e85813d..1e31e14 100644
--- a/modules/common/cassandra-ccm/cassandra-ccm-core/src/main/java/org/rhq/cassandra/Deployer.java
+++ b/modules/common/cassandra-ccm/cassandra-ccm-core/src/main/java/org/rhq/cassandra/Deployer.java
@@ -31,10 +31,12 @@ import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
+import java.util.Properties;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.rhq.core.util.PropertiesFileUpdate;
import org.rhq.core.util.TokenReplacingReader;
import org.rhq.core.util.ZipUtil;
import org.rhq.core.util.stream.StreamUtil;
@@ -83,10 +85,13 @@ public class Deployer {
applyConfigChanges(confDir, "cassandra.yaml", tokens);
applyConfigChanges(confDir, "log4j-server.properties", tokens);
- applyConfigChanges(confDir, "cassandra-env.sh", tokens);
+ applyChangesToCassandraJvmProps(confDir, deploymentOptions);
+// applyConfigChanges(confDir, "cassandra-env.sh", tokens);
}
- private void applyConfigChanges(File confDir, String fileName, Map<String, String> tokens) throws DeploymentException {
+ private void applyConfigChanges(File confDir, String fileName, Map<String, String> tokens)
+ throws DeploymentException {
+
File filteredFile = new File(confDir, fileName);
try {
if (log.isInfoEnabled()) {
@@ -104,6 +109,29 @@ public class Deployer {
}
}
+ private void applyChangesToCassandraJvmProps(File confDir, DeploymentOptions deploymentOptions)
+ throws DeploymentException {
+
+ File jvmPropsFile = new File(confDir, "cassandra-jvm.properties");
+ try {
+ log.info("Applying configuration changes to " + jvmPropsFile);
+
+ PropertiesFileUpdate propertiesUpdater = new PropertiesFileUpdate(jvmPropsFile.getAbsolutePath());
+ Properties properties = propertiesUpdater.loadExistingProperties();
+
+ properties.setProperty("heap_min", "-Xms" + deploymentOptions.getHeapSize());
+ properties.setProperty("heap_max", "-Xmx" + deploymentOptions.getHeapSize());
+ properties.setProperty("heap_new", "-Xmn" + deploymentOptions.getHeapNewSize());
+ properties.setProperty("thread_stack_size", "-Xss" + deploymentOptions.getStackSize());
+ properties.setProperty("jmx_port", deploymentOptions.getJmxPort().toString());
+
+ propertiesUpdater.update(properties);
+ } catch (IOException e) {
+ log.error("An error occurred while updating " + jvmPropsFile, e);
+ throw new DeploymentException("An error occurred while updating " + jvmPropsFile, e);
+ }
+ }
+
public void updateFilePerms() {
File deployDir = new File(deploymentOptions.getBasedir());
File binDir = new File(deployDir, "bin");
commit 7185fb3fbaf98dde194872657c7362134d342c10
Author: John Sanda <jsanda(a)redhat.com>
Date: Sat Jul 13 10:08:22 2013 -0400
remove obsolete files that are no longer used
diff --git a/modules/common/cassandra-ccm/cassandra-ccm-core/src/main/bundle/deploy.xml b/modules/common/cassandra-ccm/cassandra-ccm-core/src/main/bundle/deploy.xml
deleted file mode 100644
index 19d5647..0000000
--- a/modules/common/cassandra-ccm/cassandra-ccm-core/src/main/bundle/deploy.xml
+++ /dev/null
@@ -1,221 +0,0 @@
-<project name="rhq_cassandra_bundle"
- default="main"
- xmlns:rhq="antlib:org.rhq.bundle">
- <rhq:bundle name="${rhq.cassandra.bundle.name}"
- version="${rhq.cassandra.bundle.version}"
- description="A bundle for deploying RHQ Cassandra nodes.">
-
- <!--
- NOTE: the name attribute of an rhq:input-property does not support using a dash.
- There is a convention where dashes are used in property names in rhq properties files
- in the trailing part of a property name. If an rhq:input-property has a corresponding
- property in cassandra.properties and contains a dash, the dash will be changed to an
- underscore in this file.
- -->
-
- <rhq:input-property name="cluster.name"
- description="The name of the cluster. This is used to prevent machines in one logical cluster from joining another"
- required="true"
- defaultValue="rhqdev"
- type="string"/>
-
- <rhq:input-property name="cluster.dir"
- description="The directory in which Cassandra nodes will be installed"
- required="true"
- defaultValue=""
- type="string"/>
-
- <rhq:input-property name="data.dir"
- description="The directory where Cassandra should store data files."
- required="true"
- defaultValue="data"
- type="string"/>
-
- <rhq:input-property name="commitlog.dir"
- description="The directory where Cassandra stores its commit logs."
- required="true"
- defaultValue="commit_log"
- type="string"/>
-
- <rhq:input-property name="saved.caches.dir"
- description="The directory where Cassandra stores saved caches."
- required="true"
- defaultValue="saved_caches"
- type="string"/>
-
- <rhq:input-property name="log.dir"
- description="The directory where Cassandra stores log files."
- required="true"
- defaultValue="logs"
- type="string"/>
-
- <rhq:input-property name="rhq.cassandra.log.file.name"
- description="The name of the log file to which Cassandra writes."
- required="true"
- defaultValue="rhq-storage-node.log"
- type="string"/>
-
- <rhq:input-property name="logging.level"
- description="The log4j logging level to use."
- required="false"
- defaultValue="DEBUG"
- type="string"/>
-
- <rhq:input-property name="seeds"
- description="A comma-delimited list of IP addresses/host names that are deemed contact points. Cassandra nodes use this list of hosts to find each other and learn the topology of the ring. If you are running a local development cluster, be sure to have aliases set up for localhost."
- required="false"
- defaultValue="127.0.0.1"
- type="string"/>
-
- <rhq:input-property name="rhq.cassandra.num_tokens"
- description="Defines the number of tokens randomly assigned to a node on the ring. The more tokens, relative to other nodes, the larger the proportion of data that this node will store. You probably want all nodes to have the same number of tokens assuming they have equal hardware capability."
- required="false"
- defaultValue="256"
- type="string"/>
-
- <rhq:input-property name="jmx.port"
- description="The port over which Cassandra listens for JMX connections. Each node should be assigned a unique port."
- required="false"
- defaultValue="7200"
- type="string"/>
-
- <rhq:input-property name="rhq.cassandra.storage.port"
- description="The port used for inter-node communication."
- required="false"
- defaultValue="7000"
- type="string"/>
-
- <rhq:input-property name="rhq.cassandra.ssl.storage.port"
- description="The port used for encrypted inter-node communication."
- required="false"
- defaultValue="7001"
- type="string"/>
-
- <rhq:input-property name="listen.address"
- description="Address used for inter-node communication. Defaults to value of hostname property."
- required="true"
- defaultValue=""
- type="string"/>
-
- <rhq:input-property name="rpc.address"
- description="Address used for Thrift RPC client communication. Defaults to value of hostname property."
- required="true"
- defaultValue=""
- type="string"/>
-
- <rhq:input-property name="cassandra.ring.delay.property"
- required="false"
- defaultValue=""
- type="string"/>
-
- <rhq:input-property name="cassandra.ring.delay"
- description="When a node initializes it contacts a seed and then sleeps for RING_DELAY (milliseconds) to learn about other nodes in the cluster. Cassandra uses a default value of 30 seconds."
- required="false"
- defaultValue=""
- type="string"/>
-
- <rhq:input-property name="rhq.cassandra.native_transport_max_threads"
- description="The maximum number of threads handling native CQL requests."
- required="false"
- defaultValue="64"
- type="integer"/>
-
- <rhq:input-property name="rhq.cassandra.native_transport_port"
- description="The port for the CQL native transport to listen for clients on."
- required="false"
- defaultValue="9042"
- type="integer"/>
-
- <rhq:input-property name="rhq.cassandra.rpc_port"
- description="The port to listen for Thrift clients on."
- required="false"
- defaultValue="9160"
- type="integer"/>
-
- <rhq:input-property name="rhq.cassandra.authenticator"
- description="A class that performs authentication. The value should be a fully qualified class name and implement IAuthenticator."
- required="false"
- defaultValue="org.rhq.cassandra.auth.SimpleAuthenticator"
- type="string"/>
-
- <rhq:input-property name="rhq.cassandra.authorizer"
- description="A class that performs authorization. Used to limit/provide permissions. The value should be a fully qualified class name and implement IAuthorizer."
- required="false"
- defaultValue="org.rhq.cassandra.auth.SimpleAuthorizer"
- type="string"/>
-
- <rhq:input-property name="rhq.cassandra.password.properties.file"
- description="The location of the password properties file used by SimpleAuthenticator. If a relative path is specified, its location is resolved relative to Cassandra's bin directory."
- required="false"
- defaultValue="./../conf/passwd.properties"
- type="file"/>
-
- <rhq:input-property name="rhq.cassandra.access.properties.file"
- description="The location of the authorization properties file used by SimpleAuthority. If a relative path is specified, its location is resolved relative to Cassandra's bin directory."
- required="false"
- defaultValue="./../conf/access.properties"
- type="file"/>
-
- <rhq:input-property name="rhq.cassandra.username"
- description="The username with which to authenticate requests to Cassandra."
- required="true"
- type="string"/>
-
- <rhq:input-property name="rhq.cassandra.password"
- description="The password with which to authenticate requests to Cassandra."
- required="true"
- type="string"/>
-
- <rhq:input-property name="rhq.cassandra.max.heap.size"
- required="true"
- defaultValue="${MAX_HEAP_SIZE}"/>
-
- <rhq:input-property name="rhq.cassandra.heap.new.size"
- required="true"
- defaultValue="${HEAP_NEWSIZE}"/>
-
- <rhq:deployment-unit name="cassandra" preinstallTarget="pre-install" postinstallTarget="post-install">
-<!--
- <rhq:file name="dbsetup.script" destinationFile="scripts/dbsetup.script" replace="true"/>
--->
- <rhq:archive name="cassandra.zip">
- <rhq:replace>
- <rhq:fileset dir="conf">
- <include name="cassandra.yaml"/>
- </rhq:fileset>
- <rhq:fileset dir="conf">
- <include name="cassandra-env.sh"/>
- </rhq:fileset>
- <rhq:fileset dir="conf">
- <include name="log4j-server.properties"/>
- </rhq:fileset>
- <rhq:fileset dir="conf">
- <include name="passwd.properties"/>
- </rhq:fileset>
-<!--
- <rhq:fileset dir="scripts">
- <include name="dbsetup.script"/>
- </rhq:fileset>
--->
- </rhq:replace>
- </rhq:archive>
- </rhq:deployment-unit>
- </rhq:bundle>
-
- <target name="main"/>
-
- <target name="pre-install">
- <mkdir dir="${cluster.dir}"/>
-
- </target>
-
- <target name="post-install">
- <property name="bin.dir" value="${rhq.deploy.dir}/bin"/>
-
- <chmod file="${bin.dir}/cassandra" perm="+x"/>
- <chmod file="${bin.dir}/cqlsh" perm="+x"/>
- <chmod file="${bin.dir}/cassandra-cli" perm="+x"/>
- <chmod file="${bin.dir}/nodetool" perm="+x"/>
- </target>
-
-</project>
diff --git a/modules/common/cassandra-ccm/cassandra-ccm-core/src/main/cassandra/cli/dbsetup.script b/modules/common/cassandra-ccm/cassandra-ccm-core/src/main/cassandra/cli/dbsetup.script
deleted file mode 100644
index 73bc2a7..0000000
--- a/modules/common/cassandra-ccm/cassandra-ccm-core/src/main/cassandra/cli/dbsetup.script
+++ /dev/null
@@ -1,40 +0,0 @@
-create keyspace rhq
- with placement_strategy = 'org.apache.cassandra.locator.SimpleStrategy' and
- strategy_options = {replication_factor:1};
-
-use rhq;
-
-create column family raw_metrics
- with comparator = DateType and
- default_validation_class = DoubleType and
- key_validation_class = Int32Type;
-
-create column family one_hour_metric_data
- with comparator = 'CompositeType(DateType, Int32Type)' and
- default_validation_class = DoubleType and
- key_validation_class = Int32Type;
-
-create column family six_hour_metric_data
- with comparator = 'CompositeType(DateType, Int32Type)' and
- default_validation_class = DoubleType and
- key_validation_class = Int32Type;
-
-create column family twenty_four_hour_metric_data
- with comparator = 'CompositeType(DateType, Int32Type)' and
- default_validation_class = DoubleType and
- key_validation_class = Int32Type;
-
-create column family metrics_work_queue
- with comparator = 'CompositeType(DateType, Int32Type)' and
- default_validation_class = Int32Type and
- key_validation_class = UTF8Type;
-
-create column family resource_traits
- with comparator = 'CompositeType(DateType, Int32Type, Int32Type, UTF8Type, UTF8Type)' and
- default_validation_class = UTF8Type and
- key_validation_class = Int32Type;
-
-create column family traits
- with comparator = DateType and
- default_validation_class = UTF8Type and
- key_validation_class = Int32Type;
diff --git a/modules/common/cassandra-ccm/cassandra-ccm-core/src/main/cassandra/cql/create_keyspace.cql b/modules/common/cassandra-ccm/cassandra-ccm-core/src/main/cassandra/cql/create_keyspace.cql
deleted file mode 100644
index 9df13a0..0000000
--- a/modules/common/cassandra-ccm/cassandra-ccm-core/src/main/cassandra/cql/create_keyspace.cql
+++ /dev/null
@@ -1 +0,0 @@
-CREATE KEYSPACE rhq WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 1};
diff --git a/modules/common/cassandra-ccm/cassandra-ccm-core/src/main/cassandra/cql/dbsetup.cql b/modules/common/cassandra-ccm/cassandra-ccm-core/src/main/cassandra/cql/dbsetup.cql
deleted file mode 100644
index 189b35b..0000000
--- a/modules/common/cassandra-ccm/cassandra-ccm-core/src/main/cassandra/cql/dbsetup.cql
+++ /dev/null
@@ -1,42 +0,0 @@
-CREATE KEYSPACE rhq WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 1};
-
-USE rhq;
-
-CREATE TABLE raw_metrics (
- schedule_id int,
- time timestamp,
- value double,
- PRIMARY KEY (schedule_id, time)
-);
-
-CREATE TABLE one_hour_metrics (
- schedule_id int,
- time timestamp,
- type int,
- value double,
- PRIMARY KEY (schedule_id, time, type)
-);
-
-CREATE TABLE six_hour_metrics (
- schedule_id int,
- time timestamp,
- type int,
- value double,
- PRIMARY KEY (schedule_id, time, type)
-);
-
-CREATE TABLE twenty_four_hour_metrics (
- schedule_id int,
- time timestamp,
- type int,
- value double,
- PRIMARY KEY (schedule_id, time, type)
-);
-
-CREATE TABLE metrics_index (
- bucket varchar,
- time timestamp,
- schedule_id int,
- null_col boolean,
- PRIMARY KEY (bucket, time, schedule_id)
-);
10 years, 11 months