[rhq] 3 commits - modules/core modules/enterprise modules/plugins
by Heiko W. Rupp
modules/core/plugin-container/src/main/java/org/rhq/core/pc/util/DiscoveryComponentProxyFactory.java | 2
modules/enterprise/agent/src/main/java/org/rhq/enterprise/agent/PluginUpdate.java | 7 -
modules/plugins/augeas/src/main/java/org/rhq/plugins/augeas/AugeasConfigurationComponent.java | 41 ++++++----
modules/plugins/samba/src/main/java/org/rhq/plugins/samba/SambaShareDiscoveryComponent.java | 18 ++--
4 files changed, 41 insertions(+), 27 deletions(-)
New commits:
commit 59fa8941390850b6bb0d3f5380963592ed25e0e2
Author: Heiko W. Rupp <hwr(a)redhat.com>
Date: Sat Jun 29 13:33:40 2013 +0200
If we got an interrupted exception, there is no point of showing the stacktrace.
diff --git a/modules/core/plugin-container/src/main/java/org/rhq/core/pc/util/DiscoveryComponentProxyFactory.java b/modules/core/plugin-container/src/main/java/org/rhq/core/pc/util/DiscoveryComponentProxyFactory.java
index c160b78..ac465a6 100644
--- a/modules/core/plugin-container/src/main/java/org/rhq/core/pc/util/DiscoveryComponentProxyFactory.java
+++ b/modules/core/plugin-container/src/main/java/org/rhq/core/pc/util/DiscoveryComponentProxyFactory.java
@@ -223,7 +223,7 @@ public class DiscoveryComponentProxyFactory {
log.debug("Thread [" + Thread.currentThread().getName() + "] was interrupted.");
}
future.cancel(true); // this is a daemon thread, let's try to cancel it
- throw new RuntimeException(invokedMethodString(method, args, "was interrupted."), e);
+ throw new RuntimeException(invokedMethodString(method, args, "was interrupted."));
} catch (ExecutionException e) {
if (log.isDebugEnabled()) {
log.debug(invokedMethodString(method, args, "failed."), e);
commit 2b75b3367e0303916dce653869c8af6f69638694
Author: Heiko W. Rupp <hwr(a)redhat.com>
Date: Sat Jun 29 13:23:05 2013 +0200
BZ 725736 If no augeas just return null. Also prevent other meaningless stacktraces when Augeas is not present.
diff --git a/modules/plugins/augeas/src/main/java/org/rhq/plugins/augeas/AugeasConfigurationComponent.java b/modules/plugins/augeas/src/main/java/org/rhq/plugins/augeas/AugeasConfigurationComponent.java
index 5976ad8..63a5cd2 100644
--- a/modules/plugins/augeas/src/main/java/org/rhq/plugins/augeas/AugeasConfigurationComponent.java
+++ b/modules/plugins/augeas/src/main/java/org/rhq/plugins/augeas/AugeasConfigurationComponent.java
@@ -138,6 +138,14 @@ public class AugeasConfigurationComponent<T extends ResourceComponent<?>> implem
}
public Configuration loadResourceConfiguration() throws Exception {
+
+ if (!isAugeasAvailable()) {
+ if (log.isDebugEnabled()) {
+ log.debug("Can not load configuration as Augeas is not available");
+ }
+ return null;
+ }
+
abortIfAugeasNotAvailable();
//augeas was initialized in abortIfAugeasNotAvailable();
@@ -346,7 +354,7 @@ public class AugeasConfigurationComponent<T extends ResourceComponent<?>> implem
/**
* Returns initialized augeas instance. Augeas instance must be closed by calling method close on the Augeas instance
- * or by calling method close on AugeasConfigurationComponent instance after use of augeas.
+ * or by calling method close on AugeasConfigurationComponent instance after use of augeas.
* @return
*/
public Augeas getAugeas() {
@@ -378,9 +386,13 @@ public class AugeasConfigurationComponent<T extends ResourceComponent<?>> implem
augeas = new Augeas(this.augeasRootPath, augeasLoadPath, Augeas.NO_MODL_AUTOLOAD);
setupAugeasModules(augeas);
checkModuleErrors(augeas);
- } catch (RuntimeException e) {
+ } catch (Throwable e) {
augeas = null;
- log.error("Failed to initialize Augeas Java API.", e);
+ String msg = "Failed to initialize Augeas Java API: " + e.getMessage();
+ if (e instanceof NoClassDefFoundError) {
+ msg += " - there is probably no native library available";
+ }
+ log.warn(msg);
}
return augeas;
}
@@ -719,18 +731,19 @@ public class AugeasConfigurationComponent<T extends ResourceComponent<?>> implem
this.augeas = null;
}
this.augeas = createAugeas();
- this.augeas.load();
- checkModuleErrors(this.augeas);
- String resourceConfigRootPath = getResourceConfigurationRootPath();
- if (resourceConfigRootPath.indexOf(AugeasNode.SEPARATOR_CHAR) != 0) {
- // root path is relative - make it absolute
- this.resourceConfigRootNode = new AugeasNode("/files/", resourceConfigRootPath);
- } else {
- // root path is already absolute
- this.resourceConfigRootNode = new AugeasNode(resourceConfigRootPath);
+ if (augeas!=null) {
+ this.augeas.load();
+ checkModuleErrors(this.augeas);
+ String resourceConfigRootPath = getResourceConfigurationRootPath();
+ if (resourceConfigRootPath.indexOf(AugeasNode.SEPARATOR_CHAR) != 0) {
+ // root path is relative - make it absolute
+ this.resourceConfigRootNode = new AugeasNode("/files/", resourceConfigRootPath);
+ } else {
+ // root path is already absolute
+ this.resourceConfigRootNode = new AugeasNode(resourceConfigRootPath);
+ }
+ log.debug("Resource Config Root Node = \"" + this.resourceConfigRootNode + "\"");
}
- log.debug("Resource Config Root Node = \"" + this.resourceConfigRootNode + "\"");
-
}
private void abortIfAugeasNotAvailable() throws Exception {
diff --git a/modules/plugins/samba/src/main/java/org/rhq/plugins/samba/SambaShareDiscoveryComponent.java b/modules/plugins/samba/src/main/java/org/rhq/plugins/samba/SambaShareDiscoveryComponent.java
index 34809b7..402cbfd 100644
--- a/modules/plugins/samba/src/main/java/org/rhq/plugins/samba/SambaShareDiscoveryComponent.java
+++ b/modules/plugins/samba/src/main/java/org/rhq/plugins/samba/SambaShareDiscoveryComponent.java
@@ -45,14 +45,16 @@ public class SambaShareDiscoveryComponent implements ResourceDiscoveryComponent<
try {
augeas = serverComponent.getAugeas();
- List<String> matches = augeas.match("/files/etc/samba/smb.conf/target[. != 'global']");
- for (String match : matches) {
- String name = augeas.get(match);
- Configuration pluginConfig = discoveryContext.getDefaultPluginConfiguration();
- pluginConfig.put(new PropertySimple("targetName", name));
- DiscoveredResourceDetails detail = new DiscoveredResourceDetails(discoveryContext.getResourceType(),
- name, name + " share", null, "Samba Share [" + name + "]", pluginConfig, null);
- details.add(detail);
+ if (augeas!=null) {
+ List<String> matches = augeas.match("/files/etc/samba/smb.conf/target[. != 'global']");
+ for (String match : matches) {
+ String name = augeas.get(match);
+ Configuration pluginConfig = discoveryContext.getDefaultPluginConfiguration();
+ pluginConfig.put(new PropertySimple("targetName", name));
+ DiscoveredResourceDetails detail = new DiscoveredResourceDetails(discoveryContext.getResourceType(),
+ name, name + " share", null, "Samba Share [" + name + "]", pluginConfig, null);
+ details.add(detail);
+ }
}
return details;
commit 5cd5fad909985f184ef3728d11c35b81573fadfd
Author: Heiko W. Rupp <hwr(a)redhat.com>
Date: Fri Jun 28 17:17:04 2013 +0200
BZ 960936 - the plugin name already contains the directory. Don't add it again.
diff --git a/modules/enterprise/agent/src/main/java/org/rhq/enterprise/agent/PluginUpdate.java b/modules/enterprise/agent/src/main/java/org/rhq/enterprise/agent/PluginUpdate.java
index bf2fef0..8aa81a0 100644
--- a/modules/enterprise/agent/src/main/java/org/rhq/enterprise/agent/PluginUpdate.java
+++ b/modules/enterprise/agent/src/main/java/org/rhq/enterprise/agent/PluginUpdate.java
@@ -278,9 +278,9 @@ public class PluginUpdate {
* of streaming the plugin, the download will fail. When this happens, this method will simply
* attempt to download the plugin again (this time, hopefully, we will remain connected to the
* new server and the download will succeed).
- *
+ *
* @param plugin the plugin to download
- *
+ *
* @throws Exception if, despite our best efforts, the plugin could not be downloaded
*/
private void downloadPluginWithRetries(Plugin plugin) throws Exception {
@@ -446,9 +446,8 @@ public class PluginUpdate {
if (!latest_plugins_map.containsKey(current_plugin.getPath())) {
File plugin = getPluginFile(current_plugin);
if (plugin.exists()) {
- File plugin_dir = this.config.getPluginDirectory();
String plugin_filename = plugin.getPath();
- File plugin_backup = new File(plugin_dir, plugin_filename + ".REJECTED");
+ File plugin_backup = new File(plugin_filename + ".REJECTED");
LOG.warn(AgentI18NResourceKeys.PLUGIN_NOT_ON_SERVER, plugin_filename, plugin_backup.getName());
try {
plugin_backup.delete(); // in case an old backup is for some reason still here, get rid of it
10 years, 5 months
[rhq] Branch 'hotfix/jon3.1.2' - 8 commits - modules/plugins
by Larry O'Leary
modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatCacheDiscoveryComponent.java | 19 +
modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatConnectorComponent.java | 96 +++-------
modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatConnectorDiscoveryComponent.java | 75 +++++--
modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatDatasourceDiscoveryComponent.java | 30 ++-
modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatDiscoveryComponent.java | 9
modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatGroupComponent.java | 1
modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatRoleComponent.java | 1
modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatUserComponent.java | 1
modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatUserDatabaseComponent.java | 17 +
modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatWarComponent.java | 47 +++-
modules/plugins/tomcat/src/main/resources/META-INF/rhq-plugin.xml | 74 +++----
11 files changed, 225 insertions(+), 145 deletions(-)
New commits:
commit 082871996f26e5e2523487001661e751b2cafe13
Merge: 55c4c4d 8f9bf82
Author: Larry O'Leary <loleary(a)redhat.com>
Date: Fri Jun 28 18:38:44 2013 -0500
Merge remote-tracking branch 'origin/bug/953482' into hotfix/jon3.1.2
commit 8f9bf82c37f8961765cb2dd2ca82415e4a1360a3
Author: jfclere <jfclere(a)neo2.gva.redhat.com>
Date: Mon Apr 15 17:07:28 2013 +0200
[BZ 865460] Cannot add a Group to tomcat's UserDatabase
diff --git a/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatUserDatabaseComponent.java b/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatUserDatabaseComponent.java
index 0a95069..ead4956 100644
--- a/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatUserDatabaseComponent.java
+++ b/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatUserDatabaseComponent.java
@@ -51,6 +51,7 @@ public class TomcatUserDatabaseComponent extends MBeanResourceComponent<TomcatSe
if (TomcatGroupComponent.RESOURCE_TYPE_NAME.equals(resourceTypeName)) {
name = report.getResourceConfiguration().getSimple("groupname").getStringValue();
newRoles = report.getResourceConfiguration().getSimple(TomcatGroupComponent.CONFIG_ROLES);
+ report.getResourceConfiguration().remove(TomcatGroupComponent.CONFIG_ROLES);
objectName = String.format("Users:type=Group,groupname=\"%s\",database=UserDatabase", name);
operation = "createGroup";
} else if (TomcatRoleComponent.RESOURCE_TYPE_NAME.equals(resourceTypeName)) {
commit a84b665d222b62bd57b1c89272042cb916b4acd2
Author: jfclere <jfclere(a)neo2.gva.redhat.com>
Date: Mon Apr 15 16:28:19 2013 +0200
[BZ 921194] Additional corrections by lfuka.
diff --git a/modules/plugins/tomcat/src/main/resources/META-INF/rhq-plugin.xml b/modules/plugins/tomcat/src/main/resources/META-INF/rhq-plugin.xml
index e6e87b3..826a9e9 100644
--- a/modules/plugins/tomcat/src/main/resources/META-INF/rhq-plugin.xml
+++ b/modules/plugins/tomcat/src/main/resources/META-INF/rhq-plugin.xml
@@ -727,7 +727,9 @@
<c:simple-property
name="name"
type="string"
- readOnly="true" />
+ readOnly="true"
+ default="Default Tomcat Connector name"
+ description="Connector name."/>
<c:simple-property
name="port"
type="string"
@@ -741,8 +743,8 @@
<c:simple-property
name="connector"
type="string"
- description="Connector protocol connector. Note: Only available on Tomcat 7."
- required="false"
+ description="Connector protocol connector."
+ default="Default connector"
readOnly="true" />
<c:simple-property
name="address"
commit e28f32bd290cac7a8e2e6f8d8cbdbf25ffd3540c
Author: jfclere <jfclere(a)neo2.gva.redhat.com>
Date: Wed Apr 10 15:26:38 2013 +0200
[BZ 921261] WebModule is reported as DOWN or UNAVAILABLE ... from da0179ab26a0c3e3a50238e9997147864e5a759b
diff --git a/modules/plugins/tomcat/src/main/resources/META-INF/rhq-plugin.xml b/modules/plugins/tomcat/src/main/resources/META-INF/rhq-plugin.xml
index 8dbb251..e6e87b3 100644
--- a/modules/plugins/tomcat/src/main/resources/META-INF/rhq-plugin.xml
+++ b/modules/plugins/tomcat/src/main/resources/META-INF/rhq-plugin.xml
@@ -741,7 +741,8 @@
<c:simple-property
name="connector"
type="string"
- description="Connector protocol connector."
+ description="Connector protocol connector. Note: Only available on Tomcat 7."
+ required="false"
readOnly="true" />
<c:simple-property
name="address"
commit 5e887799e09133d17eb0344fc960c207670a9928
Author: jfclere <jfclere(a)neo2.gva.redhat.com>
Date: Wed Apr 10 15:22:52 2013 +0200
[BZ 921261] WebModule is reported as DOWN or UNAVAILABLE ... from 00e594847fe67da46f8976df58b5d2324d6ebb48
diff --git a/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatWarComponent.java b/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatWarComponent.java
index 495d920..0a51c45 100644
--- a/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatWarComponent.java
+++ b/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatWarComponent.java
@@ -154,6 +154,15 @@ public class TomcatWarComponent extends MBeanResourceComponent<TomcatVHostCompon
} catch (Exception e) {
// if not active an exception may be thrown
state = WarMBeanState.STOPPED;
+ // try "state" for Tomcat 5.5
+ try {
+ int stateInt = (Integer) this.webModuleMBean.getAttribute("state").refresh();
+ if (stateInt == 1) {
+ state = WarMBeanState.STARTED;
+ }
+ } catch (Exception ex) {
+ // Ignore
+ }
}
availability = (state.equals(WarMBeanState.STARTED)) ? AvailabilityType.UP : AvailabilityType.DOWN;
@@ -361,7 +370,23 @@ public class TomcatWarComponent extends MBeanResourceComponent<TomcatVHostCompon
mbeanOperation.invoke(paramValues);
if (!WarOperation.DESTROY.equals(operation)) {
- String state = (String) this.webModuleMBean.getAttribute("stateName").refresh();
+ String state = null;
+ try {
+ // check to see if the mbean is truly active
+ state = (String) this.webModuleMBean.getAttribute("stateName").refresh();
+ } catch (Exception e) {
+ // if not active an exception may be thrown
+ state = WarMBeanState.STOPPED;
+ // try "state" for Tomcat 5.5
+ try {
+ int stateInt = (Integer) this.webModuleMBean.getAttribute("state").refresh();
+ if (stateInt == 1) {
+ state = WarMBeanState.STARTED;
+ }
+ } catch (Exception ex) {
+ // Ignore
+ }
+ }
String expectedState = getExpectedPostExecutionState(operation);
if (!state.equals(expectedState)) {
throw new Exception("Failed to " + name + " webapp (value of the 'state' attribute of MBean '"
commit 9056a575064fdc8e25776079386d04a2442114cc
Author: jfclere <jfclere(a)neo2.gva.redhat.com>
Date: Wed Apr 10 15:17:22 2013 +0200
[BZ 921194] Connectors are not properly discovered and therefore are unavailable.. from 00e594847fe67da46f8976df58b5d2324d6ebb48.
diff --git a/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatConnectorDiscoveryComponent.java b/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatConnectorDiscoveryComponent.java
index 7a65a73..32566d5 100644
--- a/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatConnectorDiscoveryComponent.java
+++ b/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatConnectorDiscoveryComponent.java
@@ -132,12 +132,14 @@ public class TomcatConnectorDiscoveryComponent extends MBeanResourceDiscoveryCom
if (connectorON != null) {
EmsBean connectorBean = connection.getBean(connectorON);
EmsAttribute executorNameAttrib = connectorBean.getAttribute("executorName");
- Object executorNameValue = executorNameAttrib.getValue();
- if (executorNameValue != null) {
- String executorName = executorNameValue.toString();
- if (!executorName.isEmpty() && !executorName.equalsIgnoreCase("Internal")) {
- pluginConfiguration.put(new PropertySimple(
- TomcatConnectorComponent.PLUGIN_CONFIG_SHARED_EXECUTOR, executorName));
+ if (executorNameAttrib != null) {
+ Object executorNameValue = executorNameAttrib.getValue();
+ if (executorNameValue != null) {
+ String executorName = executorNameValue.toString();
+ if (!executorName.isEmpty() && !executorName.equalsIgnoreCase("Internal")) {
+ pluginConfiguration.put(new PropertySimple(
+ TomcatConnectorComponent.PLUGIN_CONFIG_SHARED_EXECUTOR, executorName));
+ }
}
}
}
commit 9691fff8d4b34f438213381b24a55e89c940b5f8
Author: jfclere <jfclere(a)neo2.gva.redhat.com>
Date: Wed Apr 10 15:13:02 2013 +0200
Fix BZ 865460 from 417fbb59817edf64a93d3cca00f2c51926379ab2
diff --git a/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatGroupComponent.java b/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatGroupComponent.java
index 1d667a7..ba68ce9 100644
--- a/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatGroupComponent.java
+++ b/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatGroupComponent.java
@@ -185,6 +185,7 @@ public class TomcatGroupComponent extends MBeanResourceComponent<TomcatUserDatab
nameProperty = new PropertySimple(CONFIG_GROUP_NAME, name.substring(1, name.length() - 1));
opConfig.put(nameProperty);
resourceContext.getParentResourceComponent().invokeOperation("removeGroup", opConfig);
+ resourceContext.getParentResourceComponent().save();
}
}
diff --git a/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatRoleComponent.java b/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatRoleComponent.java
index 92e2610..051965c 100644
--- a/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatRoleComponent.java
+++ b/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatRoleComponent.java
@@ -50,6 +50,7 @@ public class TomcatRoleComponent extends MBeanResourceComponent<TomcatUserDataba
nameProperty = new PropertySimple(CONFIG_ROLE_NAME, name);
opConfig.put(nameProperty);
resourceContext.getParentResourceComponent().invokeOperation("removeRole", opConfig);
+ resourceContext.getParentResourceComponent().save();
}
@Override
diff --git a/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatUserComponent.java b/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatUserComponent.java
index 24936cd..7eb8aa5 100644
--- a/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatUserComponent.java
+++ b/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatUserComponent.java
@@ -206,6 +206,7 @@ public class TomcatUserComponent extends MBeanResourceComponent<TomcatUserDataba
nameProperty = new PropertySimple(CONFIG_USERNAME, name.substring(1, name.length() - 1));
opConfig.put(nameProperty);
resourceContext.getParentResourceComponent().invokeOperation("removeUser", opConfig);
+ resourceContext.getParentResourceComponent().save();
}
}
diff --git a/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatUserDatabaseComponent.java b/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatUserDatabaseComponent.java
index bb13097..0a95069 100644
--- a/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatUserDatabaseComponent.java
+++ b/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatUserDatabaseComponent.java
@@ -26,6 +26,7 @@ package org.jboss.on.plugins.tomcat;
import org.jboss.on.plugins.tomcat.helper.CreateResourceHelper;
import org.rhq.core.domain.configuration.Configuration;
+import org.rhq.core.domain.configuration.PropertySimple;
import org.rhq.core.domain.resource.CreateResourceStatus;
import org.rhq.core.pluginapi.inventory.CreateChildResourceFacet;
import org.rhq.core.pluginapi.inventory.CreateResourceReport;
@@ -45,8 +46,11 @@ public class TomcatUserDatabaseComponent extends MBeanResourceComponent<TomcatSe
String objectName = null;
String operation = null;
try {
+ PropertySimple newGroups = null;
+ PropertySimple newRoles = null;
if (TomcatGroupComponent.RESOURCE_TYPE_NAME.equals(resourceTypeName)) {
name = report.getResourceConfiguration().getSimple("groupname").getStringValue();
+ newRoles = report.getResourceConfiguration().getSimple(TomcatGroupComponent.CONFIG_ROLES);
objectName = String.format("Users:type=Group,groupname=\"%s\",database=UserDatabase", name);
operation = "createGroup";
} else if (TomcatRoleComponent.RESOURCE_TYPE_NAME.equals(resourceTypeName)) {
@@ -55,6 +59,10 @@ public class TomcatUserDatabaseComponent extends MBeanResourceComponent<TomcatSe
operation = "createRole";
} else if (TomcatUserComponent.RESOURCE_TYPE_NAME.equals(resourceTypeName)) {
name = report.getResourceConfiguration().getSimple("username").getStringValue();
+ newRoles = report.getResourceConfiguration().getSimple(TomcatUserComponent.CONFIG_ROLES);
+ newGroups = report.getResourceConfiguration().getSimple(TomcatUserComponent.CONFIG_GROUPS);
+ report.getResourceConfiguration().remove(TomcatUserComponent.CONFIG_ROLES);
+ report.getResourceConfiguration().remove(TomcatUserComponent.CONFIG_GROUPS);
objectName = String.format("Users:type=User,username=\"%s\",database=UserDatabase", name);
operation = "createUser";
} else {
@@ -67,6 +75,14 @@ public class TomcatUserDatabaseComponent extends MBeanResourceComponent<TomcatSe
CreateResourceHelper.setResourceName(report, name);
this.invokeOperation(operation, report.getResourceConfiguration());
+ if (TomcatGroupComponent.RESOURCE_TYPE_NAME.equals(resourceTypeName)) {
+ report.getResourceConfiguration().put(newRoles);
+ // FIXME: Add newRoles to the group
+ } else if (TomcatUserComponent.RESOURCE_TYPE_NAME.equals(resourceTypeName)) {
+ report.getResourceConfiguration().put(newGroups);
+ report.getResourceConfiguration().put(newRoles);
+ // FIXME: Add newRoles and newGroups to the user
+ }
// If all went well, persist the changes to the Tomcat user Database
save();
diff --git a/modules/plugins/tomcat/src/main/resources/META-INF/rhq-plugin.xml b/modules/plugins/tomcat/src/main/resources/META-INF/rhq-plugin.xml
index 5ad9092..8dbb251 100644
--- a/modules/plugins/tomcat/src/main/resources/META-INF/rhq-plugin.xml
+++ b/modules/plugins/tomcat/src/main/resources/META-INF/rhq-plugin.xml
@@ -226,7 +226,9 @@
name="Tomcat Virtual Host"
discovery="TomcatVHostDiscoveryComponent"
class="TomcatVHostComponent"
- description="A virtual host in the web container">
+ description="A virtual host in the web container"
+ createDeletePolicy="both"
+ creationDataType="configuration">
<plugin-configuration>
<c:group
@@ -501,10 +503,6 @@
type="integer"
description="Maximum size of the static resource cache in kilobytes. If not specified, the default value is 10240 (10 megabytes)." />
<c:simple-property
- name="caseSensitive"
- type="boolean"
- description="If the value of this flag is true, all case sensitivity checks will be disabled. If not specified, the default value of the flag is true. NOTE: This flag MUST NOT be set to false on the Windows platform (or any other OS which does not have a case sensitive filesystem), as it will disable case sensitivity checks, allowing JSP source code disclosure, among other security problems." />
- <c:simple-property
name="cookies"
type="boolean"
description="Set to true if you want cookies to be used for session identifier communication if supported by the client (this is the default). Set to false if you want to disable the use of cookies for session identifier communication, and rely only on URL rewriting by the application." />
@@ -516,7 +514,8 @@
<c:simple-property
name="configFile"
type="string"
- description="The location of the context.xml resource or file" />
+ description="The location of the context.xml resource or file Note: Does not exist in Tomcat 7 (return type changed to URL)"
+ required="false" />
<c:simple-property
name="crossContext"
type="boolean"
@@ -526,13 +525,7 @@
readOnly="true"
required="true"
description="The docBase set for this application" />
- <!-- Although it claims to be writable, update failed in my V5 and V6 test, so read only for now. -->
- <c:simple-property
- name="eventProvider"
- type="boolean"
- description="Event provider support for this managed object?"
- readOnly="true" />
- <c:simple-property
+ <c:simple-property
name="privileged"
type="boolean"
description="Set to true to allow this context to use container servlets, like the manager servlet. Use of the privileged attribute will change the context's parent class loader to be the Server class loader rather than the Shared class loader. Note that in a default installation, the Common class loader is used for both the Server and the Shared class loaders." />
@@ -544,18 +537,6 @@
name="saveConfig"
type="boolean"
description="Write the configuration as needed on startup?" />
- <!-- Although it claims to be writable, update failed in my V5 and V6 test, so read only for now. -->
- <c:simple-property
- name="stateManageable"
- type="boolean"
- description="State management support for this managed object?"
- readOnly="true" />
- <!-- Although it claims to be writable, update failed in my V5 and V6 test, so read only for now. -->
- <c:simple-property
- name="statisticsProvider"
- type="boolean"
- description="Performance statistics support for this managed object?"
- readOnly="true" />
<c:simple-property
name="swallowOutput"
type="boolean"
@@ -857,10 +838,6 @@
type="boolean"
description="A boolean value which can be used to enable or disable the TRACE HTTP method. If not specified, this attribute is set to false." />
<c:simple-property
- name="bufferSize"
- type="integer"
- description="HTTP: The size (in bytes) of the buffer to be provided for input streams created by this connector. By default, buffers of 2048 bytes will be provided. AJP: The size of the output buffer to use. If less than or equal to zero, then output buffering is disabled. The default value is -1 (i.e. buffering disabled)" />
- <c:simple-property
name="connectionTimeout"
type="integer"
description="HTTP: The number of milliseconds this Connector will wait, after accepting a connection, for the request URI line to be presented. The default value is 60000 (i.e. 60 seconds). AJP: The number of milliseconds this Connector will wait, after accepting a connection, for the request URI line to be presented. The default value is infinite (i.e. no timeout)."
@@ -868,7 +845,8 @@
<c:simple-property
name="emptySessionPath"
type="boolean"
- description="If set to true, all paths for session cookies will be set to /. This can be useful for portlet specification implementations, but will greatly affect performance if many applications are accessed on a given server by the client. If not specified, this attribute is set to false." />
+ description="If set to true, all paths for session cookies will be set to /. This can be useful for portlet specification implementations, but will greatly affect performance if many applications are accessed on a given server by the client. If not specified, this attribute is set to false. Note: Does not exist in Tomcat 7"
+ required="false" />
<c:simple-property
name="enableLookups"
type="boolean"
commit cb5d7c3772e9eefbe6b126ce81cbd1ca00241123
Author: jfclere <jfclere(a)neo2.gva.redhat.com>
Date: Wed Apr 10 14:33:38 2013 +0200
fix for BZ: 707349 from e7d48240474fba87f1a3c4118de4618fd2c8b32d.
diff --git a/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatCacheDiscoveryComponent.java b/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatCacheDiscoveryComponent.java
index 1bb12db..e335d10 100644
--- a/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatCacheDiscoveryComponent.java
+++ b/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatCacheDiscoveryComponent.java
@@ -43,16 +43,27 @@ public class TomcatCacheDiscoveryComponent extends MBeanResourceDiscoveryCompone
@Override
public Set<DiscoveredResourceDetails> discoverResources(ResourceDiscoveryContext<TomcatWarComponent> discoveryContext) {
+ String objectNameTemplate = "";
+ Set<DiscoveredResourceDetails> resources;
+
Configuration defaultPluginConfig = discoveryContext.getDefaultPluginConfiguration();
- String objectNameTemplate = defaultPluginConfig.getSimple(PROPERTY_OBJECT_NAME).getStringValue();
String host = discoveryContext.getParentResourceContext().getPluginConfiguration().getSimpleValue(TomcatWarComponent.PROPERTY_VHOST, null);
String path = discoveryContext.getParentResourceContext().getPluginConfiguration().getSimpleValue(TomcatWarComponent.PROPERTY_CONTEXT_ROOT, null);
+
+ objectNameTemplate = defaultPluginConfig.getSimple(PROPERTY_OBJECT_NAME).getStringValue();
objectNameTemplate = objectNameTemplate.replace("%host%", host);
objectNameTemplate = objectNameTemplate.replace("%path%", path);
defaultPluginConfig.put(new PropertySimple(PROPERTY_OBJECT_NAME, objectNameTemplate));
- Set<DiscoveredResourceDetails> resources = super.performDiscovery(defaultPluginConfig, discoveryContext.getParentResourceComponent(), discoveryContext.getResourceType());
+ resources = super.performDiscovery(defaultPluginConfig, discoveryContext.getParentResourceComponent(), discoveryContext.getResourceType());
+ if (resources.size() == 0) {
+ objectNameTemplate = getCacheObjectName();
+ objectNameTemplate = objectNameTemplate.replace("%host%", host);
+ objectNameTemplate = objectNameTemplate.replace("%path%", path);
+ defaultPluginConfig.put(new PropertySimple(PROPERTY_OBJECT_NAME, objectNameTemplate));
+ resources = super.performDiscovery(defaultPluginConfig, discoveryContext.getParentResourceComponent(), discoveryContext.getResourceType());
+ }
// returns only one resource.
for (DiscoveredResourceDetails detail : resources) {
Configuration pluginConfiguration = detail.getPluginConfiguration();
@@ -63,4 +74,8 @@ public class TomcatCacheDiscoveryComponent extends MBeanResourceDiscoveryCompone
}
return resources;
}
+
+ private String getCacheObjectName() {
+ return "Catalina:type=Cache,host=%host%,context=%path%";
+ }
}
diff --git a/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatConnectorComponent.java b/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatConnectorComponent.java
index 4013376..ab35743 100644
--- a/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatConnectorComponent.java
+++ b/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatConnectorComponent.java
@@ -71,10 +71,18 @@ public class TomcatConnectorComponent extends MBeanResourceComponent<TomcatServe
*/
public static final String PLUGIN_CONFIG_ADDRESS = "address";
/**
+ * Plugin property name for the connector type the connector is bound to.
+ */
+ public static final String PLUGIN_CONFIG_CONNECTOR = "connector";
+ /**
* Plugin property name for the protocol handler. This prefix is used in the associated GlobalRequestProcessor object name.
*/
public static final String PLUGIN_CONFIG_HANDLER = "handler";
/**
+ * Plugin property name for the name.
+ */
+ public static final String PLUGIN_CONFIG_NAME = "name";
+ /**
* Plugin property name for the port the connector is listening on.
*/
public static final String PLUGIN_CONFIG_PORT = "port";
@@ -110,8 +118,8 @@ public class TomcatConnectorComponent extends MBeanResourceComponent<TomcatServe
@Override
public void start(ResourceContext<TomcatServerComponent<?>> context) {
if (UNKNOWN.equals(context.getPluginConfiguration().getSimple(PLUGIN_CONFIG_HANDLER).getStringValue())) {
- throw new InvalidPluginConfigurationException(
- "The connector is not listening for requests on the configured port. This is most likely due to the configured port being in use at Tomcat startup. In some cases (AJP connectors) Tomcat will assign an open port. This happens most often when there are multiple Tomcat servers running on the same platform. Check your Tomcat configuration for conflicts: "
+ throw new InvalidPluginConfigurationException(
+ "The connector is not listening for requests on the configured port. This is most likely due to the configured port being in use at Tomcat startup. In some cases (AJP connectors) Tomcat will assign an open port. This happens most often when there are multiple Tomcat servers running on the same platform. Check your Tomcat configuration for conflicts: "
+ context.getResourceKey());
}
@@ -123,12 +131,12 @@ public class TomcatConnectorComponent extends MBeanResourceComponent<TomcatServe
getEmsConnection(); // reload the EMS connection
for (MeasurementScheduleRequest request : requests) {
- String name = request.getName();
- name = switchConnectorThreadpoolName(name);
- name = getAttributeName(name);
+ String req = request.getName();
+ req = switchConnectorThreadpoolName(req);
+ req = getAttributeName(req);
- String beanName = name.substring(0, name.lastIndexOf(':'));
- String attributeName = name.substring(name.lastIndexOf(':') + 1);
+ String beanName = req.substring(0, req.lastIndexOf(':'));
+ String attributeName = req.substring(req.lastIndexOf(':') + 1);
try {
// Bean is cached by EMS, so no problem with getting the bean from the connection on each call
@@ -145,7 +153,7 @@ public class TomcatConnectorComponent extends MBeanResourceComponent<TomcatServe
report.addData(new MeasurementDataNumeric(request, value.doubleValue()));
} catch (Exception e) {
- log.error("Failed to obtain measurement [" + name + "]", e);
+ log.error("Failed to obtain measurement [" + req + "]", e);
}
}
}
@@ -158,46 +166,46 @@ public class TomcatConnectorComponent extends MBeanResourceComponent<TomcatServe
*
* See BZ 795531.
*
- * @param name the metric property name that may need to be switched if it is a threadpool metric
+ * @param property the metric property name that may need to be switched if it is a threadpool metric
* @return the name for the metric property, switched to use the shared executor name if appropriate
*/
- private String switchConnectorThreadpoolName(String name) {
+ private String switchConnectorThreadpoolName(String property) {
Configuration pluginConfiguration = getResourceContext().getPluginConfiguration();
String sharedExecutorName = pluginConfiguration.getSimpleValue(PLUGIN_CONFIG_SHARED_EXECUTOR, "");
if (sharedExecutorName == null || sharedExecutorName.trim().isEmpty()) {
- return name; // there is nothing special to do if the connector isn't using a shared executor for its threadpool
+ return property; // there is nothing special to do if the connector isn't using a shared executor for its threadpool
}
- // 1) Catalina:type=ThreadPool,name=%handler%%address%-%port%:currentThreadsBusy
+ // 1) Catalina:type=ThreadPool,name=%name%:currentThreadsBusy
// will be replaced with:
// Catalina:type=Executor,name=<name of shared executor>:activeCount
//
- // 2) Catalina:type=ThreadPool,name=%handler%%address%-%port%:currentThreadCount
+ // 2) Catalina:type=ThreadPool,name=%name%:currentThreadCount
// will be replaced with:
// Catalina:type=Executor,name=<name of shared executor>:poolSize
//
- // 3) Catalina:type=ThreadPool,name=%handler%%address%-%port%:maxThreads
+ // 3) Catalina:type=ThreadPool,name=%name%:maxThreads
// will be replaced with
// Catalina:type=Executor,name=<name of shared executor>:maxThreads
- final String NON_SHARED_THREADS_ACTIVE = "Catalina:type=ThreadPool,name=%handler%%address%-%port%:currentThreadsBusy";
- final String NON_SHARED_THREADS_ALLOCATED = "Catalina:type=ThreadPool,name=%handler%%address%-%port%:currentThreadCount";
- final String NON_SHARED_THREADS_MAX = "Catalina:type=ThreadPool,name=%handler%%address%-%port%:maxThreads";
+ final String NON_SHARED_THREADS_ACTIVE = "Catalina:type=ThreadPool,name=%name%:currentThreadsBusy";
+ final String NON_SHARED_THREADS_ALLOCATED = "Catalina:type=ThreadPool,name=%name%:currentThreadCount";
+ final String NON_SHARED_THREADS_MAX = "Catalina:type=ThreadPool,name=%name%:maxThreads";
final String SHARED_THREADS_ACTIVE = "Catalina:type=Executor,name=XXX:activeCount";
final String SHARED_THREADS_ALLOCATED = "Catalina:type=Executor,name=XXX:poolSize";
final String SHARED_THREADS_MAX = "Catalina:type=Executor,name=XXX:maxThreads";
- if (name.equals(NON_SHARED_THREADS_ACTIVE)) {
- name = SHARED_THREADS_ACTIVE;
- } else if (name.equals(NON_SHARED_THREADS_ALLOCATED)) {
- name = SHARED_THREADS_ALLOCATED;
- } else if (name.equals(NON_SHARED_THREADS_MAX)) {
- name = SHARED_THREADS_MAX;
+ if (property.equals(NON_SHARED_THREADS_ACTIVE)) {
+ property = SHARED_THREADS_ACTIVE;
+ } else if (property.equals(NON_SHARED_THREADS_ALLOCATED)) {
+ property = SHARED_THREADS_ALLOCATED;
+ } else if (property.equals(NON_SHARED_THREADS_MAX)) {
+ property = SHARED_THREADS_MAX;
} else {
- return name; // this isn't one of the names we need to switch, immediate return the original name as-is
+ return property; // this isn't one of the names we need to switch, immediate return the original name as-is
}
- name = name.replace("XXX", sharedExecutorName);
- return name;
+ property = property.replace("XXX", sharedExecutorName);
+ return property;
}
/**
@@ -218,42 +226,15 @@ public class TomcatConnectorComponent extends MBeanResourceComponent<TomcatServe
}
private String getGlobalRequestProcessorName() {
- String name = "Catalina:type=GlobalRequestProcessor,name=%handler%%address%-%port%";
-
- return replaceGlobalRequestProcessorNameProps(name);
+ return replaceGlobalRequestProcessorNameProps("Catalina:type=GlobalRequestProcessor,name=%name%");
}
- private String replaceGlobalRequestProcessorNameProps(String name) {
- String result = name;
+ private String replaceGlobalRequestProcessorNameProps(String property) {
Configuration pluginConfiguration = getResourceContext().getPluginConfiguration();
- String port = pluginConfiguration.getSimple(PLUGIN_CONFIG_PORT).getStringValue();
- String handler = pluginConfiguration.getSimple(PLUGIN_CONFIG_HANDLER).getStringValue();
- String address = pluginConfiguration.getSimpleValue(PLUGIN_CONFIG_ADDRESS, "");
-
- if (!"".equals(address)) {
- StringBuilder sb = new StringBuilder("-");
- sb.append(address);
- // if it's a host name, add the IP portion that Tomcat expects
- if (!address.contains(".")) {
- String ip;
-
- try {
- ip = InetAddress.getByName(address).getHostAddress();
- sb.append("%2F");
- sb.append(ip);
- address = sb.toString();
- } catch (UnknownHostException e) {
- log.debug("Failed to resolve host [" + address + "]. Can not get objectName for property: " + name);
- }
- } else {
- address = sb.toString();
- }
- }
+ String name = pluginConfiguration.getSimple(PLUGIN_CONFIG_NAME).getStringValue();
- result = result.replace("%port%", port);
- result = result.replace("%address%", address);
- result = result.replace("%handler%", handler);
+ String result = property.replace("%name%", name);
return result;
}
@@ -272,7 +253,6 @@ public class TomcatConnectorComponent extends MBeanResourceComponent<TomcatServe
}
}
if ((null == protocol) || protocol.toUpperCase().contains("AJP")) {
- // remove HTTP only properties
for (PropertyDefinition propDef : configDef.getPropertiesInGroup("HTTP")) {
report.getConfiguration().remove(propDef.getName());
}
diff --git a/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatConnectorDiscoveryComponent.java b/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatConnectorDiscoveryComponent.java
index 1591a5e..7a65a73 100644
--- a/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatConnectorDiscoveryComponent.java
+++ b/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatConnectorDiscoveryComponent.java
@@ -99,7 +99,6 @@ public class TomcatConnectorDiscoveryComponent extends MBeanResourceDiscoveryCom
// Set handler plugin config and update resource name
String handler = (null != configInfo) ? configInfo.getHandler() : TomcatConnectorComponent.UNKNOWN;
- resource.setResourceName(resource.getResourceName().replace("{handler}", handler));
// It is unusual but possible that there is a GlobalRequestProcessor object representing a configured AJP
// connector but with a different port. If the configured AJP connector port is in use, Tomcat increments
@@ -115,6 +114,16 @@ public class TomcatConnectorDiscoveryComponent extends MBeanResourceDiscoveryCom
if ((null != address) && !"".equals(address.trim())) {
pluginConfiguration.put(new PropertySimple(TomcatConnectorComponent.PLUGIN_CONFIG_ADDRESS, address));
}
+ // Set connector if it is in use
+ String connector = (null != configInfo) ? configInfo.getConnector() : null;
+ if ((null != connector) && !"".equals(connector.trim())) {
+ pluginConfiguration.put(new PropertySimple(TomcatConnectorComponent.PLUGIN_CONFIG_CONNECTOR, connector));
+ }
+
+ // Set the global request processor name (Tomcat 7 added quotes around the name value)
+ String name = (null != configInfo) ? configInfo.getName() : null;
+ resource.setResourceName(resource.getResourceName().replace("{name}", name));
+ pluginConfiguration.put(new PropertySimple(TomcatConnectorComponent.PLUGIN_CONFIG_NAME, name));
// Let's try to auto-discover if this Connector is using a shared executor for its thread pool.
// If it is, let's set the plugin config property automatically so we can collect the proper metrics.
@@ -122,15 +131,13 @@ public class TomcatConnectorDiscoveryComponent extends MBeanResourceDiscoveryCom
String connectorON = pluginConfiguration.getSimpleValue(TomcatConnectorComponent.OBJECT_NAME_PROP, null);
if (connectorON != null) {
EmsBean connectorBean = connection.getBean(connectorON);
- EmsAttribute executorNameAttrib = connectorBean.getAttribute("executorName"); // older tomcat versions won't have this attrib
- if (executorNameAttrib != null) {
- Object executorNameValue = executorNameAttrib.getValue();
- if (executorNameValue != null) {
- String executorName = executorNameValue.toString();
- if (!executorName.isEmpty() && !executorName.equalsIgnoreCase("Internal")) {
- pluginConfiguration.put(new PropertySimple(
- TomcatConnectorComponent.PLUGIN_CONFIG_SHARED_EXECUTOR, executorName));
- }
+ EmsAttribute executorNameAttrib = connectorBean.getAttribute("executorName");
+ Object executorNameValue = executorNameAttrib.getValue();
+ if (executorNameValue != null) {
+ String executorName = executorNameValue.toString();
+ if (!executorName.isEmpty() && !executorName.equalsIgnoreCase("Internal")) {
+ pluginConfiguration.put(new PropertySimple(
+ TomcatConnectorComponent.PLUGIN_CONFIG_SHARED_EXECUTOR, executorName));
}
}
}
@@ -145,10 +152,11 @@ public class TomcatConnectorDiscoveryComponent extends MBeanResourceDiscoveryCom
}
private static class ConfigInfo {
- private String name;
- private String address;
- private String handler;
- private String port;
+ private String name = "";
+ private String address = "";
+ private String handler = "";
+ private String connector = "";
+ private String port = "";
private Exception exception;
public ConfigInfo(EmsBean bean) {
@@ -159,30 +167,53 @@ public class TomcatConnectorDiscoveryComponent extends MBeanResourceDiscoveryCom
* 1) handler-port
* 2) handler-ipaddress-port
* 3) handler-host%2Fipaddress-port
+ * 4) "handler-connector-port"
+ * 5) "handler-connector-ipaddress-port"
*
* Option 2 or 3 occurs when the <address> is explicitly defined in the <connector> element.
* Option 3 occurs when the address is an alias. The alias is resolved and appended to the alias separated
* by '/' (encoded a slash comes through as %2F). Note that the host may have itself contain dashes '-'.
+ * Option 4 and 5 are Tomcat 7
*/
try {
- int firstDash = name.indexOf('-');
- int lastDash = name.lastIndexOf('-');
- handler = name.substring(0, firstDash);
- port = name.substring(lastDash + 1);
- // validate that the port is a valid int
- Integer.valueOf(port);
-
- // Check to see if an address portion exists
- if (firstDash != lastDash) {
- // For option 3 keep the alias and we'll resolve as needed
- String rawAddress = name.substring(firstDash + 1, lastDash);
- int delim = rawAddress.indexOf("%2F");
- address = (-1 == delim) ? rawAddress : rawAddress.substring(0, delim);
+ // Check to see if this is TC7
+ if (name.startsWith("\"")) {
+ int firstDash = name.indexOf('-');
+ int lastDash = name.lastIndexOf('-');
+ handler = name.substring(1, firstDash);
+ port = name.substring(lastDash + 1, name.length() - 1);
+ // validate that the port is a valid int
+ Integer.valueOf(port);
+ String middle = name.substring(firstDash + 1, lastDash);
+
+ if (middle.indexOf('-') != -1) {
+ connector = middle.substring(0, middle.indexOf('-'));
+ address = middle.substring(middle.indexOf('-') + 1);
+ } else {
+ connector = middle;
+ }
+ } else {
+ int firstDash = name.indexOf('-');
+ int lastDash = name.lastIndexOf('-');
+ handler = name.substring(0, firstDash);
+ port = name.substring(lastDash + 1);
+ // validate that the port is a valid int
+ Integer.valueOf(port);
+
+ // Check to see if an address portion exists
+ if (firstDash != lastDash) {
+ // For option 3 keep the alias and we'll resolve as needed
+ String rawAddress = name.substring(firstDash + 1, lastDash);
+ int delim = rawAddress.indexOf("%2F");
+ address = (-1 == delim) ? rawAddress : rawAddress.substring(0, delim);
+ }
}
} catch (Exception e) {
+ name = null;
port = null;
address = null;
+ connector = null;
handler = null;
exception = e;
}
@@ -196,6 +227,10 @@ public class TomcatConnectorDiscoveryComponent extends MBeanResourceDiscoveryCom
return address;
}
+ public String getConnector() {
+ return connector;
+ }
+
public String getHandler() {
return handler;
}
diff --git a/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatDatasourceDiscoveryComponent.java b/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatDatasourceDiscoveryComponent.java
index 4749544..5a9b0b4 100644
--- a/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatDatasourceDiscoveryComponent.java
+++ b/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatDatasourceDiscoveryComponent.java
@@ -35,22 +35,30 @@ import org.rhq.plugins.jmx.MBeanResourceDiscoveryComponent;
public class TomcatDatasourceDiscoveryComponent extends MBeanResourceDiscoveryComponent<TomcatWarComponent> {
@Override
- public Set<DiscoveredResourceDetails> discoverResources(
- ResourceDiscoveryContext<TomcatWarComponent> discoveryContext) {
+ public Set<DiscoveredResourceDetails> discoverResources(ResourceDiscoveryContext<TomcatWarComponent> discoveryContext) {
+
+ String objectNameTemplate = "";
+ Set<DiscoveredResourceDetails> resources;
Configuration defaultPluginConfig = discoveryContext.getDefaultPluginConfiguration();
- String objectNameTemplate = defaultPluginConfig.getSimple(PROPERTY_OBJECT_NAME).getStringValue();
- String host = discoveryContext.getParentResourceContext().getPluginConfiguration()
- .getSimpleValue(TomcatWarComponent.PROPERTY_VHOST, null);
- String path = discoveryContext.getParentResourceContext().getPluginConfiguration()
- .getSimpleValue(TomcatWarComponent.PROPERTY_CONTEXT_ROOT, null);
+ String host = discoveryContext.getParentResourceContext().getPluginConfiguration().getSimpleValue(TomcatWarComponent.PROPERTY_VHOST, null);
+ String path = discoveryContext.getParentResourceContext().getPluginConfiguration().getSimpleValue(TomcatWarComponent.PROPERTY_CONTEXT_ROOT, null);
+
+ objectNameTemplate = defaultPluginConfig.getSimple(PROPERTY_OBJECT_NAME).getStringValue();
objectNameTemplate = objectNameTemplate.replace("%host%", host);
objectNameTemplate = objectNameTemplate.replace("%path%", path);
defaultPluginConfig.put(new PropertySimple(PROPERTY_OBJECT_NAME, objectNameTemplate));
- Set<DiscoveredResourceDetails> resources = super.performDiscovery(defaultPluginConfig,
- discoveryContext.getParentResourceComponent(), discoveryContext.getResourceType());
+ resources = super.performDiscovery(defaultPluginConfig, discoveryContext.getParentResourceComponent(), discoveryContext.getResourceType());
+ if (resources.size() == 0) {
+ objectNameTemplate = getDatasourceObjectName();
+ objectNameTemplate = objectNameTemplate.replace("%host%", host);
+ objectNameTemplate = objectNameTemplate.replace("%path%", path);
+ defaultPluginConfig.put(new PropertySimple(PROPERTY_OBJECT_NAME, objectNameTemplate));
+ resources = super.performDiscovery(defaultPluginConfig, discoveryContext.getParentResourceComponent(), discoveryContext.getResourceType());
+ }
+ // returns only one resource.
for (DiscoveredResourceDetails detail : resources) {
Configuration pluginConfiguration = detail.getPluginConfiguration();
pluginConfiguration.put(new PropertySimple(TomcatDatasourceComponent.PROPERTY_HOST, host));
@@ -60,4 +68,8 @@ public class TomcatDatasourceDiscoveryComponent extends MBeanResourceDiscoveryCo
}
return resources;
}
+
+ private String getDatasourceObjectName() {
+ return "Catalina:type=DataSource,context=%path%,host=%host%,class=javax.sql.DataSource,name=%name%";
+ }
}
diff --git a/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatDiscoveryComponent.java b/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatDiscoveryComponent.java
index 542f212..0537e7e 100644
--- a/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatDiscoveryComponent.java
+++ b/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatDiscoveryComponent.java
@@ -55,7 +55,7 @@ import org.rhq.core.system.SystemInfo;
import org.rhq.plugins.jmx.JMXDiscoveryComponent;
/**
- * Discovers JBoss EWS and Apache Tomcat5, Tomcat6 server instances.
+ * Discovers JBoss EWS and Apache Tomcat5, Tomcat6, Tomcat7 server instances.
*
* @author Jay Shaughnessy
*/
@@ -106,6 +106,7 @@ public class TomcatDiscoveryComponent implements ResourceDiscoveryComponent, Man
/**
* EWS RPM Install path substrings used to identify EWS tomcat version
*/
+ public static final String EWS_TOMCAT_7 = "tomcat7";
public static final String EWS_TOMCAT_6 = "tomcat6";
public static final String EWS_TOMCAT_5 = "tomcat5";
@@ -242,7 +243,7 @@ public class TomcatDiscoveryComponent implements ResourceDiscoveryComponent, Man
if (catalinaHome == null && isWindows(context)) {
log.debug("catalina.home not found. Checking to see if this is an EWS installation.");
- // On Windows EWS uses the tomcat5.exe and tomcat6.exe executables to start tomcat. They currently do
+ // On Windows EWS uses the tomcat5.exe, tomcat6.exe or Tomcat7.exe executables to start tomcat. They currently do
// not provide the command line args that we get with the normal start up scripts that are used to
// determine catalina.home. See https://bugzilla.redhat.com/show_bug.cgi?id=580931 for more information.
//
@@ -353,8 +354,8 @@ public class TomcatDiscoveryComponent implements ResourceDiscoveryComponent, Man
return null;
}
- //EWS supports tomcat 5 or 6 and starts them using the tomcat5.exe or
- //tomcat6.exe. The catalina homes we want for them are stored inside
+ //EWS supports tomcat 5, 6 or 7 and starts them using the tomcat5.exe,
+ //tomcat6.exe or Tomcat7.exe. The catalina homes we want for them are stored inside
//$EWS_HOME/share/tomcat-<version>, where version differs.
//EWS 1.0.1 uses tomcat 6.0.24, while EWS 1.0.2 uses tomcat 6.0.32
diff --git a/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatWarComponent.java b/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatWarComponent.java
index 96ae3a3..495d920 100644
--- a/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatWarComponent.java
+++ b/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatWarComponent.java
@@ -146,17 +146,17 @@ public class TomcatWarComponent extends MBeanResourceComponent<TomcatVHostCompon
}
if (null != this.webModuleMBean) {
- int state;
+ String state;
try {
// check to see if the mbean is truly active
- state = (Integer) this.webModuleMBean.getAttribute("state").refresh();
+ state = (String) this.webModuleMBean.getAttribute("stateName").refresh();
} catch (Exception e) {
// if not active an exception may be thrown
state = WarMBeanState.STOPPED;
}
- availability = (WarMBeanState.STARTED == state) ? AvailabilityType.UP : AvailabilityType.DOWN;
+ availability = (state.equals(WarMBeanState.STARTED)) ? AvailabilityType.UP : AvailabilityType.DOWN;
if (AvailabilityType.DOWN == availability) {
// if availability is down then ensure we use a new mbean on the next try, in case we have
@@ -361,19 +361,19 @@ public class TomcatWarComponent extends MBeanResourceComponent<TomcatVHostCompon
mbeanOperation.invoke(paramValues);
if (!WarOperation.DESTROY.equals(operation)) {
- int state = (Integer) this.webModuleMBean.getAttribute("state").refresh();
- int expectedState = getExpectedPostExecutionState(operation);
- if (state != expectedState) {
+ String state = (String) this.webModuleMBean.getAttribute("stateName").refresh();
+ String expectedState = getExpectedPostExecutionState(operation);
+ if (!state.equals(expectedState)) {
throw new Exception("Failed to " + name + " webapp (value of the 'state' attribute of MBean '"
- + this.webModuleMBean.getBeanName() + "' is " + state + ", not " + expectedState + ").");
+ + this.webModuleMBean.getBeanName() + "' is \"" + state + "\", not \"" + expectedState + "\").");
}
}
return new OperationResult();
}
- private static int getExpectedPostExecutionState(WarOperation operation) {
- int expectedState;
+ private static String getExpectedPostExecutionState(WarOperation operation) {
+ String expectedState;
switch (operation) {
case START:
case RELOAD: {
@@ -446,8 +446,8 @@ public class TomcatWarComponent extends MBeanResourceComponent<TomcatVHostCompon
}
private interface WarMBeanState {
- int STOPPED = 0;
- int STARTED = 1;
+ String STOPPED = "STOPPED";
+ String STARTED = "STARTED";
}
private List<EmsBean> getVHosts() {
diff --git a/modules/plugins/tomcat/src/main/resources/META-INF/rhq-plugin.xml b/modules/plugins/tomcat/src/main/resources/META-INF/rhq-plugin.xml
index 9d082d4..5ad9092 100644
--- a/modules/plugins/tomcat/src/main/resources/META-INF/rhq-plugin.xml
+++ b/modules/plugins/tomcat/src/main/resources/META-INF/rhq-plugin.xml
@@ -4,7 +4,7 @@
name="Tomcat"
displayName="Tomcat Server"
package="org.jboss.on.plugins.tomcat"
- description="Supports management and monitoring of JBoss EWS or Apache Tomcat5, Tomcat6"
+ description="Supports management and monitoring of JBoss EWS or Apache Tomcat5, Tomcat6, Tomcat7"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="urn:xmlns:rhq-plugin"
xmlns:c="urn:xmlns:rhq-configuration">
@@ -154,13 +154,13 @@
query="process|basename|match=^java.*,arg|org.apache.catalina.startup.Bootstrap|match=.*" />
<!--
- On windows EWS uses the tomcat5.exe and tomcat6.exe executables for starting tomcat. Unlike the normal
+ On windows EWS uses the tomcat5.exe, tomcat6.exe and tomcat7.exe executables for starting tomcat. Unlike the normal
start up scripts, these do specify the command line args for determining catalina.home. See
https://bugzilla.redhat.com/show_bug.cgi?id=580931 for more details.
-->
<process-scan
name="WindowsEWSTomcat"
- query="process|basename|match=^tomcat(5|6)\.exe"/>
+ query="process|basename|match=^(T|t)omcat(5|6|7)\.exe"/>
<operation
name="start"
@@ -744,6 +744,10 @@
readOnly="true"
default="Catalina:type=Connector,port=%port%" />
<c:simple-property
+ name="name"
+ type="string"
+ readOnly="true" />
+ <c:simple-property
name="port"
type="string"
description="Port on which this connector is configured to listen."
@@ -752,7 +756,12 @@
name="handler"
type="string"
description="Connector protocol handler."
- readOnly="true" />
+ readOnly="true" />
+ <c:simple-property
+ name="connector"
+ type="string"
+ description="Connector protocol connector."
+ readOnly="true" />
<c:simple-property
name="address"
type="string"
@@ -772,7 +781,7 @@
hiddenByDefault="true">
<c:simple-property
name="nameTemplate"
- default="{handler}-{port}" />
+ default="{name}" />
<c:simple-property
name="descriptionTemplate"
default="A Tomcat connector" />
@@ -800,42 +809,42 @@
description="Resumes this connector" />
<metric
- property="Catalina:type=GlobalRequestProcessor,name=%handler%%address%-%port%:maxTime"
+ property="Catalina:type=GlobalRequestProcessor,name=%name%:maxTime"
displayName="Maximum Request Time"
description="Maximum time it took to process a request."
units="milliseconds"
category="performance" />
<metric
- property="Catalina:type=GlobalRequestProcessor,name=%handler%%address%-%port%:requestCount"
+ property="Catalina:type=GlobalRequestProcessor,name=%name%:requestCount"
displayName="Request count"
description="Total number of requests processed since last restart."
category="utilization"
measurementType="trendsup" />
<metric
- property="Catalina:type=GlobalRequestProcessor,name=%handler%%address%-%port%:errorCount"
+ property="Catalina:type=GlobalRequestProcessor,name=%name%:errorCount"
displayName="Error count"
description="Number of errors while processing since last restart."
category="utilization"
measurementType="trendsup" />
<metric
- property="Catalina:type=ThreadPool,name=%handler%%address%-%port%:currentThreadsBusy"
+ property="Catalina:type=ThreadPool,name=%name%:currentThreadsBusy"
displayName="Threadpool Threads Active"
description="Number of current busy threads."
category="utilization"
displayType="summary" />
<metric
- property="Catalina:type=ThreadPool,name=%handler%%address%-%port%:currentThreadCount"
+ property="Catalina:type=ThreadPool,name=%name%:currentThreadCount"
displayName="Threadpool Threads Allocated"
description="Number of current threads."
category="utilization"
displayType="summary" />
<metric
- property="Catalina:type=ThreadPool,name=%handler%%address%-%port%:maxThreads"
+ property="Catalina:type=ThreadPool,name=%name%:maxThreads"
displayName="Threadpool Max Threads"
description="Maximum number of threads that can be allocated for the ThreadPool."
category="utilization"
@@ -1263,4 +1272,4 @@
</server>
-</plugin>
+</plugin>
\ No newline at end of file
10 years, 5 months
[rhq] modules/enterprise
by snegrea
modules/enterprise/server/data-migration/src/main/java/org/rhq/server/metrics/migrator/DataMigratorRunner.java | 284 +++++++---
modules/enterprise/server/data-migration/src/main/resources/module/main/module.xml | 1
modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/command/Upgrade.java | 55 -
3 files changed, 227 insertions(+), 113 deletions(-)
New commits:
commit 386643938523537229cc6385351553a89454ba1c
Author: Stefan Negrea <snegrea(a)redhat.com>
Date: Fri Jun 28 15:34:18 2013 -0500
[BZ 976790] Update the data migration process to use properties from rhq-server.properties. This way the database and cassandra configurations are automatically loaded from the main source.
The hierarchy for overriding properties is:
1) default configuration - defined inside the migration runner
2) RHQ server configuration file - if explictly passed, if not attempt to use implicit configuration file (systme property)
3) additional configuration - user specified configuration file that matches command line expected arguments
4) command line arguments
This update also includes using a connection url argument (if found) instead of creating a connection url from individual properties.
diff --git a/modules/enterprise/server/data-migration/src/main/java/org/rhq/server/metrics/migrator/DataMigratorRunner.java b/modules/enterprise/server/data-migration/src/main/java/org/rhq/server/metrics/migrator/DataMigratorRunner.java
index 7eef2a3..f18bea1 100644
--- a/modules/enterprise/server/data-migration/src/main/java/org/rhq/server/metrics/migrator/DataMigratorRunner.java
+++ b/modules/enterprise/server/data-migration/src/main/java/org/rhq/server/metrics/migrator/DataMigratorRunner.java
@@ -23,8 +23,11 @@ package org.rhq.server.metrics.migrator;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
+import java.lang.reflect.Method;
+import java.net.InetAddress;
import java.util.HashMap;
import java.util.Map;
+import java.util.Map.Entry;
import java.util.Properties;
import java.util.concurrent.TimeUnit;
@@ -53,6 +56,10 @@ import org.apache.log4j.PatternLayout;
import org.hibernate.ejb.Ejb3Configuration;
import org.rhq.server.metrics.migrator.DataMigrator.DatabaseType;
+import org.rhq.server.metrics.migrator.workers.AggregateDataMigrator;
+import org.rhq.server.metrics.migrator.workers.DeleteAllData;
+import org.rhq.server.metrics.migrator.workers.MetricsIndexUpdateAccumulator;
+import org.rhq.server.metrics.migrator.workers.RawDataMigrator;
/**
@@ -74,67 +81,83 @@ public class DataMigratorRunner {
private final Log log = LogFactory.getLog(DataMigratorRunner.class);
//Cassandra
- private Option cassandraUserOption = OptionBuilder.withLongOpt("cassandra-user").hasArg().withType(String.class)
- .withDescription("Cassandra user (default: rhqadmin)").create();
- private Option cassandraPasswordOption = OptionBuilder.withLongOpt("cassandra-password").hasArg()
+ private final Option cassandraUserOption = OptionBuilder.withLongOpt("cassandra-user").hasArg()
+ .withType(String.class).withDescription("Cassandra user (default: rhqadmin)").create();
+ private final Option cassandraPasswordOption = OptionBuilder.withLongOpt("cassandra-password").hasArg()
.withDescription("Cassandra password (default: rhqadmin)").withType(String.class).create();
- private Option cassandraHostsOption = OptionBuilder.withLongOpt("cassandra-hosts").hasArg().withType(String.class)
- .withDescription("Cassandra hosts, format host_ip_1,host_ip_2,... (default: 127.0.0.1")
+ private final Option cassandraHostsOption = OptionBuilder.withLongOpt("cassandra-hosts").hasArg()
+ .withType(String.class).withDescription("Cassandra hosts, format host_ip_1,host_ip_2,... (default: 127.0.0.1")
.create();
- private Option cassandraPortOption = OptionBuilder.withLongOpt("cassandra-port").hasArg().withType(Integer.class)
- .withDescription("Cassandra native binary protocol port (default: 9142)").create();
- private Option cassandraCompressionOption = OptionBuilder.withLongOpt("cassandra-compression").hasOptionalArg()
- .withType(Boolean.class).withDescription("Enable compression for communication with Cassandra (default: true)")
+ private final Option cassandraPortOption = OptionBuilder.withLongOpt("cassandra-port").hasArg()
+ .withType(Integer.class).withDescription("Cassandra native binary protocol port (default: 9142)").create();
+ private final Option cassandraCompressionOption = OptionBuilder.withLongOpt("cassandra-compression")
+ .hasOptionalArg().withType(Boolean.class)
+ .withDescription("Enable compression for communication with Cassandra (default: true)")
.create();
//SQL
- private Option sqlUserOption = OptionBuilder.withLongOpt("sql-user").hasArg().withType(String.class)
+ private final Option sqlUserOption = OptionBuilder.withLongOpt("sql-user").hasArg().withType(String.class)
.withDescription("SQL server user (default: rhqadmin)").create();
- private Option sqlPasswordOption = OptionBuilder.withLongOpt("sql-password").hasArg().withType(String.class)
+ private final Option sqlPasswordOption = OptionBuilder.withLongOpt("sql-password").hasArg().withType(String.class)
.withDescription("SQL server password (default: rhqadmin)").create();
- private Option sqlHostOption = OptionBuilder.withLongOpt("sql-host").hasArg().withType(String.class)
+ private final Option sqlConnectionUrlOption = OptionBuilder.withLongOpt("sql-connection-url").hasArg()
+ .withType(String.class)
+ .withDescription("SQL connection url. Not used by default. If specified will override host, port and db SQL options.")
+ .create();
+ private final Option sqlHostOption = OptionBuilder.withLongOpt("sql-host").hasArg().withType(String.class)
.withDescription("SQL server host address (default: localhost)").create();
- private Option sqlPortOption = OptionBuilder.withLongOpt("sql-port").hasArg().withType(String.class)
+ private final Option sqlPortOption = OptionBuilder.withLongOpt("sql-port").hasArg().withType(String.class)
.withDescription("SQL server port (default: 5432)").create();
private Option sqlDBOption = OptionBuilder.withLongOpt("sql-db").hasArg().withType(String.class)
.withDescription("SQL database (default: rhq)").create();
- private Option sqlServerType = OptionBuilder.withLongOpt("sql-server-type").hasArg().withType(String.class)
+ private final Option sqlServerTypeOption = OptionBuilder.withLongOpt("sql-server-type").hasArg().withType(String.class)
.withDescription("SQL server type, only postgres and oracle are supported (default: postgres)").create();
- private Option sqlPostgresServer = OptionBuilder.withLongOpt("sql-server-postgres").hasOptionalArg()
+ private final Option sqlPostgresServerOption = OptionBuilder.withLongOpt("sql-server-postgres").hasOptionalArg()
.withType(Boolean.class).withDescription("Postgres SQL server.").create();
- private Option sqlOracleServer = OptionBuilder.withLongOpt("sql-server-oracle").hasOptionalArg()
- .withType(Boolean.class)
- .withDescription("Oracle SQL server.").create();
+ private final Option sqlOracleServerOption = OptionBuilder.withLongOpt("sql-server-oracle").hasOptionalArg()
+ .withType(Boolean.class).withDescription("Oracle SQL server.").create();
//Migration
- private Option disableRawOption = OptionBuilder.withLongOpt("disable-raw-migration").hasOptionalArg().withType(Boolean.class)
+ private final Option disableRawOption = OptionBuilder.withLongOpt("disable-raw-migration").hasOptionalArg()
+ .withType(Boolean.class)
.withDescription("Disable raw table migration (default: false)").create();
- private Option disable1HOption = OptionBuilder.withLongOpt("disable-1h-migration").hasOptionalArg().withType(Boolean.class)
+ private final Option disable1HOption = OptionBuilder.withLongOpt("disable-1h-migration").hasOptionalArg()
+ .withType(Boolean.class)
.withDescription("Disable 1 hour aggregates table migration (default: false)").create();
- private Option disable6HOption = OptionBuilder.withLongOpt("disable-6h-migration").hasOptionalArg().withType(Boolean.class)
+ private final Option disable6HOption = OptionBuilder.withLongOpt("disable-6h-migration").hasOptionalArg()
+ .withType(Boolean.class)
.withDescription("Disable 6 hours aggregates table migration (default: false)").create();
- private Option disable1DOption = OptionBuilder.withLongOpt("disable-1d-migration").hasOptionalArg().withType(Boolean.class)
+ private final Option disable1DOption = OptionBuilder.withLongOpt("disable-1d-migration").hasOptionalArg()
+ .withType(Boolean.class)
.withDescription("Disable 24 hours aggregates table migration (default: false)").create();
- private Option deleteDataOption = OptionBuilder.withLongOpt("delete-data").hasOptionalArg().withType(Boolean.class)
+ private final Option deleteDataOption = OptionBuilder.withLongOpt("delete-data").hasOptionalArg()
+ .withType(Boolean.class)
.withDescription("Delete SQL data at the end of migration (default: false)").create();
- private Option estimateOnlyOption = OptionBuilder.withLongOpt("estimate-only").hasOptionalArg().withType(Boolean.class)
+ private final Option estimateOnlyOption = OptionBuilder.withLongOpt("estimate-only").hasOptionalArg()
+ .withType(Boolean.class)
.withDescription("Only estimate how long the migration will take (default: false)").create();
- private Option deleteOnlyOption = OptionBuilder.withLongOpt("delete-only").hasOptionalArg().withType(Boolean.class)
+ private final Option deleteOnlyOption = OptionBuilder.withLongOpt("delete-only").hasOptionalArg()
+ .withType(Boolean.class)
.withDescription("Only delete data from the old SQL server, no migration will be performed (default: false)")
.create();
- private Option experimentalExportOption = OptionBuilder.withLongOpt("experimental-export").hasOptionalArg().withType(Boolean.class)
+ private final Option experimentalExportOption = OptionBuilder
+ .withLongOpt("experimental-export").hasOptionalArg().withType(Boolean.class)
.withDescription("Enable experimental bulk export for Postgres, option ignored for Oracle migration (default: false)")
.create();
//Runner
- private Option helpOption = OptionBuilder.withLongOpt("help").create("h");
- private Option debugLogOption = OptionBuilder.withLongOpt("debugLog")
+ private final Option helpOption = OptionBuilder.withLongOpt("help").create("h");
+ private final Option debugLogOption = OptionBuilder.withLongOpt("debugLog")
.withDescription("Enable debug level logs for the communication with Cassandra and SQL Server (default: false)")
.create("X");
- private Option configFileOption = OptionBuilder.withLongOpt("config-file").hasArg()
+ private final Option configFileOption = OptionBuilder.withLongOpt("config-file").hasArg()
.withDescription("Configuration file. All the command line options can be set in a typical properties file. " +
- "Command line arguments take precedence over default and configuration file options.")
+ "Command line arguments take precedence over default, RHQ server properties, and configuration file options.")
+ .create();
+ private final Option serverPropertiesFileOption = OptionBuilder.withLongOpt("rhq-server-properties-file").hasArg()
+ .withDescription("RHQ Server configuration file (rhq-server.properties). The RHQ server properties will be used for SQL server configuration. "
+ +"Command line arguments take precedence over default, RHQ server properties, and configuration file options.")
.create();
private Map<Object, Object> configuration = new HashMap<Object, Object>();
@@ -168,6 +191,7 @@ public class DataMigratorRunner {
}
}
+ @SuppressWarnings("rawtypes")
private static void setLogLevel(Level level) {
Logger root = Logger.getRootLogger();
root.setLevel(level);
@@ -187,6 +211,18 @@ public class DataMigratorRunner {
} else {
migratorLogging.setLevel(level);
}
+
+ //force change some of the logger levels
+ Class[] clazzes = new Class[] { DataMigratorRunner.class, DataMigrator.class, RawDataMigrator.class,
+ DeleteAllData.class, AggregateDataMigrator.class, MetricsIndexUpdateAccumulator.class };
+ for (Class clazz : clazzes) {
+ migratorLogging = root.getLogger(clazz);
+ if (Level.DEBUG.equals(level)) {
+ migratorLogging.setLevel(Level.ALL);
+ } else {
+ migratorLogging.setLevel(level);
+ }
+ }
}
private void configure(String args[]) throws Exception {
@@ -203,9 +239,10 @@ public class DataMigratorRunner {
options.addOption(sqlHostOption);
options.addOption(sqlPortOption);
options.addOption(sqlDBOption);
- options.addOption(sqlServerType);
- options.addOption(sqlPostgresServer);
- options.addOption(sqlOracleServer);
+ options.addOption(sqlServerTypeOption);
+ options.addOption(sqlPostgresServerOption);
+ options.addOption(sqlOracleServerOption);
+ options.addOption(sqlConnectionUrlOption);
options.addOption(disableRawOption);
options.addOption(disable1HOption);
@@ -219,6 +256,7 @@ public class DataMigratorRunner {
options.addOption(helpOption);
options.addOption(debugLogOption);
options.addOption(configFileOption);
+ options.addOption(serverPropertiesFileOption);
CommandLine commandLine;
try {
@@ -242,6 +280,19 @@ public class DataMigratorRunner {
}
loadDefaultConfiguration();
+
+ if (commandLine.hasOption(serverPropertiesFileOption.getLongOpt())) {
+ log.debug("Server configuration file option enabled. Loading server configuration from file: "
+ + serverPropertiesFileOption.getLongOpt());
+ loadConfigurationFromServerPropertiesFile(commandLine.getOptionValue(serverPropertiesFileOption.getLongOpt()));
+ log.debug("Server configuration file from system properties will not be loaded even if set because of the manual override.");
+ } else if (System.getProperty("rhq.server.properties-file") != null) {
+ log.debug("Server configuration file system property detected. Loading the file: "
+ + System.getProperty("rhq.server.properties-file"));
+ loadConfigurationFromServerPropertiesFile(System.getProperty("rhq.server.properties-file"));
+ log.debug("Server configuration file loaded based on system properties options.");
+ }
+
if (commandLine.hasOption(configFileOption.getLongOpt())) {
loadConfigFile(commandLine.getOptionValue(configFileOption.getLongOpt()));
}
@@ -249,16 +300,21 @@ public class DataMigratorRunner {
parseCassandraOptions(commandLine);
parseSQLOptions(commandLine);
parseMigrationOptions(commandLine);
+
+ if (commandLine.hasOption(debugLogOption.getLongOpt()) || commandLine.hasOption(debugLogOption.getOpt())) {
+ printOptions();
+ }
}
/**
* Add default configuration options to the configuration store.
+ * @throws Exception
*/
- private void loadDefaultConfiguration() {
+ private void loadDefaultConfiguration() throws Exception {
//default Cassandra configuration
configuration.put(cassandraUserOption, "rhqadmin");
configuration.put(cassandraPasswordOption, "rhqadmin");
- configuration.put(cassandraHostsOption, new String[] { "127.0.0.1" });
+ configuration.put(cassandraHostsOption, new String[] { InetAddress.getLocalHost().getHostAddress() });
configuration.put(cassandraPortOption, DEFAULT_CASSANDRA_PORT);
configuration.put(cassandraCompressionOption, true);
@@ -268,7 +324,7 @@ public class DataMigratorRunner {
configuration.put(sqlHostOption, "localhost");
configuration.put(sqlPortOption, "5432");
configuration.put(sqlDBOption, "rhq");
- configuration.put(sqlServerType, "postgres");
+ configuration.put(sqlServerTypeOption, DatabaseType.Postgres);
//default runner options
configuration.put(disableRawOption, false);
@@ -281,6 +337,56 @@ public class DataMigratorRunner {
configuration.put(experimentalExportOption, false);
}
+
+ private void loadConfigurationFromServerPropertiesFile(String file) throws Exception {
+ File configFile = new File(file);
+ if (!configFile.exists()) {
+ throw new FileNotFoundException("RHQ server properties file not found! File: " + file);
+ }
+
+ Properties serverProperties = new Properties();
+ FileInputStream stream = new FileInputStream(configFile);
+ serverProperties.load(stream);
+ stream.close();
+
+ String dbType = serverProperties.getProperty("rhq.server.database.type-mapping");
+ DatabaseType databaseType = DatabaseType.Postgres;
+ if (dbType != null && dbType.toLowerCase().contains("oracle")) {
+ databaseType = databaseType.Oracle;
+ }
+
+ configuration.put(sqlServerTypeOption, databaseType);
+ configuration.put(sqlUserOption, serverProperties.getProperty("rhq.server.database.user-name"));
+ String dbPasswordProperty = serverProperties.getProperty("rhq.server.database.password");
+ configuration.put(sqlPasswordOption, deobfuscatePassword(dbPasswordProperty));
+ configuration.put(sqlConnectionUrlOption, serverProperties.getProperty("rhq.server.database.connection-url"));
+
+ configuration.put(cassandraUserOption, serverProperties.getProperty("rhq.cassandra.username"));
+ configuration.put(cassandraPasswordOption, serverProperties.getProperty("rhq.cassandra.password"));
+
+ if (serverProperties.getProperty("rhq.cassandra.seeds") != null
+ && !serverProperties.getProperty("rhq.cassandra.seeds").trim().isEmpty()) {
+
+ StringBuffer seedHosts = new StringBuffer();
+ String cassandraPort = null;
+ for (String seed : serverProperties.getProperty("rhq.cassandra.seeds").split(",")) {
+ String[] params = seed.split("\\|");
+ if (params.length != 3) {
+ throw new IllegalArgumentException(
+ "Expected string of the form, hostname|jmxPort|nativeTransportPort: [" + seed + "]");
+ }
+
+ seedHosts.append(params[0]).append(',');
+ cassandraPort = tryParseInteger(params[2], DEFAULT_CASSANDRA_PORT) + "";
+ }
+
+ seedHosts.deleteCharAt(seedHosts.length() - 1);
+
+ configuration.put(cassandraHostsOption, seedHosts.toString());
+ configuration.put(cassandraPortOption, cassandraPort);
+ }
+ }
+
/**
* Load the configuration options from file and overlay them on top of the default
* options.
@@ -310,21 +416,21 @@ public class DataMigratorRunner {
if (option.equals(cassandraHostsOption)) {
String[] cassandraHosts = parseCassandraHosts(optionValue.toString());
configuration.put(option, cassandraHosts);
- } else if (option.equals(sqlServerType)) {
+ } else if (option.equals(sqlServerTypeOption)) {
if ("oracle".equals(optionValue)) {
- configuration.put(option, "oracle");
+ configuration.put(option, DatabaseType.Oracle);
} else {
- configuration.put(option, "postgres");
+ configuration.put(option, DatabaseType.Postgres);
}
- } else if (option.equals(sqlPostgresServer)) {
+ } else if (option.equals(sqlPostgresServerOption)) {
boolean value = tryParseBoolean(optionValue.toString(), true);
if (value == true) {
- configuration.put(sqlServerType, "postgres");
+ configuration.put(sqlServerTypeOption, DatabaseType.Postgres);
}
- } else if (option.equals(sqlOracleServer)) {
+ } else if (option.equals(sqlOracleServerOption)) {
boolean value = tryParseBoolean(optionValue.toString(), true);
if (value == true) {
- configuration.put(sqlServerType, "oracle");
+ configuration.put(sqlServerTypeOption, DatabaseType.Oracle);
}
} else if (option.getType().equals(Boolean.class)) {
configuration.put(option, tryParseBoolean(optionValue.toString(), true));
@@ -339,8 +445,6 @@ public class DataMigratorRunner {
log.error("Unable to load or process the configuration file.", e);
System.exit(1);
}
-
- log.debug(configuration.toString());
}
/**
@@ -403,16 +507,20 @@ public class DataMigratorRunner {
configuration.put(sqlDBOption, commandLine.getOptionValue(sqlDBOption.getLongOpt()));
}
- if (commandLine.hasOption(sqlServerType.getLongOpt())) {
- if ("oracle".equals(commandLine.getOptionValue(sqlServerType.getLongOpt()))) {
- configuration.put(sqlServerType, "oracle");
+ if (commandLine.hasOption(sqlConnectionUrlOption.getLongOpt())) {
+ configuration.put(sqlConnectionUrlOption, commandLine.getOptionValue(sqlConnectionUrlOption.getLongOpt()));
+ }
+
+ if (commandLine.hasOption(sqlServerTypeOption.getLongOpt())) {
+ if ("oracle".equals(commandLine.getOptionValue(sqlServerTypeOption.getLongOpt()))) {
+ configuration.put(sqlServerTypeOption, DatabaseType.Oracle);
} else {
- configuration.put(sqlServerType, "postgres");
+ configuration.put(sqlServerTypeOption, DatabaseType.Postgres);
}
- } else if (commandLine.hasOption(sqlPostgresServer.getLongOpt())) {
- configuration.put(sqlServerType, "postgres");
- } else if (commandLine.hasOption(sqlOracleServer.getLongOpt())) {
- configuration.put(sqlServerType, "oracle");
+ } else if (commandLine.hasOption(sqlPostgresServerOption.getLongOpt())) {
+ configuration.put(sqlServerTypeOption, DatabaseType.Postgres);
+ } else if (commandLine.hasOption(sqlOracleServerOption.getLongOpt())) {
+ configuration.put(sqlServerTypeOption, DatabaseType.Oracle);
}
}
@@ -471,9 +579,10 @@ public class DataMigratorRunner {
log.debug("Done creating Cassandra session");
DatabaseType databaseType = DatabaseType.Postgres;
- if ("oracle".equals(configuration.get(sqlServerType))) {
- databaseType = databaseType.Oracle;
+ if (configuration.get(sqlServerTypeOption) != null) {
+ databaseType = (DatabaseType) configuration.get(sqlServerTypeOption);
}
+
DataMigrator migrator = new DataMigrator(entityManager, cassandraSession, databaseType, tryParseBoolean(
configuration.get(experimentalExportOption), false));
@@ -596,7 +705,7 @@ public class DataMigratorRunner {
properties.put("javax.persistence.query.timeout", DataMigrator.SQL_TIMEOUT);
properties.put("hibernate.c3p0.timeout", DataMigrator.SQL_TIMEOUT);
- if ("oracle".equals(configuration.get(sqlServerType))) {
+ if (DatabaseType.Oracle.equals(configuration.get(sqlServerTypeOption))) {
String driverClassName = "oracle.jdbc.driver.OracleDriver";
try {
@@ -610,9 +719,15 @@ public class DataMigratorRunner {
properties.put("hibernate.dialect", "org.hibernate.dialect.Oracle10gDialect");
properties.put("hibernate.driver_class", driverClassName);
- properties.put("hibernate.connection.url", "jdbc:oracle:thin:@" + (String) configuration.get(sqlHostOption)
- + ":" + (String) configuration.get(sqlPortOption) + ":" + (String) configuration.get(sqlDBOption));
- properties.put("hibernate.default_schema", (String) configuration.get(sqlDBOption));
+
+ if (configuration.get(sqlConnectionUrlOption) != null) {
+ properties.put("hibernate.connection.url", (String) configuration.get(sqlConnectionUrlOption));
+ } else {
+ properties.put("hibernate.connection.url", "jdbc:oracle:thin:@" + (String) configuration.get(sqlHostOption)
+ + ":" + (String) configuration.get(sqlPortOption) + ":" + (String) configuration.get(sqlDBOption));
+ properties.put("hibernate.default_schema", (String) configuration.get(sqlDBOption));
+ }
+
properties.put("hibernate.connection.oracle.jdbc.ReadTimeout", DataMigrator.SQL_TIMEOUT);
} else {
String driverClassName = "org.postgresql.Driver";
@@ -628,8 +743,13 @@ public class DataMigratorRunner {
properties.put("hibernate.dialect", "org.hibernate.dialect.PostgreSQLDialect");
properties.put("hibernate.driver_class", driverClassName);
+
+ if (configuration.get(sqlConnectionUrlOption) != null) {
+ properties.put("hibernate.connection.url", (String) configuration.get(sqlConnectionUrlOption));
+ } else {
properties.put("hibernate.connection.url", "jdbc:postgresql://" + (String) configuration.get(sqlHostOption)
+ ":" + (String) configuration.get(sqlPortOption) + "/" + (String) configuration.get(sqlDBOption));
+ }
}
log.debug("Creating entity manager with the following configuration:");
@@ -641,6 +761,38 @@ public class DataMigratorRunner {
return factory;
}
+
+ /**
+ * Print the options used to run the migration process
+ */
+ private void printOptions() {
+ log.debug("Running migration with the following optons: ");
+ for (Entry<Object, Object> configOption : this.configuration.entrySet()) {
+ Option option = (Option) configOption.getKey();
+ if (option.getLongOpt() != null && !option.getLongOpt().contains("pass")) {
+ if (!(configOption.getValue() instanceof Object[])) {
+ log.debug(" " + option.getLongOpt() + " : " + configOption.getValue());
+ } else {
+ StringBuffer arrayProperty = new StringBuffer();
+ arrayProperty.append(" ").append(option.getLongOpt()).append(" : [");
+ boolean first = true;
+ for (Object value : (Object[]) configOption.getValue()){
+ if (!first) {
+ arrayProperty.append(", ");
+ }
+ arrayProperty.append(value);
+ first = false;
+ }
+ arrayProperty.append("]");
+
+ log.debug(arrayProperty.toString());
+ }
+ } else {
+ log.debug(" " + option.getLongOpt() + " : <obscured value>");
+ }
+ }
+ }
+
/**
* Parse Cassandra host information submitted in the form:
* host_addres,jmx_port,native_port|host_address_2,jmx_port,native_port
@@ -679,6 +831,20 @@ public class DataMigratorRunner {
}
}
+ private String deobfuscatePassword(String dbPassword) {
+ try {
+ String className = "org.picketbox.datasource.security.SecureIdentityLoginModule";
+ Class<?> clazz = Class.forName(className);
+ Object object = clazz.newInstance();
+ Method method = clazz.getDeclaredMethod("decode", String.class);
+ method.setAccessible(true);
+ char[] result = (char[]) method.invoke(object, dbPassword);
+ return new String(result);
+ } catch (Exception e) {
+ throw new RuntimeException("de-obfuscating db password failed: ", e);
+ }
+ }
+
@SuppressWarnings("serial")
private class HelpRequestedException extends Exception {
public HelpRequestedException() {
diff --git a/modules/enterprise/server/data-migration/src/main/resources/module/main/module.xml b/modules/enterprise/server/data-migration/src/main/resources/module/main/module.xml
index 78d2ac7..e02679f 100644
--- a/modules/enterprise/server/data-migration/src/main/resources/module/main/module.xml
+++ b/modules/enterprise/server/data-migration/src/main/resources/module/main/module.xml
@@ -28,5 +28,6 @@
<module name="org.rhq.oracle" optional="true" />
<module name="com.datastax.cassandra.cassandra-driver-core"/>
<module name="org.hibernate.commons-annotations" services="import"/>
+ <module name="org.picketbox"/>
</dependencies>
</module>
diff --git a/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/command/Upgrade.java b/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/command/Upgrade.java
index 2abdd0f..37667c6 100644
--- a/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/command/Upgrade.java
+++ b/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/command/Upgrade.java
@@ -31,8 +31,6 @@ import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FilenameFilter;
import java.io.IOException;
-import java.lang.reflect.Method;
-import java.net.InetAddress;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;
@@ -222,40 +220,8 @@ public class Upgrade extends AbstractInstall {
// We deduct the database parameters from the server properties
try {
- File propertiesFile = new File(getBinDir(), "rhq-server.properties");
- Properties serverProperties = new Properties();
- FileInputStream is = new FileInputStream(propertiesFile);
- serverProperties.load(is);
-
- String dbName = serverProperties.getProperty("rhq.server.database.db-name");
- String dbUser = serverProperties.getProperty("rhq.server.database.user-name");
- String dbType = serverProperties.getProperty("rhq.server.database.type-mapping");
- String dbServerName = serverProperties.getProperty("rhq.server.database.server-name");
- String dbServerPort = serverProperties.getProperty("rhq.server.database.port");
- String dbPasswordProperty = serverProperties.getProperty("rhq.server.database.password");
-
- if (dbType.toLowerCase().contains("postgres")) {
- dbType = "postgres";
- } else if (dbType.toLowerCase().contains("oracle")) {
- dbType = "oracle";
- } else {
- throw new RHQControlException("Unknown database type " + dbType + " can not migrate data");
- }
-
org.apache.commons.exec.CommandLine commandLine = getCommandLine("rhq-data-migration");
-
- String cassandraHost = InetAddress.getLocalHost().getCanonicalHostName();
- // Password in the properties file is obfuscated
- String dbPassword = deobfuscatePassword(dbPasswordProperty);
-
- commandLine.addArgument("--sql-user").addArgument(dbUser)
- .addArgument("--sql-db").addArgument(dbName)
- .addArgument("--sql-host").addArgument(dbServerName)
- .addArgument("--sql-port").addArgument(dbServerPort)
- .addArgument("--sql-server-type").addArgument(dbType)
- .addArgument("--cassandra-hosts").addArgument(cassandraHost)
- .addArgument("--sql-password ").addArgument(dbPassword);
-
+ commandLine.addArgument("-X");
if (migrationOption.equals("estimate")) {
commandLine.addArgument("--estimate-only");
}
@@ -270,25 +236,6 @@ public class Upgrade extends AbstractInstall {
log.error("Running the data migrator failed - please try to run it from the command line: "
+ e.getMessage());
}
-
- }
-
- private String deobfuscatePassword(String dbPassword) {
-
- // We need to do some mumbo jumbo, as the interesting method is private
- // in SecureIdentityLoginModule
-
- try {
- String className = "org.picketbox.datasource.security.SecureIdentityLoginModule";
- Class<?> clazz = Class.forName(className);
- Object object = clazz.newInstance();
- Method method = clazz.getDeclaredMethod("decode", String.class);
- method.setAccessible(true);
- char[] result = (char[]) method.invoke(object, dbPassword);
- return new String(result);
- } catch (Exception e) {
- throw new RuntimeException("de-obfuscating db password failed: ", e);
- }
}
private void upgradeStorage(CommandLine rhqctlCommandLine) throws Exception {
10 years, 5 months
[rhq] modules/enterprise
by John Sanda
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/cloud/StorageNodeManagerBean.java | 116 +++++++++-
1 file changed, 111 insertions(+), 5 deletions(-)
New commits:
commit f8febb1af1ccc209d7b5d953b360bdfe4064ffe7
Author: John Sanda <jsanda(a)redhat.com>
Date: Fri Jun 28 11:33:09 2013 -0400
create storage node resource group
A compatible group of storage nodes will now be created for new as well as
existing installations. When a storage node resource is committed into
inventory it is added to the group.
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/cloud/StorageNodeManagerBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/cloud/StorageNodeManagerBean.java
index 7b2d8dc..4504d53 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/cloud/StorageNodeManagerBean.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/cloud/StorageNodeManagerBean.java
@@ -49,26 +49,26 @@ import org.rhq.core.domain.cloud.StorageNode;
import org.rhq.core.domain.cloud.StorageNode.OperationMode;
import org.rhq.core.domain.cloud.StorageNodeLoadComposite;
import org.rhq.core.domain.configuration.Configuration;
-import org.rhq.core.domain.criteria.ResourceCriteria;
+import org.rhq.core.domain.criteria.ResourceGroupCriteria;
import org.rhq.core.domain.criteria.StorageNodeCriteria;
import org.rhq.core.domain.measurement.AvailabilityType;
import org.rhq.core.domain.measurement.MeasurementAggregate;
import org.rhq.core.domain.measurement.MeasurementUnits;
-import org.rhq.core.domain.operation.OperationDefinition;
-import org.rhq.core.domain.operation.ResourceOperationHistory;
-import org.rhq.core.domain.operation.bean.OperationSchedule;
import org.rhq.core.domain.resource.InventoryStatus;
import org.rhq.core.domain.resource.Resource;
import org.rhq.core.domain.resource.ResourceType;
+import org.rhq.core.domain.resource.group.ResourceGroup;
import org.rhq.core.domain.util.PageList;
import org.rhq.core.util.StringUtil;
import org.rhq.enterprise.server.RHQConstants;
+import org.rhq.enterprise.server.auth.SubjectManagerLocal;
import org.rhq.enterprise.server.authz.RequiredPermission;
import org.rhq.enterprise.server.authz.RequiredPermissions;
import org.rhq.enterprise.server.cloud.instance.ServerManagerLocal;
import org.rhq.enterprise.server.measurement.MeasurementDataManagerLocal;
import org.rhq.enterprise.server.operation.OperationManagerLocal;
-import org.rhq.enterprise.server.resource.ResourceManagerLocal;
+import org.rhq.enterprise.server.resource.ResourceTypeManagerLocal;
+import org.rhq.enterprise.server.resource.group.ResourceGroupManagerLocal;
import org.rhq.enterprise.server.rest.reporting.MeasurementConverter;
import org.rhq.enterprise.server.scheduler.SchedulerLocal;
import org.rhq.enterprise.server.scheduler.jobs.StorageNodeMaintenanceJob;
@@ -94,6 +94,12 @@ public class StorageNodeManagerBean implements StorageNodeManagerLocal, StorageN
private static final String SEEDS_PROP = "rhq.cassandra.seeds";
+ private static final String STORAGE_NODE_GROUP_NAME = "RHQ Storage Nodes";
+
+ private static final String STORAGE_NODE_RESOURCE_TYPE_NAME = "RHQ Storage Node";
+
+ private static final String STORAGE_NODE_PLUGIN_NAME = "RHQStorage";
+
@PersistenceContext(unitName = RHQConstants.PERSISTENCE_UNIT_NAME)
private EntityManager entityManager;
@@ -103,6 +109,15 @@ public class StorageNodeManagerBean implements StorageNodeManagerLocal, StorageN
@EJB
private SchedulerLocal quartzScheduler;
+ @EJB
+ private ResourceTypeManagerLocal resourceTypeManager;
+
+ @EJB
+ private SubjectManagerLocal subjectManager;
+
+ @EJB
+ private ResourceGroupManagerLocal resourceGroupManager;
+
@Override
public synchronized List<StorageNode> scanForStorageNodes() {
List<StorageNode> existingStorageNodes = getStorageNodes();
@@ -130,12 +145,23 @@ public class StorageNodeManagerBean implements StorageNodeManagerLocal, StorageN
List<StorageNode> seedNodes = parseSeedsProperty(seeds);
boolean clusterMaintenanceNeeded = false;
List<StorageNode> newNodes = null;
+
if (existingStorageNodes.isEmpty()) {
+ // This should only happen on the very first server start upon installation.
if (log.isDebugEnabled()) {
log.debug("No storage node entities exist in the database");
log.debug("Persisting seed nodes [" + StringUtil.listToString(seedNodes) + "]");
}
+ createStorageNodeGroup();
} else {
+ // There are existing storage nodes but we need to check if the storage node
+ // group exists. In the case of an upgrade, the group would not yet exist so it
+ // has to be created now.
+ if (!storageNodeGroupExists()) {
+ createStorageNodeGroup();
+ addExistingStorageNodesToGroup();
+ }
+
newNodes = findNewStorageNodes(existingStorageNodes, seedNodes);
if (!newNodes.isEmpty()) {
log.info("Detected topology change. New seed nodes will be persisted.");
@@ -210,7 +236,87 @@ public class StorageNodeManagerBean implements StorageNodeManagerLocal, StorageN
scheduleQuartzJob();
}
+
+ addStorageNodeToGroup(resource);
+ }
+ }
+
+ private void createStorageNodeGroup() {
+ log.info("Creating resource group [" + STORAGE_NODE_GROUP_NAME + "]");
+
+ ResourceGroup group = new ResourceGroup(STORAGE_NODE_GROUP_NAME);
+
+ ResourceType type = resourceTypeManager.getResourceTypeByNameAndPlugin(STORAGE_NODE_RESOURCE_TYPE_NAME,
+ STORAGE_NODE_PLUGIN_NAME);
+ group.setResourceType(type);
+ group.setRecursive(false);
+
+ resourceGroupManager.createResourceGroup(subjectManager.getOverlord(), group);
+ }
+
+ private void addExistingStorageNodesToGroup() {
+ log.info("Adding existing storage nodes to resource group [" + STORAGE_NODE_GROUP_NAME + "]");
+
+ for (StorageNode node : getStorageNodes()) {
+ if (node.getResource() != null) {
+ addStorageNodeToGroup(node.getResource());
+ }
+ }
+ }
+
+ private void addStorageNodeToGroup(Resource resource) {
+ if (log.isInfoEnabled()) {
+ log.info("Adding " + resource + " to resource group [" + STORAGE_NODE_GROUP_NAME + "]");
+ }
+
+ ResourceGroup group = getStorageNodeGroup();
+ resourceGroupManager.addResourcesToGroup(subjectManager.getOverlord(), group.getId(),
+ new int[] {resource.getId()});
+ }
+
+ /**
+ * This method is very similar to {@link #getStorageNodeGroup()} but may be called
+ * prior to the group being created.
+ *
+ * @return true if the storage node resource group exists, false otherwise.
+ */
+ private boolean storageNodeGroupExists() {
+ Subject overlord = subjectManager.getOverlord();
+
+ ResourceGroupCriteria criteria = new ResourceGroupCriteria();
+ criteria.addFilterResourceTypeName(STORAGE_NODE_RESOURCE_TYPE_NAME);
+ criteria.addFilterPluginName(STORAGE_NODE_PLUGIN_NAME);
+ criteria.addFilterName(STORAGE_NODE_GROUP_NAME);
+
+ List<ResourceGroup> groups = resourceGroupManager.findResourceGroupsByCriteria(overlord, criteria);
+
+ return !groups.isEmpty();
+ }
+
+ /**
+ * Note that this method assumes the storage node resource group already exists; as
+ * such, it should only be called from places in the code that are after the point(s)
+ * where the group has been created.
+ *
+ * @return The storage node resource group.
+ * @throws IllegalStateException if the group is not found or does not exist.
+ */
+ private ResourceGroup getStorageNodeGroup() {
+ Subject overlord = subjectManager.getOverlord();
+
+ ResourceGroupCriteria criteria = new ResourceGroupCriteria();
+ criteria.addFilterResourceTypeName(STORAGE_NODE_RESOURCE_TYPE_NAME);
+ criteria.addFilterPluginName(STORAGE_NODE_PLUGIN_NAME);
+ criteria.addFilterName(STORAGE_NODE_GROUP_NAME);
+
+ List<ResourceGroup> groups = resourceGroupManager.findResourceGroupsByCriteria(overlord, criteria);
+
+ if (groups.isEmpty()) {
+ throw new IllegalStateException("Resource group [" + STORAGE_NODE_GROUP_NAME + "] does not exist. This " +
+ "group must exist in order for the server to manage storage nodes. Restart the server for the group " +
+ "to be recreated.");
}
+ return groups.get(0);
}
@Override
10 years, 5 months
[rhq] modules/enterprise
by lkrejci
modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/content/CreateNewPackageUIBean.java | 12 +++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)
New commits:
commit 3502050af25d2a11f4fc2c7aaf1ea8b64436e266
Author: Lukas Krejci <lkrejci(a)redhat.com>
Date: Fri Jun 28 15:39:51 2013 +0200
[BZ 840649] Accomodate for package type plugins when determining pkg version
This is mostly a hack to get us going again on the JSF repository detail
page. I don't want to invest into some more elaborate and complete solution
because content subsystem is a minefield we're hopefully replacing
soon(ish).
diff --git a/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/content/CreateNewPackageUIBean.java b/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/content/CreateNewPackageUIBean.java
index 666cac8..111c39e 100644
--- a/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/content/CreateNewPackageUIBean.java
+++ b/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/content/CreateNewPackageUIBean.java
@@ -51,6 +51,7 @@ import org.rhq.core.util.MessageDigestGenerator;
import org.rhq.core.util.exception.ThrowableUtil;
import org.rhq.enterprise.gui.util.EnterpriseFacesContextUtility;
import org.rhq.enterprise.server.content.ContentException;
+import org.rhq.enterprise.server.content.ContentManagerHelper;
import org.rhq.enterprise.server.content.ContentManagerLocal;
import org.rhq.enterprise.server.content.ContentUIManagerLocal;
import org.rhq.enterprise.server.content.RepoManagerLocal;
@@ -238,9 +239,18 @@ public class CreateNewPackageUIBean {
packageUploadDetails.put(ContentManagerLocal.UPLOAD_SHA256, sha);
packageUploadDetails.put(ContentManagerLocal.UPLOAD_DISPLAY_VERSION, displayVersion);
+ //For package types that handle their own versioning, etc. let's use what the user passed in
+ //as a version. For the standard, i.e. agent-plugin defined, package types use what we want
+ //to use for them - sha-based versions to deal with improper versions discovered/declared by
+ //the packages (i.e. versions in MANIFEST.MF not properly updated)
+ //
+ //Did I say I can't wait for all this to disappear with the new provisioning? :)
+ boolean nonStandardPackageType = ContentManagerHelper.getPackageTypePluginContainer().getPluginManager().getBehavior(packageTypeId) != null;
+ String versionToUse = nonStandardPackageType ? displayVersion : formatVersion(sha);
+
Integer iRepoId = usingARepo ? Integer.parseInt(repoId) : null;
packageVersion = contentManager.getUploadedPackageVersion(subject, packageName, packageTypeId,
- formatVersion(sha), architectureId, packageStream, packageUploadDetails, iRepoId);
+ versionToUse, architectureId, packageStream, packageUploadDetails, iRepoId);
} catch (NoResultException nre) {
//eat the exception. Some of the queries return no results if no package yet exists which is fine.
10 years, 5 months
[rhq] modules/plugins
by Heiko W. Rupp
modules/plugins/hibernate/src/main/resources/META-INF/rhq-plugin.xml | 124 +++++-----
1 file changed, 63 insertions(+), 61 deletions(-)
New commits:
commit 49a4fd08ad74fb51f3cb61d82d067a6d5480e336
Author: Heiko W. Rupp <hwr(a)redhat.com>
Date: Fri Jun 28 14:47:43 2013 +0200
BZ 979320 - move the help text to <plugin> level, so that it can get displayed in the Admin screens
diff --git a/modules/plugins/hibernate/src/main/resources/META-INF/rhq-plugin.xml b/modules/plugins/hibernate/src/main/resources/META-INF/rhq-plugin.xml
index 9dff05e..7967ff0 100644
--- a/modules/plugins/hibernate/src/main/resources/META-INF/rhq-plugin.xml
+++ b/modules/plugins/hibernate/src/main/resources/META-INF/rhq-plugin.xml
@@ -141,67 +141,6 @@
description="The global number of cacheable entities/collections not found in the cache and loaded from the database since the statistics were reset"
category="throughput" measurementType="trendsup"/>
- <help>
- <![CDATA[
- <p>In order to monitor Hibernate statistics via JON, the Hibernate Session Manager MBean
- must be deployed to an object name of the format
- <tt>_"Hibernate:application=%application%,type=statistics"_</tt>, and statistics must be enabled.</p>
-
- <p>Some example code is provided below to register the Hibernate Session MBean within an EJB3 application.</p>
-
- <code><pre>
- public static void enableHibernateStatistics(EntityManager entityManager)
- {
- try
- {
- StatisticsService mBean = new StatisticsService();
- SessionFactory sessionFactory = getHibernateSession(entityManager).getSessionFactory();
- mBean.setSessionFactory(sessionFactory);
- ObjectName objectName = new ObjectName(HIBERNATE_STATISTICS_MBEAN_OBJECTNAME);
- MBeanServer jbossMBeanServer = getJBossMBeanServer();
- jbossMBeanServer.registerMBean(mBean, objectName);
- sessionFactory.getStatistics().setStatisticsEnabled(true);
- }
- catch (InstanceAlreadyExistsException iaee)
- {
- LOG.info("Duplicate MBean registration ignored: " + HIBERNATE_STATISTICS_MBEAN_OBJECTNAME);
- }
- catch (Exception e)
- {
- LOG.warn("Couldn't register Hibernate statistics MBean.", e);
- }
- }
-
- private static Session getHibernateSession(EntityManager entityManager) {
- Session session;
- if (entityManager.getDelegate() instanceof EntityManagerImpl) {
- EntityManagerImpl entityManagerImpl = (EntityManagerImpl) entityManager.getDelegate();
- session = entityManagerImpl.getSession();
- } else {
- session = (Session) entityManager.getDelegate();
- }
- return session;
- }
-
- private static MBeanServer getJBossMBeanServer() {
- List<MBeanServer> servers = MBeanServerFactory.findMBeanServer(null);
- MBeanServer jbossServer = null;
- for (MBeanServer server : servers) {
- if ("jboss".equals(server.getDefaultDomain())) {
- jbossServer = server;
- }
- }
- if (jbossServer == null) {
- jbossServer = ManagementFactory.getPlatformMBeanServer();
- }
- return jbossServer;
- }
- </pre></code>
-
- <p>See also <a href="http://hibernate.org/216.html">Publishing statistics through JMX</a> and
- <a href="http://www.redhat.com/docs/manuals/jboss/jboss-eap-4.3/doc/hibernate/Hibe...">Enabling Hibernate statistics</a></p>
- ]]>
- </help>
<service name="Hibernate Entity"
discovery="EntityDiscoveryComponent"
@@ -225,4 +164,67 @@
</service>
+ <help>
+ <![CDATA[
+ <p>In order to monitor Hibernate statistics via JON, the Hibernate Session Manager MBean
+ must be deployed to an object name of the format
+ <tt>_"Hibernate:application=%application%,type=statistics"_</tt>, and statistics must be enabled.</p>
+
+ <p>Some example code is provided below to register the Hibernate Session MBean within an EJB3 application.</p>
+
+ <code><pre>
+public static void enableHibernateStatistics(EntityManager entityManager)
+{
+try
+{
+ StatisticsService mBean = new StatisticsService();
+ SessionFactory sessionFactory = getHibernateSession(entityManager).getSessionFactory();
+ mBean.setSessionFactory(sessionFactory);
+ ObjectName objectName = new ObjectName(HIBERNATE_STATISTICS_MBEAN_OBJECTNAME);
+ MBeanServer jbossMBeanServer = getJBossMBeanServer();
+ jbossMBeanServer.registerMBean(mBean, objectName);
+ sessionFactory.getStatistics().setStatisticsEnabled(true);
+}
+catch (InstanceAlreadyExistsException iaee)
+{
+ LOG.info("Duplicate MBean registration ignored: " + HIBERNATE_STATISTICS_MBEAN_OBJECTNAME);
+}
+catch (Exception e)
+{
+ LOG.warn("Couldn't register Hibernate statistics MBean.", e);
+}
+}
+
+private static Session getHibernateSession(EntityManager entityManager) {
+Session session;
+if (entityManager.getDelegate() instanceof EntityManagerImpl) {
+ EntityManagerImpl entityManagerImpl = (EntityManagerImpl) entityManager.getDelegate();
+ session = entityManagerImpl.getSession();
+} else {
+ session = (Session) entityManager.getDelegate();
+}
+return session;
+}
+
+private static MBeanServer getJBossMBeanServer() {
+List<MBeanServer> servers = MBeanServerFactory.findMBeanServer(null);
+MBeanServer jbossServer = null;
+for (MBeanServer server : servers) {
+ if ("jboss".equals(server.getDefaultDomain())) {
+ jbossServer = server;
+ }
+}
+if (jbossServer == null) {
+ jbossServer = ManagementFactory.getPlatformMBeanServer();
+}
+return jbossServer;
+}
+ </pre></code>
+
+ <p>See also <a href="http://hibernate.org/216.html">Publishing statistics through JMX</a> and
+ <a href="http://www.redhat.com/docs/manuals/jboss/jboss-eap-4.3/doc/hibernate/Hibe...">Enabling Hibernate statistics</a></p>
+ ]]>
+ </help>
+
+
</plugin>
10 years, 5 months
[rhq] modules/enterprise pom.xml
by Thomas Segismont
modules/enterprise/gui/coregui/pom.xml | 6
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/server/listener/CoreGuiServletContextListener.java | 67 +++++++
modules/enterprise/server/ear/pom.xml | 14 -
modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/test/AbstractEJB3Test.java | 21 ++
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/ShutdownListener.java | 7
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/StartupBean.java | 10 -
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/StartupBeanPreparation.java | 68 -------
modules/enterprise/server/startup-subsystem/src/main/java/org/rhq/enterprise/startup/StartupSubsystemAdd.java | 29 ---
modules/enterprise/server/startup-subsystem/src/main/java/org/rhq/enterprise/startup/deployment/RhqDeploymentMarker.java | 49 -----
modules/enterprise/server/startup-subsystem/src/main/java/org/rhq/enterprise/startup/deployment/RhqInitializationProcessor.java | 53 -----
modules/enterprise/server/startup-subsystem/src/main/java/org/rhq/enterprise/startup/deployment/RhqShutdownBeanDependenciesProcessor.java | 94 ----------
pom.xml | 7
12 files changed, 114 insertions(+), 311 deletions(-)
New commits:
commit 0bddf58297213e94fe7d8ab426c07c1ad10dfe70
Author: Thomas Segismont <tsegismo(a)redhat.com>
Date: Fri Jun 28 12:45:50 2013 +0200
Bug 957689 - Unable to complete tasks when server is shutdown
Removed DUPs
Made Core GUI last component to get deployed and first to get undeployed
Added CoreGuiServletContextListener to initialize or shutdown RHQ server
diff --git a/modules/enterprise/gui/coregui/pom.xml b/modules/enterprise/gui/coregui/pom.xml
index 7375ec2..969ab8e 100644
--- a/modules/enterprise/gui/coregui/pom.xml
+++ b/modules/enterprise/gui/coregui/pom.xml
@@ -191,6 +191,12 @@
</dependency>
<dependency>
+ <groupId>org.jboss.spec.javax.servlet</groupId>
+ <artifactId>jboss-servlet-api_3.0_spec</artifactId>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jaxrs</artifactId>
<version>${resteasy.version}</version>
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/server/listener/CoreGuiServletContextListener.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/server/listener/CoreGuiServletContextListener.java
new file mode 100644
index 0000000..8260327
--- /dev/null
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/server/listener/CoreGuiServletContextListener.java
@@ -0,0 +1,67 @@
+/*
+ * 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.enterprise.gui.coregui.server.listener;
+
+import static java.util.concurrent.TimeUnit.SECONDS;
+
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+
+import javax.ejb.EJB;
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+import javax.servlet.annotation.WebListener;
+
+import org.rhq.enterprise.server.core.ShutdownListener;
+import org.rhq.enterprise.server.core.StartupLocal;
+
+/**
+ * Listens to {@link ServletContextEvent}s to initialize or shutdown RHQ server.
+ *
+ * @author Thomas Segismont
+ */
+@WebListener
+public class CoreGuiServletContextListener implements ServletContextListener {
+
+ private ScheduledExecutorService scheduledExecutorService;
+
+ @EJB
+ StartupLocal startupBean;
+
+ @EJB
+ ShutdownListener shutdownListener;
+
+ @Override
+ public void contextInitialized(ServletContextEvent sce) {
+ scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
+ scheduledExecutorService.schedule(new Runnable() {
+ @Override
+ public void run() {
+ startupBean.init();
+ }
+ }, 10, SECONDS);
+ }
+
+ @Override
+ public void contextDestroyed(ServletContextEvent sce) {
+ shutdownListener.handleNotification();
+ scheduledExecutorService.shutdownNow();
+ }
+}
diff --git a/modules/enterprise/server/ear/pom.xml b/modules/enterprise/server/ear/pom.xml
index a0e00f6..9a82877 100644
--- a/modules/enterprise/server/ear/pom.xml
+++ b/modules/enterprise/server/ear/pom.xml
@@ -298,13 +298,6 @@
<!-- ** WARs -->
<webModule>
<groupId>${project.groupId}</groupId>
- <artifactId>rhq-coregui</artifactId>
- <bundleFileName>coregui.war</bundleFileName>
- <contextRoot>/coregui</contextRoot>
- </webModule>
-
- <webModule>
- <groupId>${project.groupId}</groupId>
<artifactId>rhq-portal</artifactId>
<bundleFileName>rhq-portal.war</bundleFileName>
<contextRoot>/</contextRoot>
@@ -340,6 +333,13 @@
<contextRoot>/jboss-remoting-servlet-invoker</contextRoot>
</webModule>
+ <webModule>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>rhq-coregui</artifactId>
+ <bundleFileName>coregui.war</bundleFileName>
+ <contextRoot>/coregui</contextRoot>
+ </webModule>
+
</modules>
</configuration>
</plugin>
diff --git a/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/test/AbstractEJB3Test.java b/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/test/AbstractEJB3Test.java
index c0b8449..ea7ac6b 100644
--- a/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/test/AbstractEJB3Test.java
+++ b/modules/enterprise/server/itests-2/src/test/java/org/rhq/enterprise/server/test/AbstractEJB3Test.java
@@ -1,3 +1,22 @@
+/*
+ * 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.enterprise.server.test;
import java.io.File;
@@ -325,8 +344,6 @@ public abstract class AbstractEJB3Test extends Arquillian {
testEar.delete(ArchivePaths
.create("/rhq-enterprise-server-ejb3.jar/org/rhq/enterprise/server/core/StartupBean$1.class"));
testEar.delete(ArchivePaths
- .create("/rhq-enterprise-server-ejb3.jar/org/rhq/enterprise/server/core/StartupBeanPreparation.class"));
- testEar.delete(ArchivePaths
.create("/rhq-enterprise-server-ejb3.jar/org/rhq/enterprise/server/core/ShutdownListener.class"));
//replace the above startup beans with stripped down versions
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/ShutdownListener.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/ShutdownListener.java
index 585dbaf..b07a420 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/ShutdownListener.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/ShutdownListener.java
@@ -24,11 +24,9 @@ import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
-import javax.annotation.PreDestroy;
import javax.annotation.Resource;
import javax.ejb.EJB;
import javax.ejb.Singleton;
-import javax.ejb.Startup;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.sql.DataSource;
@@ -62,7 +60,6 @@ import org.rhq.enterprise.server.util.LookupUtil;
* @author Joseph Marques
*/
@Singleton
-@Startup
@TransactionAttribute(TransactionAttributeType.SUPPORTS)
public class ShutdownListener {
private final Log log = LogFactory.getLog(ShutdownListener.class);
@@ -94,10 +91,7 @@ public class ShutdownListener {
* This is called when the shutdown notification is received from the JBoss server. This gives a chance for us to
* cleanly shutdown our application in an orderly fashion.
*/
- @PreDestroy
public void handleNotification() {
- // JBossAS 4.2.3 used to send us this JMX notification on shutdown - AS7 does not have shutdown notifications.
- // So we are using the @PreDestroy mechanism on a singleton EJB to attempt to clean up the application before it is shutdown
log.info("Shutdown listener has been told we are shutting down - starting to clean up now...");
logShutdownTime();
stopScheduler();
@@ -157,6 +151,7 @@ public class ShutdownListener {
}
}
}
+
/**
* This will shutdown the scheduler.
*/
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/StartupBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/StartupBean.java
index f8185e0..9d37b75 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/StartupBean.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/StartupBean.java
@@ -1,6 +1,6 @@
/*
* RHQ Management Platform
- * Copyright (C) 2005-2011 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,8 +13,8 @@
* 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.enterprise.server.core;
@@ -65,7 +65,6 @@ import org.rhq.enterprise.server.RHQConstants;
import org.rhq.enterprise.server.alert.engine.internal.AlertConditionCacheCoordinator;
import org.rhq.enterprise.server.auth.SessionManager;
import org.rhq.enterprise.server.auth.SubjectManagerLocal;
-import org.rhq.enterprise.server.storage.StorageClientManagerBean;
import org.rhq.enterprise.server.cloud.TopologyManagerLocal;
import org.rhq.enterprise.server.cloud.instance.CacheConsistencyManagerLocal;
import org.rhq.enterprise.server.cloud.instance.ServerManagerLocal;
@@ -90,6 +89,7 @@ import org.rhq.enterprise.server.scheduler.jobs.PurgePluginsJob;
import org.rhq.enterprise.server.scheduler.jobs.PurgeResourceTypesJob;
import org.rhq.enterprise.server.scheduler.jobs.SavedSearchResultCountRecalculationJob;
import org.rhq.enterprise.server.scheduler.jobs.StorageNodeMaintenanceJob;
+import org.rhq.enterprise.server.storage.StorageClientManagerBean;
import org.rhq.enterprise.server.storage.StorageClusterHeartBeatJob;
import org.rhq.enterprise.server.system.SystemManagerLocal;
import org.rhq.enterprise.server.util.LookupUtil;
@@ -106,7 +106,6 @@ import org.rhq.enterprise.server.util.concurrent.AvailabilityReportSerializer;
* BEAN ConcurrencyManagement is enough: the {@link #initialized} property is only modified on startup.
*/
@Singleton
-//@Startup // when AS7-5530 is fixed, uncomment this and remove class StartupBeanToWorkaroundAS7_5530
@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
@ConcurrencyManagement(ConcurrencyManagementType.BEAN)
public class StartupBean implements StartupLocal {
@@ -170,7 +169,6 @@ public class StartupBean implements StartupLocal {
*
* @throws RuntimeException
*/
- //@PostConstruct // when AS7-5530 is fixed, uncomment this and remove class StartupBeanToWorkaroundAS7_5530
@Override
public void init() throws RuntimeException {
secureNaming();
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/StartupBeanPreparation.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/StartupBeanPreparation.java
deleted file mode 100644
index c66d328..0000000
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/StartupBeanPreparation.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * RHQ Management Platform
- * Copyright (C) 2005-2011 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., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-package org.rhq.enterprise.server.core;
-
-import javax.annotation.PostConstruct;
-import javax.annotation.Resource;
-import javax.ejb.EJB;
-import javax.ejb.Singleton;
-import javax.ejb.Startup;
-import javax.ejb.Timeout;
-import javax.ejb.TimerConfig;
-import javax.ejb.TimerService;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-/**
- * This startup singleton EJB is here to work around bug AS7-5530 and to
- * schedule the real StartupBean's work in a delayed fashion (this is to allow
- * AS7 to complete its deployment work before we do our work).
- *
- * See https://issues.jboss.org/browse/AS7-5530
- */
-@Singleton
-@Startup
-public class StartupBeanPreparation {
- private Log log = LogFactory.getLog(this.getClass());
-
- @EJB
- private StartupLocal startupBean;
-
- @Resource
- private TimerService timerService; // needed to schedule our startup bean init call
-
- @PostConstruct
- public void initWithTransactionBecauseAS75530() throws RuntimeException {
- timerService.createSingleActionTimer(10000, new TimerConfig(null, false)); // call StartupBean in 10s
- }
-
- @Timeout
- public void initializeServer() throws RuntimeException {
- try {
- this.startupBean.init();
- } catch (Throwable t) {
- // do NOT allow exceptions to bubble out of our method because then
- // the EJB container would simply re-trigger the timer and call us again
- // and we don't want to keep failing over and over filling the logs
- // in an infinite loop.
- log.fatal("The server failed to start up properly", t);
- }
- }
-}
diff --git a/modules/enterprise/server/startup-subsystem/src/main/java/org/rhq/enterprise/startup/StartupSubsystemAdd.java b/modules/enterprise/server/startup-subsystem/src/main/java/org/rhq/enterprise/startup/StartupSubsystemAdd.java
index 80515ed..4b1b46a 100644
--- a/modules/enterprise/server/startup-subsystem/src/main/java/org/rhq/enterprise/startup/StartupSubsystemAdd.java
+++ b/modules/enterprise/server/startup-subsystem/src/main/java/org/rhq/enterprise/startup/StartupSubsystemAdd.java
@@ -16,6 +16,7 @@
* 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.enterprise.startup;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ADD;
@@ -30,35 +31,26 @@ import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.URL
import java.io.File;
import java.io.FileNotFoundException;
import java.net.URL;
-import java.util.List;
-import org.jboss.as.controller.AbstractBoottimeAddStepHandler;
+import org.jboss.as.controller.AbstractAddStepHandler;
import org.jboss.as.controller.OperationContext;
import org.jboss.as.controller.OperationFailedException;
import org.jboss.as.controller.OperationStepHandler;
import org.jboss.as.controller.PathAddress;
import org.jboss.as.controller.PathElement;
-import org.jboss.as.controller.ServiceVerificationHandler;
import org.jboss.as.controller.operations.common.Util;
import org.jboss.as.controller.registry.ImmutableManagementResourceRegistration;
import org.jboss.as.controller.registry.Resource;
-import org.jboss.as.server.AbstractDeploymentChainStep;
-import org.jboss.as.server.DeploymentProcessorTarget;
-import org.jboss.as.server.deployment.Phase;
import org.jboss.dmr.ModelNode;
import org.jboss.logging.Logger;
import org.jboss.modules.Module;
-import org.jboss.msc.service.ServiceController;
-
-import org.rhq.enterprise.startup.deployment.RhqInitializationProcessor;
-import org.rhq.enterprise.startup.deployment.RhqShutdownBeanDependenciesProcessor;
/**
* Handler responsible for adding the subsystem resource to the model
*
* @author John Mazzitelli
*/
-class StartupSubsystemAdd extends AbstractBoottimeAddStepHandler {
+class StartupSubsystemAdd extends AbstractAddStepHandler {
private static final Logger LOG = Logger.getLogger(StartupSubsystemAdd.class);
@@ -122,19 +114,4 @@ class StartupSubsystemAdd extends AbstractBoottimeAddStepHandler {
return false;
}
- @Override
- protected void performBoottime(OperationContext context, ModelNode operation, ModelNode model,
- ServiceVerificationHandler verificationHandler, List<ServiceController<?>> newControllers)
- throws OperationFailedException {
- LOG.info("Adding RHQ deploymentUnit processors");
- context.addStep(new AbstractDeploymentChainStep() {
- public void execute(DeploymentProcessorTarget processorTarget) {
- processorTarget.addDeploymentProcessor(StartupExtension.SUBSYSTEM_NAME, Phase.STRUCTURE,
- Phase.STRUCTURE_EAR + 10, new RhqInitializationProcessor());
- processorTarget.addDeploymentProcessor(StartupExtension.SUBSYSTEM_NAME, Phase.INSTALL,
- Phase.INSTALL_DEPENDS_ON_ANNOTATION + 10, new RhqShutdownBeanDependenciesProcessor());
- }
- }, OperationContext.Stage.RUNTIME);
- }
-
}
diff --git a/modules/enterprise/server/startup-subsystem/src/main/java/org/rhq/enterprise/startup/deployment/RhqDeploymentMarker.java b/modules/enterprise/server/startup-subsystem/src/main/java/org/rhq/enterprise/startup/deployment/RhqDeploymentMarker.java
deleted file mode 100644
index ff98956..0000000
--- a/modules/enterprise/server/startup-subsystem/src/main/java/org/rhq/enterprise/startup/deployment/RhqDeploymentMarker.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * 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.enterprise.startup.deployment;
-
-import org.jboss.as.server.deployment.AttachmentKey;
-import org.jboss.as.server.deployment.DeploymentUnit;
-
-/**
- * Marker for RHQ EAR. Deployment Unit Processors will only process RHQ EAR sub deployments.
- *
- * @author Thomas Segismont
- */
-class RhqDeploymentMarker {
- private static final AttachmentKey<RhqDeploymentMarker> MARKER = AttachmentKey.create(RhqDeploymentMarker.class);
-
- private RhqDeploymentMarker() {
- // Defensive
- }
-
- static void mark(DeploymentUnit unit) {
- unit.putAttachment(MARKER, new RhqDeploymentMarker());
- }
-
- static boolean isRhqDeployment(DeploymentUnit unit) {
- DeploymentUnit deploymentUnit = unit;
- if (deploymentUnit.getParent() != null) {
- do {
- deploymentUnit = deploymentUnit.getParent();
- } while (deploymentUnit.getParent() != null);
- }
- return deploymentUnit.hasAttachment(MARKER);
- }
-}
diff --git a/modules/enterprise/server/startup-subsystem/src/main/java/org/rhq/enterprise/startup/deployment/RhqInitializationProcessor.java b/modules/enterprise/server/startup-subsystem/src/main/java/org/rhq/enterprise/startup/deployment/RhqInitializationProcessor.java
deleted file mode 100644
index 4e694ae..0000000
--- a/modules/enterprise/server/startup-subsystem/src/main/java/org/rhq/enterprise/startup/deployment/RhqInitializationProcessor.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * 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.enterprise.startup.deployment;
-
-import static org.rhq.enterprise.startup.StartupExtension.DEPLOYMENT_APP_EAR;
-
-import org.jboss.as.ee.structure.DeploymentType;
-import org.jboss.as.ee.structure.DeploymentTypeMarker;
-import org.jboss.as.server.deployment.DeploymentPhaseContext;
-import org.jboss.as.server.deployment.DeploymentUnit;
-import org.jboss.as.server.deployment.DeploymentUnitProcessingException;
-import org.jboss.as.server.deployment.DeploymentUnitProcessor;
-import org.jboss.logging.Logger;
-
-/**
- * A DUP which detects RHQ EAR deployment.
- *
- * @author Thomas Segismont
- */
-public class RhqInitializationProcessor implements DeploymentUnitProcessor {
-
- private static final Logger LOG = Logger.getLogger(RhqInitializationProcessor.class);
-
- @Override
- public void deploy(DeploymentPhaseContext phaseContext) throws DeploymentUnitProcessingException {
- DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit();
- if (deploymentUnit.getParent() == null && DEPLOYMENT_APP_EAR.equals(deploymentUnit.getName())
- && DeploymentTypeMarker.isType(DeploymentType.EAR, deploymentUnit)) {
- LOG.info("Found " + DEPLOYMENT_APP_EAR + " deployment");
- RhqDeploymentMarker.mark(deploymentUnit);
- }
- }
-
- @Override
- public void undeploy(DeploymentUnit context) {
- }
-}
diff --git a/modules/enterprise/server/startup-subsystem/src/main/java/org/rhq/enterprise/startup/deployment/RhqShutdownBeanDependenciesProcessor.java b/modules/enterprise/server/startup-subsystem/src/main/java/org/rhq/enterprise/startup/deployment/RhqShutdownBeanDependenciesProcessor.java
deleted file mode 100644
index 2b88268..0000000
--- a/modules/enterprise/server/startup-subsystem/src/main/java/org/rhq/enterprise/startup/deployment/RhqShutdownBeanDependenciesProcessor.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * 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.enterprise.startup.deployment;
-
-import static org.jboss.msc.service.ServiceBuilder.DependencyType.REQUIRED;
-
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.LinkedList;
-
-import org.jboss.as.ee.component.Attachments;
-import org.jboss.as.ee.component.ComponentDescription;
-import org.jboss.as.ee.component.EEModuleDescription;
-import org.jboss.as.ejb3.component.session.SessionBeanComponentDescription;
-import org.jboss.as.server.deployment.DeploymentPhaseContext;
-import org.jboss.as.server.deployment.DeploymentUnit;
-import org.jboss.as.server.deployment.DeploymentUnitProcessingException;
-import org.jboss.as.server.deployment.DeploymentUnitProcessor;
-
-/**
- * A DUP which makes the ShutdownListener session bean automatically depend on all other sessions beans.
- *
- * @author Thomas Segismont
- */
-public class RhqShutdownBeanDependenciesProcessor implements DeploymentUnitProcessor {
-
- public static final String SHUTDOWN_LISTENER_CLASS_NAME = "org.rhq.enterprise.server.core.ShutdownListener";
-
- @Override
- public void deploy(DeploymentPhaseContext context) throws DeploymentUnitProcessingException {
- DeploymentUnit unit = context.getDeploymentUnit();
- EEModuleDescription moduleDescription = unit.getAttachment(Attachments.EE_MODULE_DESCRIPTION);
- Collection<ComponentDescription> componentDescriptions = moduleDescription.getComponentDescriptions();
-
- if (componentDescriptions == null || componentDescriptions.isEmpty()
- || !RhqDeploymentMarker.isRhqDeployment(unit)) {
- // Only process sub deployments of the RHQ EAR
- return;
- }
-
- Collection<SessionBeanComponentDescription> sessionBeanComponentDescriptions = getSessionBeanComponentDescriptions(componentDescriptions);
-
- SessionBeanComponentDescription shutdownBeanComponentDescription = extractShutdownBeanDescription(sessionBeanComponentDescriptions);
-
- for (SessionBeanComponentDescription sessionBeanComponentDescription : sessionBeanComponentDescriptions) {
- shutdownBeanComponentDescription.addDependency(sessionBeanComponentDescription.getStartServiceName(),
- REQUIRED);
- }
- }
-
- private Collection<SessionBeanComponentDescription> getSessionBeanComponentDescriptions(
- Collection<ComponentDescription> componentDescriptions) {
- Collection<SessionBeanComponentDescription> sessionBeanComponentDescriptions = new LinkedList<SessionBeanComponentDescription>();
- for (ComponentDescription componentDescription : componentDescriptions) {
- if (componentDescription instanceof SessionBeanComponentDescription) {
- sessionBeanComponentDescriptions.add((SessionBeanComponentDescription) componentDescription);
- }
- }
- return sessionBeanComponentDescriptions;
- }
-
- private SessionBeanComponentDescription extractShutdownBeanDescription(
- Collection<SessionBeanComponentDescription> sessionBeanComponentDescriptions) {
- for (Iterator<SessionBeanComponentDescription> iterator = sessionBeanComponentDescriptions.iterator(); iterator
- .hasNext();) {
- SessionBeanComponentDescription sessionBeanComponentDescription = iterator.next();
- if (sessionBeanComponentDescription.getComponentClassName().equals(SHUTDOWN_LISTENER_CLASS_NAME)) {
- iterator.remove();
- return sessionBeanComponentDescription;
- }
- }
- return null;
- }
-
- @Override
- public void undeploy(DeploymentUnit context) {
- }
-}
diff --git a/pom.xml b/pom.xml
index 220eb30..99c1bdc 100644
--- a/pom.xml
+++ b/pom.xml
@@ -90,6 +90,7 @@
<javax.annotation.api.version>1.0.1.Final</javax.annotation.api.version>
<javax.ejb.api.version>1.0.2.Final</javax.ejb.api.version>
<javax.jms.api.version>1.0.0.Final</javax.jms.api.version>
+ <javax.servlet.api.version>1.0.2.Final</javax.servlet.api.version>
<javax.mail.api.version>1.4.4</javax.mail.api.version>
<javassist.version>3.15.0-GA</javassist.version>
<jaxb-api.version>1.0.4.Final</jaxb-api.version>
@@ -318,6 +319,12 @@
</dependency>
<dependency>
+ <groupId>org.jboss.spec.javax.servlet</groupId>
+ <artifactId>jboss-servlet-api_3.0_spec</artifactId>
+ <version>${javax.servlet.api.version}</version>
+ </dependency>
+
+ <dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>${javassist.version}</version>
10 years, 5 months
[rhq] Changes to 'bug/966777'
by Thomas Segismont
New branch 'bug/966777' available with the following commits:
commit a6c62d9bd0c8d848c2770892872f4ee200e059f0
Author: Thomas Segismont <tsegismo(a)redhat.com>
Date: Thu Jun 27 17:05:03 2013 +0200
Bug 966777 - EAP 6 plug-in is using a hard-coded operation timeout for start and stop instead of using the operation timeout or agent's default operation timeout of 10 minutes
Introduce ComponentInvocationContext class. An instance of this class is created by the plugin container and bound to facet-locked component invocation thread.
Make BaseServerComponent use ComponentInvocationContext to deal with operation timeout or cancellation.
commit 7b7f0eff22213847156e9262090f65f845842185
Author: Thomas Segismont <tsegismo(a)redhat.com>
Date: Thu Jun 27 16:09:58 2013 +0200
Bug 966777 - EAP 6 plug-in is using a hard-coded operation timeout for start and stop instead of using the operation timeout or agent's default operation timeout of 10 minutes
The component invocation handler now has a transferInterrupt parameter. If set to true, the component invocation thread will be interrupted when the caller thread is.
10 years, 5 months
[rhq] 2 commits - modules/core modules/plugins
by lkrejci
modules/core/util/src/main/java/org/rhq/core/util/file/FileUtil.java | 182 +++++++++-
modules/core/util/src/main/java/org/rhq/core/util/updater/DeploymentData.java | 54 +-
modules/core/util/src/test/java/org/rhq/core/util/file/FileUtilTest.java | 141 +++++--
modules/core/util/src/test/java/org/rhq/core/util/updater/DeployerCanonicalPathTest.java | 180 +++++++--
modules/plugins/jboss-as-5/src/main/java/org/rhq/plugins/jbossas5/ManagedComponentComponent.java | 34 +
5 files changed, 475 insertions(+), 116 deletions(-)
New commits:
commit a8472635e28dcdc053e5d3d4a700d5cd8c60e752
Author: Lukas Krejci <lkrejci(a)redhat.com>
Date: Thu Jun 27 23:46:34 2013 +0200
[BZ 917765] - Symlinks in deploy dir no longer confuse relative file path
if deployDir was:
/opt/depls/target -> /opt/realdepls/realtarget
(i.e. target was a symlink to realtarget)
and a file was to be deployed to:
../conf/file
a resulting path would be:
opt/depls/target/../conf/file
which would be resolved as:
opt/realdepls/conf/file
(i.e. the symlink would be resolved first and then the path would be
normalized)
This is not how people usually understand the paths and how they expect
the bundle deployer to function.
We therefore first manually normalize the path and only then obtain its
absolute path to point to it during the deployment process.
Notice that we no longer use the canonical paths anywhere in the deployer
code.
diff --git a/modules/core/util/src/main/java/org/rhq/core/util/file/FileUtil.java b/modules/core/util/src/main/java/org/rhq/core/util/file/FileUtil.java
index d3b3ddf..0de4e43 100644
--- a/modules/core/util/src/main/java/org/rhq/core/util/file/FileUtil.java
+++ b/modules/core/util/src/main/java/org/rhq/core/util/file/FileUtil.java
@@ -37,6 +37,7 @@ import java.util.ArrayList;
import java.util.Deque;
import java.util.LinkedList;
import java.util.List;
+import java.util.StringTokenizer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -588,4 +589,183 @@ public class FileUtil {
return s == null || s.length() == 0;
}
-}
\ No newline at end of file
+ /**
+ * Normalizes the path of the file by removing any ".." and "."
+ * <p/>
+ * This method behaves very similar to Java7's {@code Path.normalize()} method with the exception of dealing with
+ * paths jumping "above" the FS root.
+ * <p/>
+ * Java7's normalization will normalize a path like {@code C:\..\asdf} to {@code C:\asdf}, while this method will
+ * return null, because it understands {@code C:\..\asdf} as an attempt to "go above" the file system root.
+ *
+ * @return the file with the normalized path or null if the ".."s would jump further up than the number of preceding
+ * path elements (e.g. passing files with paths like ".." or "path/../.." will return null).
+ */
+ public static File normalizePath(File file) {
+ String path = file.getPath();
+
+ int rootLength = FileSystem.get().getPathRootLength(path);
+ File root = rootLength == 0 ? null : new File(path.substring(0, rootLength));
+
+ StringTokenizer tokenizer = new StringTokenizer(path.substring(rootLength), FileSystem.get().getSeparatorChars(), true);
+ LinkedList<String> pathStack = new LinkedList<String>();
+
+ boolean previousWasDelimiter = false;
+
+ while (tokenizer.hasMoreTokens()) {
+ String token = tokenizer.nextToken();
+
+ if (File.separator.equals(token)) {
+ if (!previousWasDelimiter) {
+ pathStack.push(token);
+ previousWasDelimiter = true;
+ }
+ } else if ("..".equals(token)) {
+ //yes, this is correct - ".." will jump up the stack to the next-previous delimiter, so we should
+ //declare that we're at a delimiter position.
+ previousWasDelimiter = true;
+ if (pathStack.isEmpty()) {
+ return null;
+ } else {
+ //pop the previous delimiter(s)
+ pathStack.pop();
+
+ //and pop the previous path element
+ if (pathStack.isEmpty()) {
+ return null;
+ }
+ pathStack.pop();
+ }
+ } else if (".".equals(token)) {
+ previousWasDelimiter = true;
+ } else if (token.length() > 0) {
+ previousWasDelimiter = false;
+ pathStack.push(token);
+ } else {
+ previousWasDelimiter = false;
+ }
+ }
+
+ StringBuilder normalizedPath = new StringBuilder();
+
+ for (int i = pathStack.size(); --i >= 0; ) {
+ normalizedPath.append(pathStack.get(i));
+ }
+
+ File ret = root == null ? new File(normalizedPath.toString()) : new File(root, normalizedPath.toString());
+
+ if (file.isAbsolute() != ret.isAbsolute()) {
+ // if the normalization changed the path such that it is not absolute anymore
+ // (or that it wasn't absolute but now is, which shouldn't ever happen), return null.
+ // The fact that the original file was absolute and the normalized path isn't can be caused by
+ // the normalization "climbing past" the prefix of the absolute path which is the drive letter of Windows
+ // for example.
+ return null;
+ } else {
+ return ret;
+ }
+ }
+
+ private enum FileSystem {
+ UNIX {
+ @Override
+ public int getPathRootLength(String path) {
+ if (path != null && path.charAt(0) == '/') {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+
+ @Override
+ public String getSeparatorChars() {
+ return "/";
+ }
+ },
+ WINDOWS {
+ @Override
+ public int getPathRootLength(String path) {
+ if (path == null || path.length() < 3) {
+ return 0;
+ }
+
+ // C:\asdf
+ // C:asdf
+ // \\host\share\asdf
+
+ char c0 = path.charAt(0);
+ char c1 = path.charAt(1);
+ char c2 = path.charAt(2);
+
+ switch (c0) {
+ case '\\':
+ case '/':
+ if (isSlash(c1)) {
+ //UNC
+ int nextSlash = nextSlash(path, 2);
+ if (nextSlash < 3) {
+ throw new IllegalArgumentException("Invalid UNC path - no host specified");
+ }
+
+ int hostSlash = nextSlash;
+ nextSlash = nextSlash(path, nextSlash + 1);
+
+ if (nextSlash <= hostSlash) {
+ throw new IllegalArgumentException("Invalid UNC path - no share specified");
+ }
+
+ return nextSlash;
+ } else {
+ return 0;
+ }
+ default:
+ if (c1 == ':') {
+ char driveLetter = Character.toLowerCase(c0);
+ if ('a' <= driveLetter && 'z' >= driveLetter) {
+ return c2 == '\\' ? 3 : 2;
+ } else {
+ return 0;
+ }
+ } else {
+ return 0;
+ }
+ }
+ }
+
+ @Override
+ public String getSeparatorChars() {
+ return "\\/";
+ }
+ };
+
+ private static boolean isSlash(char c) {
+ return c == '\\' || c == '/';
+ }
+
+ private static int nextSlash(String str, int from) {
+ int len = str.length();
+ for(int i = from; i < len; ++i) {
+ if (isSlash(str.charAt(i))) {
+ return i;
+ }
+ }
+
+ return -1;
+ }
+
+ public static FileSystem get() {
+ switch (File.separatorChar) {
+ case '/':
+ return UNIX;
+ case '\\':
+ return WINDOWS;
+ default:
+ throw new IllegalStateException("Unsupported filesystem");
+ }
+ }
+
+ public abstract int getPathRootLength(String path);
+
+ public abstract String getSeparatorChars();
+ }
+}
diff --git a/modules/core/util/src/main/java/org/rhq/core/util/updater/DeploymentData.java b/modules/core/util/src/main/java/org/rhq/core/util/updater/DeploymentData.java
index c55c1bc..2431332 100644
--- a/modules/core/util/src/main/java/org/rhq/core/util/updater/DeploymentData.java
+++ b/modules/core/util/src/main/java/org/rhq/core/util/updater/DeploymentData.java
@@ -23,6 +23,7 @@
package org.rhq.core.util.updater;
import java.io.File;
+import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
@@ -115,7 +116,18 @@ public class DeploymentData {
this.deploymentProps = deploymentProps;
this.zipFiles = zipFiles;
this.rawFiles = rawFiles;
- this.destinationDir = getCanonicalFile(destinationDir);
+
+ //specifically do NOT resolve symlinks here. This must to be the last thing one needs to do before deploying
+ //the files. The problem is that we use the destination dir as root for the paths of the individual files to
+ //lay down. If the destinationDir uses symlinks and the individual paths of the files were relative
+ // including ..'s, it could happen that the files would be laid down on a different place than expected.
+ //Consider this scenario:
+ //destinationDir = /opt/my/destination -> /tmp/deployments
+ //file = ../conf/some.properties
+ //One expects the file to end up in /opt/my/conf/some.properties
+ //but if we canonicalized the destination dir upfront, we'd end up with /tmp/conf/some.properties.
+ this.destinationDir = destinationDir.getAbsoluteFile();
+
this.sourceDir = sourceDir;
this.ignoreRegex = ignoreRegex;
this.manageRootDir = manageRootDir;
@@ -133,15 +145,14 @@ public class DeploymentData {
}
// We need to "normalize" all raw file paths that have ".." in them to ensure everything works properly.
- // Any raw file pathname (the values in this.rawFiles) that needs to be normalized will be converted to
- // a canonical path. Note that any pathname that is relative but have ".." paths that end up taking the file
+ // Note that any pathname that is relative but have ".." paths that end up taking the file
// above the destination directory needs to be normalized and will end up being an absolute path
// (so all log messages will indicate the full absolute path and if the file
// needs to be backed up it will be backed up as if it was an external file that was specified with an absolute path).
// If the relative path has ".." but does not take the file above the destination directory will simply have its ".."
// normalized out but will still be a relative path (relative to destination directory) (we can't make it absolute
// otherwise Deployer's update will run into errors while backing up and scanning for deleted files).
- // See BZ 917085.
+ // See BZs 917085 and 917765.
for (Map.Entry<File, File> entry : this.rawFiles.entrySet()) {
File rawFile = entry.getValue();
String rawFilePath = rawFile.getPath();
@@ -149,10 +160,10 @@ public class DeploymentData {
boolean doubledot = rawFilePath.replace('\\', '/').matches(".*((/\\.\\.)|(\\.\\./)).*"); // finds "/.." or "../" in the string
if (doubledot) {
- File fileToCanonicalize;
+ File fileToNormalize;
if (rawFile.isAbsolute()) {
- fileToCanonicalize = rawFile;
+ fileToNormalize = rawFile;
} else {
boolean isWindows = (File.separatorChar == '\\');
if (isWindows) {
@@ -169,28 +180,28 @@ public class DeploymentData {
// figure out what the absolute, normalized path is for the raw file
if ((destDirDriveLetter == null || rawFileDriveLetter == null)
|| rawFileDriveLetter.equals(destDirDriveLetter)) {
- fileToCanonicalize = new File(this.destinationDir, rawFilePathBuilder.toString());
+ fileToNormalize = new File(this.destinationDir, rawFilePathBuilder.toString());
} else {
throw new IllegalArgumentException("Cannot normalize relative path [" + rawFilePath
+ "]; its drive letter is different than the destination directory ["
+ this.destinationDir.getAbsolutePath() + "]");
}
} else {
- fileToCanonicalize = new File(this.destinationDir, rawFilePath);
+ fileToNormalize = new File(this.destinationDir, rawFilePath);
}
}
- fileToCanonicalize = getCanonicalFile(fileToCanonicalize);
+ fileToNormalize = getNormalizedFile(fileToNormalize);
- if (isPathUnderBaseDir(this.destinationDir, fileToCanonicalize)) {
+ if (isPathUnderBaseDir(this.destinationDir, fileToNormalize)) {
// we can keep rawFile path relative, but we need to normalize out the ".." paths
String baseDir = this.destinationDir.getAbsolutePath();
- String absRawFilePath = fileToCanonicalize.getAbsolutePath();
- String canonicalRelativePath = absRawFilePath.substring(baseDir.length() + 1); // should always return a valid path; if not, let it throw exception (which likely means there is a bug here)
- entry.setValue(new File(canonicalRelativePath));
+ String absRawFilePath = fileToNormalize.getAbsolutePath();
+ String relativePath = absRawFilePath.substring(baseDir.length() + 1); // should always return a valid path; if not, let it throw exception (which likely means there is a bug here)
+ entry.setValue(new File(relativePath));
} else {
// raw file path has ".." such that the file is really above destination dir - use an absolute, canonical path
- entry.setValue(fileToCanonicalize);
+ entry.setValue(fileToNormalize);
}
}
}
@@ -198,6 +209,10 @@ public class DeploymentData {
return;
}
+ private static File getNormalizedFile(File fileToNormalize) {
+ return FileUtil.normalizePath(fileToNormalize);
+ }
+
public DeploymentProperties getDeploymentProps() {
return deploymentProps;
}
@@ -242,17 +257,6 @@ public class DeploymentData {
return zipsExploded;
}
- private File getCanonicalFile(File file) {
- try {
- file = file.getCanonicalFile();
- } catch (Exception e) {
- // ignore this - this really should never happen, but if it does,
- // we want to continue and hope using the non-normalized file is ok;
- file = file.getAbsoluteFile();
- }
- return file;
- }
-
private boolean isPathUnderBaseDir(File base, File path) {
// this method assumes base and path are absolute and canonical
if (base == null) {
diff --git a/modules/core/util/src/test/java/org/rhq/core/util/file/FileUtilTest.java b/modules/core/util/src/test/java/org/rhq/core/util/file/FileUtilTest.java
index 8ad0942..6970c53 100644
--- a/modules/core/util/src/test/java/org/rhq/core/util/file/FileUtilTest.java
+++ b/modules/core/util/src/test/java/org/rhq/core/util/file/FileUtilTest.java
@@ -32,6 +32,7 @@ import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
+import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
@@ -326,56 +327,107 @@ public class FileUtilTest {
public void testGetPattern() {
Pattern regex;
- regex = assertPatternsRegex("(/basedir/(test1\\.txt))", new PathFilter("/basedir", "test1.txt"));
+ regex = assertPatternsRegex("(" + translateAbsoluteUnixPathToActualAsRegex("/basedir/(test1\\.txt)") + ")",
+ new PathFilter("/basedir", "test1.txt"));
- assert regex.matcher("/basedir/test1.txt").matches();
- assert !regex.matcher("/basedir/test2.txt").matches();
+ assert regex.matcher(translateAbsoluteUnixPathToActual("/basedir/test1.txt")).matches();
+ assert !regex.matcher(translateAbsoluteUnixPathToActual("/basedir/test2.txt")).matches();
- regex = assertPatternsRegex("(/basedir/easy\\.txt)|(/basedir/test\\.txt)", new PathFilter("/basedir/easy.txt",
+ regex = assertPatternsRegex("(" + translateAbsoluteUnixPathToActualAsRegex("/basedir/easy\\.txt") + ")|(" +
+ translateAbsoluteUnixPathToActualAsRegex("/basedir/test\\.txt") + ")", new PathFilter("/basedir/easy.txt",
null), new PathFilter("/basedir/test.txt", null));
- assert regex.matcher("/basedir/easy.txt").matches();
- assert regex.matcher("/basedir/test.txt").matches();
- assert !regex.matcher("/basedir/easyXtxt").matches();
- assert !regex.matcher("/basedir/testXtxt").matches();
- assert !regex.matcher("/basedir/easy.txtX").matches();
- assert !regex.matcher("/basedir/test.txtX").matches();
- assert !regex.matcher("/basedirX/easy.txt").matches();
- assert !regex.matcher("/basedirX/test.txt").matches();
+ assert regex.matcher(translateAbsoluteUnixPathToActual("/basedir/easy.txt")).matches();
+ assert regex.matcher(translateAbsoluteUnixPathToActual("/basedir/test.txt")).matches();
+ assert !regex.matcher(translateAbsoluteUnixPathToActual("/basedir/easyXtxt")).matches();
+ assert !regex.matcher(translateAbsoluteUnixPathToActual("/basedir/testXtxt")).matches();
+ assert !regex.matcher(translateAbsoluteUnixPathToActual("/basedir/easy.txtX")).matches();
+ assert !regex.matcher(translateAbsoluteUnixPathToActual("/basedir/test.txtX")).matches();
+ assert !regex.matcher(translateAbsoluteUnixPathToActual("/basedirX/easy.txt")).matches();
+ assert !regex.matcher(translateAbsoluteUnixPathToActual("/basedirX/test.txt")).matches();
assert !regex.matcher("easy.txt").matches() : "missing basedir";
assert !regex.matcher("test.txt").matches() : "missing basedir";
- regex = assertPatternsRegex("(/basedir/([^/]*\\.txt))", new PathFilter("/basedir", "*.txt"));
+ regex = assertPatternsRegex("(" + translateAbsoluteUnixPathToActualAsRegex("/basedir/([^/]*\\.txt)") + ")",
+ new PathFilter("/basedir", "*.txt"));
- assert regex.matcher("/basedir/foo.txt").matches();
- assert regex.matcher("/basedir/file with spaces.txt").matches();
- assert regex.matcher("/basedir/123.txt").matches();
- assert !regex.matcher("/basedir/subdir/foo.txt").matches();
- assert !regex.matcher("/basedir/foo.txt.swp").matches();
+ assert regex.matcher(translateAbsoluteUnixPathToActual("/basedir/foo.txt")).matches();
+ assert regex.matcher(translateAbsoluteUnixPathToActual("/basedir/file with spaces.txt")).matches();
+ assert regex.matcher(translateAbsoluteUnixPathToActual("/basedir/123.txt")).matches();
+ assert !regex.matcher(translateAbsoluteUnixPathToActual("/basedir/subdir/foo.txt")).matches();
+ assert !regex.matcher(translateAbsoluteUnixPathToActual("/basedir/foo.txt.swp")).matches();
- regex = assertPatternsRegex("(/var/lib/([^/]*\\.war))|(/var/lib/([^/]*\\.ear))", new PathFilter("/var/lib",
+ regex = assertPatternsRegex("(" + translateAbsoluteUnixPathToActualAsRegex("/var/lib/([^/]*\\.war)") + ")|(" +
+ translateAbsoluteUnixPathToActualAsRegex("/var/lib/([^/]*\\.ear)") + ")", new PathFilter("/var/lib",
"*.war"), new PathFilter("/var/lib", "*.ear"));
- assert regex.matcher("/var/lib/myapp.war").matches();
- assert regex.matcher("/var/lib/myapp.ear").matches();
- assert regex.matcher("/var/lib/my-app.war").matches();
- assert !regex.matcher("/var/lib/myapp.War").matches();
- assert !regex.matcher("/var/libs/myapp.war").matches();
- assert !regex.matcher("myapp.ear").matches();
- assert !regex.matcher("/var/lib/myapp.ear.rej").matches();
+ assert regex.matcher(translateAbsoluteUnixPathToActual("/var/lib/myapp.war")).matches();
+ assert regex.matcher(translateAbsoluteUnixPathToActual("/var/lib/myapp.ear")).matches();
+ assert regex.matcher(translateAbsoluteUnixPathToActual("/var/lib/my-app.war")).matches();
+ assert !regex.matcher(translateAbsoluteUnixPathToActual("/var/lib/myapp.War")).matches();
+ assert !regex.matcher(translateAbsoluteUnixPathToActual("/var/libs/myapp.war")).matches();
+ assert !regex.matcher(translateAbsoluteUnixPathToActual("myapp.ear")).matches();
+ assert !regex.matcher(translateAbsoluteUnixPathToActual("/var/lib/myapp.ear.rej")).matches();
- regex = assertPatternsRegex("(/conf/(server-.\\.conf))", new PathFilter("/conf", "server-?.conf"));
+ regex = assertPatternsRegex("(" + translateAbsoluteUnixPathToActualAsRegex("/conf/(server-.\\.conf)") + ")",
+ new PathFilter("/conf", "server-?.conf"));
- assert regex.matcher("/conf/server-1.conf").matches();
- assert regex.matcher("/conf/server-X.conf").matches();
- assert !regex.matcher("/conf/subconf/server-1.conf").matches();
- assert !regex.matcher("/conf/server.conf").matches();
+ assert regex.matcher(translateAbsoluteUnixPathToActual("/conf/server-1.conf")).matches();
+ assert regex.matcher(translateAbsoluteUnixPathToActual("/conf/server-X.conf")).matches();
+ assert !regex.matcher(translateAbsoluteUnixPathToActual("/conf/subconf/server-1.conf")).matches();
+ assert !regex.matcher(translateAbsoluteUnixPathToActual("/conf/server.conf")).matches();
- regex = assertPatternsRegex("(/etc/(.*[^/]*\\.conf))", new PathFilter("/etc", "**/*.conf"));
+ regex = assertPatternsRegex("(" + translateAbsoluteUnixPathToActualAsRegex("/etc/(.*[^/]*\\.conf)") + ")",
+ new PathFilter("/etc", "**/*.conf"));
- assert regex.matcher("/etc/yum.conf").matches();
- assert regex.matcher("/etc/httpd/httpd.conf").matches();
- assert !regex.matcher("/etc/foo.conf/foo").matches();
+ assert regex.matcher(translateAbsoluteUnixPathToActual("/etc/yum.conf")).matches();
+ assert regex.matcher(translateAbsoluteUnixPathToActual("/etc/httpd/httpd.conf")).matches();
+ assert !regex.matcher(translateAbsoluteUnixPathToActual("/etc/foo.conf/foo")).matches();
+ }
+
+ public void testNormalizePath() throws Exception {
+ if (File.separatorChar == '\\') {
+ //windows
+ checkNormalization("\\\\server\\share\\bar", "\\\\server\\share\\path\\..\\bar");
+ //we just consider the ".." the name of the share of the UNC path
+ checkNormalization("\\\\server\\..\\bar", "\\\\server\\..\\bar");
+ checkNormalization(null, "\\\\server\\share\\..\\bar");
+ checkNormalization("C:\\bar", "C:\\foo\\..\\bar");
+ checkNormalization(null, "C:\\..\\bar");
+
+ checkNormalization("\\foo", "/foo//");
+ checkNormalization("\\foo", "/foo/./");
+ checkNormalization("\\bar", "/foo/../bar");
+ checkNormalization("\\bar", "/foo/../bar/");
+ checkNormalization("\\baz", "/foo/../bar/../baz");
+ //we just consider the "." the name of the share of the UNC path
+ checkNormalization("\\\\foo\\.\\bar", "//foo//./bar");
+ checkNormalization(null, "/../");
+ checkNormalization(null, "../foo");
+ checkNormalization("foo", "foo/bar/..");
+ checkNormalization(null, "foo/../../bar");
+ checkNormalization("bar", "foo/../bar");
+ } else {
+ checkNormalization("/foo", "/foo//");
+ checkNormalization("/foo", "/foo/./");
+ checkNormalization("/bar", "/foo/../bar");
+ checkNormalization("/bar", "/foo/../bar/");
+ checkNormalization("/baz", "/foo/../bar/../baz");
+ checkNormalization("/foo/bar", "//foo//./bar");
+ checkNormalization(null, "/../");
+ checkNormalization(null, "../foo");
+ checkNormalization("foo", "foo/bar/..");
+ checkNormalization(null, "foo/../../bar");
+ checkNormalization("bar", "foo/../bar");
+ checkNormalization("~/bar", "~/foo/../bar/");
+ }
+ }
+
+ private void checkNormalization(String expectedResult, String path) {
+ File result = FileUtil.normalizePath(new File(path));
+ assert
+ expectedResult == null ? result == null : result != null && expectedResult.equals(result.getPath()) :
+ expectedResult + " failed. Should have been [" + expectedResult + "] but was [" + result + "]";
}
private Pattern assertPatternsRegex(String expectedPattern, PathFilter... filters) {
@@ -388,4 +440,23 @@ public class FileUtilTest {
return regex;
}
+ private static String translateAbsoluteUnixPathToActualAsRegex(String path) {
+ return translateAbsoluteUnixPathToActual(path, true);
+ }
+
+ private static String translateAbsoluteUnixPathToActual(String path) {
+ return translateAbsoluteUnixPathToActual(path, false);
+ }
+
+ private static String translateAbsoluteUnixPathToActual(String path, boolean asRegex) {
+ if (File.separatorChar == '\\') {
+ //get the current drive letter
+ //leave out the trailing "\" - we have an absolute unix path on input, so we "use" the "/" of it
+ String driveLetter = new File(".").getAbsoluteFile().toPath().getRoot().toString().substring(0, 2);
+
+ path = driveLetter + path.replace("/", asRegex? "\\\\" : "\\");
+ }
+
+ return path;
+ }
}
diff --git a/modules/core/util/src/test/java/org/rhq/core/util/updater/DeployerCanonicalPathTest.java b/modules/core/util/src/test/java/org/rhq/core/util/updater/DeployerCanonicalPathTest.java
index 7a62bf0..9520da0 100644
--- a/modules/core/util/src/test/java/org/rhq/core/util/updater/DeployerCanonicalPathTest.java
+++ b/modules/core/util/src/test/java/org/rhq/core/util/updater/DeployerCanonicalPathTest.java
@@ -23,15 +23,21 @@
package org.rhq.core.util.updater;
+import static org.testng.Assert.fail;
+
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
@@ -42,13 +48,16 @@ import org.rhq.core.util.file.FileUtil;
import org.rhq.core.util.stream.StreamUtil;
/**
- * Tests deploying raw files to deployment locations specified with ".." in the path.
- * This will require the deployer code to transform the paths to canonical paths.
+ * Tests deploying raw files to deployment locations specified with ".." in the path. This will require the deployer
+ * code to transform the paths to canonical paths.
*
* @author John Mazzitelli
*/
@Test
public class DeployerCanonicalPathTest {
+
+ private static final Log LOG = LogFactory.getLog(DeployerCanonicalPathTest.class);
+
private TemplateEngine templateEngine;
@BeforeClass
@@ -69,8 +78,10 @@ public class DeployerCanonicalPathTest {
public void testInitialDeployRawFilesWithCanonicalPaths() throws Exception {
File tmpDirDest = FileUtil.createTempDirectory("DeployerCanonicalPathTest", ".dest", null);
File tmpDirSrc = FileUtil.createTempDirectory("DeployerCanonicalPathTest", ".src", null);
- File rawFileRelativeDest = new File("dir-does-not-existA/../rawA.txt"); // relative to "tmpDirDest" that we just created above
- File rawFileRelativeDest2 = new File("dir-does-not-existA/../../rawA.txt"); // relative to "tmpDirDest" but it takes us above it
+ File rawFileRelativeDest = new File(
+ "dir-does-not-existA/../rawA.txt"); // relative to "tmpDirDest" that we just created above
+ File rawFileRelativeDest2 = new File(
+ "dir-does-not-existA/../../rawA.txt"); // relative to "tmpDirDest" but it takes us above it
File rawFileAbsoluteDest = new File(System.getProperty("java.io.tmpdir"), "dir-does-not-existB/../rawB.txt");
try {
@@ -102,38 +113,41 @@ public class DeployerCanonicalPathTest {
System.out.println("map-->\n" + map);
System.out.println("diff->\n" + diff);
- String rawFileRelativeDestCanonical = new File(tmpDirDest, rawFileRelativeDest.getPath()).getCanonicalPath();
- String rawFileRelativeDestCanonical2 = new File(tmpDirDest, rawFileRelativeDest2.getPath())
- .getCanonicalPath();
- String rawFileAbsoluteDestCanonical = rawFileAbsoluteDest.getCanonicalPath();
+ String rawFileRelativeDestAbsolute = FileUtil.normalizePath(new File(tmpDirDest, rawFileRelativeDest.getPath()))
+ .getAbsolutePath();
+ String rawFileRelativeDestAbsolute2 = FileUtil.normalizePath(new File(tmpDirDest, rawFileRelativeDest2.getPath()))
+ .getAbsolutePath();
+ String rawFileAbsoluteDestAbsolute = FileUtil.normalizePath(rawFileAbsoluteDest).getAbsolutePath();
assert map.size() == 3 : map;
assert map.containsKey("rawA.txt") : map;
- assert new File(rawFileRelativeDestCanonical).exists();
- assert new File(rawFileRelativeDestCanonical2).exists();
- assert MessageDigestGenerator.getDigestString(new File(rawFileRelativeDestCanonical)).equals(
+ assert new File(rawFileRelativeDestAbsolute).exists();
+ assert new File(rawFileRelativeDestAbsolute2).exists();
+ assert MessageDigestGenerator.getDigestString(new File(rawFileRelativeDestAbsolute)).equals(
map.get("rawA.txt"));
- // rawFileRelativeDestCanonical2 should be treated just like an absolute, external file
- assert MessageDigestGenerator.getDigestString(new File(rawFileRelativeDestCanonical2)).equals(
- map.get(rawFileRelativeDestCanonical2));
- assert !MessageDigestGenerator.getDigestString(testRawFileA).equals(map.get("rawA.txt")) : "should have different hash, we realize this one!";
+ // rawFileRelativeDestAbsolute2 should be treated just like an absolute, external file
+ assert MessageDigestGenerator.getDigestString(new File(rawFileRelativeDestAbsolute2)).equals(
+ map.get(rawFileRelativeDestAbsolute2));
+ assert !MessageDigestGenerator.getDigestString(testRawFileA)
+ .equals(map.get("rawA.txt")) : "should have different hash, we realize this one!";
- assert map.containsKey(rawFileAbsoluteDestCanonical) : map;
- assert new File(rawFileAbsoluteDestCanonical).exists();
- assert MessageDigestGenerator.getDigestString(new File(rawFileAbsoluteDestCanonical)).equals(
- map.get(rawFileAbsoluteDestCanonical));
- assert !MessageDigestGenerator.getDigestString(testRawFileB).equals(map.get(rawFileAbsoluteDestCanonical)) : "should have different hash, we realized this one";
+ assert map.containsKey(rawFileAbsoluteDestAbsolute) : map;
+ assert new File(rawFileAbsoluteDestAbsolute).exists();
+ assert MessageDigestGenerator.getDigestString(new File(rawFileAbsoluteDestAbsolute)).equals(
+ map.get(rawFileAbsoluteDestAbsolute));
+ assert !MessageDigestGenerator.getDigestString(testRawFileB)
+ .equals(map.get(rawFileAbsoluteDestAbsolute)) : "should have different hash, we realized this one";
assert diff.getAddedFiles().size() == 3 : diff;
assert diff.getAddedFiles().contains(diff.convertPath("rawA.txt")) : diff;
- assert diff.getAddedFiles().contains(diff.convertPath(rawFileRelativeDestCanonical2)) : diff;
- assert diff.getAddedFiles().contains(diff.convertPath(rawFileAbsoluteDestCanonical)) : diff;
+ assert diff.getAddedFiles().contains(diff.convertPath(rawFileRelativeDestAbsolute2)) : diff;
+ assert diff.getAddedFiles().contains(diff.convertPath(rawFileAbsoluteDestAbsolute)) : diff;
assert diff.getRealizedFiles().size() == 3 : diff;
assert diff.getRealizedFiles().keySet().contains(diff.convertPath("rawA.txt")) : diff;
- assert diff.getRealizedFiles().keySet().contains(diff.convertPath(rawFileRelativeDestCanonical2)) : diff;
- assert diff.getRealizedFiles().keySet().contains(diff.convertPath(rawFileAbsoluteDestCanonical)) : diff;
+ assert diff.getRealizedFiles().keySet().contains(diff.convertPath(rawFileRelativeDestAbsolute2)) : diff;
+ assert diff.getRealizedFiles().keySet().contains(diff.convertPath(rawFileAbsoluteDestAbsolute)) : diff;
} finally {
FileUtil.purge(tmpDirDest, true);
FileUtil.purge(tmpDirSrc, true);
@@ -144,8 +158,10 @@ public class DeployerCanonicalPathTest {
public void testUpdateDeployRawFileWithRelativePath() throws Exception {
File tmpDirDest = FileUtil.createTempDirectory("DeployerCanonicalPathTest", ".dest", null);
File tmpDirSrc = FileUtil.createTempDirectory("DeployerCanonicalPathTest", ".src", null);
- File rawFileRelativeDest = new File("dir-does-not-existA/../rawA.txt"); // relative to "tmpDirDest" that we just created above
- File rawFileRelativeDest2 = new File("dir-does-not-existA/../../rawA.txt"); // relative to "tmpDirDest" but it takes us above it
+ File rawFileRelativeDest = new File(
+ "dir-does-not-existA/../rawA.txt"); // relative to "tmpDirDest" that we just created above
+ File rawFileRelativeDest2 = new File(
+ "dir-does-not-existA/../../rawA.txt"); // relative to "tmpDirDest" but it takes us above it
File rawFileAbsoluteDest = new File(System.getProperty("java.io.tmpdir"), "dir-does-not-existB/../rawB.txt");
try {
@@ -176,20 +192,24 @@ public class DeployerCanonicalPathTest {
// make sure the first raw file is in the dest dir
String f = rawFileRelativeDest.getPath();
- File destFile = new File(tmpDirDest, f).getCanonicalFile(); // notice f is assumed relative to tmpDirDest, must convert to canonical path
+ File destFile = new File(tmpDirDest, f)
+ .getCanonicalFile(); // notice f is assumed relative to tmpDirDest, must convert to canonical path
assert destFile.exists() : destFile;
- FileUtil.writeFile(new ByteArrayInputStream("modifiedR".getBytes()), destFile); // change the file so we back it up during update
+ FileUtil.writeFile(new ByteArrayInputStream("modifiedR".getBytes()),
+ destFile); // change the file so we back it up during update
// make sure the second raw file, though specified originally as a relative file, is in the external location
f = rawFileRelativeDest2.getPath();
destFile = new File(tmpDirDest, f).getCanonicalFile(); // must convert to canonical path
assert destFile.exists() : destFile;
- FileUtil.writeFile(new ByteArrayInputStream("modifiedR2".getBytes()), destFile); // change the file so we back it up during update
+ FileUtil.writeFile(new ByteArrayInputStream("modifiedR2".getBytes()),
+ destFile); // change the file so we back it up during update
// make sure the third raw file is in the external location
destFile = rawFileAbsoluteDest.getCanonicalFile(); // must convert to canonical path
assert destFile.exists() : destFile;
- FileUtil.writeFile(new ByteArrayInputStream("modifiedA".getBytes()), destFile); // change the file so we back it up during update
+ FileUtil.writeFile(new ByteArrayInputStream("modifiedA".getBytes()),
+ destFile); // change the file so we back it up during update
// UPDATE
// alter the src files so we backup our changed files
@@ -206,17 +226,17 @@ public class DeployerCanonicalPathTest {
System.out.println("map-->\n" + map);
System.out.println("diff->\n" + diff);
- String rawFileRelativeDestCanonical = new File(tmpDirDest, rawFileRelativeDest.getPath())
- .getCanonicalPath();
- String rawFileRelativeDestCanonical2 = new File(tmpDirDest, rawFileRelativeDest2.getPath())
- .getCanonicalPath();
- String rawFileAbsoluteDestCanonical = rawFileAbsoluteDest.getCanonicalPath();
+ String rawFileRelativeDestAbsolute = FileUtil.normalizePath(new File(tmpDirDest, rawFileRelativeDest.getPath()))
+ .getAbsolutePath();
+ String rawFileRelativeDestAbsolute2 = FileUtil.normalizePath(new File(tmpDirDest, rawFileRelativeDest2.getPath()))
+ .getAbsolutePath();
+ String rawFileAbsoluteDestAbsolute = FileUtil.normalizePath(rawFileAbsoluteDest).getAbsolutePath();
- assert new String(StreamUtil.slurp(new FileInputStream(new File(rawFileRelativeDestCanonical))))
+ assert new String(StreamUtil.slurp(new FileInputStream(new File(rawFileRelativeDestAbsolute))))
.equals("src.modifiedR");
- assert new String(StreamUtil.slurp(new FileInputStream(new File(rawFileRelativeDestCanonical2))))
+ assert new String(StreamUtil.slurp(new FileInputStream(new File(rawFileRelativeDestAbsolute2))))
.equals("src.modifiedR2");
- assert new String(StreamUtil.slurp(new FileInputStream(new File(rawFileAbsoluteDestCanonical))))
+ assert new String(StreamUtil.slurp(new FileInputStream(new File(rawFileAbsoluteDestAbsolute))))
.equals("src.modifiedA");
boolean isWindows = File.separatorChar == '\\';
@@ -225,9 +245,9 @@ public class DeployerCanonicalPathTest {
File backupRel2;
// test the second raw file, the one that was specified originally as a relative file but took us out of the dest dir
if (!isWindows) {
- backupRel2 = new File(metadir, "1/ext-backup/" + rawFileRelativeDestCanonical2);
+ backupRel2 = new File(metadir, "1/ext-backup/" + rawFileRelativeDestAbsolute2);
} else {
- StringBuilder str = new StringBuilder(rawFileRelativeDestCanonical2);
+ StringBuilder str = new StringBuilder(rawFileRelativeDestAbsolute2);
String driveLetter = FileUtil.stripDriveLetter(str);
if (driveLetter != null) {
driveLetter = "_" + driveLetter + '/';
@@ -239,9 +259,9 @@ public class DeployerCanonicalPathTest {
// test the third raw file, the one that was specified originally as an absolute, external file
File backupAbs;
if (!isWindows) {
- backupAbs = new File(metadir, "1/ext-backup/" + rawFileAbsoluteDestCanonical);
+ backupAbs = new File(metadir, "1/ext-backup/" + rawFileAbsoluteDestAbsolute);
} else {
- StringBuilder str = new StringBuilder(rawFileAbsoluteDestCanonical);
+ StringBuilder str = new StringBuilder(rawFileAbsoluteDestAbsolute);
String driveLetter = FileUtil.stripDriveLetter(str);
if (driveLetter != null) {
driveLetter = "_" + driveLetter + '/';
@@ -259,17 +279,83 @@ public class DeployerCanonicalPathTest {
assert map.size() == 3 : map;
assert diff.getChangedFiles().size() == 3 : diff;
assert diff.getChangedFiles().contains(diff.convertPath("rawA.txt")) : diff;
- assert diff.getChangedFiles().contains(diff.convertPath(rawFileRelativeDestCanonical2)) : diff;
- assert diff.getChangedFiles().contains(diff.convertPath(rawFileAbsoluteDestCanonical)) : diff;
+ assert diff.getChangedFiles().contains(diff.convertPath(rawFileRelativeDestAbsolute2)) : diff;
+ assert diff.getChangedFiles().contains(diff.convertPath(rawFileAbsoluteDestAbsolute)) : diff;
assert diff.getDeletedFiles().isEmpty() : diff;
assert diff.getBackedUpFiles().size() == 3 : diff;
assert diff.getBackedUpFiles().keySet().contains(diff.convertPath("rawA.txt")) : diff;
- assert diff.getBackedUpFiles().keySet().contains(diff.convertPath(rawFileRelativeDestCanonical2)) : diff;
- assert diff.getBackedUpFiles().keySet().contains(diff.convertPath(rawFileAbsoluteDestCanonical)) : diff;
+ assert diff.getBackedUpFiles().keySet().contains(diff.convertPath(rawFileRelativeDestAbsolute2)) : diff;
+ assert diff.getBackedUpFiles().keySet().contains(diff.convertPath(rawFileAbsoluteDestAbsolute)) : diff;
} finally {
FileUtil.purge(tmpDirDest, true);
FileUtil.purge(tmpDirSrc, true);
rawFileAbsoluteDest.getCanonicalFile().delete();
}
}
-}
\ No newline at end of file
+
+ public void testInitialDeploymentGlossesOverSymlinksInParents() throws Exception {
+ //java7 API, but we're in tests, and require java7 to build anyway
+ Path root = FileUtil.createTempDirectory("DeployerCanonicalPathTest", ".symlink-root", null).toPath();
+ Path symlinkTarget = FileUtil.createTempDirectory("DeployerCanonicalPathTest", ".symlink-target", null)
+ .toPath();
+
+ File src = FileUtil.createTempDirectory("DeployerCanonicalPathTest", ".src", null);
+
+ Path parent = root.resolve("parent");
+ parent.toFile().mkdirs();
+
+ try {
+ File destination = null;
+
+ try {
+ destination = Files.createSymbolicLink(parent.resolve("destination"), symlinkTarget).toFile();
+ } catch (UnsupportedOperationException e) {
+ LOG.info("Skipping testInitialDeploymentGlossesOverSymlinksInParents. The current filesystem doesn't support symlinks");
+ return;
+ }
+
+ // put some source files in our tmpDirSrc location
+ File testRawFileA = new File(src, "updater-testA.txt");
+ File testRawFileA2 = new File(src, "updater-testA2.txt");
+ File testRawFileB = new File(src, "updater-testB.txt");
+ File testRawFileADest = new File(destination, "../realDest/rawA.txt");
+ File testRawFileA2Dest = new File(destination, "../realDest/rawA2.txt");
+ File testRawFileBDest = new File(destination, "../../realDest/rawB.txt");
+ FileUtil.copyFile(new File("target/test-classes/updater-testA.txt"), testRawFileA);
+ FileUtil.copyFile(new File("target/test-classes/updater-testA.txt"), testRawFileA2);
+ FileUtil.copyFile(new File("target/test-classes/updater-testB.txt"), testRawFileB);
+
+ DeploymentProperties deploymentProps = new DeploymentProperties(0, "testbundle", "1.0.test", null);
+ Set<File> zipFiles = null;
+ Map<File, File> rawFiles = new HashMap<File, File>(3);
+ rawFiles.put(testRawFileA, testRawFileADest);
+ rawFiles.put(testRawFileA2, testRawFileA2Dest);
+ rawFiles.put(testRawFileB, testRawFileBDest);
+
+ DeploymentData dd = new DeploymentData(deploymentProps, zipFiles, rawFiles, src, destination, null, null,
+ templateEngine, null, true, null);
+ Deployer deployer = new Deployer(dd);
+ DeployDifferences diff = new DeployDifferences();
+ FileHashcodeMap map = deployer.deploy(diff);
+ System.out.println("map-->\n" + map);
+ System.out.println("diff->\n" + diff);
+
+ assert map.size() == 3 : map;
+
+ assert parent.resolve("realDest/rawA.txt").toFile().exists() : "rawA.txt not deployed correctly";
+ assert parent.resolve("realDest/rawA2.txt").toFile().exists() : "rawA2.txt not deployed correctly";
+ assert root.resolve("realDest/rawB.txt").toFile().exists() : "rawB.txt not deployed correctly";
+
+ //the symlink target, being the destination of the deployment should have the .rhqdeployments directory
+ //specified. No other files should exist there though.
+ assert symlinkTarget.resolve(".rhqdeployments").toFile()
+ .exists() : "Could not find .rhqdeployments on the expected location";
+ assert symlinkTarget.toFile().listFiles().length ==
+ 1 : "The target of the symlink should have no other files than .rhqdeployments";
+ } finally {
+ FileUtil.purge(root.toFile(), true);
+ FileUtil.purge(symlinkTarget.toFile(), true);
+ FileUtil.purge(src, true);
+ }
+ }
+}
commit 4e26dfab092c2b1eede832426b6757fa4d458c72
Author: Lukas Krejci <lkrejci(a)redhat.com>
Date: Wed Jun 12 00:13:48 2013 +0200
[BZ 973415] - Empty deployments trailing behind.
If a deployment has a sole component and we delete that component, I assume
it is fairly safe to remove such deployment because it would essentially
be left empty supplying no effective configuration of the server.
Removing empty deployments fixes the strange behavior where a new
deployment was created when creating a queue, topic, datasource, connection
factory and other resources, but once such resource was deleted we would
only delete the corresponding PS component, leaving the deployment and its
config files behind. If a new attempt to create a queue/topic/etc with the
same name was made, it would fail, because a deployment with a name
auto-generated from the component name would already exist.
diff --git a/modules/plugins/jboss-as-5/src/main/java/org/rhq/plugins/jbossas5/ManagedComponentComponent.java b/modules/plugins/jboss-as-5/src/main/java/org/rhq/plugins/jbossas5/ManagedComponentComponent.java
index da0b24b..805d5b0 100644
--- a/modules/plugins/jboss-as-5/src/main/java/org/rhq/plugins/jbossas5/ManagedComponentComponent.java
+++ b/modules/plugins/jboss-as-5/src/main/java/org/rhq/plugins/jbossas5/ManagedComponentComponent.java
@@ -235,15 +235,33 @@ public class ManagedComponentComponent extends AbstractManagedComponent implemen
ManagementView managementView = getConnection().getManagementView();
managementView.removeComponent(managedComponent);
ManagedDeployment parentDeployment = managedComponent.getDeployment();
- log.debug("Redeploying parent deployment '" + parentDeployment.getName()
- + "' in order to complete removal of component " + toString(managedComponent) + "...");
- DeploymentProgress progress = deploymentManager.redeploy(parentDeployment.getName());
- DeploymentStatus redeployStatus = DeploymentUtils.run(progress);
- if (redeployStatus.isFailed()) {
- log.error("Failed to redeploy parent deployment '" + parentDeployment.getName()
- + "during removal of component " + toString(managedComponent)
- + " - removal may not persist when the app server is restarted.", redeployStatus.getFailure());
+
+ if (parentDeployment.getComponents().size() > 1 || !parentDeployment.getChildren().isEmpty()) {
+ log.debug("Redeploying parent deployment '" + parentDeployment.getName()
+ + "' in order to complete removal of component " + toString(managedComponent) + "...");
+ DeploymentProgress progress = deploymentManager.redeploy(parentDeployment.getName());
+ DeploymentStatus status = DeploymentUtils.run(progress);
+ if (status.isFailed()) {
+ log.error("Failed to redeploy parent deployment '" + parentDeployment.getName()
+ + "during removal of component " + toString(managedComponent)
+ + " - removal may not persist when the app server is restarted.", status.getFailure());
+ }
+ } else {
+ //this is the last component of the deployment and nothing would be left there after
+ //the component was removed. Let's just undeploy it in addition to removing the component.
+ //This will make sure that the deployment doesn't leave behind any defunct config files, etc.
+ log.debug("Undeploying parent deployment '" + parentDeployment.getName()
+ + "' in order to complete removal of component " + toString(managedComponent) + "...");
+ parentDeployment = managementView.getDeployment(parentDeployment.getName());
+ DeploymentProgress progress = deploymentManager.remove(parentDeployment.getName());
+ DeploymentStatus status = DeploymentUtils.run(progress);
+ if (status.isFailed()) {
+ log.error("Failed to undeploy parent deployment '" + parentDeployment.getName()
+ + "during removal of component " + toString(managedComponent)
+ + " - removal may not persist when the app server is restarted.", status.getFailure());
+ }
}
+
managementView.load();
}
10 years, 5 months
[rhq] modules/core
by mazz
modules/core/util/src/main/java/org/rhq/core/util/exec/ProcessExecutor.java | 4
modules/core/util/src/main/java/org/rhq/core/util/exec/StreamRedirector.java | 13 -
modules/core/util/src/main/java/org/rhq/core/util/exec/StreamRedirectorRunnable.java | 111 ++++++++++
3 files changed, 119 insertions(+), 9 deletions(-)
New commits:
commit ff823d5a05010cbff3263af7eb40915bdb0def1d
Author: John Mazzitelli <mazz(a)redhat.com>
Date: Thu Jun 27 16:01:10 2013 -0400
BZ 872738 - need to rename the class and resurrect the old class because the API check failed. the original patch changed the public class' hierarchy. we need to maintain that API compatibility.
diff --git a/modules/core/util/src/main/java/org/rhq/core/util/exec/ProcessExecutor.java b/modules/core/util/src/main/java/org/rhq/core/util/exec/ProcessExecutor.java
index 07b05f5..ee1e9a5 100644
--- a/modules/core/util/src/main/java/org/rhq/core/util/exec/ProcessExecutor.java
+++ b/modules/core/util/src/main/java/org/rhq/core/util/exec/ProcessExecutor.java
@@ -240,8 +240,8 @@ public class ProcessExecutor {
threadNamePrefix = process.getProgramExecutable();
}
- StreamRedirector stdoutThread = new StreamRedirector(threadNamePrefix + "-stdout", stdout, fileOutputStream);
- StreamRedirector stderrThread = new StreamRedirector(threadNamePrefix + "-stderr", stderr, fileOutputStream);
+ StreamRedirectorRunnable stdoutThread = new StreamRedirectorRunnable(threadNamePrefix + "-stdout", stdout, fileOutputStream);
+ StreamRedirectorRunnable stderrThread = new StreamRedirectorRunnable(threadNamePrefix + "-stderr", stderr, fileOutputStream);
Future<?> out = threadPool.submit(stdoutThread);
Future<?> err = threadPool.submit(stderrThread);
diff --git a/modules/core/util/src/main/java/org/rhq/core/util/exec/StreamRedirector.java b/modules/core/util/src/main/java/org/rhq/core/util/exec/StreamRedirector.java
index 2ed4ee2..afff92d 100644
--- a/modules/core/util/src/main/java/org/rhq/core/util/exec/StreamRedirector.java
+++ b/modules/core/util/src/main/java/org/rhq/core/util/exec/StreamRedirector.java
@@ -31,7 +31,7 @@ import java.io.OutputStream;
*
* @author John Mazzitelli
*/
-public class StreamRedirector implements Runnable {
+public class StreamRedirector extends Thread {
/**
* the stream where we read data from
*/
@@ -42,8 +42,6 @@ public class StreamRedirector implements Runnable {
*/
private final OutputStream m_output;
- private final String m_name;
-
/**
* Constructor for {@link StreamRedirector} that takes an input stream where we read data in and an output stream
* where we write the data read from the input stream. If the output stream is <code>null</code>, the incoming data
@@ -56,14 +54,18 @@ public class StreamRedirector implements Runnable {
* @throws IllegalArgumentException if input stream is <code>null</code>
*/
public StreamRedirector(String name, InputStream is, OutputStream os) throws IllegalArgumentException {
+ super(name);
if (is == null) {
throw new IllegalArgumentException("is=null");
}
- m_name = name;
+ setDaemon(true);
+
m_input = is;
m_output = os;
+
+ return;
}
/**
@@ -71,9 +73,6 @@ public class StreamRedirector implements Runnable {
*/
@Override
public void run() {
- Thread t = Thread.currentThread();
- t.setName(m_name);
-
final int bufferSize = 4096;
byte[] buffer = new byte[bufferSize];
boolean keepGoing = true;
diff --git a/modules/core/util/src/main/java/org/rhq/core/util/exec/StreamRedirectorRunnable.java b/modules/core/util/src/main/java/org/rhq/core/util/exec/StreamRedirectorRunnable.java
new file mode 100644
index 0000000..aa3b5ca
--- /dev/null
+++ b/modules/core/util/src/main/java/org/rhq/core/util/exec/StreamRedirectorRunnable.java
@@ -0,0 +1,111 @@
+ /*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2008 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, version 2, as
+ * published by the Free Software Foundation, and/or the GNU Lesser
+ * General Public License, version 2.1, also as published by the Free
+ * Software Foundation.
+ *
+ * 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 and the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * and the GNU Lesser General Public License along with this program;
+ * if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.rhq.core.util.exec;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * Redirects data coming in from one (input) stream into another (output) stream.
+ *
+ * @author John Mazzitelli
+ */
+public class StreamRedirectorRunnable implements Runnable {
+ /**
+ * the stream where we read data from
+ */
+ private final InputStream m_input;
+
+ /**
+ * the stream where we write data to
+ */
+ private final OutputStream m_output;
+
+ private final String m_name;
+
+ /**
+ * Constructor for {@link StreamRedirectorRunnable} that takes an input stream where we read data in and an output stream
+ * where we write the data read from the input stream. If the output stream is <code>null</code>, the incoming data
+ * is simply consumed and ignored without being redirected anywhere.
+ *
+ * @param name the name of the thread
+ * @param is the input stream that we read data from (must not be <code>null</code>)
+ * @param os the output stream that we write data to (may be <code>null</code>)
+ *
+ * @throws IllegalArgumentException if input stream is <code>null</code>
+ */
+ public StreamRedirectorRunnable(String name, InputStream is, OutputStream os) throws IllegalArgumentException {
+
+ if (is == null) {
+ throw new IllegalArgumentException("is=null");
+ }
+
+ m_name = name;
+ m_input = is;
+ m_output = os;
+ }
+
+ /**
+ * @see java.lang.Runnable#run()
+ */
+ @Override
+ public void run() {
+ Thread t = Thread.currentThread();
+ t.setName(m_name);
+
+ final int bufferSize = 4096;
+ byte[] buffer = new byte[bufferSize];
+ boolean keepGoing = true;
+
+ try {
+ while (keepGoing) {
+ int read = m_input.read(buffer, 0, bufferSize);
+ if (read > 0) {
+ if (m_output != null) {
+ m_output.write(buffer, 0, read);
+ }
+ } else {
+ keepGoing = false;
+ }
+ }
+ } catch (Exception e) {
+ // just abort the while loop and close the streams
+ }
+
+ // finished reading the input, so we can now close the streams and exit the thread
+ try {
+ m_input.close();
+ } catch (IOException e) {
+ }
+
+ try {
+ if (m_output != null) {
+ m_output.close();
+ }
+ } catch (IOException e) {
+ }
+
+ return;
+ }
+}
\ No newline at end of file
10 years, 5 months