[rhq] 2 commits - modules/plugins
by Thomas Segismont
modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ASConnection.java | 260 +++++-----
modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/BaseProcessDiscovery.java | 3
modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/BaseServerComponent.java | 1
modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/Domain2Descriptor.java | 188 +++----
modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/TemplatedComponent.java | 11
modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/json/Result.java | 8
modules/plugins/jboss-as-7/src/test/java/org/rhq/modules/plugins/jbossas7/AbstractConfigurationHandlingTest.java | 31 -
modules/plugins/jboss-as-7/src/test/java/org/rhq/modules/plugins/jbossas7/TemplatedComponentTest.java | 13
8 files changed, 273 insertions(+), 242 deletions(-)
New commits:
commit e9406f9060c6d893e03e8f1d00bbf88053b5a9ca
Author: Thomas Segismont <tsegismo(a)redhat.com>
Date: Fri Nov 29 14:51:57 2013 +0100
Reverted commit dd1f836e7df7b6be3773b6b15165baa85a7b703e and updated test code which caused NPE
diff --git a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/TemplatedComponent.java b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/TemplatedComponent.java
index 57cfadd..21211dc 100644
--- a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/TemplatedComponent.java
+++ b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/TemplatedComponent.java
@@ -1,8 +1,7 @@
/*
* RHQ Management Platform
- * Copyright 2012, Red Hat Middleware LLC, and individual contributors
- * as indicated by the @author tags. See the copyright.txt file in the
- * distribution for a full listing of individual contributors.
+ * 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
@@ -14,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.modules.plugins.jbossas7;
@@ -109,7 +108,7 @@ public class TemplatedComponent extends BaseComponent<ResourceComponent<?>> {
additionalProperties.put("attributes-only", "true");
currentAttributesOp.setAdditionalProperties(additionalProperties);
Result currentAttributes = getASConnection().execute(currentAttributesOp);
- if ((currentAttributes!=null)&&(currentAttributes.isSuccess())) {
+ if (currentAttributes.isSuccess()) {
currentAttributeList = (Map<String, Object>) currentAttributes.getResult();
}
diff --git a/modules/plugins/jboss-as-7/src/test/java/org/rhq/modules/plugins/jbossas7/AbstractConfigurationHandlingTest.java b/modules/plugins/jboss-as-7/src/test/java/org/rhq/modules/plugins/jbossas7/AbstractConfigurationHandlingTest.java
index 5eaa0e9..ca1cc36 100644
--- a/modules/plugins/jboss-as-7/src/test/java/org/rhq/modules/plugins/jbossas7/AbstractConfigurationHandlingTest.java
+++ b/modules/plugins/jboss-as-7/src/test/java/org/rhq/modules/plugins/jbossas7/AbstractConfigurationHandlingTest.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,13 +13,15 @@
* 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.modules.plugins.jbossas7;
+import static org.rhq.modules.plugins.jbossas7.json.Result.FAILURE;
+
import java.io.BufferedReader;
-import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
@@ -32,8 +34,6 @@ import javax.xml.bind.util.ValidationEventCollector;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.codehaus.jackson.JsonNode;
-import org.codehaus.jackson.JsonParseException;
-import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.node.ObjectNode;
@@ -53,15 +53,16 @@ import org.rhq.modules.plugins.jbossas7.json.Result;
* @author Heiko W. Rupp
*/
public abstract class AbstractConfigurationHandlingTest {
+ private static final Log LOG = LogFactory.getLog(AbstractConfigurationHandlingTest.class);
private static final String DESCRIPTOR_FILENAME = "test-plugin.xml";
- private Log log = LogFactory.getLog(getClass());
+
private PluginDescriptor pluginDescriptor;
void loadPluginDescriptor() throws Exception {
try {
URL descriptorUrl = this.getClass().getClassLoader().getResource(DESCRIPTOR_FILENAME);
- log.info("Loading plugin descriptor at: " + descriptorUrl);
+ LOG.info("Loading plugin descriptor at: " + descriptorUrl);
JAXBContext jaxbContext = JAXBContext.newInstance(DescriptorPackages.PC_PLUGIN);
@@ -151,15 +152,15 @@ public abstract class AbstractConfigurationHandlingTest {
@Override
public Result execute(Operation op) {
JsonNode json = executeRaw(op);
- Result result = null;
+ Result result;
try {
result = mapper.readValue(json, Result.class);
- } catch (JsonParseException e) {
- e.printStackTrace();
- } catch (JsonMappingException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
+ } catch (Exception e) {
+ LOG.warn("Could not read jsonValue", e);
+ result = new Result();
+ result.setOutcome(FAILURE);
+ result.setFailureDescription(e.getMessage());
+ result.setRhqThrowable(e);
}
return result;
}
diff --git a/modules/plugins/jboss-as-7/src/test/java/org/rhq/modules/plugins/jbossas7/TemplatedComponentTest.java b/modules/plugins/jboss-as-7/src/test/java/org/rhq/modules/plugins/jbossas7/TemplatedComponentTest.java
index 061390c..3cd06f7 100644
--- a/modules/plugins/jboss-as-7/src/test/java/org/rhq/modules/plugins/jbossas7/TemplatedComponentTest.java
+++ b/modules/plugins/jboss-as-7/src/test/java/org/rhq/modules/plugins/jbossas7/TemplatedComponentTest.java
@@ -1,8 +1,7 @@
/*
* RHQ Management Platform
- * Copyright 2011, Red Hat Middleware LLC, and individual contributors
- * as indicated by the @author tags. See the copyright.txt file in the
- * distribution for a full listing of individual contributors.
+ * 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
@@ -14,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.modules.plugins.jbossas7;
@@ -48,6 +47,8 @@ import org.rhq.core.domain.resource.ResourceType;
import org.rhq.core.pluginapi.configuration.ConfigurationUpdateReport;
import org.rhq.core.pluginapi.inventory.ResourceContext;
import org.rhq.modules.plugins.jbossas7.json.Address;
+import org.rhq.modules.plugins.jbossas7.json.ReadResource;
+import org.rhq.modules.plugins.jbossas7.json.Result;
/**
* @author Stefan Negrea
@@ -230,6 +231,7 @@ public class TemplatedComponentTest {
.thenReturn(mockConfigurationWriteDelegate);
ASConnection mockASConnection = mock(ASConnection.class);
+ when(mockASConnection.execute(any(ReadResource.class))).thenReturn(new Result());
//create object to test and inject required dependencies
@@ -287,6 +289,7 @@ public class TemplatedComponentTest {
.thenReturn(mockConfigurationWriteDelegate);
ASConnection mockASConnection = mock(ASConnection.class);
+ when(mockASConnection.execute(any(ReadResource.class))).thenReturn(new Result());
//create object to test and inject required dependencies
TemplatedComponent objectUnderTest = new TemplatedComponent();
commit 8b7322dcc1ca48ca7fc108297956a3b497c70acf
Author: Thomas Segismont <tsegismo(a)redhat.com>
Date: Fri Nov 29 14:15:13 2013 +0100
Remove finalizer from ASConnection
Make ASConnection code easier to read
diff --git a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ASConnection.java b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ASConnection.java
index 5ae86d1..bb4414f 100644
--- a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ASConnection.java
+++ b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ASConnection.java
@@ -19,14 +19,16 @@
package org.rhq.modules.plugins.jbossas7;
+import static java.lang.Boolean.FALSE;
+import static java.lang.Boolean.TRUE;
+import static java.util.concurrent.TimeUnit.NANOSECONDS;
+import static org.rhq.modules.plugins.jbossas7.json.Result.FAILURE;
+
import java.io.IOException;
import java.lang.ref.WeakReference;
-import java.util.StringTokenizer;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicInteger;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -69,6 +71,7 @@ import org.rhq.modules.plugins.jbossas7.json.Result;
* @author Thomas Segismont
*/
public class ASConnection {
+ private static final Log LOG = LogFactory.getLog(ASConnection.class);
public static final String HTTP_SCHEME = "http";
@@ -85,7 +88,7 @@ public class ASConnection {
static final String FAILURE_NO_RESPONSE = "The server closed the connection before sending the response";
- private static final Log LOG = LogFactory.getLog(ASConnection.class);
+ private static final String FAILURE_SHUTDOWN = "The HTTP connection has already been shutdown";
private static final int MAX_POOLED_CONNECTIONS = 10;
@@ -97,24 +100,8 @@ public class ASConnection {
// A shared scheduled executor service to free HttpClient resources
// One thread is enough as tasks will execute quickly
- private static final ScheduledExecutorService cleanerExecutor = Executors.newScheduledThreadPool(1,
- new ThreadFactory() {
-
- private ThreadFactory defaultThreadFactory = Executors.defaultThreadFactory();
-
- private AtomicInteger threadCounter = new AtomicInteger(0);
-
- @Override
- public Thread newThread(Runnable runnable) {
- Thread thread = defaultThreadFactory.newThread(runnable);
- thread.setName("ASConnection Cleaner-" + threadCounter.incrementAndGet());
- // With daemon threads, there is no need to call #shutdown on the executor to let the JVM go down
- thread.setDaemon(true);
- return thread;
- }
- });
-
- private String scheme = ASConnection.HTTP_SCHEME;
+ private static final ScheduledExecutorService cleanerExecutor = Executors
+ .newSingleThreadScheduledExecutor(new ThreadFactory());
private String host;
@@ -130,6 +117,8 @@ public class ASConnection {
private ObjectMapper mapper;
+ private volatile boolean shutdown;
+
/**
* Construct an ASConnection object. The real "physical" connection is done in {@link #executeRaw(Operation)}.
*
@@ -157,7 +146,6 @@ public class ASConnection {
public ASConnection(String host, int port, String user, String password, Long managementConnectionTimeout) {
// Check and store the basic parameters
-
if (host == null) {
throw new IllegalArgumentException("Management host cannot be null.");
}
@@ -169,7 +157,8 @@ public class ASConnection {
if (user != null && password != null) {
credentials = new UsernamePasswordCredentials(user, password);
}
- managementUrl = scheme + "://" + host + ":" + port + MANAGEMENT_URI;
+
+ managementUrl = HTTP_SCHEME + "://" + host + ":" + port + MANAGEMENT_URI;
// Each ASConnection instance will have its own HttpClient instance
// HttpClient will use a pooling connection manager to allow concurrent request processing
@@ -223,6 +212,8 @@ public class ASConnection {
mapper = new ObjectMapper();
mapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+
+ shutdown = false;
}
@@ -230,13 +221,12 @@ public class ASConnection {
return new ASConnection(serverPluginConfig.getHostname(), serverPluginConfig.getPort(), serverPluginConfig.getUser(), serverPluginConfig.getPassword(), serverPluginConfig.getManagementConnectionTimeout());
}
-
- @Override
- protected void finalize() throws Throwable {
+ public void shutdown() {
// Defensive call to shutdown the HttpClient connection manager
// If an ASConnection instance is no longer used, its cleaning task should already
// have closed expired connections
httpClient.getConnectionManager().shutdown();
+ shutdown = true;
}
/**
@@ -272,41 +262,33 @@ public class ASConnection {
* @see #executeComplex(org.rhq.modules.plugins.jbossas7.json.Operation)
*/
public JsonNode executeRaw(Operation operation, int timeoutSec) {
+ if (shutdown) {
+ return resultAsJsonNode(FAILURE, FAILURE_SHUTDOWN, null, FALSE);
+ }
- long requestStartTime = System.currentTimeMillis();
+ long requestStartTime = System.nanoTime();
- // Check for spaces in the path, which the AS7 server will reject. Log verbose error and
- // generate failure indicator.
- if ((operation != null) && (operation.getAddress() != null) && operation.getAddress().getPath() != null) {
- if (containsSpaces(operation.getAddress().getPath())) {
- Result noResult = new Result();
- String outcome = "- Path '" + operation.getAddress().getPath() + "' is invalid as it contains spaces -";
- if (verbose) {
- LOG.error(outcome);
- }
- noResult.setFailureDescription(outcome);
- noResult.setOutcome("failure");
- JsonNode invalidPathResult = mapper.valueToTree(noResult);
- return invalidPathResult;
+ if (addressPathContainsSpaces(operation) == TRUE) {
+ // Check for spaces in the path, which the AS7 server will reject. Log verbose error and
+ // generate failure indicator.
+ String failureDescription = "- Path '" + operation.getAddress().getPath()
+ + "' is invalid as it contains spaces -";
+ if (verbose) {
+ LOG.error(failureDescription);
}
+ return resultAsJsonNode(FAILURE, failureDescription, null, FALSE);
}
- HttpPost httpRequest = new HttpPost(managementUrl);
- httpRequest.addHeader(ACCEPT_HTTP_HEADER, ContentType.APPLICATION_JSON.getMimeType());
- HttpParams httpParams = httpClient.getParams();
- int timeoutMillis = timeoutSec * 1000;
- HttpConnectionParams.setConnectionTimeout(httpParams, timeoutMillis);
- HttpConnectionParams.setSoTimeout(httpParams, timeoutMillis);
-
+ HttpPost httpPost = null;
try {
-
String jsonToSend = mapper.writeValueAsString(operation);
if (verbose) {
LOG.info("JSON to send: " + jsonToSend);
}
- httpRequest.setEntity(new StringEntity(jsonToSend, ContentType.APPLICATION_JSON));
- HttpResponse httpResponse = httpClient.execute(httpRequest);
+ httpPost = initHttpPost(timeoutSec, jsonToSend);
+
+ HttpResponse httpResponse = httpClient.execute(httpPost);
StatusLine statusLine = httpResponse.getStatusLine();
if (isAuthorizationFailureResponse(statusLine)) {
handleAuthorizationFailureResponse(operation, statusLine);
@@ -315,83 +297,72 @@ public class ASConnection {
HttpEntity httpResponseEntity = httpResponse.getEntity();
String responseBody = httpResponseEntity == null ? StringUtil.EMPTY_STRING : EntityUtils
.toString(httpResponseEntity);
- if (statusLine.getStatusCode() >= 400) {
- if (verbose) {
- if (responseBody.contains("JBAS014807") || responseBody.contains("JBAS010850")
- || responseBody.contains("JBAS014792") || responseBody.contains("JBAS014793")
- || responseBody.contains("JBAS014739")) {
- // management resource not found or not readable or no known child-type
- LOG.info("Requested management resource not found: " + operation.getAddress().getPath());
- } else {
- LOG.warn(operation + " failed with " + statusAsString(statusLine) + " - response body was ["
- + responseBody + "].");
- }
- }
+ if (verbose && statusLine.getStatusCode() >= 400) {
+ logHttpError(operation, statusLine, responseBody);
}
JsonNode operationResult;
if (!responseBody.isEmpty()) {
- try {
- operationResult = mapper.readTree(responseBody);
- } catch (IOException ioe) {
- LOG.error("Failed to deserialize response to " + operation + " to JsonNode - response status was "
- + statusAsString(statusLine) + ", and body was [" + responseBody + "]: " + ioe);
- Result result = new Result();
- result.setOutcome("failure");
- result.setFailureDescription("Failed to deserialize response to " + operation
- + " to JsonNode - response status was " + statusAsString(statusLine) + ", and body was ["
- + responseBody + "]: " + ioe);
- result.setRolledBack(responseBody.contains("rolled-back=true"));
- result.setRhqThrowable(ioe);
- operationResult = mapper.valueToTree(result);
- }
-
+ operationResult = deserializeResponseBody(operation, statusLine, responseBody);
if (verbose) {
- ObjectMapper om2 = new ObjectMapper();
- om2.configure(SerializationConfig.Feature.INDENT_OUTPUT, true);
- try {
- String resultString = om2.writeValueAsString(operationResult);
- LOG.info(resultString);
- } catch (IOException ioe) {
- LOG.error("Failed to convert result of " + operation + " to string.", ioe);
- }
+ logFormatted(operationResult);
}
} else {
- Result noResult = new Result();
- noResult.setOutcome("failure");
- noResult.setFailureDescription("- empty response body with HTTP status code "
- + statusAsString(statusLine) + " -");
- operationResult = mapper.valueToTree(noResult);
+ operationResult = resultAsJsonNode(FAILURE, "- empty response body with HTTP status code "
+ + statusAsString(statusLine) + " -", null, FALSE);
}
-
return operationResult;
-
} catch (NoHttpResponseException e) {
// For some operations like reload or shutdown, the server closes the connection before sending the
// response. We use a specific description here so that callers can write code to decide what to do
// in this situation.
- Result failure = new Result();
- failure.setFailureDescription(FAILURE_NO_RESPONSE);
- failure.setOutcome("failure");
- failure.setRhqThrowable(e);
- JsonNode ret = mapper.valueToTree(failure);
- return ret;
+ return resultAsJsonNode(FAILURE, FAILURE_NO_RESPONSE, e, FALSE);
} catch (IOException e) {
- Result failure = new Result();
- failure.setFailureDescription(e.getMessage());
- failure.setOutcome("failure");
- failure.setRhqThrowable(e);
- JsonNode ret = mapper.valueToTree(failure);
- return ret;
+ return resultAsJsonNode(FAILURE, e.getMessage(), e, FALSE);
} finally {
- // Force release of httpclient resources
- httpRequest.abort();
- // Update statistics
- long requestEndTime = System.currentTimeMillis();
- PluginStats stats = PluginStats.getInstance();
- stats.incrementRequestCount();
- stats.addRequestTime(requestEndTime - requestStartTime);
+ if (httpPost != null) {
+ // Release of httpclient resources
+ httpPost.abort();
+ }
+ updateStatistics(requestStartTime, System.nanoTime());
+ }
+ }
+
+ private JsonNode resultAsJsonNode(String outcome, String failureDescription, Throwable rhqThrowable,
+ Boolean rolledBack) {
+ Result result = new Result();
+ result.setOutcome(outcome);
+ if (failureDescription != null) {
+ result.setFailureDescription(failureDescription);
}
+ if (rhqThrowable != null) {
+ result.setRhqThrowable(rhqThrowable);
+ }
+ if (rolledBack == TRUE) {
+ result.setRolledBack(true);
+ }
+ return mapper.valueToTree(result);
+ }
+
+ private Boolean addressPathContainsSpaces(Operation operation) {
+ Boolean addressPathContainsSpaces = FALSE;
+ if ((operation != null) && (operation.getAddress() != null) && operation.getAddress().getPath() != null) {
+ if (containsSpaces(operation.getAddress().getPath())) {
+ addressPathContainsSpaces = TRUE;
+ }
+ }
+ return addressPathContainsSpaces;
+ }
+
+ private HttpPost initHttpPost(int timeoutSec, String jsonToSend) {
+ HttpPost httpPost = new HttpPost(managementUrl);
+ httpPost.addHeader(ACCEPT_HTTP_HEADER, ContentType.APPLICATION_JSON.getMimeType());
+ HttpParams httpParams = httpClient.getParams();
+ int timeoutMillis = timeoutSec * 1000;
+ HttpConnectionParams.setConnectionTimeout(httpParams, timeoutMillis);
+ HttpConnectionParams.setSoTimeout(httpParams, timeoutMillis);
+ httpPost.setEntity(new StringEntity(jsonToSend, ContentType.APPLICATION_JSON));
+ return httpPost;
}
// When no management users have been configured, a 307 (Temporary Redirect) response will be returned, and
@@ -405,7 +376,7 @@ public class ASConnection {
private void handleAuthorizationFailureResponse(Operation operation, StatusLine statusLine) {
if (LOG.isDebugEnabled()) {
LOG.debug("Response to " + operation + " was " + statusAsString(statusLine)
- + " - throwing InvalidPluginConfigurationException...");
+ + " - throwing InvalidPluginConfigurationException...");
}
// Throw a InvalidPluginConfigurationException, so the user will get a yellow plugin connection
// warning message in the GUI.
@@ -418,18 +389,55 @@ public class ASConnection {
throw new InvalidPluginConfigurationException(message);
}
+ private void logHttpError(Operation operation, StatusLine statusLine, String responseBody) {
+ if (responseBody.contains("JBAS014807") || responseBody.contains("JBAS010850")
+ || responseBody.contains("JBAS014792") || responseBody.contains("JBAS014793")
+ || responseBody.contains("JBAS014739")) {
+ // management resource not found or not readable or no known child-type
+ LOG.info("Requested management resource not found: " + operation.getAddress().getPath());
+ } else {
+ LOG.warn(operation + " failed with " + statusAsString(statusLine) + " - response body was ["
+ + responseBody + "].");
+ }
+ }
+
+ private void logFormatted(JsonNode operationResult) {
+ ObjectMapper objectMapper = new ObjectMapper();
+ objectMapper.configure(SerializationConfig.Feature.INDENT_OUTPUT, true);
+ try {
+ LOG.info(objectMapper.writeValueAsString(operationResult));
+ } catch (IOException ignore) {
+ }
+ }
+
+ private JsonNode deserializeResponseBody(Operation operation, StatusLine statusLine, String responseBody) {
+ JsonNode operationResult;
+ try {
+ operationResult = mapper.readTree(responseBody);
+ } catch (IOException ioe) {
+ String failureDescription = "Failed to deserialize response to " + operation
+ + " to JsonNode - response status was " + statusAsString(statusLine) + ", and body was ["
+ + responseBody + "]: " + ioe;
+ LOG.error(failureDescription);
+ operationResult = resultAsJsonNode(FAILURE, failureDescription, ioe,
+ responseBody.contains("rolled-back=true"));
+ }
+ return operationResult;
+ }
+
+ private void updateStatistics(long requestStartTime, long requestEndTime) {
+ PluginStats stats = PluginStats.getInstance();
+ stats.incrementRequestCount();
+ stats.addRequestTime(NANOSECONDS.toMillis(requestEndTime - requestStartTime));
+ }
+
/** Method parses Operation.getAddress().getPath() for invalid spaces in the path passed in.
*
* @param path Operation.getAddress().getPath() value.
* @return boolean indicating invalid spaces found.
*/
private boolean containsSpaces(String path) {
- boolean includesSpaces = false;
- StringTokenizer components = new StringTokenizer(path, " ");
- if (components.countTokens() > 1) {
- includesSpaces = true;
- }
- return includesSpaces;
+ return path.indexOf(" ") != -1;
}
/**
@@ -579,8 +587,7 @@ public class ASConnection {
@Override
public void run() {
ASConnection asConnection = asConnectionWeakReference.get();
- if (asConnection != null) {
- // The target ASConnection instance has not been marked for collection yet
+ if (asConnection != null && !asConnection.shutdown) {
try {
asConnection.httpClient.getConnectionManager().closeExpiredConnections();
// Defensive call to close idle connections
@@ -595,4 +602,15 @@ public class ASConnection {
}
}
+ private static class ThreadFactory implements java.util.concurrent.ThreadFactory {
+
+ @Override
+ public Thread newThread(Runnable runnable) {
+ Thread thread = Executors.defaultThreadFactory().newThread(runnable);
+ thread.setName("ASConnection Cleaner");
+ // With daemon threads, there is no need to call #shutdown on the executor to let the JVM go down
+ thread.setDaemon(true);
+ return thread;
+ }
+ }
}
diff --git a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/BaseProcessDiscovery.java b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/BaseProcessDiscovery.java
index 85f409d..25063ac 100644
--- a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/BaseProcessDiscovery.java
+++ b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/BaseProcessDiscovery.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.modules.plugins.jbossas7;
import static java.lang.Boolean.FALSE;
@@ -725,6 +726,8 @@ public abstract class BaseProcessDiscovery implements ResourceDiscoveryComponent
} catch (InvalidPluginConfigurationException e) {
log.debug("Could not get the product info from [" + hostname + ":" + port
+ "] - probably a connection failure");
+ } finally {
+ connection.shutdown();
}
return this;
}
diff --git a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/BaseServerComponent.java b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/BaseServerComponent.java
index 1e84c06..944d7c5 100644
--- a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/BaseServerComponent.java
+++ b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/BaseServerComponent.java
@@ -123,6 +123,7 @@ public abstract class BaseServerComponent<T extends ResourceComponent<?>> extend
@Override
public void stop() {
+ connection.shutdown();
logFileEventDelegate.stopLogFileEventPollers();
previousAvailabilityType = null;
if (this.availabilityCollector != null) {
diff --git a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/Domain2Descriptor.java b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/Domain2Descriptor.java
index a532c3a..633997b 100644
--- a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/Domain2Descriptor.java
+++ b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/Domain2Descriptor.java
@@ -1,6 +1,6 @@
/*
* RHQ Management Platform
- * Copyright (C) 2005-2012 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.modules.plugins.jbossas7;
@@ -111,103 +111,107 @@ public class Domain2Descriptor {
//create connection
ASConnection conn = new ASConnection("localhost", 9990, user, pass);
-
- Address address = new Address(path);
-
- //create request to get metadata type information
- Operation op = new Operation("read-resource-description", address);
- //recurse down the tree.
- op.addAdditionalProperty("recursive", "true");
-
- //additionally request operation metadata
- if (mode == D2DMode.OPERATION) {
- op.addAdditionalProperty("operations", true);
- }
- //additionally request metric metadata
- if (mode == D2DMode.METRICS) {
- op.addAdditionalProperty("include-runtime", true);
- }
- //additionally request both metric and operations metadata
- if (mode == D2DMode.RECURSIVE) {
- op.addAdditionalProperty("operations", true);
- op.addAdditionalProperty("include-runtime", true);
- }
-
- ComplexResult res = conn.executeComplex(op);
- if (res == null) {
- System.err.println("Got no result");
- return;
- }
- if (!res.isSuccess()) {
- System.err.println("Failure: " + res.getFailureDescription());
- return;
- }
-
- //load json object hierarchy of response
- Map<String, Object> resMap = res.getResult();
- String what;
- if (mode == D2DMode.OPERATION) {
- what = "operations";
- } else {
- what = "attributes";
- }
-
- //Determine which attributes to focus on.
- Map<String, Object> attributesMap = null;
-
- //when will childtype is actually passed then...
- if (childType != null) {
-
- Map childMap = (Map) resMap.get("children");
- Map<String, Object> typeMap = (Map<String, Object>) childMap.get(childType);
- if (typeMap == null) {
- System.err.println("No child with type '" + childType + "' found");
+ try {
+
+ Address address = new Address(path);
+
+ //create request to get metadata type information
+ Operation op = new Operation("read-resource-description", address);
+ //recurse down the tree.
+ op.addAdditionalProperty("recursive", "true");
+
+ //additionally request operation metadata
+ if (mode == D2DMode.OPERATION) {
+ op.addAdditionalProperty("operations", true);
+ }
+ //additionally request metric metadata
+ if (mode == D2DMode.METRICS) {
+ op.addAdditionalProperty("include-runtime", true);
+ }
+ //additionally request both metric and operations metadata
+ if (mode == D2DMode.RECURSIVE) {
+ op.addAdditionalProperty("operations", true);
+ op.addAdditionalProperty("include-runtime", true);
+ }
+
+ ComplexResult res = conn.executeComplex(op);
+ if (res == null) {
+ System.err.println("Got no result");
return;
}
- Map descriptionMap = (Map) typeMap.get("model-description");
- if (descriptionMap == null) {
- System.err.println("No model description found");
+ if (!res.isSuccess()) {
+ System.err.println("Failure: " + res.getFailureDescription());
return;
}
- Map starMap = (Map) descriptionMap.get("*");
- if (starMap != null) {
- attributesMap = (Map<String, Object>) starMap.get(what);
- } else {//when no *map is provided check for 'classic'
- Map classicMap = (Map) descriptionMap.get("classic");
- attributesMap = (Map<String, Object>) classicMap.get(what);
- }//spinder: What about 'jsapi'? This occurs on some nodes.
- } else {//no child type passed in just load typical map
- attributesMap = (Map<String, Object>) resMap.get(what);
- }
-
- if (mode == D2DMode.OPERATION) {
- //populate operations(each special map type) and sort them for ordered listing
- Set<String> strings = attributesMap.keySet();
- String[] keys = strings.toArray(new String[strings.size()]);
- Arrays.sort(keys);
-
- for (String key : keys) {
- //exclude typical 'read-' and 'write-attribute' operations typical to all types.
- if (!isExcludedOperation(key)) {
- //for each custom operation found, retrieve child hierarchy and pass into
- Map<String, Object> value = (Map<String, Object>) attributesMap.get(key);
- createOperation(key, value);
+
+ //load json object hierarchy of response
+ Map<String, Object> resMap = res.getResult();
+ String what;
+ if (mode == D2DMode.OPERATION) {
+ what = "operations";
+ } else {
+ what = "attributes";
+ }
+
+ //Determine which attributes to focus on.
+ Map<String, Object> attributesMap = null;
+
+ //when will childtype is actually passed then...
+ if (childType != null) {
+
+ Map childMap = (Map) resMap.get("children");
+ Map<String, Object> typeMap = (Map<String, Object>) childMap.get(childType);
+ if (typeMap == null) {
+ System.err.println("No child with type '" + childType + "' found");
+ return;
}
+ Map descriptionMap = (Map) typeMap.get("model-description");
+ if (descriptionMap == null) {
+ System.err.println("No model description found");
+ return;
+ }
+ Map starMap = (Map) descriptionMap.get("*");
+ if (starMap != null) {
+ attributesMap = (Map<String, Object>) starMap.get(what);
+ } else {//when no *map is provided check for 'classic'
+ Map classicMap = (Map) descriptionMap.get("classic");
+ attributesMap = (Map<String, Object>) classicMap.get(what);
+ }//spinder: What about 'jsapi'? This occurs on some nodes.
+ } else {//no child type passed in just load typical map
+ attributesMap = (Map<String, Object>) resMap.get(what);
}
- } else if (mode == D2DMode.RECURSIVE) {// list the child nodes and properties
- String legend = "Key: - property, -M metric,* req'd, + operation, [] child node.";
- StringBuilder tree = new StringBuilder(path + " ->\t" + legend + " \n");
- if (!descriptorSegment) {
- System.out.print(tree);
- listPropertiesAndChildren(3, resMap);
+
+ if (mode == D2DMode.OPERATION) {
+ //populate operations(each special map type) and sort them for ordered listing
+ Set<String> strings = attributesMap.keySet();
+ String[] keys = strings.toArray(new String[strings.size()]);
+ Arrays.sort(keys);
+
+ for (String key : keys) {
+ //exclude typical 'read-' and 'write-attribute' operations typical to all types.
+ if (!isExcludedOperation(key)) {
+ //for each custom operation found, retrieve child hierarchy and pass into
+ Map<String, Object> value = (Map<String, Object>) attributesMap.get(key);
+ createOperation(key, value);
+ }
+ }
+ } else if (mode == D2DMode.RECURSIVE) {// list the child nodes and properties
+ String legend = "Key: - property, -M metric,* req'd, + operation, [] child node.";
+ StringBuilder tree = new StringBuilder(path + " ->\t" + legend + " \n");
+ if (!descriptorSegment) {
+ System.out.print(tree);
+ listPropertiesAndChildren(3, resMap);
+ } else {
+ System.out.println(generateSegment(path, 0));
+ listPropertiesAndChildren(3, resMap);
+ System.out.println("</service>\n");
+ }
+
} else {
- System.out.println(generateSegment(path, 0));
- listPropertiesAndChildren(3, resMap);
- System.out.println("</service>\n");
+ createProperties(mode, attributesMap, 0, false);
}
-
- } else {
- createProperties(mode, attributesMap, 0, false);
+ } finally {
+ conn.shutdown();
}
}
diff --git a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/json/Result.java b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/json/Result.java
index 3fbdb90..a490baf 100644
--- a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/json/Result.java
+++ b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/json/Result.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,9 +13,10 @@
* 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.modules.plugins.jbossas7.json;
import java.util.Map;
@@ -35,6 +36,7 @@ import org.codehaus.jackson.annotate.JsonProperty;
public class Result {
public static final String SUCCESS = "success";
+ public static final String FAILURE = "failure";
private String outcome;
private Object result;
@JsonProperty("failure-description")
10 years
[rhq] Branch 'release/jon3.2.x' - modules/enterprise
by Jiri Kremser
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/measurement/MeasurementDataManagerBean.java | 11 ++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
New commits:
commit 6f6ab84ee7ed815fd450df877a13aa533a49d8c7
Author: Jirka Kremser <jkremser(a)redhat.com>
Date: Fri Nov 29 12:19:47 2013 +0100
[BZ 1035280] - Cannot load metrics for platform resource created using rest api - check for dummy agent in MeasurementDataManagerBean.findLiveDataForGroup()
(cherry picked from commit f0bb4247151bf0bbb80f0e3de90c631d988e718c)
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/measurement/MeasurementDataManagerBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/measurement/MeasurementDataManagerBean.java
index d1aa970..861921a 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/measurement/MeasurementDataManagerBean.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/measurement/MeasurementDataManagerBean.java
@@ -853,7 +853,6 @@ public class MeasurementDataManagerBean implements MeasurementDataManagerLocal,
}
@Override
- @SuppressWarnings("unchecked")
public Set<MeasurementData> findLiveData(Subject subject, int resourceId, int[] definitionIds) {
// use default timeout
return findLiveData(subject, resourceId, definitionIds, null);
@@ -870,7 +869,7 @@ public class MeasurementDataManagerBean implements MeasurementDataManagerLocal,
Query query = entityManager.createNamedQuery(Agent.QUERY_FIND_BY_RESOURCE_ID);
query.setParameter("resourceId", resourceId);
Agent agent = (Agent) query.getSingleResult();
-
+
// return empty data if the agent is the dummy one
if (agent.getName().startsWith(ResourceHandlerBean.DUMMY_AGENT_NAME_PREFIX)
&& agent.getAgentToken().startsWith(ResourceHandlerBean.DUMMY_AGENT_TOKEN_PREFIX)) {
@@ -932,6 +931,14 @@ public class MeasurementDataManagerBean implements MeasurementDataManagerLocal,
List<ResourceIdWithAgentComposite> resourceIdsWithAgents = query.getResultList();
for (ResourceIdWithAgentComposite resourceIdWithAgent : resourceIdsWithAgents) {
+ // return empty data if the agent is the dummy one
+ if (resourceIdWithAgent.getAgent().getName().startsWith(ResourceHandlerBean.DUMMY_AGENT_NAME_PREFIX)
+ && resourceIdWithAgent.getAgent().getAgentToken()
+ .startsWith(ResourceHandlerBean.DUMMY_AGENT_TOKEN_PREFIX)) {
+ values.addAll(Collections.<MeasurementData> emptySet());
+ continue;
+ }
+
query = entityManager.createNamedQuery(MeasurementSchedule.FIND_BY_RESOURCE_IDS_AND_DEFINITION_IDS);
query.setParameter("definitionIds", ArrayUtils.wrapInList(definitionIds));
query.setParameter("resourceIds", Arrays.asList(resourceIdWithAgent.getResourceId()));
10 years
[rhq] Branch 'release/jon3.2.x' - modules/enterprise
by Heiko W. Rupp
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/AlertDefinitionHandlerBean.java | 16 +++++++++-
1 file changed, 15 insertions(+), 1 deletion(-)
New commits:
commit 0bf59fd0bcd98ad6c659e0755e2862abb3434db8
Author: Heiko W. Rupp <hwr(a)redhat.com>
Date: Fri Nov 29 12:10:22 2013 +0100
[BZ 1035816] Fix handling of "disable after fire" definitions.
(cherry picked from commit b9e35b5 & eab7656)
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/AlertDefinitionHandlerBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/AlertDefinitionHandlerBean.java
index f608251..3b43bee 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/AlertDefinitionHandlerBean.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/AlertDefinitionHandlerBean.java
@@ -402,7 +402,7 @@ public class AlertDefinitionHandlerBean extends AbstractRestBean {
private void setDampeningFromRest(AlertDefinition alertDefinition, AlertDefinitionRest adr) {
AlertDampening.Category dampeningCategory;
try {
- dampeningCategory = AlertDampening.Category.valueOf(adr.getDampeningCategory());
+ dampeningCategory = AlertDampening.Category.valueOf(adr.getDampeningCategory().toUpperCase());
}
catch (Exception e) {
AlertDampening.Category[] vals = AlertDampening.Category.values();
@@ -415,6 +415,16 @@ public class AlertDefinitionHandlerBean extends AbstractRestBean {
}
throw new BadArgumentException("dampening category","Allowed values are: " + builder.toString());
}
+ if (dampeningCategory == AlertDampening.Category.ONCE) {
+ // WillRecover = true means to disable after firing
+ // See org.rhq.enterprise.server.alert.AlertManagerBean.willDefinitionBeDisabled()
+ alertDefinition.setWillRecover(true);
+ dampeningCategory = AlertDampening.Category.NONE;
+ }
+ if (dampeningCategory == AlertDampening.Category.NO_DUPLICATES) {
+ dampeningCategory = AlertDampening.Category.NONE;
+ }
+
AlertDampening dampening = new AlertDampening(dampeningCategory);
if (adr.getDampeningCount()>-1) {
dampening.setValue(adr.getDampeningCount());
@@ -1137,6 +1147,10 @@ public class AlertDefinitionHandlerBean extends AbstractRestBean {
AlertDampening dampening = def.getAlertDampening();
adr.setDampeningCategory(dampening.getCategory().name());
+ if (dampening.getCategory()== AlertDampening.Category.NONE && def.getWillRecover()) {
+ adr.setDampeningCategory(AlertDampening.Category.ONCE.name());
+ }
+
AlertDampening.TimeUnits units = dampening.getValueUnits();
String s = units != null ? " " + units.name() : "";
adr.setDampeningCount(dampening.getValue());
10 years
[rhq] modules/enterprise
by Heiko W. Rupp
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/AlertDefinitionHandlerBean.java | 4 ++++
1 file changed, 4 insertions(+)
New commits:
commit eab76569c484c9a291f8c958b872c9f639b5e1ec
Author: Heiko W. Rupp <hwr(a)redhat.com>
Date: Fri Nov 29 12:19:05 2013 +0100
[BZ 1035816] Fix handling of "disable after fire" definitions.
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/AlertDefinitionHandlerBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/AlertDefinitionHandlerBean.java
index 318fa74..3b43bee 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/AlertDefinitionHandlerBean.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/AlertDefinitionHandlerBean.java
@@ -1147,6 +1147,10 @@ public class AlertDefinitionHandlerBean extends AbstractRestBean {
AlertDampening dampening = def.getAlertDampening();
adr.setDampeningCategory(dampening.getCategory().name());
+ if (dampening.getCategory()== AlertDampening.Category.NONE && def.getWillRecover()) {
+ adr.setDampeningCategory(AlertDampening.Category.ONCE.name());
+ }
+
AlertDampening.TimeUnits units = dampening.getValueUnits();
String s = units != null ? " " + units.name() : "";
adr.setDampeningCount(dampening.getValue());
10 years
[rhq] modules/enterprise
by Jiri Kremser
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/measurement/MeasurementDataManagerBean.java | 11 ++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
New commits:
commit f0bb4247151bf0bbb80f0e3de90c631d988e718c
Author: Jirka Kremser <jkremser(a)redhat.com>
Date: Fri Nov 29 12:19:47 2013 +0100
[BZ 1035280] - Cannot load metrics for platform resource created using rest api - check for dummy agent in MeasurementDataManagerBean.findLiveDataForGroup()
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/measurement/MeasurementDataManagerBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/measurement/MeasurementDataManagerBean.java
index 9612405..799e91f 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/measurement/MeasurementDataManagerBean.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/measurement/MeasurementDataManagerBean.java
@@ -868,7 +868,6 @@ public class MeasurementDataManagerBean implements MeasurementDataManagerLocal,
}
@Override
- @SuppressWarnings("unchecked")
public Set<MeasurementData> findLiveData(Subject subject, int resourceId, int[] definitionIds) {
// use default timeout
return findLiveData(subject, resourceId, definitionIds, null);
@@ -885,7 +884,7 @@ public class MeasurementDataManagerBean implements MeasurementDataManagerLocal,
Query query = entityManager.createNamedQuery(Agent.QUERY_FIND_BY_RESOURCE_ID);
query.setParameter("resourceId", resourceId);
Agent agent = (Agent) query.getSingleResult();
-
+
// return empty data if the agent is the dummy one
if (agent.getName().startsWith(ResourceHandlerBean.DUMMY_AGENT_NAME_PREFIX)
&& agent.getAgentToken().startsWith(ResourceHandlerBean.DUMMY_AGENT_TOKEN_PREFIX)) {
@@ -947,6 +946,14 @@ public class MeasurementDataManagerBean implements MeasurementDataManagerLocal,
List<ResourceIdWithAgentComposite> resourceIdsWithAgents = query.getResultList();
for (ResourceIdWithAgentComposite resourceIdWithAgent : resourceIdsWithAgents) {
+ // return empty data if the agent is the dummy one
+ if (resourceIdWithAgent.getAgent().getName().startsWith(ResourceHandlerBean.DUMMY_AGENT_NAME_PREFIX)
+ && resourceIdWithAgent.getAgent().getAgentToken()
+ .startsWith(ResourceHandlerBean.DUMMY_AGENT_TOKEN_PREFIX)) {
+ values.addAll(Collections.<MeasurementData> emptySet());
+ continue;
+ }
+
query = entityManager.createNamedQuery(MeasurementSchedule.FIND_BY_RESOURCE_IDS_AND_DEFINITION_IDS);
query.setParameter("definitionIds", ArrayUtils.wrapInList(definitionIds));
query.setParameter("resourceIds", Arrays.asList(resourceIdWithAgent.getResourceId()));
10 years
[rhq] modules/enterprise
by Heiko W. Rupp
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/AlertDefinitionHandlerBean.java | 12 +++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)
New commits:
commit b9e35b5602609e9236bdc21cd921a8bd92a9be7f
Author: Heiko W. Rupp <hwr(a)redhat.com>
Date: Fri Nov 29 12:10:01 2013 +0100
[BZ 1035816] Fix handling of "disable after fire" definitions.
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/AlertDefinitionHandlerBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/AlertDefinitionHandlerBean.java
index f608251..318fa74 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/AlertDefinitionHandlerBean.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/AlertDefinitionHandlerBean.java
@@ -402,7 +402,7 @@ public class AlertDefinitionHandlerBean extends AbstractRestBean {
private void setDampeningFromRest(AlertDefinition alertDefinition, AlertDefinitionRest adr) {
AlertDampening.Category dampeningCategory;
try {
- dampeningCategory = AlertDampening.Category.valueOf(adr.getDampeningCategory());
+ dampeningCategory = AlertDampening.Category.valueOf(adr.getDampeningCategory().toUpperCase());
}
catch (Exception e) {
AlertDampening.Category[] vals = AlertDampening.Category.values();
@@ -415,6 +415,16 @@ public class AlertDefinitionHandlerBean extends AbstractRestBean {
}
throw new BadArgumentException("dampening category","Allowed values are: " + builder.toString());
}
+ if (dampeningCategory == AlertDampening.Category.ONCE) {
+ // WillRecover = true means to disable after firing
+ // See org.rhq.enterprise.server.alert.AlertManagerBean.willDefinitionBeDisabled()
+ alertDefinition.setWillRecover(true);
+ dampeningCategory = AlertDampening.Category.NONE;
+ }
+ if (dampeningCategory == AlertDampening.Category.NO_DUPLICATES) {
+ dampeningCategory = AlertDampening.Category.NONE;
+ }
+
AlertDampening dampening = new AlertDampening(dampeningCategory);
if (adr.getDampeningCount()>-1) {
dampening.setValue(adr.getDampeningCount());
10 years
[rhq] modules/enterprise
by Thomas Segismont
modules/enterprise/agent/src/main/java/org/rhq/enterprise/agent/AgentMain.java | 155 ++-----
modules/enterprise/agent/src/main/java/org/rhq/enterprise/agent/PluginUpdate.java | 214 +++-------
modules/enterprise/agent/src/main/java/org/rhq/enterprise/agent/i18n/AgentI18NResourceKeys.java | 16
3 files changed, 123 insertions(+), 262 deletions(-)
New commits:
commit fd21e3a42153c9e205afc5a25418f2970c6e5c7d
Author: Elias Ross <genman(a)noderunner.net>
Date: Thu Nov 28 18:04:46 2013 +0100
Bug 1030063 - Clean up plugin update to work synchronously
The plugin update is problematic as it is driven by listener ordering and possibly has many race conditions like seen in Bug 1025844. For example, the listener is actually added before the plugin container starts. Although effectively, the dependent systems are initialized before be the listener is called, this is not something predictable or clear.
The other weird thing is a lot of polling (of directory states, etc.) for a count of files. There is no notion of completed state, i.e. the update actually completed.
I've seen agents come up with the old version of plugins (like if the server blocked for a very long time), etc.
Using marker files isn't terribly reliable either, and not really helpful. Maybe it is a diagnostic feature, but why not use a static semaphore to order updates?
Anyway, my patch is simply having AgentMain do (more or less):
new PluginUpdate(...).updatePlugins()
when the server starts.
diff --git a/modules/enterprise/agent/src/main/java/org/rhq/enterprise/agent/AgentMain.java b/modules/enterprise/agent/src/main/java/org/rhq/enterprise/agent/AgentMain.java
index 1e43996..4f05315 100644
--- a/modules/enterprise/agent/src/main/java/org/rhq/enterprise/agent/AgentMain.java
+++ b/modules/enterprise/agent/src/main/java/org/rhq/enterprise/agent/AgentMain.java
@@ -1,6 +1,6 @@
/*
* RHQ Management Platform
- * Copyright (C) 2005-2008 Red Hat, Inc.
+ * Copyright (C) 2005-2013 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -13,14 +13,11 @@
* 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.agent;
-import gnu.getopt.Getopt;
-import gnu.getopt.LongOpt;
-
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
@@ -28,7 +25,6 @@ import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
-import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
@@ -63,6 +59,8 @@ import javax.management.ObjectName;
import mazz.i18n.Logger;
import mazz.i18n.Msg;
+import gnu.getopt.Getopt;
+import gnu.getopt.LongOpt;
import org.apache.log4j.Level;
import org.apache.log4j.LogManager;
@@ -168,9 +166,6 @@ import org.rhq.enterprise.communications.util.SecurityUtil;
* @author John Mazzitelli
*/
public class AgentMain {
- /**
- * The logger.
- */
private static final Logger LOG = AgentI18NFactory.getLogger(AgentMain.class);
/**
@@ -393,6 +388,11 @@ public class AgentMain {
private boolean m_loggedNativeSystemInfoUnavailableWarning;
/**
+ * Plugin update instance, used by management.
+ */
+ private PluginUpdate m_pluginUpdate;
+
+ /**
* The main method that starts the whole thing.
*
* @param args the arguments passed on the command line (e.g. java org.rhq.enterprise.agent.AgentMain arg1 arg2 arg3)
@@ -1677,7 +1677,6 @@ public class AgentMain {
* <p/>
* <ul>
* <li>Registering with the server (if the agent needs to do so at startup)</li>
- * <li>Updating the plugins with the latest versions that are found on the server</li>
* <li>Setup a conditional restart of the plugin container, see {@link PluginContainerConditionalRestartListener}</li>
* </ul>
*
@@ -1706,11 +1705,6 @@ public class AgentMain {
m_clientSender.addStateListener(new RegisterStateListener(), true);
}
- // now we want to prepare to update the plugins if told to do so
- if (m_configuration.isUpdatePluginsAtStartupEnabled()) {
- updatePlugins();
- }
-
//the next thing is to setup the conditional restart of the PC if it fails to merge
//the upgrade results with the server due to some network glitch
m_clientSender.addStateListener(new PluginContainerConditionalRestartListener(), false);
@@ -1719,12 +1713,20 @@ public class AgentMain {
}
/**
- * This asks that the agent update its plugins. If the RHQ Server is already up and the agent has detected it, this
- * method will immediately pull down the new/updated plugins. Otherwise, this will schedule the agent to update the
- * plugins from the server once it comes up and the agent detects it.
+ * Management method to manually update plugins.
+ * This method will fail if the server is down.
+ * @throws IllegalStateException if the container is not initialized
+ * @throws RuntimeException for any other reason (failed to download, etc.)
*/
public void updatePlugins() {
- m_clientSender.addStateListener(new UpdatePluginsStateListener(), true);
+ if (m_pluginUpdate == null) {
+ throw new IllegalStateException("plugin update uninitialized");
+ }
+ try {
+ m_pluginUpdate.updatePlugins();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
}
/**
@@ -1885,59 +1887,34 @@ public class AgentMain {
return false;
}
- try {
- File plugin_dir = pc_config.getPluginDirectory();
- boolean keep_waiting = (plugin_dir.list().length == 0)
- || PluginUpdate.waitForUpdateToComplete(pc_config, 1000L);
-
- // we block until we get our plugins - there is no sense continuing until we have plugins
- // there may be instances, though, where we don't want to block (in unit tests for example)
- // so allow this to be configurable via the "update plugins at startup" flag.
- if (m_configuration.isUpdatePluginsAtStartupEnabled()) {
- boolean notified_user = false;
-
- while (keep_waiting) {
- if (!notified_user) {
- LOG.info(AgentI18NResourceKeys.WAITING_FOR_PLUGINS_WITH_DIR, plugin_dir);
- getOut().println(MSG.getMsg(AgentI18NResourceKeys.WAITING_FOR_PLUGINS));
- notified_user = true;
- } else {
- // let's keep logging this at debug level so we don't look hung
- LOG.debug(AgentI18NResourceKeys.WAITING_FOR_PLUGINS_WITH_DIR, plugin_dir);
- }
-
- boolean updating = PluginUpdate.waitForUpdateToComplete(pc_config, 30000L);
- int after = plugin_dir.list().length;
-
- if ((after == 0) && !updating) {
- // still nothing and it doesn't look like we are downloading - try to update them again right now
- // (doing this because I saw a case where the startup update somehow happened just prior to the
- // registration finishing, so the original update was rejected by the server as "unauthorized")
- updatePluginsNow(m_clientSender);
- after = plugin_dir.list().length;
- }
-
- keep_waiting = ((after == 0) || (updating));
+ File plugin_dir = pc_config.getPluginDirectory();
- if (!keep_waiting) {
- after = plugin_dir.list(new FilenameFilter() {
- public boolean accept(File dir, String name) {
- return name.endsWith(".jar");
- }
- }).length;
- LOG.info(AgentI18NResourceKeys.DONE_WAITING_FOR_PLUGINS, after);
- getOut().println(MSG.getMsg(AgentI18NResourceKeys.DONE_WAITING_FOR_PLUGINS, after));
- }
+ // we block until we get our plugins - there is no sense continuing until we have plugins
+ // there may be instances, though, where we don't want to block (in unit tests for example)
+ // so allow this to be configurable via the "update plugins at startup" flag.
+ m_pluginUpdate = new PluginUpdate(pc_config.getServerServices().getCoreServerService(), pc_config);
+ if (m_configuration.isUpdatePluginsAtStartupEnabled()) {
+ boolean notified_user = false;
+ // this can block forever...perhaps exit after a few tries?
+ while (true) {
+ if (!notified_user) {
+ LOG.info(AgentI18NResourceKeys.WAITING_FOR_PLUGINS_WITH_DIR, plugin_dir);
+ getOut().println(MSG.getMsg(AgentI18NResourceKeys.WAITING_FOR_PLUGINS));
+ notified_user = true;
+ } else {
+ // let's keep logging this at debug level so we don't look hung
+ LOG.debug(AgentI18NResourceKeys.WAITING_FOR_PLUGINS_WITH_DIR, plugin_dir);
+ }
+ try {
+ m_pluginUpdate.updatePlugins();
+ break;
+ } catch (Exception e) {
+ LOG.error(e, AgentI18NResourceKeys.UPDATING_PLUGINS_FAILURE, e);
}
- } else if (plugin_dir.list().length == 0) {
- LOG.warn(AgentI18NResourceKeys.NO_PLUGINS);
- getOut().println(MSG.getMsg(AgentI18NResourceKeys.NO_PLUGINS));
- return false;
}
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- LOG.warn(AgentI18NResourceKeys.PLUGIN_CONTAINER_INITIALIZATION_INTERRUPTED);
- getOut().println(MSG.getMsg(AgentI18NResourceKeys.PLUGIN_CONTAINER_INITIALIZATION_INTERRUPTED));
+ } else if (plugin_dir.list().length == 0) {
+ LOG.warn(AgentI18NResourceKeys.NO_PLUGINS);
+ getOut().println(MSG.getMsg(AgentI18NResourceKeys.NO_PLUGINS));
return false;
}
@@ -3522,29 +3499,6 @@ public class AgentMain {
m_startTime = (started) ? System.currentTimeMillis() : 0L;
}
- /**
- * Immediately sends a request to the server to update the plugins.
- *
- * @param sender the sender used to comminucate with server
- *
- * @return <code>true</code> if the plugins were succesfully updated, <code>false</code> if an error occurred
- *
- * @see PluginUpdate
- */
- private boolean updatePluginsNow(ClientCommandSender sender) {
- try {
- ClientRemotePojoFactory factory = sender.getClientRemotePojoFactory();
- CoreServerService server = factory.getRemotePojo(CoreServerService.class);
- PluginContainerConfiguration pc_config = m_configuration.getPluginContainerConfiguration();
- PluginUpdate plugin_update = new PluginUpdate(server, pc_config);
- plugin_update.updatePlugins();
- return true;
- } catch (Exception e) {
- LOG.warn(e, AgentI18NResourceKeys.UPDATING_PLUGINS_FAILURE);
- return false;
- }
- }
-
private static void reconfigureJavaLogging() {
try {
LOG.debug(AgentI18NResourceKeys.RECONFIGURE_JAVA_LOGGING_START);
@@ -3582,21 +3536,6 @@ public class AgentMain {
}
/**
- * Listener that will update the plugins once the sender is able to start sending.
- */
- private class UpdatePluginsStateListener implements ClientCommandSenderStateListener {
- public boolean startedSending(ClientCommandSender sender) {
- updatePluginsNow(sender);
-
- return false; // no need to keep listening
- }
-
- public boolean stoppedSending(ClientCommandSender sender) {
- return true; // no-op but keep listening
- }
- }
-
- /**
* Sender listener that will remove the command listener once the sender starts. It will also add the command
* listener once the sender stops. The command listener will allow us to immediately turn on the sender when the
* server sends us a message. We don't need this command listener once we know the sender has started (because that
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 8aa81a0..5e24b14 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
@@ -1,6 +1,6 @@
/*
* RHQ Management Platform
- * Copyright (C) 2005-2008 Red Hat, Inc.
+ * Copyright (C) 2005-2013 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -13,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.agent;
@@ -26,10 +26,9 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
-import java.util.concurrent.locks.ReadWriteLock;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
import mazz.i18n.Logger;
@@ -55,57 +54,15 @@ import org.rhq.enterprise.communications.command.client.RemoteIOException;
public class PluginUpdate {
private static final Logger LOG = AgentI18NFactory.getLogger(PluginUpdate.class);
- private static final String MARKER_FILENAME = ".updatelock";
-
/**
- * Static lock that prohibits concurrent plugin updates.
+ * Lock that prohibits concurrent plugin updates between threads.
*/
- private static final ReadWriteLock lock = new ReentrantReadWriteLock();
+ private static final Semaphore SEMAPHORE = new Semaphore(1);
private final CoreServerService coreServerService;
private final PluginContainerConfiguration config;
/**
- * All {@link PluginUpdate} objects know if they are currently updating plugins given a specific <code>
- * config</code>. Call this static method to ask if any plugin update object is currently updating plugins with the
- * given configuration
- *
- * @param config used to determine where the plugins are being updated
- *
- * @return <code>true</code> if a plugin updater object is currently updating plugin; <code>false</code> if all
- * plugins are up-to-date and nothing is being updated anymore.
- */
- public static boolean isCurrentlyUpdating(PluginContainerConfiguration config) {
- File marker = new File(config.getPluginDirectory(), MARKER_FILENAME);
- return marker.exists();
- }
-
- /**
- * Blocks the calling thread for a maximum of the given amount of milliseconds timeout waiting for a plugin update
- * to completely. This will return sooner if the update finishes early or if there is no update currently happening.
- *
- * @param config used to determine where the plugins are being updated
- * @param timeout max milliseconds to wait
- *
- * @return <code>true</code> if a plugin updater object is currently updating plugin and this method timed out;
- * <code>false</code> if all plugins are up-to-date and nothing is being updated anymore.
- *
- * @throws InterruptedException if thread was interrupted while waiting
- */
- public static boolean waitForUpdateToComplete(PluginContainerConfiguration config, long timeout)
- throws InterruptedException {
- long time_limit = System.currentTimeMillis() + timeout;
- boolean currently_updating = true; // for us to sleep at least an initial amount before checking the first time
-
- while (currently_updating && (time_limit > System.currentTimeMillis())) {
- Thread.sleep(2000L);
- currently_updating = isCurrentlyUpdating(config);
- }
-
- return currently_updating;
- }
-
- /**
* Constructor for {@link PluginUpdate}. You can pass in a <code>null</code> <code>core_server_service</code> if you
* only plan to use this object to obtain information on the currently installed plugins and not actually update
* them.
@@ -151,97 +108,101 @@ public class PluginUpdate {
List<Plugin> updated_plugins = new ArrayList<Plugin>();
// block if some other thread is updating, too - we can only ever have one thread updating plugins
- if (!PluginUpdate.lock.writeLock().tryLock(3600, TimeUnit.SECONDS)) {
+ if (!SEMAPHORE.tryAcquire(3600, TimeUnit.SECONDS)) {
// it should never take this long to update plugins. But if it does, just barf
throw new TimeoutException();
}
try {
- createMarkerFile();
-
- try {
- List<String> disabled_plugin_names = this.config.getDisabledPlugins();
+ List<String> disabled_plugin_names = this.config.getDisabledPlugins();
- // find out what plugins we already have locally
- Map<String, Plugin> current_plugins = getCurrentPlugins();
+ // find out what plugins we already have locally
+ Map<String, Plugin> current_plugins = getCurrentPlugins();
- // find out what the latest plugins are available to us
- List<Plugin> latest_plugins = coreServerService.getLatestPlugins();
+ // find out what the latest plugins are available to us
+ List<Plugin> latest_plugins = coreServerService.getLatestPlugins();
+ if (LOG.isDebugEnabled()) {
if (LOG.isDebugEnabled()) {
LOG.debug(AgentI18NResourceKeys.LATEST_PLUGINS_COUNT, latest_plugins.size());
- for (Plugin latest_plugin : latest_plugins) {
+ }
+ for (Plugin latest_plugin : latest_plugins) {
+ if (LOG.isDebugEnabled()) {
LOG.debug(AgentI18NResourceKeys.LATEST_PLUGIN, latest_plugin.getId(), latest_plugin.getName(),
latest_plugin.getDisplayName(), latest_plugin.getVersion(), latest_plugin.getPath(),
latest_plugin.getMd5(), latest_plugin.isEnabled(), latest_plugin.getDescription());
}
}
+ }
- Map<String, Plugin> latest_plugins_map = new HashMap<String, Plugin>(latest_plugins.size());
+ Map<String, Plugin> latest_plugins_map = new HashMap<String, Plugin>(latest_plugins.size());
- // determine if we need to upgrade any of our current plugins to the latest versions
- for (Plugin latest_plugin : latest_plugins) {
- String plugin_filename = latest_plugin.getPath();
- latest_plugins_map.put(plugin_filename, latest_plugin);
- Plugin current_plugin = current_plugins.get(plugin_filename);
+ // determine if we need to upgrade any of our current plugins to the latest versions
+ for (Plugin latest_plugin : latest_plugins) {
+ String plugin_filename = latest_plugin.getPath();
+ latest_plugins_map.put(plugin_filename, latest_plugin);
+ Plugin current_plugin = current_plugins.get(plugin_filename);
- if (current_plugin == null) {
- updated_plugins.add(latest_plugin); // we don't have any version of this plugin, we'll need to get it
+ if (current_plugin == null) {
+ updated_plugins.add(latest_plugin); // we don't have any version of this plugin, we'll need to get it
+ if (LOG.isDebugEnabled()) {
LOG.debug(AgentI18NResourceKeys.NEED_MISSING_PLUGIN, plugin_filename);
- } else {
- if (latest_plugin.isEnabled() && !disabled_plugin_names.contains(latest_plugin.getName())) {
- String latest_md5 = latest_plugin.getMD5();
- String current_md5 = current_plugin.getMD5();
-
- if (!current_md5.equals(latest_md5)) {
- updated_plugins.add(latest_plugin);
- LOG.debug(AgentI18NResourceKeys.PLUGIN_NEEDS_TO_BE_UPDATED, plugin_filename,
- current_md5, latest_md5);
- } else {
- LOG.debug(AgentI18NResourceKeys.PLUGIN_ALREADY_AT_LATEST, plugin_filename);
+ }
+ } else {
+ if (latest_plugin.isEnabled() && !disabled_plugin_names.contains(latest_plugin.getName())) {
+ String latest_md5 = latest_plugin.getMD5();
+ String current_md5 = current_plugin.getMD5();
+
+ if (!current_md5.equals(latest_md5)) {
+ updated_plugins.add(latest_plugin);
+ if (LOG.isDebugEnabled()) {
+ LOG.debug(AgentI18NResourceKeys.PLUGIN_NEEDS_TO_BE_UPDATED, plugin_filename, current_md5,
+ latest_md5);
}
} else {
- // we have a plugin file locally, but it is to be disabled, so delete the plugin .jar
- File disabled_file = getPluginFile(latest_plugin);
- if (disabled_file.delete()) {
- LOG.info(AgentI18NResourceKeys.PLUGIN_DISABLED_PLUGIN_DELETED, disabled_file);
- } else {
- LOG.error(AgentI18NResourceKeys.PLUGIN_DISABLED_PLUGIN_DELETE_FAILED, disabled_file);
+ if (LOG.isDebugEnabled()) {
+ LOG.debug(AgentI18NResourceKeys.PLUGIN_ALREADY_AT_LATEST, plugin_filename);
}
}
+ } else {
+ // we have a plugin file locally, but it is to be disabled, so delete the plugin .jar
+ File disabled_file = getPluginFile(latest_plugin);
+ if (disabled_file.delete()) {
+ LOG.info(AgentI18NResourceKeys.PLUGIN_DISABLED_PLUGIN_DELETED, disabled_file);
+ } else {
+ LOG.error(AgentI18NResourceKeys.PLUGIN_DISABLED_PLUGIN_DELETE_FAILED, disabled_file);
+ }
}
}
+ }
- deleteIllegitimatePlugins(current_plugins, latest_plugins_map);
-
- // Let's go ahead and download all the plugins that we need.
- // Try to update all plugins, even if one or more fails to update. At the end,
- // if an exception was thrown, we'll rethrow it but only after all update attempts were made
- // NOTE: we do not download any plugins that are to be disabled
- Exception last_error = null;
-
- for (Plugin updated_plugin : updated_plugins) {
- String name = updated_plugin.getName();
- if (updated_plugin.isEnabled() && !disabled_plugin_names.contains(name)) {
- try {
- downloadPluginWithRetries(updated_plugin); // tries our very best to get it
- } catch (Exception e) {
- last_error = e;
- }
- } else {
- LOG.info(AgentI18NResourceKeys.PLUGIN_DISABLED_PLUGIN_DOWNLOAD_SKIPPED, name);
- updated_plugin.setEnabled(false);
+ deleteIllegitimatePlugins(current_plugins, latest_plugins_map);
+
+ // Let's go ahead and download all the plugins that we need.
+ // Try to update all plugins, even if one or more fails to update. At the end,
+ // if an exception was thrown, we'll rethrow it but only after all update attempts were made
+ // NOTE: we do not download any plugins that are to be disabled
+ Exception last_error = null;
+
+ for (Plugin updated_plugin : updated_plugins) {
+ String name = updated_plugin.getName();
+ if (updated_plugin.isEnabled() && !disabled_plugin_names.contains(name)) {
+ try {
+ downloadPluginWithRetries(updated_plugin); // tries our very best to get it
+ } catch (Exception e) {
+ last_error = e;
}
+ } else {
+ LOG.info(AgentI18NResourceKeys.PLUGIN_DISABLED_PLUGIN_DOWNLOAD_SKIPPED, name);
+ updated_plugin.setEnabled(false);
}
+ }
- if (last_error != null) {
- throw last_error;
- }
- } finally {
- deleteMarkerFile();
+ if (last_error != null) {
+ throw last_error;
}
} finally {
- PluginUpdate.lock.writeLock().unlock();
+ SEMAPHORE.release();
}
LOG.info(AgentI18NResourceKeys.UPDATING_PLUGINS_COMPLETE);
@@ -408,39 +369,6 @@ public class PluginUpdate {
return plugins;
}
- private void createMarkerFile() {
- File marker = null;
- try {
- marker = new File(config.getPluginDirectory(), MARKER_FILENAME);
-
- // shouldn't exist, but if it does, oh well, just reuse it
- if (!marker.exists()) {
- new FileOutputStream(marker).close();
- }
- } catch (Exception e) {
- LOG.warn(AgentI18NResourceKeys.UPDATING_PLUGINS_MARKER_CREATE_FAILURE, marker, e);
- }
-
- return;
- }
-
- private void deleteMarkerFile() {
- try {
- File marker = new File(config.getPluginDirectory(), MARKER_FILENAME);
-
- // it should exist, but if it doesn't oh well, just skip trying to delete it
- if (marker.exists()) {
- if (!marker.delete()) {
- LOG.warn(AgentI18NResourceKeys.UPDATING_PLUGINS_MARKER_DELETE_FAILURE, marker);
- }
- }
- } catch (Throwable t) {
- LOG.warn(AgentI18NResourceKeys.UPDATING_PLUGINS_MARKER_DELETE_FAILURE, MARKER_FILENAME);
- }
-
- return;
- }
-
private void deleteIllegitimatePlugins(Map<String, Plugin> current_plugins, Map<String, Plugin> latest_plugins_map) {
for (Plugin current_plugin : current_plugins.values()) {
if (!latest_plugins_map.containsKey(current_plugin.getPath())) {
@@ -473,4 +401,4 @@ public class PluginUpdate {
File file = new File(plugin_dir, plugin_filename);
return file;
}
-}
\ No newline at end of file
+}
diff --git a/modules/enterprise/agent/src/main/java/org/rhq/enterprise/agent/i18n/AgentI18NResourceKeys.java b/modules/enterprise/agent/src/main/java/org/rhq/enterprise/agent/i18n/AgentI18NResourceKeys.java
index 16c110a..8c35d13 100644
--- a/modules/enterprise/agent/src/main/java/org/rhq/enterprise/agent/i18n/AgentI18NResourceKeys.java
+++ b/modules/enterprise/agent/src/main/java/org/rhq/enterprise/agent/i18n/AgentI18NResourceKeys.java
@@ -1,6 +1,6 @@
/*
* RHQ Management Platform
- * Copyright (C) 2005-2010 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.agent.i18n;
@@ -356,12 +356,6 @@ public interface AgentI18NResourceKeys {
@I18NMessage("Completed updating the plugins to their latest versions.")
String UPDATING_PLUGINS_COMPLETE = "PluginUpdate.updating-complete";
- @I18NMessage("Failed to create updater marker file [{0}] - will continue but agent startup may fail. If so, restart agent. Cause. {1}")
- String UPDATING_PLUGINS_MARKER_CREATE_FAILURE = "PluginUpdate.marker-create-failure";
-
- @I18NMessage("Failed to delete updater marker file [{0}] - will continue but agent startup may fail. If so, delete the file manually.")
- String UPDATING_PLUGINS_MARKER_DELETE_FAILURE = "PluginUpdate.marker-delete-failure";
-
@I18NMessage("The plugin [{0}] is current and does not need to be updated.")
String PLUGIN_ALREADY_AT_LATEST = "PluginUpdate.already-at-latest";
@@ -1608,10 +1602,10 @@ public interface AgentI18NResourceKeys {
@I18NMessage("The agent will now wait until it has registered with the server...")
String WAITING_TO_BE_REGISTERED_BEGIN = "AgentMain.waiting-to-be-registered-begin";
- @I18NMessage("The agent does not have plugins - it will now wait for them to be downloaded...")
+ @I18NMessage("The agent is waiting for plugins to be downloaded...")
String WAITING_FOR_PLUGINS = "AgentMain.waiting-for-plugins";
- @I18NMessage("The agent does not have plugins - it will now wait for them to be downloaded to [{0}]...")
+ @I18NMessage("The agent is waiting for plugins to be downloaded to [{0}]...")
String WAITING_FOR_PLUGINS_WITH_DIR = "AgentMain.waiting-for-plugins-with-dir";
@I18NMessage("[{0}] plugins downloaded.")
10 years
[rhq] modules/plugins
by Jean-Frederic Clere
modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatDiscoveryComponent.java | 68 +++++-----
1 file changed, 34 insertions(+), 34 deletions(-)
New commits:
commit 003b64a68d29f99c134749e6c9d7db8e8e61837c
Author: Jean-Frederic Clere <jfclere(a)redhat.com>
Date: Thu Nov 28 15:36:35 2013 +0100
[BZ 971615] Tomcat plugin ignores processes if container running as 'rhq' user
Submitted by Elias Ross (genman(a)noderunner.net)
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 0537e7e..602f1ff 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
@@ -59,9 +59,8 @@ import org.rhq.plugins.jmx.JMXDiscoveryComponent;
*
* @author Jay Shaughnessy
*/
-@SuppressWarnings("unchecked")
public class TomcatDiscoveryComponent implements ResourceDiscoveryComponent, ManualAddFacet {
- private final Log log = LogFactory.getLog(this.getClass());
+ private static final Log LOG = LogFactory.getLog(TomcatDiscoveryComponent.class);
/**
* Indicates the version information could not be determined.
@@ -111,28 +110,29 @@ public class TomcatDiscoveryComponent implements ResourceDiscoveryComponent, Man
public static final String EWS_TOMCAT_5 = "tomcat5";
public Set<DiscoveredResourceDetails> discoverResources(ResourceDiscoveryContext context) {
- log.debug("Discovering Tomcat servers...");
+ LOG.debug("Discovering Tomcat servers...");
Set<DiscoveredResourceDetails> resources = new HashSet<DiscoveredResourceDetails>();
// For each Tomcat process found in the context, create a resource details instance
+ @SuppressWarnings("unchecked")
List<ProcessScanResult> autoDiscoveryResults = context.getAutoDiscoveredProcesses();
for (ProcessScanResult autoDiscoveryResult : autoDiscoveryResults) {
- if (log.isDebugEnabled()) {
- log.debug("Discovered potential Tomcat process: " + autoDiscoveryResult);
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Discovered potential Tomcat process: " + autoDiscoveryResult);
}
try {
DiscoveredResourceDetails resource = parseTomcatProcess(context, autoDiscoveryResult);
if (resource != null) {
- if (log.isDebugEnabled()) {
- log.debug("Verified Tomcat process: " + autoDiscoveryResult);
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Verified Tomcat process: " + autoDiscoveryResult);
}
resources.add(resource);
}
} catch (Exception e) {
- log.error("Error creating discovered resource for process: " + autoDiscoveryResult, e);
+ LOG.error("Error creating discovered resource for process: " + autoDiscoveryResult, e);
}
}
@@ -146,7 +146,7 @@ public class TomcatDiscoveryComponent implements ResourceDiscoveryComponent, Man
try {
catalinaHome = FileUtils.getCanonicalPath(catalinaHome);
} catch (Exception e) {
- log.warn("Failed to canonicalize catalina.home path [" + catalinaHome + "] - cause: " + e);
+ LOG.warn("Failed to canonicalize catalina.home path [" + catalinaHome + "] - cause: " + e);
// leave as is
}
File catalinaHomeDir = new File(catalinaHome);
@@ -156,7 +156,7 @@ public class TomcatDiscoveryComponent implements ResourceDiscoveryComponent, Man
try {
catalinaBase = FileUtils.getCanonicalPath(catalinaBase);
} catch (Exception e) {
- log.warn("Failed to canonicalize catalina.base path [" + catalinaBase + "] - cause: " + e);
+ LOG.warn("Failed to canonicalize catalina.base path [" + catalinaBase + "] - cause: " + e);
// leave as is
}
@@ -172,8 +172,8 @@ public class TomcatDiscoveryComponent implements ResourceDiscoveryComponent, Man
// if the specified home dir does not exist locally assume this is a remote Tomcat server
// We can't determine version. Try to get the hostname from the connect url
if (!catalinaHomeDir.isDirectory()) {
- log.info("Manually added Tomcat Server directory does not exist locally. Assuming remote Tomcat Server: "
- + catalinaHome);
+ LOG.info("Manually added Tomcat Server directory does not exist locally. Assuming remote Tomcat Server: "
+ + catalinaHome);
Matcher matcher = TOMCAT_MANAGER_URL_PATTERN.matcher(pluginConfig.getSimpleValue(
JMXDiscoveryComponent.CONNECTOR_ADDRESS_CONFIG_PROPERTY, null));
@@ -207,7 +207,9 @@ public class TomcatDiscoveryComponent implements ResourceDiscoveryComponent, Man
DiscoveredResourceDetails resource = new DiscoveredResourceDetails(discoveryContext.getResourceType(),
resourceKey, resourceName, version, productDescription, pluginConfig, null);
- log.debug("Verified manually-added Tomcat Resource with plugin config: " + pluginConfig);
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Verified manually-added Tomcat Resource with plugin config: " + pluginConfig);
+ }
return resource;
}
@@ -227,22 +229,18 @@ public class TomcatDiscoveryComponent implements ResourceDiscoveryComponent, Man
ProcessInfo processInfo = autoDiscoveryResult.getProcessInfo();
String[] commandLine = processInfo.getCommandLine();
- if (null == processInfo.getExecutable()) {
- log.debug("Ignoring Tomcat instance (agent may not be owner) with following command line: "
- + Arrays.toString(commandLine));
- return null;
- }
-
if (!isStandalone(commandLine) && !isWindows(context)) {
- log.debug("Ignoring embedded Tomcat instance (catalina.home not found) with following command line: "
- + Arrays.toString(commandLine));
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Ignoring embedded Tomcat instance (catalina.home not found) with following command line: "
+ + Arrays.toString(commandLine));
+ }
return null;
}
String catalinaHome = determineCatalinaHome(commandLine);
if (catalinaHome == null && isWindows(context)) {
- log.debug("catalina.home not found. Checking to see if this is an EWS installation.");
+ LOG.debug("catalina.home not found. Checking to see if this is an EWS installation.");
// 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.
@@ -252,15 +250,15 @@ public class TomcatDiscoveryComponent implements ResourceDiscoveryComponent, Man
}
if (null == catalinaHome) {
- log.error("Ignoring Tomcat instance due to invalid setting of catalina.home in command line: "
- + Arrays.toString(commandLine));
+ LOG.error("Ignoring Tomcat instance due to invalid setting of catalina.home in command line: "
+ + Arrays.toString(commandLine));
return null;
}
String catalinaBase = determineCatalinaBase(commandLine, catalinaHome);
if (null == catalinaBase) {
- log.error("Ignoring Tomcat instance due to invalid setting of catalina.base in command line: "
- + Arrays.toString(commandLine));
+ LOG.error("Ignoring Tomcat instance due to invalid setting of catalina.base in command line: "
+ + Arrays.toString(commandLine));
return null;
}
@@ -313,7 +311,7 @@ public class TomcatDiscoveryComponent implements ResourceDiscoveryComponent, Man
* Looks for tomcat home in the command line properties. Requires a full path for the catalina.home
* property. The path may be a symbolic link.
*
- * @param startup command line
+ * @param cmdLine startup command line
*
* @return A canonical form of the catalina home path set in the command line. Symbolic links
* are not resolved to ensure that we discover the same resource repeatedly for the same symlink
@@ -386,14 +384,16 @@ public class TomcatDiscoveryComponent implements ResourceDiscoveryComponent, Man
if (tomcatInstallDirs.length == 0) {
return null;
} else if (tomcatInstallDirs.length > 1) {
- log.warn("Could not unambiguously determine the tomcat installation dir for EWS executable " + exePath.getAbsolutePath() + ". The candidates are: " + Arrays.asList(tomcatInstallDirs));
+ LOG.warn("Could not unambiguously determine the tomcat installation dir for EWS executable " + exePath.getAbsolutePath() + ". The candidates are: " + Arrays.asList(tomcatInstallDirs));
return null;
}
File tomcatDir = tomcatInstallDirs[0];
if (tomcatDir.exists()) {
- log.debug("Detected EWS installation. catalina.home found at " + tomcatDir.getAbsolutePath());
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Detected EWS installation. catalina.home found at " + tomcatDir.getAbsolutePath());
+ }
return tomcatDir.getAbsolutePath();
}
@@ -404,7 +404,7 @@ public class TomcatDiscoveryComponent implements ResourceDiscoveryComponent, Man
* Looks for tomcat instance base in the command line properties. Requires a full path for the catalina.base, if
* specified. The path may be a symbolic link.
*
- * @param startup command line
+ * @param cmdLine startup command line
*
* @return A canonical form of the catalina base path if set in the command line. Symbolic links
* are not resolved to ensure that we discover the same resource repeatedly for the same symlink
@@ -464,7 +464,7 @@ public class TomcatDiscoveryComponent implements ResourceDiscoveryComponent, Man
File versionScriptFile = new File(versionScriptFileName);
if (!versionScriptFile.exists()) {
- log.warn("Version script file not found in expected location: " + versionScriptFile);
+ LOG.warn("Version script file not found in expected location: " + versionScriptFile);
return UNKNOWN_VERSION;
}
@@ -482,8 +482,8 @@ public class TomcatDiscoveryComponent implements ResourceDiscoveryComponent, Man
String version = getVersionFromVersionScriptOutput(versionOutput);
if (UNKNOWN_VERSION.equals(version)) {
- log.warn("Failed to determine Tomcat Server Version Given:\nVersionInfo:" + versionOutput
- + "\ncatalinaHome: " + catalinaHome + "\nScript:" + versionScriptFileName + "\ntimeout=" + timeout);
+ LOG.warn("Failed to determine Tomcat Server Version Given:\nVersionInfo:" + versionOutput
+ + "\ncatalinaHome: " + catalinaHome + "\nScript:" + versionScriptFileName + "\ntimeout=" + timeout);
}
return version;
@@ -552,7 +552,7 @@ public class TomcatDiscoveryComponent implements ResourceDiscoveryComponent, Man
/**
* Check from the command line if this is an EWS tomcat
*
- * @param commandLine
+ * @param catalinaHome
*
* @return
*/
10 years
[rhq] modules/plugins
by Thomas Segismont
modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/QueryCacheDiscovery.java | 76 ++++++++++
modules/plugins/jboss-as-7/src/main/resources/META-INF/rhq-plugin.xml | 7
2 files changed, 79 insertions(+), 4 deletions(-)
New commits:
commit 583c119780e0d69727de6c2a7bd6aaca33b22b69
Author: Thomas Segismont <tsegismo(a)redhat.com>
Date: Thu Nov 28 15:18:06 2013 +0100
Bug 1033130 - [AS7] Exception during discovery of Query Cache resources of RHQ Server resource
Query Cache management nodes have a very long name. So the default discovery class was creating a too long resource key and name.
Now there is a dedicated discovery class for Query Cache resources and the resource key and name are just the hash of the query-name attribute.
diff --git a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/QueryCacheDiscovery.java b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/QueryCacheDiscovery.java
new file mode 100644
index 0000000..48a972f
--- /dev/null
+++ b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/QueryCacheDiscovery.java
@@ -0,0 +1,76 @@
+/*
+ * 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.modules.plugins.jbossas7;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.rhq.core.domain.configuration.Configuration;
+import org.rhq.core.pluginapi.inventory.DiscoveredResourceDetails;
+import org.rhq.core.pluginapi.inventory.InvalidPluginConfigurationException;
+import org.rhq.core.pluginapi.inventory.ResourceDiscoveryComponent;
+import org.rhq.core.pluginapi.inventory.ResourceDiscoveryContext;
+import org.rhq.core.util.MessageDigestGenerator;
+import org.rhq.modules.plugins.jbossas7.json.Address;
+import org.rhq.modules.plugins.jbossas7.json.ReadChildrenNames;
+import org.rhq.modules.plugins.jbossas7.json.Result;
+
+/**
+ * @author Thomas Segismont
+ */
+public class QueryCacheDiscovery implements ResourceDiscoveryComponent<BaseComponent<?>> {
+ private static final String QUERY_CACHE_TYPE_NAME = "query-cache";
+ private static final String RESOURCE_NAME_PREFIX = "Query Cache ";
+
+ @Override
+ public Set<DiscoveredResourceDetails> discoverResources(ResourceDiscoveryContext<BaseComponent<?>> context)
+ throws InvalidPluginConfigurationException {
+
+ BaseComponent parentComponent = context.getParentResourceComponent();
+ String parentComponentPath = parentComponent.getPath();
+ Address parentAddress = new Address(parentComponentPath);
+
+ Result readChildrenNamesResult = parentComponent.getASConnection().execute(
+ new ReadChildrenNames(parentAddress, QUERY_CACHE_TYPE_NAME));
+
+ if (readChildrenNamesResult.isSuccess()) {
+ Set<DiscoveredResourceDetails> details = new HashSet<DiscoveredResourceDetails>();
+ List<String> childrenNames = (List<String>) readChildrenNamesResult.getResult();
+ for (String childName : childrenNames) {
+ Configuration pluginConfiguration = context.getDefaultPluginConfiguration();
+ pluginConfiguration.setSimpleValue("path", parentComponentPath + "," + QUERY_CACHE_TYPE_NAME + "="
+ + childName);
+ String resourceKey = MessageDigestGenerator.getDigestString(childName);
+ details.add( //
+ new DiscoveredResourceDetails( //
+ context.getResourceType(), // DataType
+ resourceKey, // Key
+ RESOURCE_NAME_PREFIX + resourceKey, // Name
+ null, // Version
+ context.getResourceType().getDescription(), // subsystem.description
+ pluginConfiguration, null));
+ }
+ return details;
+ }
+ return Collections.emptySet();
+ }
+}
diff --git a/modules/plugins/jboss-as-7/src/main/resources/META-INF/rhq-plugin.xml b/modules/plugins/jboss-as-7/src/main/resources/META-INF/rhq-plugin.xml
index 39aa818..4e0bf38 100644
--- a/modules/plugins/jboss-as-7/src/main/resources/META-INF/rhq-plugin.xml
+++ b/modules/plugins/jboss-as-7/src/main/resources/META-INF/rhq-plugin.xml
@@ -10131,12 +10131,11 @@
<service name="Query Cache"
class="BaseComponent"
- discovery="SubsystemDiscovery"
- description="Statistics for individual queries."
- singleton="true">
+ discovery="QueryCacheDiscovery"
+ description="Statistics for individual queries.">
<plugin-configuration>
- <c:simple-property name="path" default="query-cache" readOnly="true"/>
+ <c:simple-property name="path" readOnly="true"/>
</plugin-configuration>
<metric property="query-cache-hit-count" displayType="summary" measurementType="trendsup" description="Get the number of times query was retrieved from cache."/>
10 years
[rhq] Branch 'release/jon3.2.x' - modules/enterprise
by lkrejci
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/measurement/MeasurementScheduleManagerBean.java | 3 -
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/util/CriteriaQueryGenerator.java | 24 +++++++++-
2 files changed, 25 insertions(+), 2 deletions(-)
New commits:
commit ea707eaf2cb4650b15a04ea1d8c228961807bbac
Author: Lukas Krejci <lkrejci(a)redhat.com>
Date: Thu Nov 28 13:39:26 2013 +0100
[BZ 1035767] - Enable altering count query along with alterProjection
If CriteriaQueryGeneration.alterProjection changes the projection such
that the actual number of returned results changes (e.g. using distinct),
the default count query would no longer match and the returned results
would be inconsistent with the count found by the count query.
Because alterProjection is essentially free-form JPQL, we need to provide
a similar means to alter the count query so that the data query and count
query can be modified to return consistent data.
(cherry picked from commit 25f768afb5c72e5eb0fa17c6789b3b8aaa895be9)
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/measurement/MeasurementScheduleManagerBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/measurement/MeasurementScheduleManagerBean.java
index d53a037..5d5c48a 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/measurement/MeasurementScheduleManagerBean.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/measurement/MeasurementScheduleManagerBean.java
@@ -1485,6 +1485,7 @@ public class MeasurementScheduleManagerBean implements MeasurementScheduleManage
// the JPQL above, I've chosen to just make a change to the custom altered projection, using
// the JPQL to guide me.
generator.alterProjection(" distinct orderingField0");
+ generator.alterCountProjection(" count(distinct orderingField0)");
CriteriaQueryRunner<MeasurementDefinition> queryRunner = new CriteriaQueryRunner(criteria, generator,
entityManager);
definitions = queryRunner.execute();
@@ -1609,4 +1610,4 @@ public class MeasurementScheduleManagerBean implements MeasurementScheduleManage
// }
// }
-}
\ No newline at end of file
+}
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/util/CriteriaQueryGenerator.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/util/CriteriaQueryGenerator.java
index a1f3122..36b3770 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/util/CriteriaQueryGenerator.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/util/CriteriaQueryGenerator.java
@@ -84,6 +84,7 @@ public final class CriteriaQueryGenerator {
private String alias;
private String className;
private String projection;
+ private String countProjection;
private String groupByClause;
private String havingClause;
private static String NL = System.getProperty("line.separator");
@@ -411,7 +412,10 @@ public final class CriteriaQueryGenerator {
boolean useJoinFetch = projection == null && pc.isUnlimited() && !fetchFields.isEmpty();
if (countQuery) {
- if (groupByClause == null) { // non-grouped method
+ if (countProjection != null) {
+ //just use whatever we are told
+ results.append(countProjection).append(NL);
+ } else if (groupByClause == null) { // non-grouped method
// use count(*) instead of count(alias) due to https://bugzilla.redhat.com/show_bug.cgi?id=699842
results.append("COUNT(*)").append(NL);
} else {
@@ -840,6 +844,24 @@ public final class CriteriaQueryGenerator {
this.projection = projection;
}
+ /**
+ * Sometimes the altered projection ({@link #alterProjection(String)}) might cause the result set to have different
+ * number of results than the default/unaltered projection. Leaving the count query in the default form could then
+ * generate seemingly inconsistent results, where the data query and the count query wouldn't match up.
+ * <p/>
+ * An example of a projection that might alter the number of results is the {@code " distinct ..."} projection that
+ * would only return distinct results from a dataset, while the default count query (COUNT(*)) would produce the
+ * count including duplicate results that were eliminated in the returned data.
+ * <p/>
+ * In these cases one can also alter the count query to count the results the data query will return.
+ *
+ * @param countProjection a complete JPQL fragment expressing the count expression (e.g.
+ * {@code COUNT(DISTINCT ...)})
+ */
+ public void alterCountProjection(String countProjection) {
+ this.countProjection = countProjection;
+ }
+
public boolean isProjectionAltered() {
return this.projection != null;
}
10 years